[llvm] da65d6a - [KnownFPClass] Fix canonicalize incorrectly dropping fcNegZero under positive-zero denormal mode (#202268)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 12 03:41:51 PDT 2026
Author: lijinpei-amd
Date: 2026-06-12T12:41:47+02:00
New Revision: da65d6afe74463745dae9af0ce47f31e4186778e
URL: https://github.com/llvm/llvm-project/commit/da65d6afe74463745dae9af0ce47f31e4186778e
DIFF: https://github.com/llvm/llvm-project/commit/da65d6afe74463745dae9af0ce47f31e4186778e.diff
LOG: [KnownFPClass] Fix canonicalize incorrectly dropping fcNegZero under positive-zero denormal mode (#202268)
The denormal mode only flushes *denormal* (subnormal) values; -0.0 is
not a denormal, and per LangRef canonicalize must conserve the sign of
zero (canonicalize(-0.0) == -0.0).
Alive2 (InstCombine fold of canonicalize on a {+/-0, nan} value):
before (miscompiles -0.0 -> +0.0): https://alive2.llvm.org/ce/z/ZRK-sr
after (verifies): https://alive2.llvm.org/ce/z/L3tPu3
Added:
Modified:
llvm/lib/Support/KnownFPClass.cpp
llvm/test/Transforms/Attributor/nofpclass-canonicalize.ll
llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll
Removed:
################################################################################
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 3e2f6a1704b01..0aca7b7afbe29 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -228,8 +228,14 @@ KnownFPClass KnownFPClass::canonicalize(const KnownFPClass &KnownSrc,
if (DenormMode.Input == DenormalMode::PositiveZero ||
(DenormMode.Output == DenormalMode::PositiveZero &&
- DenormMode.Input == DenormalMode::IEEE))
- Known.knownNot(fcNegZero);
+ DenormMode.Input == DenormalMode::IEEE)) {
+ // -0.0 is not a subnormal and should not be flushed.
+ if (KnownSrc.isKnownNever(fcNegZero))
+ Known.knownNot(fcNegZero);
+
+ if (KnownSrc.isKnownNever(fcPosZero | fcSubnormal))
+ Known.knownNot(fcPosZero);
+ }
return Known;
}
diff --git a/llvm/test/Transforms/Attributor/nofpclass-canonicalize.ll b/llvm/test/Transforms/Attributor/nofpclass-canonicalize.ll
index 3ff0505e868a6..f934cdc899b43 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-canonicalize.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-canonicalize.ll
@@ -44,9 +44,9 @@ define float @ret_canonicalize_daz_denormal(float nofpclass(inf) %arg0) denormal
}
define float @ret_canonicalize_dapz_denormal(float nofpclass(inf) %arg0) denormal_fpenv(dynamic|positivezero) {
-; CHECK-LABEL: define nofpclass(snan inf nzero sub) float @ret_canonicalize_dapz_denormal
+; CHECK-LABEL: define nofpclass(snan inf sub) float @ret_canonicalize_dapz_denormal
; CHECK-SAME: (float nofpclass(inf) [[ARG0:%.*]]) #[[ATTR4:[0-9]+]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan inf nzero sub) float @llvm.canonicalize.f32(float nofpclass(inf) [[ARG0]]) #[[ATTR12]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan inf sub) float @llvm.canonicalize.f32(float nofpclass(inf) [[ARG0]]) #[[ATTR12]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.canonicalize.f32(float %arg0)
@@ -64,9 +64,9 @@ define float @ret_canonicalize_ftpz_dapz_denormal(float nofpclass(inf) %arg0) de
}
define float @ret_canonicalize_ftpz_ieee_denormal(float nofpclass(inf) %arg0) denormal_fpenv(positivezero|ieee) {
-; CHECK-LABEL: define nofpclass(snan inf nzero sub) float @ret_canonicalize_ftpz_ieee_denormal
+; CHECK-LABEL: define nofpclass(snan inf sub) float @ret_canonicalize_ftpz_ieee_denormal
; CHECK-SAME: (float nofpclass(inf) [[ARG0:%.*]]) #[[ATTR6:[0-9]+]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan inf nzero sub) float @llvm.canonicalize.f32(float nofpclass(inf) [[ARG0]]) #[[ATTR12]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan inf sub) float @llvm.canonicalize.f32(float nofpclass(inf) [[ARG0]]) #[[ATTR12]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.canonicalize.f32(float %arg0)
@@ -334,9 +334,9 @@ define float @ret_canonicalize_dapz_constant_pos_zero() denormal_fpenv(positivez
}
define float @ret_canonicalize_dapz_constant_neg_zero() denormal_fpenv(positivezero|positivezero) {
-; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub norm) float @ret_canonicalize_dapz_constant_neg_zero
+; CHECK-LABEL: define noundef nofpclass(nan inf pzero sub norm) float @ret_canonicalize_dapz_constant_neg_zero
; CHECK-SAME: () #[[ATTR11]] {
-; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(nan inf nzero sub norm) float @llvm.canonicalize.f32(float noundef -0.000000e+00) #[[ATTR12]]
+; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(nan inf pzero sub norm) float @llvm.canonicalize.f32(float noundef -0.000000e+00) #[[ATTR12]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.canonicalize.f32(float -0.0)
@@ -344,9 +344,9 @@ define float @ret_canonicalize_dapz_constant_neg_zero() denormal_fpenv(positivez
}
define float @ret_canonicalize_dapz_constant_pos_normal() denormal_fpenv(positivezero|positivezero) {
-; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub nnorm) float @ret_canonicalize_dapz_constant_pos_normal
+; CHECK-LABEL: define noundef nofpclass(nan inf zero sub nnorm) float @ret_canonicalize_dapz_constant_pos_normal
; CHECK-SAME: () #[[ATTR11]] {
-; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(nan inf nzero sub nnorm) float @llvm.canonicalize.f32(float noundef 8.000000e+00) #[[ATTR12]]
+; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(nan inf zero sub nnorm) float @llvm.canonicalize.f32(float noundef 8.000000e+00) #[[ATTR12]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.canonicalize.f32(float 8.0)
@@ -354,9 +354,9 @@ define float @ret_canonicalize_dapz_constant_pos_normal() denormal_fpenv(positiv
}
define float @ret_canonicalize_dapz_constant_neg_normal() denormal_fpenv(positivezero|positivezero) {
-; CHECK-LABEL: define noundef nofpclass(nan inf nzero sub pnorm) float @ret_canonicalize_dapz_constant_neg_normal
+; CHECK-LABEL: define noundef nofpclass(nan inf zero sub pnorm) float @ret_canonicalize_dapz_constant_neg_normal
; CHECK-SAME: () #[[ATTR11]] {
-; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(nan inf nzero sub pnorm) float @llvm.canonicalize.f32(float noundef -8.000000e+00) #[[ATTR12]]
+; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(nan inf zero sub pnorm) float @llvm.canonicalize.f32(float noundef -8.000000e+00) #[[ATTR12]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.canonicalize.f32(float -8.0)
@@ -364,9 +364,9 @@ define float @ret_canonicalize_dapz_constant_neg_normal() denormal_fpenv(positiv
}
define float @ret_canonicalize_dapz_constant_pos_inf() denormal_fpenv(positivezero|positivezero) {
-; CHECK-LABEL: define noundef nofpclass(nan ninf nzero sub norm) float @ret_canonicalize_dapz_constant_pos_inf
+; CHECK-LABEL: define noundef nofpclass(nan ninf zero sub norm) float @ret_canonicalize_dapz_constant_pos_inf
; CHECK-SAME: () #[[ATTR11]] {
-; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(nan ninf nzero sub norm) float @llvm.canonicalize.f32(float noundef +inf) #[[ATTR12]]
+; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(nan ninf zero sub norm) float @llvm.canonicalize.f32(float noundef +inf) #[[ATTR12]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.canonicalize.f32(float 0x7FF0000000000000)
@@ -374,9 +374,9 @@ define float @ret_canonicalize_dapz_constant_pos_inf() denormal_fpenv(positiveze
}
define float @ret_canonicalize_dapz_constant_neg_inf() denormal_fpenv(positivezero|positivezero) {
-; CHECK-LABEL: define noundef nofpclass(nan pinf nzero sub norm) float @ret_canonicalize_dapz_constant_neg_inf
+; CHECK-LABEL: define noundef nofpclass(nan pinf zero sub norm) float @ret_canonicalize_dapz_constant_neg_inf
; CHECK-SAME: () #[[ATTR11]] {
-; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(nan pinf nzero sub norm) float @llvm.canonicalize.f32(float noundef -inf) #[[ATTR12]]
+; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(nan pinf zero sub norm) float @llvm.canonicalize.f32(float noundef -inf) #[[ATTR12]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.canonicalize.f32(float 0xFFF0000000000000)
@@ -384,9 +384,9 @@ define float @ret_canonicalize_dapz_constant_neg_inf() denormal_fpenv(positiveze
}
define float @ret_canonicalize_dapz_constant_qnan() denormal_fpenv(positivezero|positivezero) {
-; CHECK-LABEL: define noundef nofpclass(snan inf nzero sub norm) float @ret_canonicalize_dapz_constant_qnan
+; CHECK-LABEL: define noundef nofpclass(snan inf zero sub norm) float @ret_canonicalize_dapz_constant_qnan
; CHECK-SAME: () #[[ATTR11]] {
-; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(snan inf nzero sub norm) float @llvm.canonicalize.f32(float noundef +qnan) #[[ATTR12]]
+; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(snan inf zero sub norm) float @llvm.canonicalize.f32(float noundef +qnan) #[[ATTR12]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.canonicalize.f32(float 0x7FF8000000000000)
@@ -394,9 +394,9 @@ define float @ret_canonicalize_dapz_constant_qnan() denormal_fpenv(positivezero|
}
define float @ret_canonicalize_dapz_constant_snan() denormal_fpenv(positivezero|positivezero) {
-; CHECK-LABEL: define noundef nofpclass(snan inf nzero sub norm) float @ret_canonicalize_dapz_constant_snan
+; CHECK-LABEL: define noundef nofpclass(snan inf zero sub norm) float @ret_canonicalize_dapz_constant_snan
; CHECK-SAME: () #[[ATTR11]] {
-; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(snan inf nzero sub norm) float @llvm.canonicalize.f32(float noundef +snan(0x80000)) #[[ATTR12]]
+; CHECK-NEXT: [[CALL:%.*]] = call noundef nofpclass(snan inf zero sub norm) float @llvm.canonicalize.f32(float noundef +snan(0x80000)) #[[ATTR12]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.canonicalize.f32(float 0x7FF1000000000000)
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll
index 8a380567b61ec..f7a4348685f4c 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-canonicalize.ll
@@ -561,7 +561,7 @@ define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__dynamic(
define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__dapz(i1 %cond, float nofpclass(sub norm inf) %must.be.zero.or.nan) #2 {
; CHECK-LABEL: define nofpclass(nan) float @ret_nofpclass_nan__canonicalize_only_zero__dapz(
; CHECK-SAME: i1 [[COND:%.*]], float nofpclass(inf sub norm) [[MUST_BE_ZERO_OR_NAN:%.*]]) #[[ATTR2]] {
-; CHECK-NEXT: ret float 0.000000e+00
+; CHECK-NEXT: ret float [[MUST_BE_ZERO_OR_NAN]]
;
%canon = call float @llvm.canonicalize.f32(float %must.be.zero.or.nan)
ret float %canon
More information about the llvm-commits
mailing list