[llvm] [InstCombine] Freeze X in fabs(X) op fabs(X) -> X op X to fix undef unsoundness (PR #202217)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jun 7 11:17:32 PDT 2026
https://github.com/lijinpei-amd updated https://github.com/llvm/llvm-project/pull/202217
>From 0b49c04c2337276755f240e2604c09635b0d8e4d Mon Sep 17 00:00:00 2001
From: Li Jinpei <jinpli at amd.com>
Date: Mon, 8 Jun 2026 01:31:37 +0800
Subject: [PATCH 1/2] [InstCombine] Add tests for fabs(X) op fabs(X) folds
(NFC)
Pre-commit tests for the fabs(X) * fabs(X) -> X * X and fabs(X) / fabs(X) ->
X / X folds across the nnan/ninf/nsz/fast flag combinations, plus a noundef
argument. These currently reuse X without a freeze; a follow-up fixes the undef
unsoundness and updates the CHECK lines.
---
llvm/test/Transforms/InstCombine/fdiv.ll | 26 ++++++++++++--
llvm/test/Transforms/InstCombine/fmul.ll | 44 ++++++++++++++++++++++--
2 files changed, 65 insertions(+), 5 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/fdiv.ll b/llvm/test/Transforms/InstCombine/fdiv.ll
index e992ba59b8574..8bac5fd37a6ad 100644
--- a/llvm/test/Transforms/InstCombine/fdiv.ll
+++ b/llvm/test/Transforms/InstCombine/fdiv.ll
@@ -591,7 +591,7 @@ define float @fdiv_fneg1_extra_use(float %x, float %y) {
define float @fabs_same_op(float %x) {
; CHECK-LABEL: @fabs_same_op(
-; CHECK-NEXT: [[R:%.*]] = fdiv float [[X:%.*]], [[X]]
+; CHECK-NEXT: [[R:%.*]] = fdiv float [[X_FR:%.*]], [[X_FR]]
; CHECK-NEXT: ret float [[R]]
;
%a = call float @llvm.fabs.f32(float %x)
@@ -601,9 +601,9 @@ define float @fabs_same_op(float %x) {
define float @fabs_same_op_extra_use(float %x) {
; CHECK-LABEL: @fabs_same_op_extra_use(
-; CHECK-NEXT: [[A:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
+; CHECK-NEXT: [[A:%.*]] = call float @llvm.fabs.f32(float [[X_FR:%.*]])
; CHECK-NEXT: call void @use_f32(float [[A]])
-; CHECK-NEXT: [[R:%.*]] = fdiv reassoc ninf float [[X]], [[X]]
+; CHECK-NEXT: [[R:%.*]] = fdiv reassoc ninf float [[X_FR]], [[X_FR]]
; CHECK-NEXT: ret float [[R]]
;
%a = call float @llvm.fabs.f32(float %x)
@@ -612,6 +612,26 @@ define float @fabs_same_op_extra_use(float %x) {
ret float %r
}
+define float @fabs_same_op_ninf(float %x) {
+; CHECK-LABEL: @fabs_same_op_ninf(
+; CHECK-NEXT: [[R:%.*]] = fdiv ninf float [[X:%.*]], [[X]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %a = call float @llvm.fabs.f32(float %x)
+ %r = fdiv ninf float %a, %a
+ ret float %r
+}
+
+define float @fabs_same_op_nsz(float %x) {
+; CHECK-LABEL: @fabs_same_op_nsz(
+; CHECK-NEXT: [[R:%.*]] = fdiv nsz float [[X_FR:%.*]], [[X_FR]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %a = call float @llvm.fabs.f32(float %x)
+ %r = fdiv nsz float %a, %a
+ ret float %r
+}
+
define float @fabs_fabs(float %x, float %y) {
; CHECK-LABEL: @fabs_fabs(
; CHECK-NEXT: [[TMP1:%.*]] = fdiv float [[X:%.*]], [[Y:%.*]]
diff --git a/llvm/test/Transforms/InstCombine/fmul.ll b/llvm/test/Transforms/InstCombine/fmul.ll
index c93982f814e43..936f8ec6de5fc 100644
--- a/llvm/test/Transforms/InstCombine/fmul.ll
+++ b/llvm/test/Transforms/InstCombine/fmul.ll
@@ -462,7 +462,7 @@ declare float @llvm.fabs.f32(float) nounwind readnone
define float @fabs_squared(float %x) {
; CHECK-LABEL: @fabs_squared(
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X:%.*]], [[X]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X_FR:%.*]], [[X_FR]]
; CHECK-NEXT: ret float [[MUL]]
;
%x.fabs = call float @llvm.fabs.f32(float %x)
@@ -472,7 +472,7 @@ define float @fabs_squared(float %x) {
define float @fabs_squared_fast(float %x) {
; CHECK-LABEL: @fabs_squared_fast(
-; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[X:%.*]], [[X]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[X_FR:%.*]], [[X_FR]]
; CHECK-NEXT: ret float [[MUL]]
;
%x.fabs = call float @llvm.fabs.f32(float %x)
@@ -480,6 +480,46 @@ define float @fabs_squared_fast(float %x) {
ret float %mul
}
+define float @fabs_squared_nnan(float %x) {
+; CHECK-LABEL: @fabs_squared_nnan(
+; CHECK-NEXT: [[MUL:%.*]] = fmul nnan float [[X:%.*]], [[X]]
+; CHECK-NEXT: ret float [[MUL]]
+;
+ %x.fabs = call float @llvm.fabs.f32(float %x)
+ %mul = fmul nnan float %x.fabs, %x.fabs
+ ret float %mul
+}
+
+define float @fabs_squared_ninf(float %x) {
+; CHECK-LABEL: @fabs_squared_ninf(
+; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[X:%.*]], [[X]]
+; CHECK-NEXT: ret float [[MUL]]
+;
+ %x.fabs = call float @llvm.fabs.f32(float %x)
+ %mul = fmul ninf float %x.fabs, %x.fabs
+ ret float %mul
+}
+
+define float @fabs_squared_nsz(float %x) {
+; CHECK-LABEL: @fabs_squared_nsz(
+; CHECK-NEXT: [[MUL:%.*]] = fmul nsz float [[X_FR:%.*]], [[X_FR]]
+; CHECK-NEXT: ret float [[MUL]]
+;
+ %x.fabs = call float @llvm.fabs.f32(float %x)
+ %mul = fmul nsz float %x.fabs, %x.fabs
+ ret float %mul
+}
+
+define float @fabs_squared_noundef(float noundef %x) {
+; CHECK-LABEL: @fabs_squared_noundef(
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X:%.*]], [[X]]
+; CHECK-NEXT: ret float [[MUL]]
+;
+ %x.fabs = call float @llvm.fabs.f32(float %x)
+ %mul = fmul float %x.fabs, %x.fabs
+ ret float %mul
+}
+
define float @fabs_fabs(float %x, float %y) {
; CHECK-LABEL: @fabs_fabs(
; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X:%.*]], [[Y:%.*]]
>From 87b6b4f0b18351b5df05f1d6b5175264887e5971 Mon Sep 17 00:00:00 2001
From: Li Jinpei <jinpli at amd.com>
Date: Mon, 8 Jun 2026 01:32:47 +0800
Subject: [PATCH 2/2] [InstCombine] Freeze X in fabs(X) op fabs(X) -> X op X to
fix undef unsoundness
Folding
```
Y = fabs(X);
Z = Y * Y;
```
into
```
Z = X * X;
```
is unsound when X is undef, because each use of X may take a different value.
The same applies to fdiv fabs(X), fabs(X) -> X / X (which may then fold to 1.0).
Fix this by freezing X when needed. The freeze is unnecessary when the fmul or
fdiv carries a fast-math flag that can produce poison (nnan or ninf): undef can
be refined to a value that makes the result poison, and poison can be refined to
any value, so reusing X is sound without the freeze.
---
llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | 5 ++++-
llvm/test/Transforms/InstCombine/fdiv.ll | 6 ++++--
llvm/test/Transforms/InstCombine/fmul.ll | 6 ++++--
3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 17ac09c10f41c..5f41151f178af 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -616,8 +616,11 @@ Instruction *InstCombinerImpl::foldFPSignBitOps(BinaryOperator &I) {
// fabs(X) * fabs(X) -> X * X
// fabs(X) / fabs(X) -> X / X
- if (Op0 == Op1 && match(Op0, m_FAbs(m_Value(X))))
+ if (Op0 == Op1 && match(Op0, m_FAbs(m_Value(X)))) {
+ if (!I.hasNoNaNs() && !I.hasNoInfs() && !isGuaranteedNotToBeUndef(X))
+ X = Builder.CreateFreeze(X, X->getName() + ".fr");
return BinaryOperator::CreateWithCopiedFlags(Opcode, X, X, &I);
+ }
// fabs(X) * fabs(Y) --> fabs(X * Y)
// fabs(X) / fabs(Y) --> fabs(X / Y)
diff --git a/llvm/test/Transforms/InstCombine/fdiv.ll b/llvm/test/Transforms/InstCombine/fdiv.ll
index 8bac5fd37a6ad..38dd8a951c7e2 100644
--- a/llvm/test/Transforms/InstCombine/fdiv.ll
+++ b/llvm/test/Transforms/InstCombine/fdiv.ll
@@ -591,7 +591,8 @@ define float @fdiv_fneg1_extra_use(float %x, float %y) {
define float @fabs_same_op(float %x) {
; CHECK-LABEL: @fabs_same_op(
-; CHECK-NEXT: [[R:%.*]] = fdiv float [[X_FR:%.*]], [[X_FR]]
+; CHECK-NEXT: [[X_FR:%.*]] = freeze float [[X:%.*]]
+; CHECK-NEXT: [[R:%.*]] = fdiv float [[X_FR]], [[X_FR]]
; CHECK-NEXT: ret float [[R]]
;
%a = call float @llvm.fabs.f32(float %x)
@@ -624,7 +625,8 @@ define float @fabs_same_op_ninf(float %x) {
define float @fabs_same_op_nsz(float %x) {
; CHECK-LABEL: @fabs_same_op_nsz(
-; CHECK-NEXT: [[R:%.*]] = fdiv nsz float [[X_FR:%.*]], [[X_FR]]
+; CHECK-NEXT: [[X_FR:%.*]] = freeze float [[X:%.*]]
+; CHECK-NEXT: [[R:%.*]] = fdiv nsz float [[X_FR]], [[X_FR]]
; CHECK-NEXT: ret float [[R]]
;
%a = call float @llvm.fabs.f32(float %x)
diff --git a/llvm/test/Transforms/InstCombine/fmul.ll b/llvm/test/Transforms/InstCombine/fmul.ll
index 936f8ec6de5fc..66a8839e16516 100644
--- a/llvm/test/Transforms/InstCombine/fmul.ll
+++ b/llvm/test/Transforms/InstCombine/fmul.ll
@@ -462,7 +462,8 @@ declare float @llvm.fabs.f32(float) nounwind readnone
define float @fabs_squared(float %x) {
; CHECK-LABEL: @fabs_squared(
-; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X_FR:%.*]], [[X_FR]]
+; CHECK-NEXT: [[X_FR:%.*]] = freeze float [[X:%.*]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X_FR]], [[X_FR]]
; CHECK-NEXT: ret float [[MUL]]
;
%x.fabs = call float @llvm.fabs.f32(float %x)
@@ -502,7 +503,8 @@ define float @fabs_squared_ninf(float %x) {
define float @fabs_squared_nsz(float %x) {
; CHECK-LABEL: @fabs_squared_nsz(
-; CHECK-NEXT: [[MUL:%.*]] = fmul nsz float [[X_FR:%.*]], [[X_FR]]
+; CHECK-NEXT: [[X_FR:%.*]] = freeze float [[X:%.*]]
+; CHECK-NEXT: [[MUL:%.*]] = fmul nsz float [[X_FR]], [[X_FR]]
; CHECK-NEXT: ret float [[MUL]]
;
%x.fabs = call float @llvm.fabs.f32(float %x)
More information about the llvm-commits
mailing list