[llvm-branch-commits] [llvm] ef8b9a7 - Revert "[InstCombine] Fix #163110: Support peeling off matching shifts from i…"
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Apr 6 10:59:12 PDT 2026
Author: Kirill Stoimenov
Date: 2026-04-06T10:59:07-07:00
New Revision: ef8b9a76ef2e99c6a26fb73bbecf82c7e9079c68
URL: https://github.com/llvm/llvm-project/commit/ef8b9a76ef2e99c6a26fb73bbecf82c7e9079c68
DIFF: https://github.com/llvm/llvm-project/commit/ef8b9a76ef2e99c6a26fb73bbecf82c7e9079c68.diff
LOG: Revert "[InstCombine] Fix #163110: Support peeling off matching shifts from i…"
This reverts commit 05ff170026eb9164f8157a655a041bbe622efd0a.
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
llvm/lib/Transforms/InstCombine/InstCombineInternal.h
llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
llvm/test/Transforms/InstCombine/apint-shift.ll
llvm/test/Transforms/InstCombine/icmp-select.ll
Removed:
llvm/test/Transforms/InstCombine/icmp-shl-add-to-add.ll
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 242e831045369..ff1868f3a5840 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7698,34 +7698,6 @@ Instruction *InstCombinerImpl::foldICmpCommutative(CmpPredicate Pred,
}
}
- // icmp (shl nsw/nuw X, L), (add nsw/nuw (shl nsw/nuw Y, L), K)
- // -> icmp X, (add nsw/nuw Y, K >> L)
- // We use AShr for nsw and LShr for nuw to safely peel off the shift.
- Value *X;
- uint64_t ShAmt;
- if (match(Op0, m_NUWShl(m_Value(X), m_ConstantInt(ShAmt))) &&
- !CxtI.isSigned()) {
- if (ShAmt >= X->getType()->getScalarSizeInBits())
- return nullptr;
- if (canEvaluateShifted(Op1, ShAmt, /*IsLeftShift=*/false,
- ShiftSemantics::Unsigned, &CxtI)) {
- Value *NewOp1 = getShiftedValue(Op1, ShAmt, /*IsLeftShift=*/false,
- ShiftSemantics::Unsigned);
- return new ICmpInst(Pred, X, NewOp1);
- }
- }
-
- if (match(Op0, m_NSWShl(m_Value(X), m_ConstantInt(ShAmt))) &&
- !CxtI.isUnsigned()) {
- if (ShAmt >= X->getType()->getScalarSizeInBits())
- return nullptr;
- if (canEvaluateShifted(Op1, ShAmt, /*IsLeftShift=*/false,
- ShiftSemantics::Signed, &CxtI)) {
- Value *NewOp1 = getShiftedValue(Op1, ShAmt, /*IsLeftShift=*/false,
- ShiftSemantics::Signed);
- return new ICmpInst(Pred, X, NewOp1);
- }
- }
return nullptr;
}
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
index c3277f3f0ab4d..160f766b60973 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
+++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h
@@ -58,15 +58,6 @@ class ProfileSummaryInfo;
class TargetLibraryInfo;
class User;
-/// Enum to specify how shift operations should be evaluated in
-/// canEvaluateShifted.
-/// Lossy: Allows lossy transformations
-/// Signed: Requires lossless transformation, using ashr to restore for shl,
-/// or represents ashr handling for right shifts
-/// Unsigned: Requires lossless transformation, using lshr to restore for shl,
-/// or represents lshr handling for right shifts
-enum class ShiftSemantics { Lossy, Signed, Unsigned };
-
class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
: public InstCombiner,
public InstVisitor<InstCombinerImpl, Instruction *> {
@@ -441,11 +432,6 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
bool InvertFalseVal = false);
Value *getSelectCondition(Value *A, Value *B, bool ABIsTheSame);
- bool canEvaluateShifted(Value *V, unsigned NumBits, bool IsLeftShift,
- ShiftSemantics Semantics, Instruction *CxtI);
- Value *getShiftedValue(Value *V, unsigned NumBits, bool IsLeftShift,
- ShiftSemantics Semantics);
-
Instruction *foldLShrOverflowBit(BinaryOperator &I);
Instruction *foldExtractOfOverflowIntrinsic(ExtractValueInst &EV);
Instruction *foldIntrinsicWithOverflowCommon(IntrinsicInst *II);
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index b6c78f36f1e4b..e416059ef28ae 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -538,7 +538,6 @@ Instruction *InstCombinerImpl::commonShiftTransforms(BinaryOperator &I) {
/// Return true if we can simplify two logical (either left or right) shifts
/// that have constant shift amounts: OuterShift (InnerShift X, C1), C2.
static bool canEvaluateShiftedShift(unsigned OuterShAmt, bool IsOuterShl,
- ShiftSemantics Semantics,
Instruction *InnerShift,
InstCombinerImpl &IC, Instruction *CxtI) {
assert(InnerShift->isLogicalShift() && "Unexpected instruction type");
@@ -552,10 +551,6 @@ static bool canEvaluateShiftedShift(unsigned OuterShAmt, bool IsOuterShl,
// shl (shl X, C1), C2 --> shl X, C1 + C2
// lshr (lshr X, C1), C2 --> lshr X, C1 + C2
bool IsInnerShl = InnerShift->getOpcode() == Instruction::Shl;
-
- if (!IsOuterShl && Semantics == ShiftSemantics::Signed)
- return IsInnerShl && cast<BinaryOperator>(InnerShift)->hasNoSignedWrap() &&
- *InnerShiftConst == OuterShAmt;
if (IsInnerShl == IsOuterShl)
return true;
@@ -585,30 +580,20 @@ static bool canEvaluateShiftedShift(unsigned OuterShAmt, bool IsOuterShl,
}
/// See if we can compute the specified value, but shifted logically to the left
-/// or right by some number of bits. This should return true if the
-/// transformation is valid. If the Semantics is not lossy,
-/// we must get the same value when we shift this value and then shift back.
-/// This is used to eliminate extraneous shifting from things like:
+/// or right by some number of bits. This should return true if the expression
+/// can be computed for the same cost as the current expression tree. This is
+/// used to eliminate extraneous shifting from things like:
/// %C = shl i128 %A, 64
/// %D = shl i128 %B, 96
/// %E = or i128 %C, %D
/// %F = lshr i128 %E, 64
/// where the client will ask if E can be computed shifted right by 64-bits. If
/// this succeeds, getShiftedValue() will be called to produce the value.
-bool InstCombinerImpl::canEvaluateShifted(Value *V, unsigned NumBits,
- bool IsLeftShift,
- ShiftSemantics Semantics,
- Instruction *CxtI) {
- // We can always evaluate immediate constants shifted left. For right shifts,
- // the constant must be a multiple of 2^NumBits to avoid losing information.
- if (match(V, m_ImmConstant())) {
- if (Semantics == ShiftSemantics::Lossy)
- return true;
- const APInt *C;
- if (match(V, m_APIntAllowPoison(C)) && !IsLeftShift)
- return C->countr_zero() >= NumBits;
- return false;
- }
+static bool canEvaluateShifted(Value *V, unsigned NumBits, bool IsLeftShift,
+ InstCombinerImpl &IC, Instruction *CxtI) {
+ // We can always evaluate immediate constants.
+ if (match(V, m_ImmConstant()))
+ return true;
Instruction *I = dyn_cast<Instruction>(V);
if (!I) return false;
@@ -623,22 +608,19 @@ bool InstCombinerImpl::canEvaluateShifted(Value *V, unsigned NumBits,
case Instruction::Or:
case Instruction::Xor:
// Bitwise operators can all arbitrarily be arbitrarily evaluated shifted.
- return canEvaluateShifted(I->getOperand(0), NumBits, IsLeftShift, Semantics,
- I) &&
- canEvaluateShifted(I->getOperand(1), NumBits, IsLeftShift, Semantics,
- I);
+ return canEvaluateShifted(I->getOperand(0), NumBits, IsLeftShift, IC, I) &&
+ canEvaluateShifted(I->getOperand(1), NumBits, IsLeftShift, IC, I);
case Instruction::Shl:
case Instruction::LShr:
- return canEvaluateShiftedShift(NumBits, IsLeftShift, Semantics, I, *this,
- CxtI);
+ return canEvaluateShiftedShift(NumBits, IsLeftShift, I, IC, CxtI);
case Instruction::Select: {
SelectInst *SI = cast<SelectInst>(I);
Value *TrueVal = SI->getTrueValue();
Value *FalseVal = SI->getFalseValue();
- return canEvaluateShifted(TrueVal, NumBits, IsLeftShift, Semantics, SI) &&
- canEvaluateShifted(FalseVal, NumBits, IsLeftShift, Semantics, SI);
+ return canEvaluateShifted(TrueVal, NumBits, IsLeftShift, IC, SI) &&
+ canEvaluateShifted(FalseVal, NumBits, IsLeftShift, IC, SI);
}
case Instruction::PHI: {
// We can change a phi if we can change all operands. Note that we never
@@ -646,48 +628,23 @@ bool InstCombinerImpl::canEvaluateShifted(Value *V, unsigned NumBits,
// instructions with a single use.
PHINode *PN = cast<PHINode>(I);
for (Value *IncValue : PN->incoming_values())
- if (!canEvaluateShifted(IncValue, NumBits, IsLeftShift, Semantics, PN))
+ if (!canEvaluateShifted(IncValue, NumBits, IsLeftShift, IC, PN))
return false;
return true;
}
case Instruction::Mul: {
const APInt *MulConst;
// We can fold (shr (mul X, -(1 << C)), C) -> (and (neg X), C`)
- return !IsLeftShift && Semantics == ShiftSemantics::Unsigned &&
- match(I->getOperand(1), m_APInt(MulConst)) &&
+ return !IsLeftShift && match(I->getOperand(1), m_APInt(MulConst)) &&
MulConst->isNegatedPowerOf2() && MulConst->countr_zero() == NumBits;
}
- case Instruction::Add: {
- auto *BinOp = cast<BinaryOperator>(I);
- // Left shift case
- if (IsLeftShift) {
- if (Semantics == ShiftSemantics::Lossy)
- return canEvaluateShifted(I->getOperand(0), NumBits, IsLeftShift,
- Semantics, I) &&
- canEvaluateShifted(I->getOperand(1), NumBits, IsLeftShift,
- Semantics, I);
-
- return false;
- }
-
- if (Semantics == ShiftSemantics::Lossy)
- return false;
- bool WrapRequired =
- (Semantics == ShiftSemantics::Signed && BinOp->hasNoSignedWrap()) ||
- (Semantics == ShiftSemantics::Unsigned && BinOp->hasNoUnsignedWrap());
- return WrapRequired &&
- canEvaluateShifted(I->getOperand(0), NumBits, IsLeftShift, Semantics,
- I) &&
- canEvaluateShifted(I->getOperand(1), NumBits, IsLeftShift, Semantics,
- I);
- }
}
}
/// Fold OuterShift (InnerShift X, C1), C2.
/// See canEvaluateShiftedShift() for the constraints on these instructions.
static Value *foldShiftedShift(BinaryOperator *InnerShift, unsigned OuterShAmt,
- bool IsOuterShl, ShiftSemantics Semantics,
+ bool IsOuterShl,
InstCombiner::BuilderTy &Builder) {
bool IsInnerShl = InnerShift->getOpcode() == Instruction::Shl;
Type *ShType = InnerShift->getType();
@@ -725,16 +682,6 @@ static Value *foldShiftedShift(BinaryOperator *InnerShift, unsigned OuterShAmt,
// lshr (shl X, C), C --> and X, C'
// shl (lshr X, C), C --> and X, C'
if (InnerShAmt == OuterShAmt) {
- if (!IsOuterShl && Semantics == ShiftSemantics::Signed) {
- assert(IsInnerShl && InnerShift->hasNoSignedWrap() &&
- "Signed Semantics should have nsw and inner shl per "
- "canEvaluateShiftedShift");
- return InnerShift->getOperand(0);
- }
- if (!IsOuterShl && Semantics == ShiftSemantics::Unsigned && IsInnerShl &&
- InnerShift->hasNoUnsignedWrap())
- return InnerShift->getOperand(0);
-
APInt Mask = IsInnerShl
? APInt::getLowBitsSet(TypeWidth, TypeWidth - OuterShAmt)
: APInt::getHighBitsSet(TypeWidth, TypeWidth - OuterShAmt);
@@ -759,21 +706,18 @@ static Value *foldShiftedShift(BinaryOperator *InnerShift, unsigned OuterShAmt,
/// When canEvaluateShifted() returns true for an expression, this function
/// inserts the new computation that produces the shifted value.
-Value *InstCombinerImpl::getShiftedValue(Value *V, unsigned NumBits,
- bool IsLeftShift,
- ShiftSemantics Semantics) {
+static Value *getShiftedValue(Value *V, unsigned NumBits, bool isLeftShift,
+ InstCombinerImpl &IC, const DataLayout &DL) {
// We can always evaluate constants shifted.
if (Constant *C = dyn_cast<Constant>(V)) {
- Instruction::BinaryOps ShiftOp =
- IsLeftShift ? Instruction::Shl
- : (Semantics == ShiftSemantics::Signed ? Instruction::AShr
- : Instruction::LShr);
- return Builder.CreateBinOp(ShiftOp, C,
- ConstantInt::get(C->getType(), NumBits));
+ if (isLeftShift)
+ return IC.Builder.CreateShl(C, NumBits);
+ else
+ return IC.Builder.CreateLShr(C, NumBits);
}
Instruction *I = cast<Instruction>(V);
- addToWorklist(I);
+ IC.addToWorklist(I);
switch (I->getOpcode()) {
default: llvm_unreachable("Inconsistency with CanEvaluateShifted");
@@ -782,21 +726,21 @@ Value *InstCombinerImpl::getShiftedValue(Value *V, unsigned NumBits,
case Instruction::Xor:
// Bitwise operators can all arbitrarily be arbitrarily evaluated shifted.
I->setOperand(
- 0, getShiftedValue(I->getOperand(0), NumBits, IsLeftShift, Semantics));
+ 0, getShiftedValue(I->getOperand(0), NumBits, isLeftShift, IC, DL));
I->setOperand(
- 1, getShiftedValue(I->getOperand(1), NumBits, IsLeftShift, Semantics));
+ 1, getShiftedValue(I->getOperand(1), NumBits, isLeftShift, IC, DL));
return I;
case Instruction::Shl:
case Instruction::LShr:
- return foldShiftedShift(cast<BinaryOperator>(I), NumBits, IsLeftShift,
- Semantics, Builder);
+ return foldShiftedShift(cast<BinaryOperator>(I), NumBits, isLeftShift,
+ IC.Builder);
case Instruction::Select:
I->setOperand(
- 1, getShiftedValue(I->getOperand(1), NumBits, IsLeftShift, Semantics));
+ 1, getShiftedValue(I->getOperand(1), NumBits, isLeftShift, IC, DL));
I->setOperand(
- 2, getShiftedValue(I->getOperand(2), NumBits, IsLeftShift, Semantics));
+ 2, getShiftedValue(I->getOperand(2), NumBits, isLeftShift, IC, DL));
return I;
case Instruction::PHI: {
// We can change a phi if we can change all operands. Note that we never
@@ -805,28 +749,19 @@ Value *InstCombinerImpl::getShiftedValue(Value *V, unsigned NumBits,
PHINode *PN = cast<PHINode>(I);
for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i)
PN->setIncomingValue(i, getShiftedValue(PN->getIncomingValue(i), NumBits,
- IsLeftShift, Semantics));
+ isLeftShift, IC, DL));
return PN;
}
case Instruction::Mul: {
- assert(!IsLeftShift && "Unexpected shift direction!");
+ assert(!isLeftShift && "Unexpected shift direction!");
auto *Neg = BinaryOperator::CreateNeg(I->getOperand(0));
- InsertNewInstWith(Neg, I->getIterator());
+ IC.InsertNewInstWith(Neg, I->getIterator());
unsigned TypeWidth = I->getType()->getScalarSizeInBits();
APInt Mask = APInt::getLowBitsSet(TypeWidth, TypeWidth - NumBits);
auto *And = BinaryOperator::CreateAnd(Neg,
ConstantInt::get(I->getType(), Mask));
And->takeName(I);
- return InsertNewInstWith(And, I->getIterator());
- }
- case Instruction::Add: {
- if (IsLeftShift)
- I->dropPoisonGeneratingFlags();
- I->setOperand(
- 0, getShiftedValue(I->getOperand(0), NumBits, IsLeftShift, Semantics));
- I->setOperand(
- 1, getShiftedValue(I->getOperand(1), NumBits, IsLeftShift, Semantics));
- return I;
+ return IC.InsertNewInstWith(And, I->getIterator());
}
}
}
@@ -897,20 +832,15 @@ Instruction *InstCombinerImpl::FoldShiftByConstant(Value *Op0, Constant *C1,
// See if we can propagate this shift into the input, this covers the trivial
// cast of lshr(shl(x,c1),c2) as well as other more complex cases.
- if (I.getOpcode() != Instruction::AShr) {
- bool IsLeftShift = I.getOpcode() == Instruction::Shl;
- ShiftSemantics Semantics =
- IsLeftShift ? ShiftSemantics::Lossy : ShiftSemantics::Unsigned;
- if (canEvaluateShifted(Op0, Op1C->getZExtValue(), IsLeftShift, Semantics,
- &I)) {
- LLVM_DEBUG(
- dbgs() << "ICE: GetShiftedValue propagating shift through expression"
- " to eliminate shift:\n IN: "
- << *Op0 << "\n SH: " << I << "\n");
-
- return replaceInstUsesWith(I, getShiftedValue(Op0, Op1C->getZExtValue(),
- IsLeftShift, Semantics));
- }
+ if (I.getOpcode() != Instruction::AShr &&
+ canEvaluateShifted(Op0, Op1C->getZExtValue(), IsLeftShift, *this, &I)) {
+ LLVM_DEBUG(
+ dbgs() << "ICE: GetShiftedValue propagating shift through expression"
+ " to eliminate shift:\n IN: "
+ << *Op0 << "\n SH: " << I << "\n");
+
+ return replaceInstUsesWith(
+ I, getShiftedValue(Op0, Op1C->getZExtValue(), IsLeftShift, *this, DL));
}
if (Instruction *FoldedShift = foldBinOpIntoSelectOrPhi(I))
diff --git a/llvm/test/Transforms/InstCombine/apint-shift.ll b/llvm/test/Transforms/InstCombine/apint-shift.ll
index a2d9159e58e88..4dd0811bb7ecb 100644
--- a/llvm/test/Transforms/InstCombine/apint-shift.ll
+++ b/llvm/test/Transforms/InstCombine/apint-shift.ll
@@ -538,9 +538,9 @@ define <2 x i43> @lshr_shl_eq_amt_multi_use_splat_vec(<2 x i43> %A) {
define i37 @test25(i37 %AA, i37 %BB) {
; CHECK-LABEL: @test25(
; CHECK-NEXT: [[D:%.*]] = and i37 [[AA:%.*]], -131072
-; CHECK-NEXT: [[F:%.*]] = and i37 [[C2:%.*]], -131072
-; CHECK-NEXT: [[E1:%.*]] = add i37 [[F]], [[D]]
-; CHECK-NEXT: ret i37 [[E1]]
+; CHECK-NEXT: [[C2:%.*]] = add i37 [[BB:%.*]], [[D]]
+; CHECK-NEXT: [[F:%.*]] = and i37 [[C2]], -131072
+; CHECK-NEXT: ret i37 [[F]]
;
%C = lshr i37 %BB, 17
%D = lshr i37 %AA, 17
diff --git a/llvm/test/Transforms/InstCombine/icmp-select.ll b/llvm/test/Transforms/InstCombine/icmp-select.ll
index c1a7e4dfe1fea..4b24f423841f0 100644
--- a/llvm/test/Transforms/InstCombine/icmp-select.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-select.ll
@@ -917,7 +917,7 @@ define i1 @shl_failed_to_simplify(i8 %a, i1 %cond) {
define i1 @shl_nuw_ne(i8 %a, i8 %b, i8 %c, i1 %cond) {
; CHECK-LABEL: @shl_nuw_ne(
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND:%.*]], i8 [[B:%.*]], i8 4
-; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[A:%.*]], [[TMP1]]
+; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%shl_a = shl nuw i8 %a, 3
diff --git a/llvm/test/Transforms/InstCombine/icmp-shl-add-to-add.ll b/llvm/test/Transforms/InstCombine/icmp-shl-add-to-add.ll
deleted file mode 100644
index eb0a19f9459ad..0000000000000
--- a/llvm/test/Transforms/InstCombine/icmp-shl-add-to-add.ll
+++ /dev/null
@@ -1,311 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt < %s -passes=instcombine -S | FileCheck %s
-
-; Test case: Fold (X << 5) == ((Y << 5) + 32) into X == (Y + 1).
-; This corresponds to the provided alive2 proof.
-
-declare void @use_i64(i64)
-
-define i1 @shl_add_const_eq_base(i64 %v0, i64 %v3) {
-; CHECK-LABEL: @shl_add_const_eq_base(
-; CHECK-NEXT: [[V5:%.*]] = add nsw i64 [[V3:%.*]], 1
-; CHECK-NEXT: [[V6:%.*]] = icmp eq i64 [[V1:%.*]], [[V5]]
-; CHECK-NEXT: ret i1 [[V6]]
-;
- %v1 = shl nsw i64 %v0, 5
- %v4 = shl nsw i64 %v3, 5
- %v5 = add nsw i64 %v4, 32
- %v6 = icmp eq i64 %v1, %v5
- ret i1 %v6
-}
-
-; Test: icmp ne
-define i1 @shl_add_const_ne(i64 %v0, i64 %v3) {
-; CHECK-LABEL: @shl_add_const_ne(
-; CHECK-NEXT: [[V5:%.*]] = add nsw i64 [[V3:%.*]], 1
-; CHECK-NEXT: [[V6:%.*]] = icmp ne i64 [[V1:%.*]], [[V5]]
-; CHECK-NEXT: ret i1 [[V6]]
-;
- %v1 = shl nsw i64 %v0, 5
- %v4 = shl nsw i64 %v3, 5
- %v5 = add nsw i64 %v4, 32
- %v6 = icmp ne i64 %v1, %v5 ; Note: icmp ne
- ret i1 %v6
-}
-
-; Test: shl amounts do not match (5 vs 4).
-define i1 @shl_add_const_eq_mismatch_shl_amt(i64 %v0, i64 %v3) {
-; CHECK-LABEL: @shl_add_const_eq_mismatch_shl_amt(
-; CHECK-NEXT: [[V1:%.*]] = shl nsw i64 [[V0:%.*]], 5
-; CHECK-NEXT: [[V4:%.*]] = shl nsw i64 [[V3:%.*]], 4
-; CHECK-NEXT: [[V5:%.*]] = add nsw i64 [[V4]], 16
-; CHECK-NEXT: [[V6:%.*]] = icmp eq i64 [[V1]], [[V5]]
-; CHECK-NEXT: ret i1 [[V6]]
-;
- %v1 = shl nsw i64 %v0, 5
- %v4 = shl nsw i64 %v3, 4 ; Shift amount mismatch
- %v5 = add nsw i64 %v4, 16
- %v6 = icmp eq i64 %v1, %v5
- ret i1 %v6
-}
-
-; Test: Constant K is a multiple of 2^L (64 vs 32). Should simplify to K/2^L = 2.
-define i1 @shl_add_const_eq_k_multiple_of_pow2(i64 %v0, i64 %v3) {
-; CHECK-LABEL: @shl_add_const_eq_k_multiple_of_pow2(
-; CHECK-NEXT: [[V5:%.*]] = add nsw i64 [[V3:%.*]], 2
-; CHECK-NEXT: [[V6:%.*]] = icmp eq i64 [[V1:%.*]], [[V5]]
-; CHECK-NEXT: ret i1 [[V6]]
-;
- %v1 = shl nsw i64 %v0, 5
- %v4 = shl nsw i64 %v3, 5
- %v5 = add nsw i64 %v4, 64 ; Constant mismatch
- %v6 = icmp eq i64 %v1, %v5
- ret i1 %v6
-}
-
-; Test: Missing NSW flag on one of the shl instructions.
-define i1 @shl_add_const_eq_no_nsw_on_v1(i64 %v0, i64 %v3) {
-; CHECK-LABEL: @shl_add_const_eq_no_nsw_on_v1(
-; CHECK-NEXT: [[V1:%.*]] = shl i64 [[V0:%.*]], 5
-; CHECK-NEXT: [[V4:%.*]] = shl nsw i64 [[V3:%.*]], 5
-; CHECK-NEXT: [[V5:%.*]] = add nsw i64 [[V4]], 32
-; CHECK-NEXT: [[V6:%.*]] = icmp eq i64 [[V1]], [[V5]]
-; CHECK-NEXT: ret i1 [[V6]]
-;
- %v1 = shl i64 %v0, 5 ; Missing nsw
- %v4 = shl nsw i64 %v3, 5
- %v5 = add nsw i64 %v4, 32
- %v6 = icmp eq i64 %v1, %v5
- ret i1 %v6
-}
-
-; Test: Lower bit width (i8) and
diff erent shift amount (3). Constant is 8.
-define i1 @shl_add_const_eq_i8(i8 %v0, i8 %v3) {
-; CHECK-LABEL: @shl_add_const_eq_i8(
-; CHECK-NEXT: [[TMP1:%.*]] = add nsw i8 [[V3:%.*]], 1
-; CHECK-NEXT: [[V6:%.*]] = icmp eq i8 [[V0:%.*]], [[TMP1]]
-; CHECK-NEXT: ret i1 [[V6]]
-;
- %v1 = shl nsw i8 %v0, 3
- %v4 = shl nsw i8 %v3, 3
- %v5 = add nsw i8 %v4, 8 ; 2^3 = 8
- %v6 = icmp eq i8 %v1, %v5
- ret i1 %v6
-}
-
-; Test: i32 bit width and larger shift amount (10). Constant is 1024.
-define i1 @shl_add_const_eq_i32(i32 %v0, i32 %v3) {
-; CHECK-LABEL: @shl_add_const_eq_i32(
-; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[V3:%.*]], 1
-; CHECK-NEXT: [[V6:%.*]] = icmp eq i32 [[V0:%.*]], [[TMP1]]
-; CHECK-NEXT: ret i1 [[V6]]
-;
- %v1 = shl nsw i32 %v0, 10
- %v4 = shl nsw i32 %v3, 10
- %v5 = add nsw i32 %v4, 1024 ; 2^10 = 1024
- %v6 = icmp eq i32 %v1, %v5
- ret i1 %v6
-}
-
-; Test: Multi-use case. The optimization should still occur if applicable,
-; but the extraneous call must be preserved.
-define i1 @shl_add_const_eq_multi_use(i64 %v0, i64 %v3) {
-; CHECK-LABEL: @shl_add_const_eq_multi_use(
-; CHECK-NEXT: [[V1:%.*]] = shl nsw i64 [[V0:%.*]], 5
-; CHECK-NEXT: call void @use_i64(i64 [[V1]])
-; CHECK-NEXT: [[V5:%.*]] = add nsw i64 [[V3:%.*]], 1
-; CHECK-NEXT: [[V6:%.*]] = icmp eq i64 [[V0]], [[V5]]
-; CHECK-NEXT: ret i1 [[V6]]
-;
- %v1 = shl nsw i64 %v0, 5
- call void @use_i64(i64 %v1) ; Additional use of v1
- %v4 = shl nsw i64 %v3, 5
- %v5 = add nsw i64 %v4, 32
- %v6 = icmp eq i64 %v1, %v5
- ret i1 %v6
-}
-
-; Test: Vector splat. Should fold once optimization is applied.
-define <2 x i1> @shl_add_const_eq_vec_splat(<2 x i64> %v0, <2 x i64> %v3) {
-; CHECK-LABEL: @shl_add_const_eq_vec_splat(
-; CHECK-NEXT: [[V5:%.*]] = add nsw <2 x i64> [[V3:%.*]], splat (i64 1)
-; CHECK-NEXT: [[V6:%.*]] = icmp eq <2 x i64> [[V1:%.*]], [[V5]]
-; CHECK-NEXT: ret <2 x i1> [[V6]]
-;
- %v1 = shl nsw <2 x i64> %v0, <i64 5, i64 5>
- %v4 = shl nsw <2 x i64> %v3, <i64 5, i64 5>
- %v5 = add nsw <2 x i64> %v4, <i64 32, i64 32>
- %v6 = icmp eq <2 x i64> %v1, %v5
- ret <2 x i1> %v6
-}
-
-; Test: Vector splat with poison. Should fold once optimization is applied.
-define <2 x i1> @shl_add_const_eq_vec_splat_poison(<2 x i64> %v0, <2 x i64> %v3) {
-; CHECK-LABEL: @shl_add_const_eq_vec_splat_poison(
-; CHECK-NEXT: [[V5:%.*]] = add nsw <2 x i64> [[V3:%.*]], <i64 1, i64 poison>
-; CHECK-NEXT: [[V6:%.*]] = icmp eq <2 x i64> [[V1:%.*]], [[V5]]
-; CHECK-NEXT: ret <2 x i1> [[V6]]
-;
- %v1 = shl nsw <2 x i64> %v0, <i64 5, i64 5>
- %v4 = shl nsw <2 x i64> %v3, <i64 5, i64 5>
- %v5 = add nsw <2 x i64> %v4, <i64 32, i64 poison>
- %v6 = icmp eq <2 x i64> %v1, %v5
- ret <2 x i1> %v6
-}
-
-; Test: Vector non-splat (should not fold).
-define <2 x i1> @shl_add_const_eq_vec_non_splat(<2 x i64> %v0, <2 x i64> %v3) {
-; CHECK-LABEL: @shl_add_const_eq_vec_non_splat(
-; CHECK-NEXT: [[V1:%.*]] = shl nsw <2 x i64> [[V0:%.*]], <i64 5, i64 6>
-; CHECK-NEXT: [[V4:%.*]] = shl nsw <2 x i64> [[V3:%.*]], <i64 5, i64 6>
-; CHECK-NEXT: [[V5:%.*]] = add nsw <2 x i64> [[V4]], <i64 32, i64 64>
-; CHECK-NEXT: [[V6:%.*]] = icmp eq <2 x i64> [[V1]], [[V5]]
-; CHECK-NEXT: ret <2 x i1> [[V6]]
-;
- %v1 = shl nsw <2 x i64> %v0, <i64 5, i64 6>
- %v4 = shl nsw <2 x i64> %v3, <i64 5, i64 6>
- %v5 = add nsw <2 x i64> %v4, <i64 32, i64 64>
- %v6 = icmp eq <2 x i64> %v1, %v5
- ret <2 x i1> %v6
-}
-
-; Test: Commutative (shl on the right side).
-define i1 @shl_add_const_eq_commutative(i64 %v0, i64 %v3) {
-; CHECK-LABEL: @shl_add_const_eq_commutative(
-; CHECK-NEXT: [[V5:%.*]] = add nsw i64 [[V3:%.*]], 1
-; CHECK-NEXT: [[V6:%.*]] = icmp eq i64 [[V0:%.*]], [[V5]]
-; CHECK-NEXT: ret i1 [[V6]]
-;
- %v1 = shl nsw i64 %v0, 5
- %v4 = shl nsw i64 %v3, 5
- %v5 = add nsw i64 %v4, 32
- %v6 = icmp eq i64 %v5, %v1
- ret i1 %v6
-}
-
-; Test: Variable shift amount with nuw (Logical)
-define i1 @icmp_shl_var_amount_nuw(i32 %x, i32 %y) {
-; CHECK-LABEL: @icmp_shl_var_amount_nuw(
-; CHECK-NEXT: [[Y:%.*]] = add nuw i32 [[Y1:%.*]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y]]
-; CHECK-NEXT: ret i1 [[CMP]]
-;
- %shlx = shl nuw i32 %x, 5
- %shly = shl nuw i32 %y, 5
- %add = add nuw i32 %shly, 32
- %cmp = icmp eq i32 %shlx, %add
- ret i1 %cmp
-}
-
-; Test: Variable shift amount with nsw (Arithmetic)
-define i1 @icmp_shl_var_amount_nsw(i32 %x, i32 %y) {
-; CHECK-LABEL: @icmp_shl_var_amount_nsw(
-; CHECK-NEXT: [[Y:%.*]] = add nsw i32 [[Y1:%.*]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y]]
-; CHECK-NEXT: ret i1 [[CMP]]
-;
- %shlx = shl nsw i32 %x, 5
- %shly = shl nsw i32 %y, 5
- %add = add nsw i32 %shly, 32
- %cmp = icmp eq i32 %shlx, %add
- ret i1 %cmp
-}
-
-; Test: ult (Unsigned Less Than) with nuw
-define i1 @icmp_shl_nuw_ult(i32 %x, i32 %y) {
-; CHECK-LABEL: @icmp_shl_nuw_ult(
-; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: ret i1 [[CMP]]
-;
- %shlx = shl nuw i32 %x, 5
- %shly = shl nuw i32 %y, 5
- %add = add nuw i32 %shly, 32
- %cmp = icmp ult i32 %shlx, %add
- ret i1 %cmp
-}
-
-; Test: ugt (Unsigned Greater Than) with nuw
-define i1 @icmp_shl_nuw_ugt(i32 %x, i32 %y) {
-; CHECK-LABEL: @icmp_shl_nuw_ugt(
-; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[Y:%.*]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[X:%.*]], [[TMP1]]
-; CHECK-NEXT: ret i1 [[CMP]]
-;
- %shlx = shl nuw i32 %x, 5
- %shly = shl nuw i32 %y, 5
- %add = add nuw i32 %shly, 32
- %cmp = icmp ugt i32 %shlx, %add
- ret i1 %cmp
-}
-
-; Test: slt (Signed Less Than) with nsw
-define i1 @icmp_shl_nsw_slt(i32 %x, i32 %y) {
-; CHECK-LABEL: @icmp_shl_nsw_slt(
-; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: ret i1 [[CMP]]
-;
- %shlx = shl nsw i32 %x, 5
- %shly = shl nsw i32 %y, 5
- %add = add nsw i32 %shly, 32
- %cmp = icmp slt i32 %shlx, %add
- ret i1 %cmp
-}
-
-; Test: sgt (Signed Greater Than) with nsw
-define i1 @icmp_shl_nsw_sgt(i32 %x, i32 %y) {
-; CHECK-LABEL: @icmp_shl_nsw_sgt(
-; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[Y:%.*]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[X:%.*]], [[TMP1]]
-; CHECK-NEXT: ret i1 [[CMP]]
-;
- %shlx = shl nsw i32 %x, 5
- %shly = shl nsw i32 %y, 5
- %add = add nsw i32 %shly, 32
- %cmp = icmp sgt i32 %shlx, %add
- ret i1 %cmp
-}
-
-; Test: sle (Signed Less or Equal) with nsw
-define i1 @icmp_shl_nsw_sle(i32 %x, i32 %y) {
-; CHECK-LABEL: @icmp_shl_nsw_sle(
-; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[Y:%.*]], 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[X:%.*]], [[TMP1]]
-; CHECK-NEXT: ret i1 [[CMP]]
-;
- %shlx = shl nsw i32 %x, 5
- %shly = shl nsw i32 %y, 5
- %add = add nsw i32 %shly, 32
- %cmp = icmp sle i32 %shlx, %add
- ret i1 %cmp
-}
-
-; NOTE: This is a regression test for a miscompile discovered by fuzzing.
-define i1 @icmp_slt_shl_nsw_add_nsw_fuzz(i32 %x, i32 %y) {
-; CHECK-LABEL: @icmp_slt_shl_nsw_add_nsw_fuzz(
-; CHECK-NEXT: [[SHLX:%.*]] = shl nsw i32 [[X:%.*]], 5
-; CHECK-NEXT: [[SHLY:%.*]] = shl nuw i32 [[Y:%.*]], 5
-; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[SHLX]], [[SHLY]]
-; CHECK-NEXT: ret i1 [[CMP]]
-;
- %shlx = shl nsw i32 %x, 5
- %shly = shl nuw i32 %y, 5
- %add = add nsw i32 32, %shly
- %cmp = icmp slt i32 %shlx, %add
- ret i1 %cmp
-}
-
-; NOTE: This is a regression test for a miscompile discovered by fuzzing (unsigned comparison).
-define i1 @icmp_ugt_shl_nuw_add_nsw_fuzz(i32 %x, i32 %y) {
-; CHECK-LABEL: @icmp_ugt_shl_nuw_add_nsw_fuzz(
-; CHECK-NEXT: [[SHLX:%.*]] = shl nuw i32 [[X:%.*]], 5
-; CHECK-NEXT: [[SHLY:%.*]] = shl nsw i32 [[Y:%.*]], 5
-; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SHLY]], 32
-; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i32 [[SHLX]], [[ADD]]
-; CHECK-NEXT: ret i1 [[CMP]]
-;
- %shlx = shl nuw i32 %x, 5
- %shly = shl nsw i32 %y, 5
- %add = add nsw i32 %shly, 32
- %cmp = icmp ugt i32 %shlx, %add
- ret i1 %cmp
-}
More information about the llvm-branch-commits
mailing list