Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2064,13 +2064,13 @@ A->getType()->isIntOrIntVectorTy(1)) return SelectInst::Create(A, Op0, Constant::getNullValue(Ty)); - // and(ashr(subNSW(Y, X), ScalarSizeInBits(Y)-1), X) --> X s> Y ? X : 0. - if (match(&I, m_c_And(m_OneUse(m_AShr( - m_NSWSub(m_Value(Y), m_Value(X)), - m_SpecificInt(Ty->getScalarSizeInBits() - 1))), - m_Deferred(X)))) { - Value *NewICmpInst = Builder.CreateICmpSGT(X, Y); - return SelectInst::Create(NewICmpInst, X, ConstantInt::getNullValue(Ty)); + // (iN X s>> (N-1)) & Y --> (X < 0) ? Y : 0 + unsigned FullShift = Ty->getScalarSizeInBits() - 1; + if (match(&I, m_c_And(m_OneUse(m_AShr(m_Value(X), m_SpecificInt(FullShift))), + m_Value(Y)))) { + Constant *Zero = ConstantInt::getNullValue(Ty); + Value *Cmp = Builder.CreateICmpSLT(X, Zero, "isneg"); + return SelectInst::Create(Cmp, Y, Zero); } // (~x) & y --> ~(x | (~y)) iff that gets rid of inversions Index: llvm/test/Transforms/InstCombine/and.ll =================================================================== --- llvm/test/Transforms/InstCombine/and.ll +++ llvm/test/Transforms/InstCombine/and.ll @@ -1403,8 +1403,8 @@ define i8 @ashr_bitwidth_mask(i8 %x, i8 %y) { ; CHECK-LABEL: @ashr_bitwidth_mask( -; CHECK-NEXT: [[SIGN:%.*]] = ashr i8 [[X:%.*]], 7 -; CHECK-NEXT: [[NEG_OR_ZERO:%.*]] = and i8 [[SIGN]], [[Y:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i8 [[X:%.*]], 0 +; CHECK-NEXT: [[NEG_OR_ZERO:%.*]] = select i1 [[ISNEG]], i8 [[Y:%.*]], i8 0 ; CHECK-NEXT: ret i8 [[NEG_OR_ZERO]] ; %sign = ashr i8 %x, 7 @@ -1415,8 +1415,8 @@ define <2 x i8> @ashr_bitwidth_mask_vec_commute(<2 x i8> %x, <2 x i8> %py) { ; CHECK-LABEL: @ashr_bitwidth_mask_vec_commute( ; CHECK-NEXT: [[Y:%.*]] = mul <2 x i8> [[PY:%.*]], -; CHECK-NEXT: [[SIGN:%.*]] = ashr <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[NEG_OR_ZERO:%.*]] = and <2 x i8> [[Y]], [[SIGN]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer +; CHECK-NEXT: [[NEG_OR_ZERO:%.*]] = select <2 x i1> [[ISNEG]], <2 x i8> [[Y]], <2 x i8> zeroinitializer ; CHECK-NEXT: ret <2 x i8> [[NEG_OR_ZERO]] ; %y = mul <2 x i8> %py, ; thwart complexity-based ordering @@ -1425,6 +1425,8 @@ ret <2 x i8> %neg_or_zero } +; negative test - extra use + define i8 @ashr_bitwidth_mask_use(i8 %x, i8 %y) { ; CHECK-LABEL: @ashr_bitwidth_mask_use( ; CHECK-NEXT: [[SIGN:%.*]] = ashr i8 [[X:%.*]], 7 @@ -1438,6 +1440,8 @@ ret i8 %r } +; negative test - wrong shift amount + define i8 @ashr_not_bitwidth_mask(i8 %x, i8 %y) { ; CHECK-LABEL: @ashr_not_bitwidth_mask( ; CHECK-NEXT: [[SIGN:%.*]] = ashr i8 [[X:%.*]], 6 @@ -1449,6 +1453,8 @@ ret i8 %r } +; negative test - wrong shift opcode + define i8 @lshr_bitwidth_mask(i8 %x, i8 %y) { ; CHECK-LABEL: @lshr_bitwidth_mask( ; CHECK-NEXT: [[SIGN:%.*]] = lshr i8 [[X:%.*]], 7 Index: llvm/test/Transforms/InstCombine/icmp.ll =================================================================== --- llvm/test/Transforms/InstCombine/icmp.ll +++ llvm/test/Transforms/InstCombine/icmp.ll @@ -100,8 +100,8 @@ define i32 @test6(i32 %a, i32 %b) { ; CHECK-LABEL: @test6( -; CHECK-NEXT: [[A_LOBIT_NEG:%.*]] = ashr i32 [[A:%.*]], 31 -; CHECK-NEXT: [[F:%.*]] = and i32 [[A_LOBIT_NEG]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0 +; CHECK-NEXT: [[F:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0 ; CHECK-NEXT: ret i32 [[F]] ; %c = icmp sle i32 %a, -1 Index: llvm/test/Transforms/InstCombine/mul-inseltpoison.ll =================================================================== --- llvm/test/Transforms/InstCombine/mul-inseltpoison.ll +++ llvm/test/Transforms/InstCombine/mul-inseltpoison.ll @@ -45,8 +45,8 @@ define i32 @test10(i32 %a, i32 %b) { ; CHECK-LABEL: @test10( -; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31 -; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0 +; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0 ; CHECK-NEXT: ret i32 [[E]] ; %c = icmp slt i32 %a, 0 @@ -57,8 +57,8 @@ define i32 @test11(i32 %a, i32 %b) { ; CHECK-LABEL: @test11( -; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31 -; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0 +; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0 ; CHECK-NEXT: ret i32 [[E]] ; %c = icmp sle i32 %a, -1 @@ -72,8 +72,8 @@ define i32 @test12(i32 %a, i32 %b) { ; CHECK-LABEL: @test12( ; CHECK-NEXT: [[A_LOBIT:%.*]] = lshr i32 [[A:%.*]], 31 -; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A]], 31 -; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A]], 0 +; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0 ; CHECK-NEXT: call void @use32(i32 [[A_LOBIT]]) ; CHECK-NEXT: ret i32 [[E]] ; @@ -310,8 +310,8 @@ define i32 @signbit_mul(i32 %a, i32 %b) { ; CHECK-LABEL: @signbit_mul( -; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31 -; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0 +; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0 ; CHECK-NEXT: ret i32 [[E]] ; %d = lshr i32 %a, 31 @@ -322,8 +322,8 @@ define i32 @signbit_mul_commute_extra_use(i32 %a, i32 %b) { ; CHECK-LABEL: @signbit_mul_commute_extra_use( ; CHECK-NEXT: [[D:%.*]] = lshr i32 [[A:%.*]], 31 -; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A]], 31 -; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A]], 0 +; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0 ; CHECK-NEXT: call void @use32(i32 [[D]]) ; CHECK-NEXT: ret i32 [[E]] ; @@ -337,8 +337,8 @@ define <2 x i32> @signbit_mul_vec(<2 x i32> %a, <2 x i32> %b) { ; CHECK-LABEL: @signbit_mul_vec( -; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i32> [[A:%.*]], -; CHECK-NEXT: [[E:%.*]] = and <2 x i32> [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i32> [[A:%.*]], zeroinitializer +; CHECK-NEXT: [[E:%.*]] = select <2 x i1> [[ISNEG]], <2 x i32> [[B:%.*]], <2 x i32> zeroinitializer ; CHECK-NEXT: ret <2 x i32> [[E]] ; %d = lshr <2 x i32> %a, @@ -348,8 +348,8 @@ define <2 x i32> @signbit_mul_vec_commute(<2 x i32> %a, <2 x i32> %b) { ; CHECK-LABEL: @signbit_mul_vec_commute( -; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i32> [[A:%.*]], -; CHECK-NEXT: [[E:%.*]] = and <2 x i32> [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i32> [[A:%.*]], zeroinitializer +; CHECK-NEXT: [[E:%.*]] = select <2 x i1> [[ISNEG]], <2 x i32> [[B:%.*]], <2 x i32> zeroinitializer ; CHECK-NEXT: ret <2 x i32> [[E]] ; %d = lshr <2 x i32> %a, Index: llvm/test/Transforms/InstCombine/mul.ll =================================================================== --- llvm/test/Transforms/InstCombine/mul.ll +++ llvm/test/Transforms/InstCombine/mul.ll @@ -45,8 +45,8 @@ define i32 @test10(i32 %a, i32 %b) { ; CHECK-LABEL: @test10( -; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31 -; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0 +; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0 ; CHECK-NEXT: ret i32 [[E]] ; %c = icmp slt i32 %a, 0 @@ -57,8 +57,8 @@ define i32 @test11(i32 %a, i32 %b) { ; CHECK-LABEL: @test11( -; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31 -; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0 +; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0 ; CHECK-NEXT: ret i32 [[E]] ; %c = icmp sle i32 %a, -1 @@ -72,8 +72,8 @@ define i32 @test12(i32 %a, i32 %b) { ; CHECK-LABEL: @test12( ; CHECK-NEXT: [[A_LOBIT:%.*]] = lshr i32 [[A:%.*]], 31 -; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A]], 31 -; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A]], 0 +; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0 ; CHECK-NEXT: call void @use32(i32 [[A_LOBIT]]) ; CHECK-NEXT: ret i32 [[E]] ; @@ -376,12 +376,12 @@ ret i32 %r } -; (A >>u 31) * B --> (A >>s 31) & B +; (A >>u 31) * B --> (A >>s 31) & B --> A < 0 ? B : 0 define i32 @signbit_mul(i32 %a, i32 %b) { ; CHECK-LABEL: @signbit_mul( -; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31 -; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0 +; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0 ; CHECK-NEXT: ret i32 [[E]] ; %d = lshr i32 %a, 31 @@ -392,8 +392,8 @@ define i32 @signbit_mul_commute_extra_use(i32 %a, i32 %b) { ; CHECK-LABEL: @signbit_mul_commute_extra_use( ; CHECK-NEXT: [[D:%.*]] = lshr i32 [[A:%.*]], 31 -; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A]], 31 -; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A]], 0 +; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0 ; CHECK-NEXT: call void @use32(i32 [[D]]) ; CHECK-NEXT: ret i32 [[E]] ; @@ -403,12 +403,12 @@ ret i32 %e } -; (A >>u 31)) * B --> (A >>s 31) & B +; (A >>u 31)) * B --> (A >>s 31) & B --> A < 0 ? B : 0 define <2 x i32> @signbit_mul_vec(<2 x i32> %a, <2 x i32> %b) { ; CHECK-LABEL: @signbit_mul_vec( -; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i32> [[A:%.*]], -; CHECK-NEXT: [[E:%.*]] = and <2 x i32> [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i32> [[A:%.*]], zeroinitializer +; CHECK-NEXT: [[E:%.*]] = select <2 x i1> [[ISNEG]], <2 x i32> [[B:%.*]], <2 x i32> zeroinitializer ; CHECK-NEXT: ret <2 x i32> [[E]] ; %d = lshr <2 x i32> %a, @@ -418,8 +418,8 @@ define <2 x i32> @signbit_mul_vec_commute(<2 x i32> %a, <2 x i32> %b) { ; CHECK-LABEL: @signbit_mul_vec_commute( -; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i32> [[A:%.*]], -; CHECK-NEXT: [[E:%.*]] = and <2 x i32> [[TMP1]], [[B:%.*]] +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i32> [[A:%.*]], zeroinitializer +; CHECK-NEXT: [[E:%.*]] = select <2 x i1> [[ISNEG]], <2 x i32> [[B:%.*]], <2 x i32> zeroinitializer ; CHECK-NEXT: ret <2 x i32> [[E]] ; %d = lshr <2 x i32> %a, Index: llvm/test/Transforms/InstCombine/sub-ashr-and-to-icmp-select.ll =================================================================== --- llvm/test/Transforms/InstCombine/sub-ashr-and-to-icmp-select.ll +++ llvm/test/Transforms/InstCombine/sub-ashr-and-to-icmp-select.ll @@ -131,8 +131,8 @@ ; CHECK-LABEL: @sub_ashr_and_i32_extra_use_sub( ; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: store i32 [[SUB]], i32* [[P:%.*]], align 4 -; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i32 [[Y]], [[X]] -; CHECK-NEXT: [[AND:%.*]] = select i1 [[TMP1]], i32 [[X]], i32 0 +; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[SUB]], 0 +; CHECK-NEXT: [[AND:%.*]] = select i1 [[ISNEG]], i32 [[X]], i32 0 ; CHECK-NEXT: ret i32 [[AND]] ; %sub = sub nsw i32 %y, %x