[llvm] 519cb46 - [SCCP] Remove masking operations (#142736)

via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 4 07:31:12 PDT 2025


Author: Yingwei Zheng
Date: 2025-06-04T22:31:08+08:00
New Revision: 519cb460f6fa58d1c36ad55d5812882f7ba38e2a

URL: https://github.com/llvm/llvm-project/commit/519cb460f6fa58d1c36ad55d5812882f7ba38e2a
DIFF: https://github.com/llvm/llvm-project/commit/519cb460f6fa58d1c36ad55d5812882f7ba38e2a.diff

LOG: [SCCP] Remove masking operations (#142736)

CVP version:
https://github.com/llvm/llvm-project/commit/2d5820cd72255e04aaef2da3c21d62396fdd7fb9
Compile-time impact:
https://llvm-compile-time-tracker.com/compare.php?from=3ec0c5c7fef03985b43432c6b914c289d8a5435e&to=92b4df90695dd37defdabf8a30f0b0322b648a00&stat=instructions:u

Added: 
    

Modified: 
    llvm/lib/Transforms/Utils/SCCPSolver.cpp
    llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll
    llvm/test/Transforms/SCCP/range-and.ll
    llvm/test/Transforms/SCCP/range-with-undef.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index 4535f86f9d68b..1a2e422356270 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -20,6 +20,7 @@
 #include "llvm/Analysis/ValueLatticeUtils.h"
 #include "llvm/Analysis/ValueTracking.h"
 #include "llvm/IR/InstVisitor.h"
+#include "llvm/IR/PatternMatch.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -30,6 +31,7 @@
 #include <vector>
 
 using namespace llvm;
+using namespace PatternMatch;
 
 #define DEBUG_TYPE "sccp"
 
@@ -83,20 +85,28 @@ bool SCCPSolver::tryToReplaceWithConstant(Value *V) {
   return true;
 }
 
+/// Helper for getting ranges from \p Solver. Instructions inserted during
+/// simplification are unavailable in the solver, so we return a full range for
+/// them.
+static ConstantRange getRange(Value *Op, SCCPSolver &Solver,
+                              const SmallPtrSetImpl<Value *> &InsertedValues) {
+  if (auto *Const = dyn_cast<Constant>(Op))
+    return Const->toConstantRange();
+  if (InsertedValues.contains(Op)) {
+    unsigned Bitwidth = Op->getType()->getScalarSizeInBits();
+    return ConstantRange::getFull(Bitwidth);
+  }
+  return Solver.getLatticeValueFor(Op).asConstantRange(Op->getType(),
+                                                       /*UndefAllowed=*/false);
+}
+
 /// Try to use \p Inst's value range from \p Solver to infer the NUW flag.
 static bool refineInstruction(SCCPSolver &Solver,
                               const SmallPtrSetImpl<Value *> &InsertedValues,
                               Instruction &Inst) {
   bool Changed = false;
   auto GetRange = [&Solver, &InsertedValues](Value *Op) {
-    if (auto *Const = dyn_cast<Constant>(Op))
-      return Const->toConstantRange();
-    if (InsertedValues.contains(Op)) {
-      unsigned Bitwidth = Op->getType()->getScalarSizeInBits();
-      return ConstantRange::getFull(Bitwidth);
-    }
-    return Solver.getLatticeValueFor(Op).asConstantRange(
-        Op->getType(), /*UndefAllowed=*/false);
+    return getRange(Op, Solver, InsertedValues);
   };
 
   if (isa<OverflowingBinaryOperator>(Inst)) {
@@ -167,16 +177,8 @@ static bool replaceSignedInst(SCCPSolver &Solver,
                               SmallPtrSetImpl<Value *> &InsertedValues,
                               Instruction &Inst) {
   // Determine if a signed value is known to be >= 0.
-  auto isNonNegative = [&Solver](Value *V) {
-    // If this value was constant-folded, it may not have a solver entry.
-    // Handle integers. Otherwise, return false.
-    if (auto *C = dyn_cast<Constant>(V)) {
-      auto *CInt = dyn_cast<ConstantInt>(C);
-      return CInt && !CInt->isNegative();
-    }
-    const ValueLatticeElement &IV = Solver.getLatticeValueFor(V);
-    return IV.isConstantRange(/*UndefAllowed=*/false) &&
-           IV.getConstantRange().isAllNonNegative();
+  auto isNonNegative = [&Solver, &InsertedValues](Value *V) {
+    return getRange(V, Solver, InsertedValues).isAllNonNegative();
   };
 
   Instruction *NewInst = nullptr;
@@ -185,7 +187,7 @@ static bool replaceSignedInst(SCCPSolver &Solver,
   case Instruction::SExt: {
     // If the source value is not negative, this is a zext/uitofp.
     Value *Op0 = Inst.getOperand(0);
-    if (InsertedValues.count(Op0) || !isNonNegative(Op0))
+    if (!isNonNegative(Op0))
       return false;
     NewInst = CastInst::Create(Inst.getOpcode() == Instruction::SExt
                                    ? Instruction::ZExt
@@ -197,7 +199,7 @@ static bool replaceSignedInst(SCCPSolver &Solver,
   case Instruction::AShr: {
     // If the shifted value is not negative, this is a logical shift right.
     Value *Op0 = Inst.getOperand(0);
-    if (InsertedValues.count(Op0) || !isNonNegative(Op0))
+    if (!isNonNegative(Op0))
       return false;
     NewInst = BinaryOperator::CreateLShr(Op0, Inst.getOperand(1), "", Inst.getIterator());
     NewInst->setIsExact(Inst.isExact());
@@ -207,8 +209,7 @@ static bool replaceSignedInst(SCCPSolver &Solver,
   case Instruction::SRem: {
     // If both operands are not negative, this is the same as udiv/urem.
     Value *Op0 = Inst.getOperand(0), *Op1 = Inst.getOperand(1);
-    if (InsertedValues.count(Op0) || InsertedValues.count(Op1) ||
-        !isNonNegative(Op0) || !isNonNegative(Op1))
+    if (!isNonNegative(Op0) || !isNonNegative(Op1))
       return false;
     auto NewOpcode = Inst.getOpcode() == Instruction::SDiv ? Instruction::UDiv
                                                            : Instruction::URem;
@@ -232,6 +233,26 @@ static bool replaceSignedInst(SCCPSolver &Solver,
   return true;
 }
 
+/// Try to use \p Inst's value range from \p Solver to simplify it.
+static Value *simplifyInstruction(SCCPSolver &Solver,
+                                  SmallPtrSetImpl<Value *> &InsertedValues,
+                                  Instruction &Inst) {
+  auto GetRange = [&Solver, &InsertedValues](Value *Op) {
+    return getRange(Op, Solver, InsertedValues);
+  };
+
+  Value *X;
+  const APInt *RHSC;
+  // Remove masking operations.
+  if (match(&Inst, m_And(m_Value(X), m_LowBitMask(RHSC)))) {
+    ConstantRange LRange = GetRange(Inst.getOperand(0));
+    if (LRange.getUnsignedMax().ule(*RHSC))
+      return X;
+  }
+
+  return nullptr;
+}
+
 bool SCCPSolver::simplifyInstsInBlock(BasicBlock &BB,
                                       SmallPtrSetImpl<Value *> &InsertedValues,
                                       Statistic &InstRemovedStat,
@@ -251,6 +272,11 @@ bool SCCPSolver::simplifyInstsInBlock(BasicBlock &BB,
       ++InstReplacedStat;
     } else if (refineInstruction(*this, InsertedValues, Inst)) {
       MadeChanges = true;
+    } else if (auto *V = simplifyInstruction(*this, InsertedValues, Inst)) {
+      Inst.replaceAllUsesWith(V);
+      Inst.eraseFromParent();
+      ++InstRemovedStat;
+      MadeChanges = true;
     }
   }
   return MadeChanges;

diff  --git a/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll b/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll
index 8b4dea462757e..b49a40abaaeb1 100644
--- a/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll
+++ b/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll
@@ -36,8 +36,6 @@ false:
 
 declare void @use.i32(i32)
 
-; It is not allowed to use the range information from the condition to remove
-; %a.127 = and ... in the true block, as %a could be undef.
 define void @val_undef_range() {
 ; CHECK-LABEL: @val_undef_range(
 ; CHECK-NEXT:  entry:
@@ -46,8 +44,7 @@ define void @val_undef_range() {
 ; CHECK-NEXT:    br i1 [[BC_1]], label [[TRUE:%.*]], label [[FALSE:%.*]]
 ; CHECK:       true:
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[A_127:%.*]] = and i32 [[A]], 127
-; CHECK-NEXT:    call void @use.i32(i32 [[A_127]])
+; CHECK-NEXT:    call void @use.i32(i32 [[A]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       false:
 ; CHECK-NEXT:    ret void
@@ -82,8 +79,7 @@ define void @val_singlecrfromundef_range(i1 %cond) {
 ; CHECK-NEXT:    br label [[TRUE:%.*]]
 ; CHECK:       true:
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[P_127:%.*]] = and i32 10, 127
-; CHECK-NEXT:    call void @use.i32(i32 [[P_127]])
+; CHECK-NEXT:    call void @use.i32(i32 10)
 ; CHECK-NEXT:    ret void
 ;
 entry:
@@ -113,9 +109,6 @@ false:
   ret void
 }
 
-
-; It is not allowed to use the information from the condition ([0, 128))
-; to remove a.127.2 = and i32 %p, 127, as %p might be undef.
 define void @val_undef_to_cr_to_overdef_range(i32 %a, i1 %cond) {
 ; CHECK-LABEL: @val_undef_to_cr_to_overdef_range(
 ; CHECK-NEXT:  entry:
@@ -131,8 +124,7 @@ define void @val_undef_to_cr_to_overdef_range(i32 %a, i1 %cond) {
 ; CHECK-NEXT:    br i1 [[BC_1]], label [[TRUE:%.*]], label [[FALSE:%.*]]
 ; CHECK:       true:
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[P_127:%.*]] = and i32 [[P]], 127
-; CHECK-NEXT:    call void @use.i32(i32 [[P_127]])
+; CHECK-NEXT:    call void @use.i32(i32 [[P]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       false:
 ; CHECK-NEXT:    ret void
@@ -164,6 +156,43 @@ false:
   ret void
 }
 
+; It is not allowed to use the range information from the condition to remove
+; %p.127 = and i32 %p, 127, as %p could be undef.
+define void @masked_incoming_val_with_undef(i32 %a, i1 %cond) {
+; CHECK-LABEL: @masked_incoming_val_with_undef(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[A_127:%.*]] = and i32 [[A:%.*]], 127
+; CHECK-NEXT:    br i1 [[COND:%.*]], label [[INC1:%.*]], label [[INC2:%.*]]
+; CHECK:       inc1:
+; CHECK-NEXT:    br label [[IF:%.*]]
+; CHECK:       inc2:
+; CHECK-NEXT:    br label [[IF]]
+; CHECK:       if:
+; CHECK-NEXT:    [[P:%.*]] = phi i32 [ [[A_127]], [[INC1]] ], [ undef, [[INC2]] ]
+; CHECK-NEXT:    [[P_127:%.*]] = and i32 [[P]], 127
+; CHECK-NEXT:    call void @use.i32(i32 [[P_127]])
+; CHECK-NEXT:    ret void
+;
+entry:
+  %a.127 = and i32 %a, 127
+  br i1 %cond, label %inc1, label %inc2
+
+inc1:
+  br label %if
+
+inc2:
+  br label %if
+
+if:
+  %p = phi i32 [ %a.127, %inc1 ], [ undef, %inc2 ]
+  %p.127 = and i32 %p, 127
+  call void @use.i32(i32 %p.127)
+  ret void
+
+false:
+  ret void
+}
+
 ; All uses of %p can be replaced by a constant (10), we are allowed to use it
 ; as a bound too.
 define void @bound_singlecrfromundef(i32 %a, i1 %cond) {

diff  --git a/llvm/test/Transforms/SCCP/range-and.ll b/llvm/test/Transforms/SCCP/range-and.ll
index ef8758fcba9e2..f3452f45e1c02 100644
--- a/llvm/test/Transforms/SCCP/range-and.ll
+++ b/llvm/test/Transforms/SCCP/range-and.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --verbose
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
 ; RUN: opt -S -passes=sccp %s | FileCheck %s
 
 declare void @use(i1)
@@ -140,9 +140,8 @@ define i64 @constant_range_and_255_100(i1 %cond, i64 %a) {
 ; CHECK-NEXT:    br label [[BB3]]
 ; CHECK:       bb3:
 ; CHECK-NEXT:    [[P:%.*]] = phi i64 [ [[R_1]], [[BB1]] ], [ [[R_2]], [[BB2]] ]
-; CHECK-NEXT:    [[P_AND:%.*]] = and i64 [[P]], 255
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    ret i64 [[P_AND]]
+; CHECK-NEXT:    ret i64 [[P]]
 ;
 entry:
   br i1 %cond, label %bb1, label %bb2

diff  --git a/llvm/test/Transforms/SCCP/range-with-undef.ll b/llvm/test/Transforms/SCCP/range-with-undef.ll
index 9b8d415171140..774d95ceff428 100644
--- a/llvm/test/Transforms/SCCP/range-with-undef.ll
+++ b/llvm/test/Transforms/SCCP/range-with-undef.ll
@@ -12,8 +12,7 @@ define i8 @test_binop(i1 %cond, i8 %a) {
 ; CHECK-NEXT:    [[A_EXT:%.*]] = zext i8 [[A]] to i16
 ; CHECK-NEXT:    br label %[[JOIN]]
 ; CHECK:       [[JOIN]]:
-; CHECK-NEXT:    [[PHI:%.*]] = phi i16 [ undef, %[[ENTRY]] ], [ [[A_EXT]], %[[IF]] ]
-; CHECK-NEXT:    [[AND:%.*]] = and i16 [[PHI]], -1
+; CHECK-NEXT:    [[AND:%.*]] = phi i16 [ undef, %[[ENTRY]] ], [ [[A_EXT]], %[[IF]] ]
 ; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i16 [[AND]] to i8
 ; CHECK-NEXT:    ret i8 [[TRUNC]]
 ;


        


More information about the llvm-commits mailing list