diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 11b39751b542f..55d48d7722a0c 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -2048,20 +2048,19 @@ bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth, return isKnownToBeAPowerOfTwo(I->getOperand(0), OrZero, Depth, Q); return false; case Instruction::Mul: - return OrZero && - isKnownToBeAPowerOfTwo(I->getOperand(1), OrZero, Depth, Q) && - isKnownToBeAPowerOfTwo(I->getOperand(0), OrZero, Depth, Q); + return isKnownToBeAPowerOfTwo(I->getOperand(1), OrZero, Depth, Q) && + isKnownToBeAPowerOfTwo(I->getOperand(0), OrZero, Depth, Q) && + (OrZero || isKnownNonZero(I, Depth, Q)); case Instruction::And: - if (OrZero) { - // A power of two and'd with anything is a power of two or zero. - if (isKnownToBeAPowerOfTwo(I->getOperand(1), /*OrZero*/ true, Depth, Q) || - isKnownToBeAPowerOfTwo(I->getOperand(0), /*OrZero*/ true, Depth, Q)) - return true; - // X & (-X) is always a power of two or zero. - if (match(I->getOperand(0), m_Neg(m_Specific(I->getOperand(1)))) || - match(I->getOperand(1), m_Neg(m_Specific(I->getOperand(0))))) - return true; - } + // A power of two and'd with anything is a power of two or zero. + if (OrZero && + (isKnownToBeAPowerOfTwo(I->getOperand(1), /*OrZero*/ true, Depth, Q) || + isKnownToBeAPowerOfTwo(I->getOperand(0), /*OrZero*/ true, Depth, Q))) + return true; + // X & (-X) is always a power of two or zero. + if (match(I->getOperand(0), m_Neg(m_Specific(I->getOperand(1)))) || + match(I->getOperand(1), m_Neg(m_Specific(I->getOperand(0))))) + return OrZero || isKnownNonZero(I->getOperand(0), Depth, Q); return false; case Instruction::Add: { // Adding a power-of-two or zero to the same power-of-two or zero yields diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp index 83defd5816f59..94fa9f14ffb95 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -941,6 +941,60 @@ Instruction *InstCombinerImpl::foldLShrOverflowBit(BinaryOperator &I) { return new ZExtInst(Overflow, Ty); } +// Try to set nuw/nsw flags on shl or exact flag on lshr/ashr using knownbits. +static bool setShiftFlags(BinaryOperator &I, const SimplifyQuery &Q) { + assert(I.isShift() && "Expected a shift as input"); + // We already have all the flags. + if (I.getOpcode() == Instruction::Shl) { + if (I.hasNoUnsignedWrap() && I.hasNoSignedWrap()) + return false; + } else { + if (I.isExact()) + return false; + } + + // Compute what we know about shift count. + KnownBits KnownCnt = + computeKnownBits(I.getOperand(1), Q.DL, /*Depth*/ 0, Q.AC, Q.CxtI, Q.DT); + // If we know nothing about shift count or its a poison shift, we won't be + // able to prove anything so return before computing shift amount. + if (KnownCnt.isUnknown()) + return false; + unsigned BitWidth = KnownCnt.getBitWidth(); + APInt MaxCnt = KnownCnt.getMaxValue(); + if (MaxCnt.uge(BitWidth)) + return false; + + KnownBits KnownAmt = + computeKnownBits(I.getOperand(0), Q.DL, /*Depth*/ 0, Q.AC, Q.CxtI, Q.DT); + bool Changed = false; + + if (I.getOpcode() == Instruction::Shl) { + // If we have as many leading zeros than maximum shift cnt we have nuw. + if (!I.hasNoUnsignedWrap() && MaxCnt.ule(KnownAmt.countMinLeadingZeros())) { + I.setHasNoUnsignedWrap(); + Changed = true; + } + // If we have more sign bits than maximum shift cnt we have nsw. + if (!I.hasNoSignedWrap()) { + if (MaxCnt.ult(KnownAmt.countMinSignBits()) || + MaxCnt.ult(ComputeNumSignBits(I.getOperand(0), Q.DL, /*Depth*/ 0, + Q.AC, Q.CxtI, Q.DT))) { + I.setHasNoSignedWrap(); + Changed = true; + } + } + return Changed; + } + if (!I.isExact()) { + // If we have at least as many trailing zeros as maximum count then we have + // exact. + Changed = MaxCnt.ule(KnownAmt.countMinTrailingZeros()); + I.setIsExact(Changed); + } + return Changed; +} + Instruction *InstCombinerImpl::visitShl(BinaryOperator &I) { const SimplifyQuery Q = SQ.getWithInstruction(&I); @@ -1121,22 +1175,11 @@ Instruction *InstCombinerImpl::visitShl(BinaryOperator &I) { Value *NewShift = Builder.CreateShl(X, Op1); return BinaryOperator::CreateSub(NewLHS, NewShift); } - - // If the shifted-out value is known-zero, then this is a NUW shift. - if (!I.hasNoUnsignedWrap() && - MaskedValueIsZero(Op0, APInt::getHighBitsSet(BitWidth, ShAmtC), 0, - &I)) { - I.setHasNoUnsignedWrap(); - return &I; - } - - // If the shifted-out value is all signbits, then this is a NSW shift. - if (!I.hasNoSignedWrap() && ComputeNumSignBits(Op0, 0, &I) > ShAmtC) { - I.setHasNoSignedWrap(); - return &I; - } } + if (setShiftFlags(I, Q)) + return &I; + // Transform (x >> y) << y to x & (-1 << y) // Valid for any type of right-shift. Value *X; @@ -1427,15 +1470,12 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) { Value *And = Builder.CreateAnd(BoolX, BoolY); return new ZExtInst(And, Ty); } - - // If the shifted-out value is known-zero, then this is an exact shift. - if (!I.isExact() && - MaskedValueIsZero(Op0, APInt::getLowBitsSet(BitWidth, ShAmtC), 0, &I)) { - I.setIsExact(); - return &I; - } } + const SimplifyQuery Q = SQ.getWithInstruction(&I); + if (setShiftFlags(I, Q)) + return &I; + // Transform (x << y) >> y to x & (-1 >> y) if (match(Op0, m_OneUse(m_Shl(m_Value(X), m_Specific(Op1))))) { Constant *AllOnes = ConstantInt::getAllOnesValue(Ty); @@ -1594,15 +1634,12 @@ Instruction *InstCombinerImpl::visitAShr(BinaryOperator &I) { if (match(Op0, m_OneUse(m_NSWSub(m_Value(X), m_Value(Y))))) return new SExtInst(Builder.CreateICmpSLT(X, Y), Ty); } - - // If the shifted-out value is known-zero, then this is an exact shift. - if (!I.isExact() && - MaskedValueIsZero(Op0, APInt::getLowBitsSet(BitWidth, ShAmt), 0, &I)) { - I.setIsExact(); - return &I; - } } + const SimplifyQuery Q = SQ.getWithInstruction(&I); + if (setShiftFlags(I, Q)) + return &I; + // Prefer `-(x & 1)` over `(x << (bitwidth(x)-1)) a>> (bitwidth(x)-1)` // as the pattern to splat the lowest bit. // FIXME: iff X is already masked, we don't need the one-use check. diff --git a/llvm/test/Analysis/ValueTracking/known-power-of-two.ll b/llvm/test/Analysis/ValueTracking/known-power-of-two.ll index b86cf59fa2046..7bcf96065a69d 100644 --- a/llvm/test/Analysis/ValueTracking/known-power-of-two.ll +++ b/llvm/test/Analysis/ValueTracking/known-power-of-two.ll @@ -413,11 +413,11 @@ define i1 @mul_is_pow2(i16 %x, i16 %y, i16 %z) { ; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]], i16 [[Z:%.*]]) { ; CHECK-NEXT: [[XSMALL:%.*]] = and i16 [[X]], 3 ; CHECK-NEXT: [[ZSMALL:%.*]] = and i16 [[Z]], 3 -; CHECK-NEXT: [[XP2:%.*]] = shl i16 4, [[XSMALL]] -; CHECK-NEXT: [[ZP2:%.*]] = shl i16 2, [[ZSMALL]] -; CHECK-NEXT: [[XX:%.*]] = mul nuw nsw i16 [[XP2]], [[ZP2]] +; CHECK-NEXT: [[ZP2:%.*]] = shl nuw nsw i16 2, [[ZSMALL]] +; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i16 [[XSMALL]], 2 +; CHECK-NEXT: [[XX:%.*]] = shl nuw nsw i16 [[ZP2]], [[TMP1]] ; CHECK-NEXT: [[AND:%.*]] = and i16 [[XX]], [[Y]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i16 [[AND]], [[XX]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i16 [[AND]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %xsmall = and i16 %x, 3 @@ -436,9 +436,9 @@ define i1 @mul_is_pow2_fail(i16 %x, i16 %y, i16 %z) { ; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]], i16 [[Z:%.*]]) { ; CHECK-NEXT: [[XSMALL:%.*]] = and i16 [[X]], 7 ; CHECK-NEXT: [[ZSMALL:%.*]] = and i16 [[Z]], 7 -; CHECK-NEXT: [[XP2:%.*]] = shl i16 4, [[XSMALL]] -; CHECK-NEXT: [[ZP2:%.*]] = shl i16 2, [[ZSMALL]] -; CHECK-NEXT: [[XX:%.*]] = mul i16 [[XP2]], [[ZP2]] +; CHECK-NEXT: [[ZP2:%.*]] = shl nuw nsw i16 2, [[ZSMALL]] +; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i16 [[XSMALL]], 2 +; CHECK-NEXT: [[XX:%.*]] = shl i16 [[ZP2]], [[TMP1]] ; CHECK-NEXT: [[AND:%.*]] = and i16 [[XX]], [[Y]] ; CHECK-NEXT: [[R:%.*]] = icmp eq i16 [[AND]], [[XX]] ; CHECK-NEXT: ret i1 [[R]] @@ -459,9 +459,9 @@ define i1 @mul_is_pow2_fail2(i16 %x, i16 %y, i16 %z) { ; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]], i16 [[Z:%.*]]) { ; CHECK-NEXT: [[XSMALL:%.*]] = and i16 [[X]], 3 ; CHECK-NEXT: [[ZSMALL:%.*]] = and i16 [[Z]], 3 -; CHECK-NEXT: [[XP2:%.*]] = shl i16 3, [[XSMALL]] -; CHECK-NEXT: [[ZP2:%.*]] = shl i16 2, [[ZSMALL]] -; CHECK-NEXT: [[XX:%.*]] = mul nuw nsw i16 [[XP2]], [[ZP2]] +; CHECK-NEXT: [[XP2:%.*]] = shl nuw nsw i16 3, [[XSMALL]] +; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i16 [[ZSMALL]], 1 +; CHECK-NEXT: [[XX:%.*]] = shl nuw nsw i16 [[XP2]], [[TMP1]] ; CHECK-NEXT: [[AND:%.*]] = and i16 [[XX]], [[Y]] ; CHECK-NEXT: [[R:%.*]] = icmp eq i16 [[AND]], [[XX]] ; CHECK-NEXT: ret i1 [[R]] @@ -481,9 +481,9 @@ define i1 @shl_is_pow2(i16 %x, i16 %y) { ; CHECK-LABEL: define i1 @shl_is_pow2 ; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) { ; CHECK-NEXT: [[XSMALL:%.*]] = and i16 [[X]], 7 -; CHECK-NEXT: [[XX:%.*]] = shl i16 4, [[XSMALL]] +; CHECK-NEXT: [[XX:%.*]] = shl nuw nsw i16 4, [[XSMALL]] ; CHECK-NEXT: [[AND:%.*]] = and i16 [[XX]], [[Y]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i16 [[AND]], [[XX]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i16 [[AND]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %xsmall = and i16 %x, 7 @@ -515,7 +515,7 @@ define i1 @shl_is_pow2_fail2(i16 %x, i16 %y) { ; CHECK-LABEL: define i1 @shl_is_pow2_fail2 ; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) { ; CHECK-NEXT: [[XSMALL:%.*]] = and i16 [[X]], 7 -; CHECK-NEXT: [[XX:%.*]] = shl i16 5, [[XSMALL]] +; CHECK-NEXT: [[XX:%.*]] = shl nuw nsw i16 5, [[XSMALL]] ; CHECK-NEXT: [[AND:%.*]] = and i16 [[XX]], [[Y]] ; CHECK-NEXT: [[R:%.*]] = icmp eq i16 [[AND]], [[XX]] ; CHECK-NEXT: ret i1 [[R]] @@ -532,9 +532,9 @@ define i1 @lshr_is_pow2(i16 %x, i16 %y) { ; CHECK-LABEL: define i1 @lshr_is_pow2 ; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) { ; CHECK-NEXT: [[XSMALL:%.*]] = and i16 [[X]], 7 -; CHECK-NEXT: [[XX:%.*]] = lshr i16 512, [[XSMALL]] +; CHECK-NEXT: [[XX:%.*]] = lshr exact i16 512, [[XSMALL]] ; CHECK-NEXT: [[AND:%.*]] = and i16 [[XX]], [[Y]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i16 [[AND]], [[XX]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i16 [[AND]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %xsmall = and i16 %x, 7 @@ -584,9 +584,9 @@ define i1 @and_is_pow2(i16 %x, i16 %y) { ; CHECK-SAME: (i16 [[X:%.*]], i16 [[Y:%.*]]) { ; CHECK-NEXT: [[XNZ:%.*]] = or i16 [[X]], 4 ; CHECK-NEXT: [[X_NEG:%.*]] = sub nsw i16 0, [[XNZ]] -; CHECK-NEXT: [[XX:%.*]] = and i16 [[XNZ]], [[X_NEG]] -; CHECK-NEXT: [[AND:%.*]] = and i16 [[XX]], [[Y]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i16 [[AND]], [[XX]] +; CHECK-NEXT: [[TMP1:%.*]] = and i16 [[X_NEG]], [[Y]] +; CHECK-NEXT: [[AND:%.*]] = and i16 [[TMP1]], [[XNZ]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i16 [[AND]], 0 ; CHECK-NEXT: ret i1 [[R]] ; %xnz = or i16 %x, 4 diff --git a/llvm/test/Transforms/InstCombine/and-add-shl.ll b/llvm/test/Transforms/InstCombine/and-add-shl.ll index 28778f34137e0..92b3a8144d62c 100644 --- a/llvm/test/Transforms/InstCombine/and-add-shl.ll +++ b/llvm/test/Transforms/InstCombine/and-add-shl.ll @@ -29,7 +29,7 @@ define i8 @and_not_shl(i8 %x) { ; CHECK-SAME: (i8 [[X:%.*]]) { ; CHECK-NEXT: [[OP1_P2:%.*]] = icmp ult i8 [[X]], 6 ; CHECK-NEXT: call void @llvm.assume(i1 [[OP1_P2]]) -; CHECK-NEXT: [[SHIFT:%.*]] = shl i8 -1, [[X]] +; CHECK-NEXT: [[SHIFT:%.*]] = shl nsw i8 -1, [[X]] ; CHECK-NEXT: [[NOT:%.*]] = and i8 [[SHIFT]], 32 ; CHECK-NEXT: [[R:%.*]] = xor i8 [[NOT]], 32 ; CHECK-NEXT: ret i8 [[R]] diff --git a/llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll b/llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll index 96dc6c68f4d4f..b06a90e2cd99b 100644 --- a/llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll +++ b/llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll @@ -5,10 +5,10 @@ define i32 @src(i1 %x2) { ; CHECK-LABEL: @src( ; CHECK-NEXT: [[X13:%.*]] = zext i1 [[X2:%.*]] to i32 -; CHECK-NEXT: [[_7:%.*]] = shl i32 -1, [[X13]] +; CHECK-NEXT: [[_7:%.*]] = shl nsw i32 -1, [[X13]] ; CHECK-NEXT: [[MASK:%.*]] = xor i32 [[_7]], -1 ; CHECK-NEXT: [[_8:%.*]] = and i32 [[MASK]], [[X13]] -; CHECK-NEXT: [[_9:%.*]] = shl i32 [[_8]], [[X13]] +; CHECK-NEXT: [[_9:%.*]] = shl nuw nsw i32 [[_8]], [[X13]] ; CHECK-NEXT: ret i32 [[_9]] ; %x13 = zext i1 %x2 to i32 diff --git a/llvm/test/Transforms/InstCombine/rotate.ll b/llvm/test/Transforms/InstCombine/rotate.ll index fece47534819e..ed5145255b2f0 100644 --- a/llvm/test/Transforms/InstCombine/rotate.ll +++ b/llvm/test/Transforms/InstCombine/rotate.ll @@ -705,7 +705,7 @@ define i9 @rotateleft_9_neg_mask_wide_amount_commute(i9 %v, i33 %shamt) { ; CHECK-NEXT: [[LSHAMT:%.*]] = and i33 [[SHAMT]], 8 ; CHECK-NEXT: [[RSHAMT:%.*]] = and i33 [[NEG]], 8 ; CHECK-NEXT: [[CONV:%.*]] = zext i9 [[V:%.*]] to i33 -; CHECK-NEXT: [[SHL:%.*]] = shl i33 [[CONV]], [[LSHAMT]] +; CHECK-NEXT: [[SHL:%.*]] = shl nuw nsw i33 [[CONV]], [[LSHAMT]] ; CHECK-NEXT: [[SHR:%.*]] = lshr i33 [[CONV]], [[RSHAMT]] ; CHECK-NEXT: [[OR:%.*]] = or i33 [[SHL]], [[SHR]] ; CHECK-NEXT: [[RET:%.*]] = trunc i33 [[OR]] to i9 diff --git a/llvm/test/Transforms/InstCombine/shift-flags.ll b/llvm/test/Transforms/InstCombine/shift-flags.ll new file mode 100644 index 0000000000000..08cf4821d85b4 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/shift-flags.ll @@ -0,0 +1,119 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +define i8 @shl_add_nuw(i8 %amt_in, i8 %cnt_in) { +; CHECK-LABEL: @shl_add_nuw( +; CHECK-NEXT: [[AMT:%.*]] = and i8 [[AMT_IN:%.*]], 63 +; CHECK-NEXT: [[CNT:%.*]] = and i8 [[CNT_IN:%.*]], 2 +; CHECK-NEXT: [[R:%.*]] = shl nuw i8 [[AMT]], [[CNT]] +; CHECK-NEXT: ret i8 [[R]] +; + %amt = and i8 %amt_in, 63 + %cnt = and i8 %cnt_in, 2 + %r = shl i8 %amt, %cnt + ret i8 %r +} + +define i8 @shl_add_nuw_fail(i8 %amt_in, i8 %cnt_in) { +; CHECK-LABEL: @shl_add_nuw_fail( +; CHECK-NEXT: [[AMT:%.*]] = and i8 [[AMT_IN:%.*]], 63 +; CHECK-NEXT: [[CNT:%.*]] = and i8 [[CNT_IN:%.*]], 3 +; CHECK-NEXT: [[R:%.*]] = shl i8 [[AMT]], [[CNT]] +; CHECK-NEXT: ret i8 [[R]] +; + %amt = and i8 %amt_in, 63 + %cnt = and i8 %cnt_in, 3 + %r = shl i8 %amt, %cnt + ret i8 %r +} + +define i8 @shl_add_nuw_and_nsw(i8 %amt_in, i8 %cnt_in) { +; CHECK-LABEL: @shl_add_nuw_and_nsw( +; CHECK-NEXT: [[AMT:%.*]] = and i8 [[AMT_IN:%.*]], 31 +; CHECK-NEXT: [[CNT:%.*]] = and i8 [[CNT_IN:%.*]], 2 +; CHECK-NEXT: [[R:%.*]] = shl nuw nsw i8 [[AMT]], [[CNT]] +; CHECK-NEXT: ret i8 [[R]] +; + %amt = and i8 %amt_in, 31 + %cnt = and i8 %cnt_in, 2 + %r = shl i8 %amt, %cnt + ret i8 %r +} + +define i8 @shl_add_nsw(i8 %amt_in, i8 %cnt_in) { +; CHECK-LABEL: @shl_add_nsw( +; CHECK-NEXT: [[AMT:%.*]] = or i8 [[AMT_IN:%.*]], -32 +; CHECK-NEXT: [[CNT:%.*]] = and i8 [[CNT_IN:%.*]], 2 +; CHECK-NEXT: [[R:%.*]] = shl nsw i8 [[AMT]], [[CNT]] +; CHECK-NEXT: ret i8 [[R]] +; + %amt = or i8 %amt_in, 224 + %cnt = and i8 %cnt_in, 2 + %r = shl i8 %amt, %cnt + ret i8 %r +} + +define i8 @shl_add_nsw_fail(i8 %amt_in, i8 %cnt_in) { +; CHECK-LABEL: @shl_add_nsw_fail( +; CHECK-NEXT: [[AMT:%.*]] = or i8 [[AMT_IN:%.*]], -64 +; CHECK-NEXT: [[CNT:%.*]] = and i8 [[CNT_IN:%.*]], 2 +; CHECK-NEXT: [[R:%.*]] = shl i8 [[AMT]], [[CNT]] +; CHECK-NEXT: ret i8 [[R]] +; + %amt = or i8 %amt_in, 192 + %cnt = and i8 %cnt_in, 2 + %r = shl i8 %amt, %cnt + ret i8 %r +} + +define i8 @lshr_add_exact(i8 %amt_in, i8 %cnt_in) { +; CHECK-LABEL: @lshr_add_exact( +; CHECK-NEXT: [[AMT:%.*]] = and i8 [[AMT_IN:%.*]], -4 +; CHECK-NEXT: [[CNT:%.*]] = and i8 [[CNT_IN:%.*]], 2 +; CHECK-NEXT: [[R:%.*]] = lshr exact i8 [[AMT]], [[CNT]] +; CHECK-NEXT: ret i8 [[R]] +; + %amt = and i8 %amt_in, -4 + %cnt = and i8 %cnt_in, 2 + %r = lshr i8 %amt, %cnt + ret i8 %r +} + +define i8 @lshr_add_exact_fail(i8 %amt_in, i8 %cnt_in) { +; CHECK-LABEL: @lshr_add_exact_fail( +; CHECK-NEXT: [[AMT:%.*]] = and i8 [[AMT_IN:%.*]], -7 +; CHECK-NEXT: [[CNT:%.*]] = and i8 [[CNT_IN:%.*]], 2 +; CHECK-NEXT: [[R:%.*]] = lshr i8 [[AMT]], [[CNT]] +; CHECK-NEXT: ret i8 [[R]] +; + %amt = and i8 %amt_in, -7 + %cnt = and i8 %cnt_in, 2 + %r = lshr i8 %amt, %cnt + ret i8 %r +} + +define i8 @ashr_add_exact(i8 %amt_in, i8 %cnt_in) { +; CHECK-LABEL: @ashr_add_exact( +; CHECK-NEXT: [[AMT:%.*]] = and i8 [[AMT_IN:%.*]], -14 +; CHECK-NEXT: [[CNT:%.*]] = and i8 [[CNT_IN:%.*]], 1 +; CHECK-NEXT: [[R:%.*]] = ashr exact i8 [[AMT]], [[CNT]] +; CHECK-NEXT: ret i8 [[R]] +; + %amt = and i8 %amt_in, -14 + %cnt = and i8 %cnt_in, 1 + %r = ashr i8 %amt, %cnt + ret i8 %r +} + +define i8 @ashr_add_exact_fail(i8 %amt_in, i8 %cnt_in) { +; CHECK-LABEL: @ashr_add_exact_fail( +; CHECK-NEXT: [[AMT:%.*]] = and i8 [[AMT_IN:%.*]], -14 +; CHECK-NEXT: [[CNT:%.*]] = and i8 [[CNT_IN:%.*]], 2 +; CHECK-NEXT: [[R:%.*]] = ashr i8 [[AMT]], [[CNT]] +; CHECK-NEXT: ret i8 [[R]] +; + %amt = and i8 %amt_in, -14 + %cnt = and i8 %cnt_in, 2 + %r = ashr i8 %amt, %cnt + ret i8 %r +} diff --git a/llvm/test/Transforms/InstCombine/trunc-inseltpoison.ll b/llvm/test/Transforms/InstCombine/trunc-inseltpoison.ll index ac0115a0f5715..b5dcb9b67d676 100644 --- a/llvm/test/Transforms/InstCombine/trunc-inseltpoison.ll +++ b/llvm/test/Transforms/InstCombine/trunc-inseltpoison.ll @@ -345,7 +345,7 @@ define i64 @test11(i32 %A, i32 %B) { ; CHECK-NEXT: [[C:%.*]] = zext i32 [[A:%.*]] to i64 ; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B:%.*]], 31 ; CHECK-NEXT: [[E:%.*]] = zext i32 [[TMP1]] to i64 -; CHECK-NEXT: [[F:%.*]] = shl i64 [[C]], [[E]] +; CHECK-NEXT: [[F:%.*]] = shl nuw nsw i64 [[C]], [[E]] ; CHECK-NEXT: ret i64 [[F]] ; %C = zext i32 %A to i128 @@ -361,7 +361,7 @@ define <2 x i64> @test11_vec(<2 x i32> %A, <2 x i32> %B) { ; CHECK-NEXT: [[C:%.*]] = zext <2 x i32> [[A:%.*]] to <2 x i64> ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[B:%.*]], ; CHECK-NEXT: [[E:%.*]] = zext <2 x i32> [[TMP1]] to <2 x i64> -; CHECK-NEXT: [[F:%.*]] = shl <2 x i64> [[C]], [[E]] +; CHECK-NEXT: [[F:%.*]] = shl nuw nsw <2 x i64> [[C]], [[E]] ; CHECK-NEXT: ret <2 x i64> [[F]] ; %C = zext <2 x i32> %A to <2 x i128> @@ -377,7 +377,7 @@ define <2 x i64> @test11_vec_nonuniform(<2 x i32> %A, <2 x i32> %B) { ; CHECK-NEXT: [[C:%.*]] = zext <2 x i32> [[A:%.*]] to <2 x i64> ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[B:%.*]], ; CHECK-NEXT: [[E:%.*]] = zext <2 x i32> [[TMP1]] to <2 x i64> -; CHECK-NEXT: [[F:%.*]] = shl <2 x i64> [[C]], [[E]] +; CHECK-NEXT: [[F:%.*]] = shl nuw nsw <2 x i64> [[C]], [[E]] ; CHECK-NEXT: ret <2 x i64> [[F]] ; %C = zext <2 x i32> %A to <2 x i128> diff --git a/llvm/test/Transforms/InstCombine/trunc.ll b/llvm/test/Transforms/InstCombine/trunc.ll index e04bcaf073b64..33baee858493a 100644 --- a/llvm/test/Transforms/InstCombine/trunc.ll +++ b/llvm/test/Transforms/InstCombine/trunc.ll @@ -345,7 +345,7 @@ define i64 @test11(i32 %A, i32 %B) { ; CHECK-NEXT: [[C:%.*]] = zext i32 [[A:%.*]] to i64 ; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[B:%.*]], 31 ; CHECK-NEXT: [[E:%.*]] = zext i32 [[TMP1]] to i64 -; CHECK-NEXT: [[F:%.*]] = shl i64 [[C]], [[E]] +; CHECK-NEXT: [[F:%.*]] = shl nuw nsw i64 [[C]], [[E]] ; CHECK-NEXT: ret i64 [[F]] ; %C = zext i32 %A to i128 @@ -361,7 +361,7 @@ define <2 x i64> @test11_vec(<2 x i32> %A, <2 x i32> %B) { ; CHECK-NEXT: [[C:%.*]] = zext <2 x i32> [[A:%.*]] to <2 x i64> ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[B:%.*]], ; CHECK-NEXT: [[E:%.*]] = zext <2 x i32> [[TMP1]] to <2 x i64> -; CHECK-NEXT: [[F:%.*]] = shl <2 x i64> [[C]], [[E]] +; CHECK-NEXT: [[F:%.*]] = shl nuw nsw <2 x i64> [[C]], [[E]] ; CHECK-NEXT: ret <2 x i64> [[F]] ; %C = zext <2 x i32> %A to <2 x i128> @@ -377,7 +377,7 @@ define <2 x i64> @test11_vec_nonuniform(<2 x i32> %A, <2 x i32> %B) { ; CHECK-NEXT: [[C:%.*]] = zext <2 x i32> [[A:%.*]] to <2 x i64> ; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i32> [[B:%.*]], ; CHECK-NEXT: [[E:%.*]] = zext <2 x i32> [[TMP1]] to <2 x i64> -; CHECK-NEXT: [[F:%.*]] = shl <2 x i64> [[C]], [[E]] +; CHECK-NEXT: [[F:%.*]] = shl nuw nsw <2 x i64> [[C]], [[E]] ; CHECK-NEXT: ret <2 x i64> [[F]] ; %C = zext <2 x i32> %A to <2 x i128> diff --git a/llvm/test/Transforms/InstSimplify/ctpop-pow2.ll b/llvm/test/Transforms/InstSimplify/ctpop-pow2.ll index eae368f03ca7e..48cc8895aebbc 100644 --- a/llvm/test/Transforms/InstSimplify/ctpop-pow2.ll +++ b/llvm/test/Transforms/InstSimplify/ctpop-pow2.ll @@ -41,10 +41,7 @@ define i16 @ctpop_x_and_negx(i16 %x) { define i8 @ctpop_x_nz_and_negx(i8 %x) { ; CHECK-LABEL: @ctpop_x_nz_and_negx( -; CHECK-NEXT: [[X1:%.*]] = or i8 [[X:%.*]], 1 -; CHECK-NEXT: [[V0:%.*]] = sub i8 0, [[X1]] -; CHECK-NEXT: [[V1:%.*]] = and i8 [[X1]], [[V0]] -; CHECK-NEXT: ret i8 [[V1]] +; CHECK-NEXT: ret i8 1 ; %x1 = or i8 %x, 1 %v0 = sub i8 0, %x1