[llvm] [KnownFPClass] Fix KnownFPClass::frem subnormal handling and improve deductions. (PR #219303)

via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 14:47:10 PDT 2026


================
@@ -1064,9 +1064,353 @@ define float @ret_known_inf_or_nan_frem_known_inf_or_nan(float nofpclass(norm su
   ret float %frem
 }
 
+; frem(x, y) == x if |x| < |y|, up to the denormal mode.
+
+define float @ret_frem_lhs_poszero_possubnormal_rhs_posnormal(float nofpclass(nan inf nzero nsub norm) %lhs, float nofpclass(nan inf zero sub nnorm) %rhs) {
+; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @ret_frem_lhs_poszero_possubnormal_rhs_posnormal
+; CHECK-SAME: (float nofpclass(nan inf nzero nsub norm) [[LHS:%.*]], float nofpclass(nan inf zero sub nnorm) [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+define float @ret_frem_lhs_negzero_negsubnormal_rhs_negnormal(float nofpclass(nan inf pzero psub norm) %lhs, float nofpclass(nan inf zero sub pnorm) %rhs) {
+; CHECK-LABEL: define nofpclass(nan inf pzero psub pnorm) float @ret_frem_lhs_negzero_negsubnormal_rhs_negnormal
+; CHECK-SAME: (float nofpclass(nan inf pzero psub norm) [[LHS:%.*]], float nofpclass(nan inf zero sub pnorm) [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+define float @ret_frem_lhs_negzero_negsubnormal_rhs_negnormal_mode_ftpz_dapz(float nofpclass(nan inf pzero psub norm) %lhs, float nofpclass(nan inf zero sub pnorm) %rhs) #5 {
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @ret_frem_lhs_negzero_negsubnormal_rhs_negnormal_mode_ftpz_dapz
+; CHECK-SAME: (float nofpclass(nan inf pzero psub norm) [[LHS:%.*]], float nofpclass(nan inf zero sub pnorm) [[RHS:%.*]]) #[[ATTR5:[0-9]+]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+define float @ret_frem_lhs_negzero_negsubnormal_rhs_negnormal_mode_dynamic_dynamic(float nofpclass(nan inf pzero psub norm) %lhs, float nofpclass(nan inf zero sub pnorm) %rhs) #4 {
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @ret_frem_lhs_negzero_negsubnormal_rhs_negnormal_mode_dynamic_dynamic
+; CHECK-SAME: (float nofpclass(nan inf pzero psub norm) [[LHS:%.*]], float nofpclass(nan inf zero sub pnorm) [[RHS:%.*]]) #[[ATTR6:[0-9]+]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+define float @ret_frem_lhs_zero_subnormal_rhs_normal(float nofpclass(nan inf norm) %lhs, float nofpclass(nan inf zero sub) %rhs) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_frem_lhs_zero_subnormal_rhs_normal
+; CHECK-SAME: (float nofpclass(nan inf norm) [[LHS:%.*]], float nofpclass(nan inf zero sub) [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+define float @ret_frem_lhs_posfinite_rhs_posinf(float nofpclass(nan inf nzero nsub nnorm) %lhs, float nofpclass(nan ninf zero sub norm) %rhs) {
+; CHECK-LABEL: define nofpclass(nan inf nzero nsub nnorm) float @ret_frem_lhs_posfinite_rhs_posinf
+; CHECK-SAME: (float nofpclass(nan inf nzero nsub nnorm) [[LHS:%.*]], float nofpclass(nan ninf zero sub norm) [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+define float @ret_frem_lhs_negfinite_rhs_neginf(float nofpclass(nan inf pzero psub pnorm) %lhs, float nofpclass(nan pinf zero sub norm) %rhs) {
+; CHECK-LABEL: define nofpclass(nan inf pzero psub pnorm) float @ret_frem_lhs_negfinite_rhs_neginf
+; CHECK-SAME: (float nofpclass(nan inf pzero psub pnorm) [[LHS:%.*]], float nofpclass(nan pinf zero sub norm) [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+define float @ret_frem_lhs_negfinite_rhs_neginf_mode_ftpz_dapz(float nofpclass(nan inf pzero psub pnorm) %lhs, float nofpclass(nan pinf zero sub norm) %rhs) #5 {
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @ret_frem_lhs_negfinite_rhs_neginf_mode_ftpz_dapz
+; CHECK-SAME: (float nofpclass(nan inf pzero psub pnorm) [[LHS:%.*]], float nofpclass(nan pinf zero sub norm) [[RHS:%.*]]) #[[ATTR5]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+define float @ret_frem_lhs_negfinite_rhs_neginf_mode_dynamic_dynamic(float nofpclass(nan inf pzero psub pnorm) %lhs, float nofpclass(nan pinf zero sub norm) %rhs) #4 {
+; CHECK-LABEL: define nofpclass(nan inf psub pnorm) float @ret_frem_lhs_negfinite_rhs_neginf_mode_dynamic_dynamic
+; CHECK-SAME: (float nofpclass(nan inf pzero psub pnorm) [[LHS:%.*]], float nofpclass(nan pinf zero sub norm) [[RHS:%.*]]) #[[ATTR6]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+define float @ret_frem_lhs_finite_rhs_inf(float nofpclass(nan inf) %lhs, float nofpclass(nan zero sub norm) %rhs) {
+; CHECK-LABEL: define nofpclass(nan inf) float @ret_frem_lhs_finite_rhs_inf
+; CHECK-SAME: (float nofpclass(nan inf) [[LHS:%.*]], float nofpclass(nan zero sub norm) [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+; Sign preservation
+
+define float @ret_frem_lhs_posnormal_possubnormal_rhs_any(float nofpclass(nan inf zero nsub nnorm) %lhs, float %rhs) {
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_frem_lhs_posnormal_possubnormal_rhs_any
+; CHECK-SAME: (float nofpclass(nan inf zero nsub nnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+define float @ret_frem_lhs_negnormal_negsubnormal_rhs_any(float nofpclass(nan inf zero psub pnorm) %lhs, float %rhs) {
+; CHECK-LABEL: define nofpclass(inf pzero psub pnorm) float @ret_frem_lhs_negnormal_negsubnormal_rhs_any
+; CHECK-SAME: (float nofpclass(nan inf zero psub pnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+define float @ret_frem_lhs_posfinite_rhs_any(float nofpclass(nan inf nzero nsub nnorm) %lhs, float %rhs) {
+; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_frem_lhs_posfinite_rhs_any
+; CHECK-SAME: (float nofpclass(nan inf nzero nsub nnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+define float @ret_frem_lhs_posfinite_negzero_rhs_any(float nofpclass(nan inf nsub nnorm) %lhs, float %rhs) {
+; CHECK-LABEL: define nofpclass(inf nsub nnorm) float @ret_frem_lhs_posfinite_negzero_rhs_any
+; CHECK-SAME: (float nofpclass(nan inf nsub nnorm) [[LHS:%.*]], float [[RHS:%.*]]) #[[ATTR4]] {
+; CHECK-NEXT:    [[FREM:%.*]] = frem float [[LHS]], [[RHS]]
+; CHECK-NEXT:    ret float [[FREM]]
+;
+  %frem = frem float %lhs, %rhs
+  ret float %frem
+}
+
+; TODO: If we can guarantee that subnormals flush to positive zero under DAPZ,
+; then we can rule out negatives here.
+define float @ret_frem_lhs_posfinite_negsubnormal_rhs_any_mode_dynamic_dapz(float nofpclass(nan inf nzero nnorm) %lhs, float %rhs) #8 {
----------------
ZERICO2005 wrote:

This test covers a potential future deduction if `DAPZ` is established to always flush `fcNegSubnormal` to `fcPosZero`, rather than only possibly doing so.
https://github.com/llvm/llvm-project/pull/214987#discussion_r3743949657

https://github.com/llvm/llvm-project/pull/219303


More information about the llvm-commits mailing list