[llvm] [Support][KnownFPClass] Generalize scaling refinement to an exponent range (PR #215094)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 15 17:14:01 PDT 2026
================
@@ -1056,9 +1056,294 @@ define float @ret_known_inf_or_nan_fdiv_known_inf_or_nan(float nofpclass(norm su
ret float %fdiv
}
+; Dividing by a constant of magnitude >= 1 cannot overflow.
+define float @ret_fdiv_noinf_const_1_5(float nofpclass(inf) %arg0) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_fdiv_noinf_const_1_5
+; CHECK-SAME: (float nofpclass(inf) [[ARG0:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], 1.500000e+00
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, 1.5
+ ret float %fdiv
+}
+
+; Negative test, 1 / 0.75 is greater than one.
+define float @ret_fdiv_noinf_const_0_75(float nofpclass(inf) %arg0) {
+; CHECK-LABEL: define float @ret_fdiv_noinf_const_0_75
+; CHECK-SAME: (float nofpclass(inf) [[ARG0:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], 7.500000e-01
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, 0.75
+ ret float %fdiv
+}
+
+define float @ret_fdiv_nopinf_const_3(float nofpclass(pinf) %arg0) {
+; CHECK-LABEL: define nofpclass(pinf) float @ret_fdiv_nopinf_const_3
+; CHECK-SAME: (float nofpclass(pinf) [[ARG0:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], 3.000000e+00
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, 3.0
+ ret float %fdiv
+}
+
+; Dividing by a constant of magnitude <= 1 cannot underflow.
+define float @ret_fdiv_nozerosub_const_1(float nofpclass(zero sub) %arg0) {
+; CHECK-LABEL: define nofpclass(zero sub) float @ret_fdiv_nozerosub_const_1
+; CHECK-SAME: (float nofpclass(zero sub) [[ARG0:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], 1.000000e+00
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, 1.0
+ ret float %fdiv
+}
+
+; Negative test, 1 / 1.5 is less than one.
+define float @ret_fdiv_nozerosub_const_1_5(float nofpclass(zero sub) %arg0) {
+; CHECK-LABEL: define float @ret_fdiv_nozerosub_const_1_5
+; CHECK-SAME: (float nofpclass(zero sub) [[ARG0:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], 1.500000e+00
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, 1.5
+ ret float %fdiv
+}
+
+; A power of two divides exactly. The bound is a single exponent, not a range.
+define float @ret_fdiv_noinf_const_2(float nofpclass(inf) %arg0) {
+; CHECK-LABEL: define nofpclass(inf) float @ret_fdiv_noinf_const_2
+; CHECK-SAME: (float nofpclass(inf) [[ARG0:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], 2.000000e+00
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, 2.0
+ ret float %fdiv
+}
+
+define float @ret_fdiv_nozerosub_const_0_5(float nofpclass(zero sub) %arg0) {
+; CHECK-LABEL: define nofpclass(zero sub) float @ret_fdiv_nozerosub_const_0_5
+; CHECK-SAME: (float nofpclass(zero sub) [[ARG0:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], 5.000000e-01
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, 0.5
+ ret float %fdiv
+}
+
+; The exponent comes from the magnitude. A negative power of two keeps the
+; exact bound and only mirrors the sign.
+define float @ret_fdiv_nozero_nopsub_const_neg1(float nofpclass(zero psub) %arg0) {
+; CHECK-LABEL: define nofpclass(zero nsub) float @ret_fdiv_nozero_nopsub_const_neg1
+; CHECK-SAME: (float nofpclass(zero psub) [[ARG0:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], -1.000000e+00
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, -1.0
+ ret float %fdiv
+}
+
+define float @ret_fdiv_nopsub_const_0_75(float nofpclass(psub) %arg0) {
+; CHECK-LABEL: define nofpclass(psub) float @ret_fdiv_nopsub_const_0_75
+; CHECK-SAME: (float nofpclass(psub) [[ARG0:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], 7.500000e-01
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, 0.75
+ ret float %fdiv
+}
+
+; Negative test, a subnormal source reads as either zero under this mode.
+define float @ret_fdiv_nozero_const_0_75_daz(float nofpclass(zero) %arg0) #1 {
+; CHECK-LABEL: define float @ret_fdiv_nozero_const_0_75_daz
+; CHECK-SAME: (float nofpclass(zero) [[ARG0:%.*]]) #[[ATTR1]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], 7.500000e-01
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, 0.75
+ ret float %fdiv
+}
+
+; A positive zero input mode reads -sub as +0. Only -0.0 is ruled out.
+define float @ret_fdiv_nozero_const_0_75_dapz(float nofpclass(zero) %arg0) #2 {
+; CHECK-LABEL: define nofpclass(nzero) float @ret_fdiv_nozero_const_0_75_dapz
+; CHECK-SAME: (float nofpclass(zero) [[ARG0:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], 7.500000e-01
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, 0.75
+ ret float %fdiv
+}
+
+; The same, mirrored by a negative divisor. Only +0.0 is ruled out.
+define float @ret_fdiv_nozero_const_neg0_75_dapz(float nofpclass(zero) %arg0) #2 {
+; CHECK-LABEL: define nofpclass(pzero) float @ret_fdiv_nozero_const_neg0_75_dapz
+; CHECK-SAME: (float nofpclass(zero) [[ARG0:%.*]]) #[[ATTR2]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], -7.500000e-01
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, -0.75
+ ret float %fdiv
+}
+
+; Negative test, a dynamic input mode may read a subnormal as either zero.
+define float @ret_fdiv_nozero_const_0_75_dadyn(float nofpclass(zero) %arg0) #3 {
+; CHECK-LABEL: define float @ret_fdiv_nozero_const_0_75_dadyn
+; CHECK-SAME: (float nofpclass(zero) [[ARG0:%.*]]) #[[ATTR3]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], 7.500000e-01
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, 0.75
+ ret float %fdiv
+}
+
+; The constant divisor is matched through a vector splat as well.
+define <2 x float> @ret_fdiv_v2f32_nozerosub_splat_0_5(<2 x float> nofpclass(zero sub) %arg0) {
+; CHECK-LABEL: define nofpclass(zero sub) <2 x float> @ret_fdiv_v2f32_nozerosub_splat_0_5
+; CHECK-SAME: (<2 x float> nofpclass(zero sub) [[ARG0:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv <2 x float> [[ARG0]], splat (float 5.000000e-01)
+; CHECK-NEXT: ret <2 x float> [[FDIV]]
+;
+ %fdiv = fdiv <2 x float> %arg0, splat (float 0.5)
+ ret <2 x float> %fdiv
+}
+
+; Scaling up by at least 2^MantissaBits leaves the subnormal range.
+define float @ret_fdiv_exponent_f32_neg23(float %arg0) {
+; CHECK-LABEL: define nofpclass(sub) float @ret_fdiv_exponent_f32_neg23
+; CHECK-SAME: (float [[ARG0:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], f0x34000000
+; CHECK-NEXT: ret float [[FDIV]]
+;
+ %fdiv = fdiv float %arg0, 0x3E80000000000000
----------------
ZERICO2005 wrote:
`0x34000000 == 0x3E80000000000000` (see other comment on using 32-bit float literals)
I would like to see a test using `nextup(2^-23)` and `nextdown(2^23)`
https://github.com/llvm/llvm-project/pull/215094
More information about the llvm-commits
mailing list