[llvm] a654a27 - [InstCombine] Fold min/max(fpext x, C) to fpext(min/max(x, fptrunc C)) (#179968)

via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 9 01:13:31 PST 2026


Author: Nikita Popov
Date: 2026-02-09T09:13:26Z
New Revision: a654a27fcd4a44e6c76a93fabc11aed2cb3b97ef

URL: https://github.com/llvm/llvm-project/commit/a654a27fcd4a44e6c76a93fabc11aed2cb3b97ef
DIFF: https://github.com/llvm/llvm-project/commit/a654a27fcd4a44e6c76a93fabc11aed2cb3b97ef.diff

LOG: [InstCombine] Fold min/max(fpext x, C) to fpext(min/max(x, fptrunc C)) (#179968)

Fold `min/max(fpext x, C)` to `fpext(min/max(x, fptrunc C))` in cases
where the truncation of the constant is lossless.

This helps eliminate fpext/fptrunc pairs around min/max and addresses
the regression from https://github.com/llvm/llvm-project/pull/177988.

Proof: https://alive2.llvm.org/ce/z/y_Bcdd

Added: 
    

Modified: 
    llvm/lib/Analysis/ConstantFolding.cpp
    llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
    llvm/test/Transforms/InstCombine/minnum.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index c0754d3a41264..ab060b1b9320a 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -4748,6 +4748,17 @@ Constant *llvm::getLosslessInvCast(Constant *C, Type *InvCastTo,
     }
     return InvC;
   }
+  case Instruction::FPExt: {
+    Constant *InvC =
+        ConstantFoldCastOperand(Instruction::FPTrunc, C, InvCastTo, DL);
+    if (InvC) {
+      Constant *CastInvC =
+          ConstantFoldCastOperand(CastOp, InvC, C->getType(), DL);
+      if (CastInvC == C)
+        return InvC;
+    }
+    return nullptr;
+  }
   default:
     return nullptr;
   }

diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 1b42ed5e4a349..7be083c2ebbd7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -2878,6 +2878,18 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
       return new FPExtInst(NewCall, II->getType());
     }
 
+    // m(fpext X, C) -> fpext m(X, TruncC) if C can be losslessly truncated.
+    Constant *C;
+    if (match(Arg0, m_OneUse(m_FPExt(m_Value(X)))) &&
+        match(Arg1, m_ImmConstant(C))) {
+      if (Constant *TruncC =
+              getLosslessInvCast(C, X->getType(), Instruction::FPExt, DL)) {
+        Value *NewCall =
+            Builder.CreateBinaryIntrinsic(IID, X, TruncC, II, II->getName());
+        return new FPExtInst(NewCall, II->getType());
+      }
+    }
+
     // max X, -X --> fabs X
     // min X, -X --> -(fabs X)
     // TODO: Remove one-use limitation? That is obviously better for max,

diff  --git a/llvm/test/Transforms/InstCombine/minnum.ll b/llvm/test/Transforms/InstCombine/minnum.ll
index 093e6e78a4c11..7ac83bf91163e 100644
--- a/llvm/test/Transforms/InstCombine/minnum.ll
+++ b/llvm/test/Transforms/InstCombine/minnum.ll
@@ -486,6 +486,45 @@ define float @reduce_precision_multi_use_2(float %x, float %y, ptr %p, ptr %p2)
   ret float %trunc
 }
 
+define float @reduce_precision_const(float %x) {
+; CHECK-LABEL: @reduce_precision_const(
+; CHECK-NEXT:    [[TRUNC:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 1.000000e+00)
+; CHECK-NEXT:    ret float [[TRUNC]]
+;
+  %x.ext = fpext float %x to double
+  %minnum = call double @llvm.minnum.f64(double %x.ext, double 1.0)
+  %trunc = fptrunc double %minnum to float
+  ret float %trunc
+}
+
+define float @reduce_precision_const_not_lossless(float %x) {
+; CHECK-LABEL: @reduce_precision_const_not_lossless(
+; CHECK-NEXT:    [[X_EXT:%.*]] = fpext float [[X:%.*]] to double
+; CHECK-NEXT:    [[MINNUM:%.*]] = call double @llvm.minnum.f64(double [[X_EXT]], double 1.000000e-01)
+; CHECK-NEXT:    [[TRUNC:%.*]] = fptrunc double [[MINNUM]] to float
+; CHECK-NEXT:    ret float [[TRUNC]]
+;
+  %x.ext = fpext float %x to double
+  %minnum = call double @llvm.minnum.f64(double %x.ext, double 0.1)
+  %trunc = fptrunc double %minnum to float
+  ret float %trunc
+}
+
+define float @reduce_precision_const_multi_use(float %x) {
+; CHECK-LABEL: @reduce_precision_const_multi_use(
+; CHECK-NEXT:    [[X_EXT:%.*]] = fpext float [[X:%.*]] to double
+; CHECK-NEXT:    call void @use(double [[X_EXT]])
+; CHECK-NEXT:    [[MINNUM:%.*]] = call double @llvm.minnum.f64(double [[X_EXT]], double 1.000000e+00)
+; CHECK-NEXT:    [[TRUNC:%.*]] = fptrunc double [[MINNUM]] to float
+; CHECK-NEXT:    ret float [[TRUNC]]
+;
+  %x.ext = fpext float %x to double
+  call void @use(double %x.ext)
+  %minnum = call double @llvm.minnum.f64(double %x.ext, double 1.0)
+  %trunc = fptrunc double %minnum to float
+  ret float %trunc
+}
+
 define float @negated_op(float %x) {
 ; CHECK-LABEL: @negated_op(
 ; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])


        


More information about the llvm-commits mailing list