[llvm] [ValueTracking] Improve KnownBits for signed min-max clamping (PR #120576)
Craig Topper via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 26 21:36:41 PST 2024
================
@@ -1065,6 +1065,63 @@ void llvm::adjustKnownBitsForSelectArm(KnownBits &Known, Value *Cond,
Known = CondRes;
}
+// Match a signed min+max clamp pattern like smax(smin(In, CHigh), CLow).
+// Returns the input and lower/upper bounds.
+static bool isSignedMinMaxClamp(const Value *Select, const Value *&In,
+ const APInt *&CLow, const APInt *&CHigh) {
+ assert(isa<Operator>(Select) &&
+ cast<Operator>(Select)->getOpcode() == Instruction::Select &&
+ "Input should be a Select!");
+
+ const Value *LHS = nullptr, *RHS = nullptr;
+ SelectPatternFlavor SPF = matchSelectPattern(Select, LHS, RHS).Flavor;
+ if (SPF != SPF_SMAX && SPF != SPF_SMIN)
+ return false;
+
+ if (!match(RHS, m_APInt(CLow)))
+ return false;
+
+ const Value *LHS2 = nullptr, *RHS2 = nullptr;
+ SelectPatternFlavor SPF2 = matchSelectPattern(LHS, LHS2, RHS2).Flavor;
+ if (getInverseMinMaxFlavor(SPF) != SPF2)
+ return false;
+
+ if (!match(RHS2, m_APInt(CHigh)))
+ return false;
+
+ if (SPF == SPF_SMIN)
+ std::swap(CLow, CHigh);
+
+ In = LHS2;
+ return CLow->sle(*CHigh);
+}
+
+static bool isSignedMinMaxIntrinsicClamp(const IntrinsicInst *II,
+ const APInt *&CLow,
+ const APInt *&CHigh) {
+ assert((II->getIntrinsicID() == Intrinsic::smin ||
+ II->getIntrinsicID() == Intrinsic::smax) &&
+ "Must be smin/smax");
+
+ Intrinsic::ID InverseID = getInverseMinMaxIntrinsic(II->getIntrinsicID());
+ auto *InnerII = dyn_cast<IntrinsicInst>(II->getArgOperand(0));
+ if (!InnerII || InnerII->getIntrinsicID() != InverseID ||
+ !match(II->getArgOperand(1), m_APInt(CLow)) ||
+ !match(InnerII->getArgOperand(1), m_APInt(CHigh)))
+ return false;
+
+ if (II->getIntrinsicID() == Intrinsic::smin)
+ std::swap(CLow, CHigh);
+ return CLow->sle(*CHigh);
+}
+
+static void unionWithMinMaxIntrinsicClamp(const IntrinsicInst *II,
+ KnownBits &Known) {
+ const APInt *CLow, *CHigh;
+ if (isSignedMinMaxIntrinsicClamp(II, CLow, CHigh))
+ Known = Known.unionWith(ConstantRange(*CLow, *CHigh + 1).toKnownBits());
----------------
topperc wrote:
The ConstantRange constructor will assert if CLow and CHigh+1 are the same value.
For example, this incomplete unittest I threw together
```
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 0145ee70a14c..889f6bd5e78a 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -1262,6 +1262,16 @@ TEST_F(ComputeKnownBitsTest, ComputeKnownBits) {
expectKnownBits(/*zero*/ 4278190085u, /*one*/ 10u);
}
+TEST_F(ComputeKnownBitsTest, ComputeKnownBitsClamp) {
+ parseAssembly(
+ "define i32 @test(i32 %a) {\n"
+ " %amin = tail call i32 @llvm.smin.i32(i32 %a, i32 2147483647)\n"
+ " %A = tail call i32 @llvm.smax.i32(i32 %amin, i32 2147483648)\n"
+ " ret i32 %A\n"
+ "}\n");
+ expectKnownBits(/*zero*/ 0u, /*one*/ 0u);
+}
+
TEST_F(ComputeKnownBitsTest, ComputeKnownMulBits) {
parseAssembly(
"define i32 @test(i32 %a, i32 %b) {\n"
```
https://github.com/llvm/llvm-project/pull/120576
More information about the llvm-commits
mailing list