[llvm] [InstCombine] Drop wrong ninf for `(-X / Y) + Z` (PR #228684)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Oct 3 02:04:38 PDT 2026
https://github.com/suogesi created https://github.com/llvm/llvm-project/pull/228684
When folding (-X / Y) + Z into Z - X / Y, it is treated as a `BinaryOperator` so final `ninf` is same as the add instruction. This iswrong when add instruction has `ninf` but div instruction doesn't have `ninf`.
Take first operand as FMFSource so the optimized div instruction have correct ninf now.
Fixes #228521
>From e4b7f39d53f8ebcc3fa0ecb5d6aa643e8bbcb259 Mon Sep 17 00:00:00 2001
From: Wu Haoyu <3540385658 at qq.com>
Date: Sat, 3 Oct 2026 16:34:15 +0800
Subject: [PATCH 1/2] [InstCombine] Add tests for (-X / Y) + Z and its variants
---
llvm/test/Transforms/InstCombine/fadd.ll | 58 ++++++++++++++++++++++--
1 file changed, 53 insertions(+), 5 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/fadd.ll b/llvm/test/Transforms/InstCombine/fadd.ll
index c3f5cc742dd28..2cc95a1f91e6b 100644
--- a/llvm/test/Transforms/InstCombine/fadd.ll
+++ b/llvm/test/Transforms/InstCombine/fadd.ll
@@ -45,6 +45,18 @@ define double @fdiv_fneg1(double %x, double %y, double %pz) {
ret double %r
}
+define double @fdiv_fneg1_ninf(double %x, double %y, double %z) {
+; CHECK-LABEL: @fdiv_fneg1_ninf(
+; CHECK-NEXT: [[TMP1:%.*]] = fdiv ninf double [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = fsub ninf double [[Z:%.*]], [[TMP1]]
+; CHECK-NEXT: ret double [[R]]
+;
+ %nx = fneg double %x
+ %d = fdiv double %nx, %y
+ %r = fadd ninf double %z, %d
+ ret double %r
+}
+
; Z + (Y / -X) --> Z - (Y / X)
define <2 x double> @fdiv_fneg2(<2 x double> %x, <2 x double> %y, <2 x double> %pz) {
@@ -61,6 +73,18 @@ define <2 x double> @fdiv_fneg2(<2 x double> %x, <2 x double> %y, <2 x double> %
ret <2 x double> %r
}
+define double @fdiv_fneg2_ninf(double %x, double %y, double %z) {
+; CHECK-LABEL: @fdiv_fneg2_ninf(
+; CHECK-NEXT: [[TMP1:%.*]] = fdiv ninf double [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[R:%.*]] = fsub ninf double [[Z:%.*]], [[TMP1]]
+; CHECK-NEXT: ret double [[R]]
+;
+ %nx = fneg double %x
+ %d = fdiv double %y, %nx
+ %r = fadd ninf double %z, %d
+ ret double %r
+}
+
; Z + (-X * Y) --> Z - (X * Y)
define double @fmul_fneg1(double %x, double %y, double %pz) {
@@ -111,6 +135,18 @@ define double @fdiv_fneg1_commute(double %x, double %y, double %pz) {
ret double %r
}
+define double @fdiv_fneg1_commute_ninf(double %x, double %y, double %z) {
+; CHECK-LABEL: @fdiv_fneg1_commute_ninf(
+; CHECK-NEXT: [[TMP1:%.*]] = fdiv ninf double [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[R:%.*]] = fsub ninf double [[Z:%.*]], [[TMP1]]
+; CHECK-NEXT: ret double [[R]]
+;
+ %nx = fneg double %x
+ %d = fdiv double %nx, %y
+ %r = fadd ninf double %d, %z
+ ret double %r
+}
+
; (Y / -X) + Z --> Z - (Y / X)
define <2 x double> @fdiv_fneg2_commute(<2 x double> %x, <2 x double> %y, <2 x double> %pz) {
@@ -127,6 +163,18 @@ define <2 x double> @fdiv_fneg2_commute(<2 x double> %x, <2 x double> %y, <2 x d
ret <2 x double> %r
}
+define double @fdiv_fneg2_commute_ninf(double %x, double %y, double %z) {
+; CHECK-LABEL: @fdiv_fneg2_commute_ninf(
+; CHECK-NEXT: [[TMP1:%.*]] = fdiv ninf double [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[R:%.*]] = fsub ninf double [[Z:%.*]], [[TMP1]]
+; CHECK-NEXT: ret double [[R]]
+;
+ %nx = fneg double %x
+ %d = fdiv double %y, %nx
+ %r = fadd ninf double %d, %z
+ ret double %r
+}
+
; (-X * Y) + Z --> Z - (X * Y)
define double @fmul_fneg1_commute(double %x, double %y, double %pz) {
@@ -829,11 +877,11 @@ define float @fadd_reduce_sqr_sum_varA_not_one_use1(float %a, float %b) {
define float @fadd_reduce_sqr_sum_varA_not_one_use2(float %a, float %b) {
; CHECK-LABEL: @fadd_reduce_sqr_sum_varA_not_one_use2(
-; CHECK-NEXT: [[A_SQ:%.*]] = fmul float [[A:%.*]], [[A:%.*]]
-; CHECK-NEXT: [[AB:%.*]] = fadd reassoc nsz float [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[AB_SQ:%.*]] = fmul reassoc nsz float [[AB:%.*]], [[AB:%.*]]
-; CHECK-NEXT: tail call void @fake_func(float [[A_SQ:%.*]])
-; CHECK-NEXT: ret float [[AB_SQ:%.*]]
+; CHECK-NEXT: [[A_SQ:%.*]] = fmul float [[A:%.*]], [[A]]
+; CHECK-NEXT: [[AB:%.*]] = fadd reassoc nsz float [[A]], [[B:%.*]]
+; CHECK-NEXT: [[AB_SQ:%.*]] = fmul reassoc nsz float [[AB]], [[AB]]
+; CHECK-NEXT: tail call void @fake_func(float [[A_SQ]])
+; CHECK-NEXT: ret float [[AB_SQ]]
;
%a_sq = fmul float %a, %a
%two_a = fmul float %a, 2.0
>From abd2750a0b8f421c66ae0e0ee943333596189e53 Mon Sep 17 00:00:00 2001
From: Wu Haoyu <3540385658 at qq.com>
Date: Sat, 3 Oct 2026 16:52:12 +0800
Subject: [PATCH 2/2] [InstCombine] Drop wrong `ninf` for `(-X / Y) + Z`
When folding `(-X / Y) + Z` into `Z - X / Y`, it is treated as a
`BinaryOperator` so final `ninf` is same as the add instruction. This is
wrong when add instruction has `ninf` but div instruction doesn't have
`ninf`.
Take first operand as `FMFSource` so the optimized div instruction have
correct `ninf` now.
Fixes #228521
---
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp | 4 +++-
llvm/test/Transforms/InstCombine/fadd.ll | 8 ++++----
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 281e3b353f6dd..4622e3f02b87e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2167,7 +2167,9 @@ Instruction *InstCombinerImpl::visitFAdd(BinaryOperator &I) {
m_Value(Z))) ||
match(&I, m_c_FAdd(m_OneUse(m_FDiv(m_Value(X), m_FNeg(m_Value(Y)))),
m_Value(Z)))) {
- Value *XY = Builder.CreateFDivFMF(X, Y, &I);
+ Value *Div = I.getOperand(0);
+ auto *DivInst = cast<BinaryOperator>(Div);
+ Value *XY = Builder.CreateFDivFMF(X, Y, DivInst);
return BinaryOperator::CreateFSubFMF(Z, XY, &I);
}
diff --git a/llvm/test/Transforms/InstCombine/fadd.ll b/llvm/test/Transforms/InstCombine/fadd.ll
index 2cc95a1f91e6b..cce857f83f73b 100644
--- a/llvm/test/Transforms/InstCombine/fadd.ll
+++ b/llvm/test/Transforms/InstCombine/fadd.ll
@@ -47,7 +47,7 @@ define double @fdiv_fneg1(double %x, double %y, double %pz) {
define double @fdiv_fneg1_ninf(double %x, double %y, double %z) {
; CHECK-LABEL: @fdiv_fneg1_ninf(
-; CHECK-NEXT: [[TMP1:%.*]] = fdiv ninf double [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = fdiv double [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[R:%.*]] = fsub ninf double [[Z:%.*]], [[TMP1]]
; CHECK-NEXT: ret double [[R]]
;
@@ -75,7 +75,7 @@ define <2 x double> @fdiv_fneg2(<2 x double> %x, <2 x double> %y, <2 x double> %
define double @fdiv_fneg2_ninf(double %x, double %y, double %z) {
; CHECK-LABEL: @fdiv_fneg2_ninf(
-; CHECK-NEXT: [[TMP1:%.*]] = fdiv ninf double [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = fdiv double [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[R:%.*]] = fsub ninf double [[Z:%.*]], [[TMP1]]
; CHECK-NEXT: ret double [[R]]
;
@@ -137,7 +137,7 @@ define double @fdiv_fneg1_commute(double %x, double %y, double %pz) {
define double @fdiv_fneg1_commute_ninf(double %x, double %y, double %z) {
; CHECK-LABEL: @fdiv_fneg1_commute_ninf(
-; CHECK-NEXT: [[TMP1:%.*]] = fdiv ninf double [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = fdiv double [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[R:%.*]] = fsub ninf double [[Z:%.*]], [[TMP1]]
; CHECK-NEXT: ret double [[R]]
;
@@ -165,7 +165,7 @@ define <2 x double> @fdiv_fneg2_commute(<2 x double> %x, <2 x double> %y, <2 x d
define double @fdiv_fneg2_commute_ninf(double %x, double %y, double %z) {
; CHECK-LABEL: @fdiv_fneg2_commute_ninf(
-; CHECK-NEXT: [[TMP1:%.*]] = fdiv ninf double [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = fdiv double [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: [[R:%.*]] = fsub ninf double [[Z:%.*]], [[TMP1]]
; CHECK-NEXT: ret double [[R]]
;
More information about the llvm-commits
mailing list