[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