[llvm] [InstCombine] Avoid folding `select(umin(X, Y), X)` with min/max values in false arm (PR #143020)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 6 08:57:24 PDT 2025


================
@@ -1654,6 +1654,29 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
   if (Value *FreedOp = getFreedOperand(&CI, &TLI))
     return visitFree(CI, FreedOp);
 
+  if (Function *F = CI.getCalledFunction()) {
+    if (F->getIntrinsicID() == Intrinsic::umin ||
+        F->getIntrinsicID() == Intrinsic::umax) {
+      for (Value *Arg : CI.args()) {
+        auto *SI = dyn_cast<SelectInst>(Arg);
+        if (!SI)
+          continue;
+
+        auto *TrueC = dyn_cast<Constant>(SI->getTrueValue());
+        auto *FalseC = dyn_cast<Constant>(SI->getFalseValue());
+
+        // Block only if the select is masking, e.g. select(cond, val, -1)
+        if ((TrueC && TrueC->isAllOnesValue()) ||
+            (FalseC && FalseC->isAllOnesValue())) {
+          LLVM_DEBUG(
+              dbgs()
+              << "InstCombine: skipping umin/umax folding for masked select\n");
+          return nullptr;
+        }
+      }
+    }
+  }
----------------
nikic wrote:

> I'd like to disable this fold when the binary intrinsic is a reduction. We have a similar helper `matchSimpleRecurrence` in ValueTracking.

I agree that testing specifically for a recurrence would be best.

I think a simple check would look something like this (untested):

```
if (isa<MinMaxIntrinsic>(&Op))
  for (Value *IntrinOp : Op.operands())
    if (auto *PN = dyn_cast<PHINode>(IntrinOp))
      for (Value *PhiOp = PN->operands())
        if (PhiOp == &Op)
          return nullptr;
```

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


More information about the llvm-commits mailing list