[llvm] [InstCombine] Preserve fdiv metadata on fneg folds (PR #179157)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Feb 1 19:03:51 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Wenju He (wenju-he)
<details>
<summary>Changes</summary>
Copy metadata from the original fdiv when folding fneg into fdiv or hoisting fneg above fdiv. This keeps !fpmath (and other metadata) intact, preventing !fpmath loss seen in libclc tanpi function. fneg only flips sign bit, so it does not affect precision.
---
Full diff: https://github.com/llvm/llvm-project/pull/179157.diff
2 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp (+11-4)
- (modified) llvm/test/Transforms/InstCombine/fneg.ll (+33)
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 72a6e64ccdc10..8eeeccbc86523 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2987,9 +2987,13 @@ static Instruction *foldFNegIntoConstant(Instruction &I, const DataLayout &DL) {
return BinaryOperator::CreateFMulFMF(X, NegC, FMF);
}
// -(X / C) --> X / (-C)
- if (match(FNegOp, m_FDiv(m_Value(X), m_Constant(C))))
- if (Constant *NegC = ConstantFoldUnaryOpOperand(Instruction::FNeg, C, DL))
- return BinaryOperator::CreateFDivFMF(X, NegC, &I);
+ if (match(FNegOp, m_FDiv(m_Value(X), m_Constant(C)))) {
+ if (Constant *NegC = ConstantFoldUnaryOpOperand(Instruction::FNeg, C, DL)) {
+ Instruction *FDiv = BinaryOperator::CreateFDivFMF(X, NegC, &I);
+ FDiv->copyMetadata(*FNegOp);
+ return FDiv;
+ }
+ }
// -(C / X) --> (-C) / X
if (match(FNegOp, m_FDiv(m_Constant(C), m_Value(X))))
if (Constant *NegC = ConstantFoldUnaryOpOperand(Instruction::FNeg, C, DL)) {
@@ -3002,6 +3006,7 @@ static Instruction *foldFNegIntoConstant(Instruction &I, const DataLayout &DL) {
FastMathFlags OpFMF = FNegOp->getFastMathFlags();
FDiv->setHasNoSignedZeros(FMF.noSignedZeros() && OpFMF.noSignedZeros());
FDiv->setHasNoInfs(FMF.noInfs() && OpFMF.noInfs());
+ FDiv->copyMetadata(*FNegOp);
return FDiv;
}
// With NSZ [ counter-example with -0.0: -(-0.0 + 0.0) != 0.0 + -0.0 ]:
@@ -3024,8 +3029,10 @@ Instruction *InstCombinerImpl::hoistFNegAboveFMulFDiv(Value *FNegOp,
}
if (match(FNegOp, m_FDiv(m_Value(X), m_Value(Y)))) {
- return cast<Instruction>(Builder.CreateFDivFMF(
+ auto *FDiv = cast<Instruction>(Builder.CreateFDivFMF(
Builder.CreateFNegFMF(X, &FMFSource), Y, &FMFSource));
+ FDiv->copyMetadata(*cast<Instruction>(FNegOp));
+ return FDiv;
}
if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(FNegOp)) {
diff --git a/llvm/test/Transforms/InstCombine/fneg.ll b/llvm/test/Transforms/InstCombine/fneg.ll
index 4e6477f804314..ed4d43eaea235 100644
--- a/llvm/test/Transforms/InstCombine/fneg.ll
+++ b/llvm/test/Transforms/InstCombine/fneg.ll
@@ -110,6 +110,19 @@ define <4 x double> @fmul_fneg_vec(<4 x double> %x) {
ret <4 x double> %r
}
+; -(X / Y) --> (-X) / Y
+
+define float @fdiv_fneg_fpmath(float %x, float %y) {
+; CHECK-LABEL: @fdiv_fneg_fpmath(
+; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]]
+; CHECK-NEXT: [[R:%.*]] = fdiv float [[NEG]], [[Y:%.*]], !fpmath
+; CHECK-NEXT: ret float [[R]]
+;
+ %z = fdiv arcp float %x, %y, !fpmath !{float 2.5}
+ %w = fneg float %z
+ ret float %w
+}
+
; -(X / C) --> X / (-C)
define float @fdiv_op1_constant_fsub(float %x) {
@@ -204,6 +217,16 @@ define <4 x double> @fdiv_op1_constant_fneg_vec(<4 x double> %x) {
ret <4 x double> %r
}
+define float @fdiv_op1_constant_fneg_fpmath(float %x) {
+; CHECK-LABEL: @fdiv_op1_constant_fneg_fpmath(
+; CHECK-NEXT: [[R:%.*]] = fdiv float [[X:%.*]], 4.200000e+01, !fpmath
+; CHECK-NEXT: ret float [[R]]
+;
+ %d = fdiv float %x, -42.0, !fpmath !{float 2.5}
+ %r = fneg float %d
+ ret float %r
+}
+
; -(C / X) --> (-C) / X
define float @fdiv_op0_constant_fsub(float %x) {
@@ -308,6 +331,16 @@ define float @fdiv_op0_constant_fneg_nnan(float %x) {
ret float %r
}
+define float @fdiv_op0_constant_fneg_fpmath(float %x) {
+; CHECK-LABEL: @fdiv_op0_constant_fneg_fpmath(
+; CHECK-NEXT: [[R:%.*]] = fdiv float -1.000000e+00, [[X:%.*]], !fpmath
+; CHECK-NEXT: ret float [[R]]
+;
+ %d = fdiv float 1.0, %x, !fpmath !{float 2.5}
+ %r = fneg float %d
+ ret float %r
+}
+
; Extra use prevents the fold. We don't want to replace the fneg with an fdiv.
define float @fdiv_op0_constant_fsub_extra_use(float %x) {
``````````
</details>
https://github.com/llvm/llvm-project/pull/179157
More information about the llvm-commits
mailing list