diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1369,6 +1369,13 @@ } } + // (A & 2^C1) + A => A & (2^C1 - 1) iff bit C1 in A is a sign bit + if (match(&I, m_c_Add(m_And(m_Value(A), m_APInt(C1)), m_Deferred(A))) && + C1->isPowerOf2() && (ComputeNumSignBits(A) > C1->countLeadingZeros())) { + Constant *NewMask = ConstantInt::get(RHS->getType(), *C1 - 1); + return BinaryOperator::CreateAnd(A, NewMask); + } + // A+B --> A|B iff A and B have no bits set in common. if (haveNoCommonBitsSet(LHS, RHS, DL, &AC, &I, &DT)) return BinaryOperator::CreateOr(LHS, RHS); diff --git a/llvm/test/Transforms/InstCombine/add-mask.ll b/llvm/test/Transforms/InstCombine/add-mask.ll --- a/llvm/test/Transforms/InstCombine/add-mask.ll +++ b/llvm/test/Transforms/InstCombine/add-mask.ll @@ -7,9 +7,8 @@ define i32 @add_mask_sign_i32(i32 %x) { ; CHECK-LABEL: @add_mask_sign_i32( -; CHECK-NEXT: [[A:%.*]] = ashr i32 [[X:%.*]], 31 -; CHECK-NEXT: [[M:%.*]] = and i32 [[A]], 8 -; CHECK-NEXT: [[R:%.*]] = add nsw i32 [[M]], [[A]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNEG]], i32 7, i32 0 ; CHECK-NEXT: ret i32 [[R]] ; %a = ashr i32 %x, 31 @@ -20,9 +19,8 @@ define i32 @add_mask_sign_commute_i32(i32 %x) { ; CHECK-LABEL: @add_mask_sign_commute_i32( -; CHECK-NEXT: [[A:%.*]] = ashr i32 [[X:%.*]], 31 -; CHECK-NEXT: [[M:%.*]] = and i32 [[A]], 8 -; CHECK-NEXT: [[R:%.*]] = add nsw i32 [[A]], [[M]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[R:%.*]] = select i1 [[ISNEG]], i32 7, i32 0 ; CHECK-NEXT: ret i32 [[R]] ; %a = ashr i32 %x, 31 @@ -33,9 +31,8 @@ define <2 x i32> @add_mask_sign_v2i32(<2 x i32> %x) { ; CHECK-LABEL: @add_mask_sign_v2i32( -; CHECK-NEXT: [[A:%.*]] = ashr <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[M:%.*]] = and <2 x i32> [[A]], -; CHECK-NEXT: [[R:%.*]] = add nsw <2 x i32> [[M]], [[A]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i32> [[X:%.*]], zeroinitializer +; CHECK-NEXT: [[R:%.*]] = select <2 x i1> [[ISNEG]], <2 x i32> , <2 x i32> zeroinitializer ; CHECK-NEXT: ret <2 x i32> [[R]] ; %a = ashr <2 x i32> %x, @@ -59,9 +56,8 @@ define i32 @add_mask_ashr28_i32(i32 %x) { ; CHECK-LABEL: @add_mask_ashr28_i32( -; CHECK-NEXT: [[A:%.*]] = ashr i32 [[X:%.*]], 28 -; CHECK-NEXT: [[M:%.*]] = and i32 [[A]], 8 -; CHECK-NEXT: [[R:%.*]] = add nsw i32 [[M]], [[A]] +; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], 28 +; CHECK-NEXT: [[R:%.*]] = and i32 [[TMP1]], 7 ; CHECK-NEXT: ret i32 [[R]] ; %a = ashr i32 %x, 28 diff --git a/llvm/test/Transforms/InstCombine/modulo.ll b/llvm/test/Transforms/InstCombine/modulo.ll --- a/llvm/test/Transforms/InstCombine/modulo.ll +++ b/llvm/test/Transforms/InstCombine/modulo.ll @@ -4,9 +4,7 @@ ; PR21929 define i32 @modulo2(i32 %x) { ; CHECK-LABEL: @modulo2( -; CHECK-NEXT: [[REM_I:%.*]] = srem i32 [[X:%.*]], 2 -; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[REM_I]], 2 -; CHECK-NEXT: [[RET_I:%.*]] = add nsw i32 [[TMP1]], [[REM_I]] +; CHECK-NEXT: [[RET_I:%.*]] = and i32 [[X:%.*]], 1 ; CHECK-NEXT: ret i32 [[RET_I]] ; %rem.i = srem i32 %x, 2 @@ -18,9 +16,7 @@ define <2 x i32> @modulo2_vec(<2 x i32> %x) { ; CHECK-LABEL: @modulo2_vec( -; CHECK-NEXT: [[REM_I:%.*]] = srem <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[REM_I]], -; CHECK-NEXT: [[RET_I:%.*]] = add nsw <2 x i32> [[TMP1]], [[REM_I]] +; CHECK-NEXT: [[RET_I:%.*]] = and <2 x i32> [[X:%.*]], ; CHECK-NEXT: ret <2 x i32> [[RET_I]] ; %rem.i = srem <2 x i32> %x, @@ -62,9 +58,7 @@ define i32 @modulo4(i32 %x) { ; CHECK-LABEL: @modulo4( -; CHECK-NEXT: [[REM_I:%.*]] = srem i32 [[X:%.*]], 4 -; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[REM_I]], 4 -; CHECK-NEXT: [[RET_I:%.*]] = add nsw i32 [[TMP1]], [[REM_I]] +; CHECK-NEXT: [[RET_I:%.*]] = and i32 [[X:%.*]], 3 ; CHECK-NEXT: ret i32 [[RET_I]] ; %rem.i = srem i32 %x, 4 @@ -76,9 +70,7 @@ define <2 x i32> @modulo4_vec(<2 x i32> %x) { ; CHECK-LABEL: @modulo4_vec( -; CHECK-NEXT: [[REM_I:%.*]] = srem <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[REM_I]], -; CHECK-NEXT: [[RET_I:%.*]] = add nsw <2 x i32> [[TMP1]], [[REM_I]] +; CHECK-NEXT: [[RET_I:%.*]] = and <2 x i32> [[X:%.*]], ; CHECK-NEXT: ret <2 x i32> [[RET_I]] ; %rem.i = srem <2 x i32> %x, @@ -120,9 +112,7 @@ define i32 @modulo32(i32 %x) { ; CHECK-LABEL: @modulo32( -; CHECK-NEXT: [[REM_I:%.*]] = srem i32 [[X:%.*]], 32 -; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[REM_I]], 32 -; CHECK-NEXT: [[RET_I:%.*]] = add nsw i32 [[TMP1]], [[REM_I]] +; CHECK-NEXT: [[RET_I:%.*]] = and i32 [[X:%.*]], 31 ; CHECK-NEXT: ret i32 [[RET_I]] ; %rem.i = srem i32 %x, 32 @@ -134,9 +124,7 @@ define <2 x i32> @modulo32_vec(<2 x i32> %x) { ; CHECK-LABEL: @modulo32_vec( -; CHECK-NEXT: [[REM_I:%.*]] = srem <2 x i32> [[X:%.*]], -; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[REM_I]], -; CHECK-NEXT: [[RET_I:%.*]] = add nsw <2 x i32> [[TMP1]], [[REM_I]] +; CHECK-NEXT: [[RET_I:%.*]] = and <2 x i32> [[X:%.*]], ; CHECK-NEXT: ret <2 x i32> [[RET_I]] ; %rem.i = srem <2 x i32> %x,