[llvm] [KnownFPClass] Add sign preserving deductions to `atan2(y, x)` (PR #223176)
Eric Ross via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 12 14:32:12 PDT 2026
https://github.com/ZERICO2005 created https://github.com/llvm/llvm-project/pull/223176
`atan2(y, x)` should return the same sign as `y` (up to the denormal mode):
- If `y >= +0.0`, then `atan2(y, x) >= +0.0`
- If `y <= -0.0`, then `atan2(y, x) <= -0.0`
AI Disclosure:
I used ChatGPT Codex (5.6 sol) to help write the tests.
>From 5e73409eeb8612b39a00b316654cb8eb7a9956b3 Mon Sep 17 00:00:00 2001
From: zerico <zerico2005 at gmail.com>
Date: Sat, 12 Sep 2026 12:35:53 -0600
Subject: [PATCH] [KnownFPClass] Add sign preserving deductions to atan2(y, x)
---
llvm/lib/Analysis/ValueTracking.cpp | 8 +
.../CodeGen/GlobalISel/GISelValueTracking.cpp | 8 +
llvm/lib/Support/KnownFPClass.cpp | 20 +-
.../Transforms/Attributor/nofpclass-atan2.ll | 458 ++++++++++++++++--
.../simplify-demanded-fpclass-atan2.ll | 25 +
.../CodeGen/GlobalISel/KnownFPClassTest.cpp | 6 +-
6 files changed, 490 insertions(+), 35 deletions(-)
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 1580571a01451..f0e86a3bf9905 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -5503,6 +5503,14 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
FPClassTest InterestedY = InterestedClasses;
FPClassTest InterestedX = InterestedClasses;
+ // We can rule out negative values if y cannot have a negative value.
+ if ((InterestedClasses & fcNegFinite) != fcNone)
+ InterestedY |= fcNegative;
+
+ // We can rule out positive values if y cannot have a positive value.
+ if ((InterestedClasses & fcPosFinite) != fcNone)
+ InterestedY |= fcPositive | fcNegSubnormal;
+
// We can rule out zero and subnormal if x cannot have a positive value.
if ((InterestedClasses & (fcZero | fcSubnormal)) != fcNone)
InterestedX |= fcPositive | fcNegSubnormal;
diff --git a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
index 0bbafeb6dca41..ad07e0055fc7a 100644
--- a/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/GISelValueTracking.cpp
@@ -1406,6 +1406,14 @@ void GISelValueTracking::computeKnownFPClass(Register R,
FPClassTest InterestedY = InterestedClasses;
FPClassTest InterestedX = InterestedClasses;
+ // We can rule out negative values if y cannot have a negative value.
+ if ((InterestedClasses & fcNegFinite) != fcNone)
+ InterestedY |= fcNegative;
+
+ // We can rule out positive values if y cannot have a positive value.
+ if ((InterestedClasses & fcPosFinite) != fcNone)
+ InterestedY |= fcPositive | fcNegSubnormal;
+
// We can rule out zero and subnormal if x cannot have a positive value.
if ((InterestedClasses & (fcZero | fcSubnormal)) != fcNone)
InterestedX |= fcPositive | fcNegSubnormal;
diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp
index 75636ffc73361..930d91be93045 100644
--- a/llvm/lib/Support/KnownFPClass.cpp
+++ b/llvm/lib/Support/KnownFPClass.cpp
@@ -798,13 +798,29 @@ KnownFPClass KnownFPClass::atan2(const KnownFPClass &KnownY,
Known.propagateNonNaN(KnownY, KnownX);
// Negative subnormals could be treated like positive zero.
- const bool XCannotHavePositiveValue = KnownX.isKnownNever(fcPositive) &&
+ const bool XCannotHavePositiveInput = KnownX.isKnownNever(fcPositive) &&
KnownX.isKnownNeverLogicalPosZero(Mode);
+ const bool YCannotHavePositiveInput = KnownY.isKnownNever(fcPositive) &&
+ KnownY.isKnownNeverLogicalPosZero(Mode);
// If x <= -0.0, then |atan2(y, x)| >= pi/2
- if (XCannotHavePositiveValue)
+ if (XCannotHavePositiveInput)
Known.knownNot(fcZero | fcSubnormal);
+ // If y >= +0.0, then atan2(y, x) >= +0.0
+ if (KnownY.isKnownNever(fcNegative))
+ Known.knownNot(fcNegative);
+
+ // If y <= -0.0, then atan2(y, x) <= -0.0
+ // We do this deduction last in case we were able to rule out a negative
+ // subnormal result earlier.
+ if (YCannotHavePositiveInput) {
+ Known.knownNot(fcPosSubnormal | fcPosNormal | fcPosInf);
+ // Negative subnormal results can flush to +0.0.
+ if (Known.isKnownNever(fcNegSubnormal) || !Mode.outputsMayBePositiveZero())
+ Known.knownNot(fcPosZero);
+ }
+
return Known;
}
diff --git a/llvm/test/Transforms/Attributor/nofpclass-atan2.ll b/llvm/test/Transforms/Attributor/nofpclass-atan2.ll
index feb4a7075b435..ae0e7c6f34ea2 100644
--- a/llvm/test/Transforms/Attributor/nofpclass-atan2.ll
+++ b/llvm/test/Transforms/Attributor/nofpclass-atan2.ll
@@ -7,7 +7,7 @@ declare float @llvm.atan2.f32(float, float)
define float @ret_atan2(float %arg0, float %arg1) {
; CHECK-LABEL: define nofpclass(inf) float @ret_atan2(
; CHECK-SAME: float [[ARG0:%.*]], float [[ARG1:%.*]]) #[[ATTR1:[0-9]+]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.atan2.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR6:[0-9]+]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.atan2.f32(float [[ARG0]], float [[ARG1]]) #[[ATTR10:[0-9]+]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.atan2.f32(float %arg0, float %arg1)
@@ -17,7 +17,7 @@ define float @ret_atan2(float %arg0, float %arg1) {
define float @ret_atan2_nonan(float nofpclass(nan) %arg0, float nofpclass(nan) %arg1) {
; CHECK-LABEL: define nofpclass(nan inf) float @ret_atan2_nonan(
; CHECK-SAME: float nofpclass(nan) [[ARG0:%.*]], float nofpclass(nan) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf) float @llvm.atan2.f32(float nofpclass(nan) [[ARG0]], float nofpclass(nan) [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf) float @llvm.atan2.f32(float nofpclass(nan) [[ARG0]], float nofpclass(nan) [[ARG1]]) #[[ATTR10]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.atan2.f32(float %arg0, float %arg1)
@@ -27,18 +27,180 @@ define float @ret_atan2_nonan(float nofpclass(nan) %arg0, float nofpclass(nan) %
define float @ret_atan2_nosnan(float nofpclass(snan) %arg0, float nofpclass(snan) %arg1) {
; CHECK-LABEL: define nofpclass(snan inf) float @ret_atan2_nosnan(
; CHECK-SAME: float nofpclass(snan) [[ARG0:%.*]], float nofpclass(snan) [[ARG1:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan inf) float @llvm.atan2.f32(float nofpclass(snan) [[ARG0]], float nofpclass(snan) [[ARG1]]) #[[ATTR6]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(snan inf) float @llvm.atan2.f32(float nofpclass(snan) [[ARG0]], float nofpclass(snan) [[ARG1]]) #[[ATTR10]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.atan2.f32(float %arg0, float %arg1)
ret float %call
}
+; Quadrant tests
+
+define float @ret_atan2_normal_quad_1(float nofpclass(nan inf zero sub nnorm) %y, float nofpclass(nan inf zero sub nnorm) %x) {
+; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @ret_atan2_normal_quad_1(
+; CHECK-SAME: float nofpclass(nan inf zero sub nnorm) [[Y:%.*]], float nofpclass(nan inf zero sub nnorm) [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf nzero nsub nnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero sub nnorm) [[Y]], float nofpclass(nan inf zero sub nnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_quad_2(float nofpclass(nan inf zero sub nnorm) %y, float nofpclass(nan inf zero sub pnorm) %x) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub nnorm) float @ret_atan2_normal_quad_2(
+; CHECK-SAME: float nofpclass(nan inf zero sub nnorm) [[Y:%.*]], float nofpclass(nan inf zero sub pnorm) [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf zero sub nnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero sub nnorm) [[Y]], float nofpclass(nan inf zero sub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_quad_3(float nofpclass(nan inf zero sub pnorm) %y, float nofpclass(nan inf zero sub pnorm) %x) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub pnorm) float @ret_atan2_normal_quad_3(
+; CHECK-SAME: float nofpclass(nan inf zero sub pnorm) [[Y:%.*]], float nofpclass(nan inf zero sub pnorm) [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf zero sub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero sub pnorm) [[Y]], float nofpclass(nan inf zero sub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_quad_4(float nofpclass(nan inf zero sub pnorm) %y, float nofpclass(nan inf zero sub nnorm) %x) {
+; CHECK-LABEL: define nofpclass(nan inf pzero psub pnorm) float @ret_atan2_normal_quad_4(
+; CHECK-SAME: float nofpclass(nan inf zero sub pnorm) [[Y:%.*]], float nofpclass(nan inf zero sub nnorm) [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf pzero psub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero sub pnorm) [[Y]], float nofpclass(nan inf zero sub nnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_subnormal_quad_1(float nofpclass(nan inf zero nsub nnorm) %y, float nofpclass(nan inf zero nsub nnorm) %x) {
+; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @ret_atan2_normal_subnormal_quad_1(
+; CHECK-SAME: float nofpclass(nan inf zero nsub nnorm) [[Y:%.*]], float nofpclass(nan inf zero nsub nnorm) [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf nzero nsub nnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero nsub nnorm) [[Y]], float nofpclass(nan inf zero nsub nnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_subnormal_quad_2(float nofpclass(nan inf zero nsub nnorm) %y, float nofpclass(nan inf zero psub pnorm) %x) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub nnorm) float @ret_atan2_normal_subnormal_quad_2(
+; CHECK-SAME: float nofpclass(nan inf zero nsub nnorm) [[Y:%.*]], float nofpclass(nan inf zero psub pnorm) [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf zero sub nnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero nsub nnorm) [[Y]], float nofpclass(nan inf zero psub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_subnormal_quad_3(float nofpclass(nan inf zero psub pnorm) %y, float nofpclass(nan inf zero psub pnorm) %x) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub pnorm) float @ret_atan2_normal_subnormal_quad_3(
+; CHECK-SAME: float nofpclass(nan inf zero psub pnorm) [[Y:%.*]], float nofpclass(nan inf zero psub pnorm) [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf zero sub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero psub pnorm) [[Y]], float nofpclass(nan inf zero psub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_subnormal_quad_4(float nofpclass(nan inf zero psub pnorm) %y, float nofpclass(nan inf zero nsub nnorm) %x) {
+; CHECK-LABEL: define nofpclass(nan inf pzero psub pnorm) float @ret_atan2_normal_subnormal_quad_4(
+; CHECK-SAME: float nofpclass(nan inf zero psub pnorm) [[Y:%.*]], float nofpclass(nan inf zero nsub nnorm) [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf pzero psub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero psub pnorm) [[Y]], float nofpclass(nan inf zero nsub nnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_subnormal_quad_1_mode_dynamic_dynamic(float nofpclass(nan inf zero nsub nnorm) %y, float nofpclass(nan inf zero nsub nnorm) %x) denormal_fpenv(float: dynamic|dynamic) {
+; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @ret_atan2_normal_subnormal_quad_1_mode_dynamic_dynamic(
+; CHECK-SAME: float nofpclass(nan inf zero nsub nnorm) [[Y:%.*]], float nofpclass(nan inf zero nsub nnorm) [[X:%.*]]) #[[ATTR2:[0-9]+]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf nzero nsub nnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero nsub nnorm) [[Y]], float nofpclass(nan inf zero nsub nnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_subnormal_quad_2_mode_dynamic_dynamic(float nofpclass(nan inf zero nsub nnorm) %y, float nofpclass(nan inf zero psub pnorm) %x) denormal_fpenv(float: dynamic|dynamic) {
+; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @ret_atan2_normal_subnormal_quad_2_mode_dynamic_dynamic(
+; CHECK-SAME: float nofpclass(nan inf zero nsub nnorm) [[Y:%.*]], float nofpclass(nan inf zero psub pnorm) [[X:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf nzero nsub nnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero nsub nnorm) [[Y]], float nofpclass(nan inf zero psub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_subnormal_quad_3_mode_dynamic_dynamic(float nofpclass(nan inf zero psub pnorm) %y, float nofpclass(nan inf zero psub pnorm) %x) denormal_fpenv(float: dynamic|dynamic) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_atan2_normal_subnormal_quad_3_mode_dynamic_dynamic(
+; CHECK-SAME: float nofpclass(nan inf zero psub pnorm) [[Y:%.*]], float nofpclass(nan inf zero psub pnorm) [[X:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf) float @llvm.atan2.f32(float nofpclass(nan inf zero psub pnorm) [[Y]], float nofpclass(nan inf zero psub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_subnormal_quad_4_mode_dynamic_dynamic(float nofpclass(nan inf zero psub pnorm) %y, float nofpclass(nan inf zero nsub nnorm) %x) denormal_fpenv(float: dynamic|dynamic) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_atan2_normal_subnormal_quad_4_mode_dynamic_dynamic(
+; CHECK-SAME: float nofpclass(nan inf zero psub pnorm) [[Y:%.*]], float nofpclass(nan inf zero nsub nnorm) [[X:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf) float @llvm.atan2.f32(float nofpclass(nan inf zero psub pnorm) [[Y]], float nofpclass(nan inf zero nsub nnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_subnormal_quad_1_mode_ftpz_dapz(float nofpclass(nan inf zero nsub nnorm) %y, float nofpclass(nan inf zero nsub nnorm) %x) denormal_fpenv(float: positivezero|positivezero) {
+; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @ret_atan2_normal_subnormal_quad_1_mode_ftpz_dapz(
+; CHECK-SAME: float nofpclass(nan inf zero nsub nnorm) [[Y:%.*]], float nofpclass(nan inf zero nsub nnorm) [[X:%.*]]) #[[ATTR3:[0-9]+]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf nzero nsub nnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero nsub nnorm) [[Y]], float nofpclass(nan inf zero nsub nnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_subnormal_quad_2_mode_ftpz_dapz(float nofpclass(nan inf zero nsub nnorm) %y, float nofpclass(nan inf zero psub pnorm) %x) denormal_fpenv(float: positivezero|positivezero) {
+; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @ret_atan2_normal_subnormal_quad_2_mode_ftpz_dapz(
+; CHECK-SAME: float nofpclass(nan inf zero nsub nnorm) [[Y:%.*]], float nofpclass(nan inf zero psub pnorm) [[X:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf nzero nsub nnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero nsub nnorm) [[Y]], float nofpclass(nan inf zero psub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_subnormal_quad_3_mode_ftpz_dapz(float nofpclass(nan inf zero psub pnorm) %y, float nofpclass(nan inf zero psub pnorm) %x) denormal_fpenv(float: positivezero|positivezero) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_atan2_normal_subnormal_quad_3_mode_ftpz_dapz(
+; CHECK-SAME: float nofpclass(nan inf zero psub pnorm) [[Y:%.*]], float nofpclass(nan inf zero psub pnorm) [[X:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf) float @llvm.atan2.f32(float nofpclass(nan inf zero psub pnorm) [[Y]], float nofpclass(nan inf zero psub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_normal_subnormal_quad_4_mode_ftpz_dapz(float nofpclass(nan inf zero psub pnorm) %y, float nofpclass(nan inf zero nsub nnorm) %x) denormal_fpenv(float: positivezero|positivezero) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_atan2_normal_subnormal_quad_4_mode_ftpz_dapz(
+; CHECK-SAME: float nofpclass(nan inf zero psub pnorm) [[Y:%.*]], float nofpclass(nan inf zero nsub nnorm) [[X:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf) float @llvm.atan2.f32(float nofpclass(nan inf zero psub pnorm) [[Y]], float nofpclass(nan inf zero nsub nnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
; |atan2(y, x)| >= pi/2 when x is a negative normal or negative infinity.
-define float @ret_atan2_neg_normal_x(float %y, float nofpclass(nan pinf zero sub pnorm) %x) {
-; CHECK-LABEL: define nofpclass(inf zero sub) float @ret_atan2_neg_normal_x(
+define float @ret_atan2_negnormal_neginf_x(float %y, float nofpclass(nan pinf zero sub pnorm) %x) {
+; CHECK-LABEL: define nofpclass(inf zero sub) float @ret_atan2_negnormal_neginf_x(
; CHECK-SAME: float [[Y:%.*]], float nofpclass(nan pinf zero sub pnorm) [[X:%.*]]) #[[ATTR1]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf zero sub) float @llvm.atan2.f32(float [[Y]], float nofpclass(nan pinf zero sub pnorm) [[X]]) #[[ATTR6]]
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf zero sub) float @llvm.atan2.f32(float [[Y]], float nofpclass(nan pinf zero sub pnorm) [[X]]) #[[ATTR10]]
; CHECK-NEXT: ret float [[CALL]]
;
%call = call float @llvm.atan2.f32(float %y, float %x)
@@ -49,50 +211,286 @@ define float @ret_atan2_neg_normal_x(float %y, float nofpclass(nan pinf zero sub
; be zero or subnormal. However, a negative subnormal may be treated as a
; logical positive zero depending on how the floating point environment handles
; denormals. Here we make sure to test every input denormal-mode combination.
-define float @ret_atan2_neg_subnormal_x_ieee_ieee(
-; CHECK-LABEL: define nofpclass(inf zero sub) float @ret_atan2_neg_subnormal_x_ieee_ieee(
-; CHECK-SAME: float [[Y:%.*]], float nofpclass(nan inf zero psub norm) [[X:%.*]]) #[[ATTR2:[0-9]+]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf zero sub) float @llvm.atan2.f32(float [[Y]], float nofpclass(nan inf zero psub norm) [[X]]) #[[ATTR6]]
+define float @ret_atan2_negsubnormal_x_mode_ieee_ieee(float %y, float nofpclass(nan inf zero psub norm) %x) denormal_fpenv(float: ieee|ieee) {
+; CHECK-LABEL: define nofpclass(inf zero sub) float @ret_atan2_negsubnormal_x_mode_ieee_ieee(
+; CHECK-SAME: float [[Y:%.*]], float nofpclass(nan inf zero psub norm) [[X:%.*]]) #[[ATTR4:[0-9]+]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf zero sub) float @llvm.atan2.f32(float [[Y]], float nofpclass(nan inf zero psub norm) [[X]]) #[[ATTR10]]
; CHECK-NEXT: ret float [[CALL]]
;
- float %y, float nofpclass(nan inf zero norm psub) %x)
- denormal_fpenv(float: ieee|ieee) {
%call = call float @llvm.atan2.f32(float %y, float %x)
ret float %call
}
-define float @ret_atan2_neg_subnormal_x_ieee_preservesign(
-; CHECK-LABEL: define nofpclass(inf zero sub) float @ret_atan2_neg_subnormal_x_ieee_preservesign(
-; CHECK-SAME: float [[Y:%.*]], float nofpclass(nan inf zero psub norm) [[X:%.*]]) #[[ATTR3:[0-9]+]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf zero sub) float @llvm.atan2.f32(float [[Y]], float nofpclass(nan inf zero psub norm) [[X]]) #[[ATTR6]]
+define float @ret_atan2_negsubnormal_x_mode_ieee_daz(float %y, float nofpclass(nan inf zero psub norm) %x) denormal_fpenv(float: ieee|preservesign) {
+; CHECK-LABEL: define nofpclass(inf zero sub) float @ret_atan2_negsubnormal_x_mode_ieee_daz(
+; CHECK-SAME: float [[Y:%.*]], float nofpclass(nan inf zero psub norm) [[X:%.*]]) #[[ATTR5:[0-9]+]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf zero sub) float @llvm.atan2.f32(float [[Y]], float nofpclass(nan inf zero psub norm) [[X]]) #[[ATTR10]]
; CHECK-NEXT: ret float [[CALL]]
;
- float %y, float nofpclass(nan inf zero norm psub) %x)
- denormal_fpenv(float: ieee|preservesign) {
%call = call float @llvm.atan2.f32(float %y, float %x)
ret float %call
}
-define float @ret_atan2_neg_subnormal_x_ieee_positivezero(
-; CHECK-LABEL: define nofpclass(inf) float @ret_atan2_neg_subnormal_x_ieee_positivezero(
-; CHECK-SAME: float [[Y:%.*]], float nofpclass(nan inf zero psub norm) [[X:%.*]]) #[[ATTR4:[0-9]+]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.atan2.f32(float [[Y]], float nofpclass(nan inf zero psub norm) [[X]]) #[[ATTR6]]
+define float @ret_atan2_negsubnormal_x_mode_ieee_dapz(float %y, float nofpclass(nan inf zero psub norm) %x) denormal_fpenv(float: ieee|positivezero) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_atan2_negsubnormal_x_mode_ieee_dapz(
+; CHECK-SAME: float [[Y:%.*]], float nofpclass(nan inf zero psub norm) [[X:%.*]]) #[[ATTR6:[0-9]+]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.atan2.f32(float [[Y]], float nofpclass(nan inf zero psub norm) [[X]]) #[[ATTR10]]
; CHECK-NEXT: ret float [[CALL]]
;
- float %y, float nofpclass(nan inf zero norm psub) %x)
- denormal_fpenv(float: ieee|positivezero) {
%call = call float @llvm.atan2.f32(float %y, float %x)
ret float %call
}
-define float @ret_atan2_neg_subnormal_x_ieee_dynamic(
-; CHECK-LABEL: define nofpclass(inf) float @ret_atan2_neg_subnormal_x_ieee_dynamic(
-; CHECK-SAME: float [[Y:%.*]], float nofpclass(nan inf zero psub norm) [[X:%.*]]) #[[ATTR5:[0-9]+]] {
-; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.atan2.f32(float [[Y]], float nofpclass(nan inf zero psub norm) [[X]]) #[[ATTR6]]
+define float @ret_atan2_negsubnormal_x_mode_ieee_dynamic(float %y, float nofpclass(nan inf zero psub norm) %x) denormal_fpenv(float: ieee|dynamic) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_atan2_negsubnormal_x_mode_ieee_dynamic(
+; CHECK-SAME: float [[Y:%.*]], float nofpclass(nan inf zero psub norm) [[X:%.*]]) #[[ATTR7:[0-9]+]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.atan2.f32(float [[Y]], float nofpclass(nan inf zero psub norm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+; If y >= +0.0, then atan2(y, x) >= +0.0
+
+define float @ret_atan2_positive_y(float nofpclass(nan ninf nzero nsub nnorm) %y, float %x) {
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_atan2_positive_y(
+; CHECK-SAME: float nofpclass(nan ninf nzero nsub nnorm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.atan2.f32(float nofpclass(nan ninf nzero nsub nnorm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_positive_y_mode_dynamic_dynamic(float nofpclass(nan ninf nzero nsub nnorm) %y, float %x) denormal_fpenv(float: dynamic|dynamic) {
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_atan2_positive_y_mode_dynamic_dynamic(
+; CHECK-SAME: float nofpclass(nan ninf nzero nsub nnorm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.atan2.f32(float nofpclass(nan ninf nzero nsub nnorm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_positive_y_mode_ftpz_dapz(float nofpclass(nan ninf nzero nsub nnorm) %y, float %x) denormal_fpenv(float: positivezero|positivezero) {
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_atan2_positive_y_mode_ftpz_dapz(
+; CHECK-SAME: float nofpclass(nan ninf nzero nsub nnorm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf nzero nsub nnorm) float @llvm.atan2.f32(float nofpclass(nan ninf nzero nsub nnorm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_positive_or_negzero_y(float nofpclass(nan ninf nsub nnorm) %y, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_atan2_positive_or_negzero_y(
+; CHECK-SAME: float nofpclass(nan ninf nsub nnorm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.atan2.f32(float nofpclass(nan ninf nsub nnorm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_positive_or_negsubnormal_y(float nofpclass(nan ninf nzero nnorm) %y, float %x) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_atan2_positive_or_negsubnormal_y(
+; CHECK-SAME: float nofpclass(nan ninf nzero nnorm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.atan2.f32(float nofpclass(nan ninf nzero nnorm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+; TODO: If we can guarantee that negative subnormals flush to positive zero,
+; then we should be able to rule out y being negative.
+define float @ret_atan2_positive_or_negsubnormal_y_mode_ieee_dapz(float nofpclass(nan ninf nzero nnorm) %y, float %x) denormal_fpenv(float: ieee|positivezero) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_atan2_positive_or_negsubnormal_y_mode_ieee_dapz(
+; CHECK-SAME: float nofpclass(nan ninf nzero nnorm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR6]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.atan2.f32(float nofpclass(nan ninf nzero nnorm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+; If y <= -0.0, then atan2(y, x) <= -0.0
+
+define float @ret_atan2_negnormal_neginf_y(float nofpclass(nan pinf zero sub pnorm) %y, float %x) {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_atan2_negnormal_neginf_y(
+; CHECK-SAME: float nofpclass(nan pinf zero sub pnorm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf pzero psub pnorm) float @llvm.atan2.f32(float nofpclass(nan pinf zero sub pnorm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_negsubnormal_y_mode_ieee_ieee(float nofpclass(nan inf zero psub norm) %y, float %x) denormal_fpenv(float: ieee|ieee) {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_atan2_negsubnormal_y_mode_ieee_ieee(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf pzero psub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_negsubnormal_y_mode_ieee_daz(float nofpclass(nan inf zero psub norm) %y, float %x) denormal_fpenv(float: ieee|preservesign) {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_atan2_negsubnormal_y_mode_ieee_daz(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR5]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf pzero psub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_negsubnormal_y_mode_ieee_dapz(float nofpclass(nan inf zero psub norm) %y, float %x) denormal_fpenv(float: ieee|positivezero) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_atan2_negsubnormal_y_mode_ieee_dapz(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR6]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_negsubnormal_y_mode_ieee_dynamic(float nofpclass(nan inf zero psub norm) %y, float %x) denormal_fpenv(float: ieee|dynamic) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_atan2_negsubnormal_y_mode_ieee_dynamic(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR7]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+; If the output could flush to positive zero, then we cannot rule out positive
+; zero.
+
+define float @ret_atan2_negsubnormal_y_mode_dynamic_ieee(float nofpclass(nan inf zero psub norm) %y, float %x) denormal_fpenv(float: dynamic|ieee) {
+; CHECK-LABEL: define nofpclass(inf psub pnorm) float @ret_atan2_negsubnormal_y_mode_dynamic_ieee(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR8:[0-9]+]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf psub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_negsubnormal_y_mode_ftpz_ieee(float nofpclass(nan inf zero psub norm) %y, float %x) denormal_fpenv(float: positivezero|ieee) {
+; CHECK-LABEL: define nofpclass(inf psub pnorm) float @ret_atan2_negsubnormal_y_mode_ftpz_ieee(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR9:[0-9]+]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf psub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+; A preserve-sign output mode may flush a negative subnormal result to -0.0,
+; but cannot produce +0.0.
+define float @ret_atan2_negsubnormal_y_mode_preservesign_ieee(float nofpclass(nan inf zero psub norm) %y, float %x) denormal_fpenv(float: preservesign|ieee) {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_atan2_negsubnormal_y_mode_preservesign_ieee(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR11:[0-9]+]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf pzero psub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_negnormal_y_mode_dynamic_ieee(float nofpclass(nan inf zero sub pnorm) %y, float %x) denormal_fpenv(float: dynamic|ieee) {
+; CHECK-LABEL: define nofpclass(inf psub pnorm) float @ret_atan2_negnormal_y_mode_dynamic_ieee(
+; CHECK-SAME: float nofpclass(nan inf zero sub pnorm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR8]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf psub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero sub pnorm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_negnormal_y_mode_ftpz_ieee(float nofpclass(nan inf zero sub pnorm) %y, float %x) denormal_fpenv(float: positivezero|ieee) {
+; CHECK-LABEL: define nofpclass(inf psub pnorm) float @ret_atan2_negnormal_y_mode_ftpz_ieee(
+; CHECK-SAME: float nofpclass(nan inf zero sub pnorm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR9]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf psub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero sub pnorm) [[Y]], float [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+; We can still rule out positive zero if negative subnormals were ruled out of
+; the possible results at an earlier deduction.
+
+define float @ret_atan2_negsubnormal_y_negnormal_x_mode_ieee_dynamic(float nofpclass(nan inf zero psub norm) %y, float nofpclass(nan inf zero sub pnorm) %x) denormal_fpenv(float: ieee|dynamic) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub) float @ret_atan2_negsubnormal_y_negnormal_x_mode_ieee_dynamic(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float nofpclass(nan inf zero sub pnorm) [[X:%.*]]) #[[ATTR7]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf zero sub) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float nofpclass(nan inf zero sub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_negsubnormal_y_negnormal_x_mode_ieee_dapz(float nofpclass(nan inf zero psub norm) %y, float nofpclass(nan inf zero sub pnorm) %x) denormal_fpenv(float: ieee|positivezero) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub) float @ret_atan2_negsubnormal_y_negnormal_x_mode_ieee_dapz(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float nofpclass(nan inf zero sub pnorm) [[X:%.*]]) #[[ATTR6]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf zero sub) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float nofpclass(nan inf zero sub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_negsubnormal_y_negnormal_x_mode_dynamic_ieee(float nofpclass(nan inf zero psub norm) %y, float nofpclass(nan inf zero sub pnorm) %x) denormal_fpenv(float: dynamic|ieee) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub pnorm) float @ret_atan2_negsubnormal_y_negnormal_x_mode_dynamic_ieee(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float nofpclass(nan inf zero sub pnorm) [[X:%.*]]) #[[ATTR8]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf zero sub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float nofpclass(nan inf zero sub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_negsubnormal_y_negnormal_x_mode_ftpz_ieee(float nofpclass(nan inf zero psub norm) %y, float nofpclass(nan inf zero sub pnorm) %x) denormal_fpenv(float: positivezero|ieee) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub pnorm) float @ret_atan2_negsubnormal_y_negnormal_x_mode_ftpz_ieee(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float nofpclass(nan inf zero sub pnorm) [[X:%.*]]) #[[ATTR9]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf zero sub pnorm) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float nofpclass(nan inf zero sub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_negsubnormal_y_negnormal_x_mode_dynamic_dynamic(float nofpclass(nan inf zero psub norm) %y, float nofpclass(nan inf zero sub pnorm) %x) denormal_fpenv(float: dynamic|dynamic) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub) float @ret_atan2_negsubnormal_y_negnormal_x_mode_dynamic_dynamic(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float nofpclass(nan inf zero sub pnorm) [[X:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf zero sub) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float nofpclass(nan inf zero sub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_negsubnormal_y_negnormal_x_mode_ftpz_dapz(float nofpclass(nan inf zero psub norm) %y, float nofpclass(nan inf zero sub pnorm) %x) denormal_fpenv(float: positivezero|positivezero) {
+; CHECK-LABEL: define nofpclass(nan inf zero sub) float @ret_atan2_negsubnormal_y_negnormal_x_mode_ftpz_dapz(
+; CHECK-SAME: float nofpclass(nan inf zero psub norm) [[Y:%.*]], float nofpclass(nan inf zero sub pnorm) [[X:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(nan inf zero sub) float @llvm.atan2.f32(float nofpclass(nan inf zero psub norm) [[Y]], float nofpclass(nan inf zero sub pnorm) [[X]]) #[[ATTR10]]
+; CHECK-NEXT: ret float [[CALL]]
+;
+ %call = call float @llvm.atan2.f32(float %y, float %x)
+ ret float %call
+}
+
+define float @ret_atan2_nan_y_mode_dynamic_dynamic(float nofpclass(inf zero sub norm) %y, float %x) denormal_fpenv(float: dynamic|dynamic) {
+; CHECK-LABEL: define nofpclass(inf zero sub norm) float @ret_atan2_nan_y_mode_dynamic_dynamic(
+; CHECK-SAME: float nofpclass(inf zero sub norm) [[Y:%.*]], float [[X:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT: [[CALL:%.*]] = call nofpclass(inf zero sub norm) float @llvm.atan2.f32(float nofpclass(inf zero sub norm) [[Y]], float [[X]]) #[[ATTR10]]
; CHECK-NEXT: ret float [[CALL]]
;
- float %y, float nofpclass(nan inf zero norm psub) %x)
- denormal_fpenv(float: ieee|dynamic) {
%call = call float @llvm.atan2.f32(float %y, float %x)
ret float %call
}
diff --git a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-atan2.ll b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-atan2.ll
index 47a6dd2b0d4a0..6af207c88f7c7 100644
--- a/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-atan2.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-demanded-fpclass-atan2.ll
@@ -28,3 +28,28 @@ define i1 @atan2_negative_x_is_subnormal(float %y, float %x) {
%class = call i1 @llvm.is.fpclass.f32(float %atan2, i32 144)
ret i1 %class
}
+
+define i1 @atan2_positive_y_is_negzero(float %y, float %x) {
+; CHECK-LABEL: define i1 @atan2_positive_y_is_negzero(
+; CHECK-SAME: float [[Y:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT: ret i1 false
+;
+ %abs_y = call float @llvm.fabs.f32(float %y)
+ %positive_y = fadd float %abs_y, 1.000000e+00
+ %atan2 = call float @llvm.atan2.f32(float %positive_y, float %x)
+ %class = call i1 @llvm.is.fpclass.f32(float %atan2, i32 32)
+ ret i1 %class
+}
+
+define i1 @atan2_negative_y_is_poszero(float %y, float %x) {
+; CHECK-LABEL: define i1 @atan2_negative_y_is_poszero(
+; CHECK-SAME: float [[Y:%.*]], float [[X:%.*]]) {
+; CHECK-NEXT: ret i1 false
+;
+ %abs_y = call float @llvm.fabs.f32(float %y)
+ %positive_y = fadd float %abs_y, 1.000000e+00
+ %negative_y = fneg float %positive_y
+ %atan2 = call float @llvm.atan2.f32(float %negative_y, float %x)
+ %class = call i1 @llvm.is.fpclass.f32(float %atan2, i32 64)
+ ret i1 %class
+}
diff --git a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
index 8ff84820276d5..4b50789e7e613 100644
--- a/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
+++ b/llvm/unittests/CodeGen/GlobalISel/KnownFPClassTest.cpp
@@ -1804,7 +1804,7 @@ TEST_F(AArch64GISelMITest, TestFPClassFAtan2) {
}
TEST_F(AArch64GISelMITest, TestFPClassFAtan2NNaN) {
- // atan2 with two non-NaN inputs is non-NaN and non-Inf.
+ // atan2 with two non-negative finite inputs is non-negative and finite.
StringRef MIRString = R"(
%ptr:_(p0) = G_IMPLICIT_DEF
%y:_(s32) = G_LOAD %ptr(p0) :: (load (s32))
@@ -1822,8 +1822,8 @@ TEST_F(AArch64GISelMITest, TestFPClassFAtan2NNaN) {
Register SrcReg = FinalCopy->getOperand(1).getReg();
GISelValueTracking Info(*MF);
KnownFPClass Known = Info.computeKnownFPClass(SrcReg);
- EXPECT_EQ(fcFinite, Known.getKnownFPClasses());
- EXPECT_EQ(std::nullopt, Known.getSignBit());
+ EXPECT_EQ(fcPosFinite, Known.getKnownFPClasses());
+ EXPECT_EQ(false, Known.getSignBit());
}
// isAbsoluteValueULEOne: x - floor(x) is in [0, 1), so multiplying a known-
More information about the llvm-commits
mailing list