[llvm] [SCCP] Remove masking operations (PR #142736)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 4 04:21:15 PDT 2025
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/142736
>From b2fd3c7b13b73441d59c9886f1a1c967e3c28a61 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 2 Jun 2025 21:53:35 +0800
Subject: [PATCH 1/4] [SCCP] Remove masking operations
---
llvm/lib/Transforms/Utils/SCCPSolver.cpp | 19 +++++++++++++++++--
.../SCCP/conditions-ranges-with-undef.ll | 9 +++------
llvm/test/Transforms/SCCP/range-and.ll | 5 ++---
llvm/test/Transforms/SCCP/range-with-undef.ll | 3 +--
4 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index 4535f86f9d68b..f9c075eaa602b 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"
@@ -86,7 +88,7 @@ bool SCCPSolver::tryToReplaceWithConstant(Value *V) {
/// 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) {
+ Instruction &Inst, Statistic &InstRemovedStat) {
bool Changed = false;
auto GetRange = [&Solver, &InsertedValues](Value *Op) {
if (auto *Const = dyn_cast<Constant>(Op))
@@ -99,6 +101,9 @@ static bool refineInstruction(SCCPSolver &Solver,
Op->getType(), /*UndefAllowed=*/false);
};
+ Value *X;
+ const APInt *RHSC;
+
if (isa<OverflowingBinaryOperator>(Inst)) {
if (Inst.hasNoSignedWrap() && Inst.hasNoUnsignedWrap())
return false;
@@ -157,6 +162,15 @@ static bool refineInstruction(SCCPSolver &Solver,
GEPNoWrapFlags::noUnsignedWrap());
Changed = true;
}
+ } else if (match(&Inst, m_And(m_Value(X), m_LowBitMask(RHSC)))) {
+ ConstantRange LRange = GetRange(Inst.getOperand(0));
+ if (!LRange.getUnsignedMax().ule(*RHSC))
+ return false;
+
+ Inst.replaceAllUsesWith(X);
+ Inst.eraseFromParent();
+ ++InstRemovedStat;
+ Changed = true;
}
return Changed;
@@ -249,7 +263,8 @@ bool SCCPSolver::simplifyInstsInBlock(BasicBlock &BB,
} else if (replaceSignedInst(*this, InsertedValues, Inst)) {
MadeChanges = true;
++InstReplacedStat;
- } else if (refineInstruction(*this, InsertedValues, Inst)) {
+ } else if (refineInstruction(*this, InsertedValues, Inst,
+ InstRemovedStat)) {
MadeChanges = true;
}
}
diff --git a/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll b/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll
index 8b4dea462757e..207f303b83460 100644
--- a/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll
+++ b/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll
@@ -46,8 +46,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 +81,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:
@@ -131,8 +129,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
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]]
;
>From 39c7b9e1b1b655387572e9f49246d7c60b0372e6 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 4 Jun 2025 16:20:33 +0800
Subject: [PATCH 2/4] [SCCP] Update tests. NFC.
---
.../SCCP/conditions-ranges-with-undef.ll | 42 ++++++++++++++++---
1 file changed, 37 insertions(+), 5 deletions(-)
diff --git a/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll b/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll
index 207f303b83460..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:
@@ -111,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:
@@ -161,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) {
>From 175612e6c01d0ad1401973a0d2dbc5522b74dfac Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 4 Jun 2025 16:28:16 +0800
Subject: [PATCH 3/4] [SCCP] Move the logic out of `refineInstruction`. NFC.
---
llvm/lib/Transforms/Utils/SCCPSolver.cpp | 49 ++++++++++++++++--------
1 file changed, 34 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index f9c075eaa602b..3c6f39ce1f3c9 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -88,7 +88,7 @@ bool SCCPSolver::tryToReplaceWithConstant(Value *V) {
/// 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, Statistic &InstRemovedStat) {
+ Instruction &Inst) {
bool Changed = false;
auto GetRange = [&Solver, &InsertedValues](Value *Op) {
if (auto *Const = dyn_cast<Constant>(Op))
@@ -101,9 +101,6 @@ static bool refineInstruction(SCCPSolver &Solver,
Op->getType(), /*UndefAllowed=*/false);
};
- Value *X;
- const APInt *RHSC;
-
if (isa<OverflowingBinaryOperator>(Inst)) {
if (Inst.hasNoSignedWrap() && Inst.hasNoUnsignedWrap())
return false;
@@ -162,15 +159,6 @@ static bool refineInstruction(SCCPSolver &Solver,
GEPNoWrapFlags::noUnsignedWrap());
Changed = true;
}
- } else if (match(&Inst, m_And(m_Value(X), m_LowBitMask(RHSC)))) {
- ConstantRange LRange = GetRange(Inst.getOperand(0));
- if (!LRange.getUnsignedMax().ule(*RHSC))
- return false;
-
- Inst.replaceAllUsesWith(X);
- Inst.eraseFromParent();
- ++InstRemovedStat;
- Changed = true;
}
return Changed;
@@ -246,6 +234,33 @@ 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) {
+ 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);
+ };
+
+ 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,
@@ -263,8 +278,12 @@ bool SCCPSolver::simplifyInstsInBlock(BasicBlock &BB,
} else if (replaceSignedInst(*this, InsertedValues, Inst)) {
MadeChanges = true;
++InstReplacedStat;
- } else if (refineInstruction(*this, InsertedValues, Inst,
- InstRemovedStat)) {
+ } else if (refineInstruction(*this, InsertedValues, Inst)) {
+ MadeChanges = true;
+ } else if (auto *V = simplifyInstruction(*this, InsertedValues, Inst)) {
+ Inst.replaceAllUsesWith(V);
+ Inst.eraseFromParent();
+ ++InstRemovedStat;
MadeChanges = true;
}
}
>From 96a2a17fe5b983a6b9d3b42479ace97680faf557 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 4 Jun 2025 19:20:44 +0800
Subject: [PATCH 4/4] [SCCP] Simplify code. NFC.
---
llvm/lib/Transforms/Utils/SCCPSolver.cpp | 52 ++++++++++--------------
1 file changed, 22 insertions(+), 30 deletions(-)
diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index 3c6f39ce1f3c9..1a2e422356270 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -85,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)) {
@@ -169,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;
@@ -187,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
@@ -199,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());
@@ -209,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;
@@ -239,14 +238,7 @@ static Value *simplifyInstruction(SCCPSolver &Solver,
SmallPtrSetImpl<Value *> &InsertedValues,
Instruction &Inst) {
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);
};
Value *X;
More information about the llvm-commits
mailing list