[llvm] [InstCombine] Fold icmp with clamp into unsigned bound check (PR #161303)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 30 23:52:49 PDT 2025


================
@@ -5780,6 +5780,44 @@ Instruction *InstCombinerImpl::foldICmpWithMinMax(Instruction &I,
   return nullptr;
 }
 
+/// Match and fold patterns like:
+///   icmp eq/ne X, min(max(X, Lo), Hi)
+/// which represents a range check and can be repsented as a ConstantRange.
+///
+/// For icmp eq, build ConstantRange [Lo, Hi + 1) and convert to:
+///   (X - Lo) u< (Hi + 1 - Lo)
+/// For icmp ne, build ConstantRange [Hi + 1, Lo) and convert to:
+///   (X - (Hi + 1)) u< (Lo - (Hi + 1))
+Instruction *InstCombinerImpl::foldICmpWithClamp(ICmpInst &I, Value *X,
+                                                 MinMaxIntrinsic *Min) {
+  if (!I.isEquality() || !Min->hasOneUse())
+    return nullptr;
+
+  const APInt *Lo = nullptr, *Hi = nullptr;
+  if (Min->isSigned()) {
+    if (!match(Min->getLHS(), m_OneUse(m_SMax(m_Specific(X), m_APInt(Lo)))) ||
+        !match(Min->getRHS(), m_APInt(Hi)) || !Lo->slt(*Hi))
+      return nullptr;
+  } else {
+    if (!match(Min->getLHS(), m_OneUse(m_UMax(m_Specific(X), m_APInt(Lo)))) ||
+        !match(Min->getRHS(), m_APInt(Hi)) || !Lo->ult(*Hi))
+      return nullptr;
+  }
+
+  ConstantRange CR(*Lo, *Hi + 1);
----------------
dtcxzyw wrote:

```suggestion
  ConstantRange CR = ConstantRange::getNonEmpty(*Lo, *Hi + 1);
```
I noticed that `%Up = add i8 %Hi, 1 %precond2 = icmp ne i8 %Lo, %Up call void @llvm.assume(i1 %precond2)` in the proof is not checked by the code. Although it is unlikely to happen in practice, it would be better to guard against this case with `getNonEmpty`.

https://github.com/llvm/llvm-project/pull/161303


More information about the llvm-commits mailing list