[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