[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