[llvm] [Instcombine] Fix crash in foldMinimumMaximumSharedOp. (PR #173705)

via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 26 21:28:34 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Justin Lebar (jlebar)

<details>
<summary>Changes</summary>

We were missing a check that the inner intrinsic is in fact a min/max
op.  We'd crash if it was any other intrinsic!

This was found by a fuzzer I'm working on.  The high-level design is to
randomly generate LLVM IR, run a pass on it, and then run the original
and new IR through the interpreter.  They should produce the same
results.  Right now I'm only fuzzing instcombine.


---
Full diff: https://github.com/llvm/llvm-project/pull/173705.diff


2 Files Affected:

- (modified) llvm/lib/Analysis/InstructionSimplify.cpp (+16-5) 
- (added) llvm/test/Transforms/InstCombine/minmax-fp-shared-op.ll (+16) 


``````````diff
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 927d05b3f1eac..5ffa2a4143d08 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -6554,10 +6554,21 @@ static Value *foldMinMaxSharedOp(Intrinsic::ID IID, Value *Op0, Value *Op1) {
 /// is expected to swap the operand arguments to handle commutation.
 static Value *foldMinimumMaximumSharedOp(Intrinsic::ID IID, Value *Op0,
                                          Value *Op1) {
-  assert((IID == Intrinsic::maxnum || IID == Intrinsic::minnum ||
-          IID == Intrinsic::maximum || IID == Intrinsic::minimum ||
-          IID == Intrinsic::maximumnum || IID == Intrinsic::minimumnum) &&
-         "Unsupported intrinsic");
+  auto IsMinimumMaximumIntrinsic = [](Intrinsic::ID ID) {
+    switch (ID) {
+    case Intrinsic::maxnum:
+    case Intrinsic::minnum:
+    case Intrinsic::maximum:
+    case Intrinsic::minimum:
+    case Intrinsic::maximumnum:
+    case Intrinsic::minimumnum:
+      return true;
+    default:
+      return false;
+    }
+  };
+
+  assert(IsMinimumMaximumIntrinsic(IID) && "Unsupported intrinsic");
 
   auto *M0 = dyn_cast<IntrinsicInst>(Op0);
   // If Op0 is not the same intrinsic as IID, do not process.
@@ -6577,7 +6588,7 @@ static Value *foldMinimumMaximumSharedOp(Intrinsic::ID IID, Value *Op0,
     return M0;
 
   auto *M1 = dyn_cast<IntrinsicInst>(Op1);
-  if (!M1)
+  if (!M1 || !IsMinimumMaximumIntrinsic(M1->getIntrinsicID()))
     return nullptr;
   Value *X1 = M1->getOperand(0);
   Value *Y1 = M1->getOperand(1);
diff --git a/llvm/test/Transforms/InstCombine/minmax-fp-shared-op.ll b/llvm/test/Transforms/InstCombine/minmax-fp-shared-op.ll
new file mode 100644
index 0000000000000..856d2da523e35
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/minmax-fp-shared-op.ll
@@ -0,0 +1,16 @@
+; RUN: opt -passes=instcombine -S %s -o - | FileCheck %s
+
+declare float @llvm.minnum.f32(float, float)
+declare float @llvm.fma.f32(float, float, float)
+
+; CHECK-LABEL: @minnum_shared_op_mixed(
+; CHECK: call float @llvm.minnum.f32
+; CHECK: call float @llvm.fma.f32
+; CHECK: call float @llvm.minnum.f32
+define float @minnum_shared_op_mixed(float %x) {
+entry:
+  %m0 = call float @llvm.minnum.f32(float %x, float 0.000000e+00)
+  %f = call float @llvm.fma.f32(float %x, float 0.000000e+00, float %x)
+  %m2 = call float @llvm.minnum.f32(float %f, float %m0)
+  ret float %m2
+}

``````````

</details>


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


More information about the llvm-commits mailing list