[llvm] goldsteinn/value tracking improvements (PR #67758)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 28 18:01:01 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
<details>
<summary>Changes</summary>
- [ValueTracking] Do more thorough non-zero check in `isKnownToBePowerOfTwo` when `OrZero` is no set.
- [InstCombine] Tests for adding flags to shifts; NFC
- [InstCombine] Improve logic for adding flags to shift instructions.
---
Patch is 23.27 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/67758.diff
11 Files Affected:
- (modified) llvm/lib/Analysis/ValueTracking.cpp (+12-13)
- (modified) llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp (+64-28)
- (modified) llvm/test/Analysis/ValueTracking/known-power-of-two.ll (+18-18)
- (modified) llvm/test/Transforms/InstCombine/and-add-shl.ll (+1-1)
- (modified) llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll (+2-2)
- (modified) llvm/test/Transforms/InstCombine/rotate.ll (+1-1)
- (added) llvm/test/Transforms/InstCombine/shift-flags.ll (+119)
- (modified) llvm/test/Transforms/InstCombine/trunc-inseltpoison.ll (+3-3)
- (modified) llvm/test/Transforms/InstCombine/trunc.ll (+3-3)
- (modified) llvm/test/Transforms/InstSimplify/ctpop-pow2.ll (+1-4)
- (modified) llvm/test/Transforms/PhaseOrdering/X86/SROA-after-final-loop-unrolling-2.ll (+4-4)
``````````diff
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index d93e030cdfa0c5b..c7df1ddc90091f4 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -2055,20 +2055,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 a25a7dd4160d24e..85bfcf4e0917342 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -936,6 +936,59 @@ 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) {
+ // 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);
@@ -1116,22 +1169,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;
@@ -1422,15 +1464,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);
@@ -1589,15 +1628,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 b86cf59fa2046c3..7bcf96065a69d99 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 28778f34137e06f..92b3a8144d62ccd 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 96dc6c68f4d4fb3..b06a90e2cd99b7d 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 fece47534819e48..ed5145255b2f072 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 000000000000000..08cf4821d85b489
--- /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 ac0115a0f571514..b5dcb9b67d676ed 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:%.*]], <i32 31, i32 31>
; 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:%.*]], <i32 31, i32 15>
; 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 e04bcaf073b64e4..33baee858493a63 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:%.*]], <i32 31, i32 31>
; CHECK-NEXT: [[E:%.*]] = zext <2 x i32> [[TMP1]] to <2 x i64>...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/67758
More information about the llvm-commits
mailing list