[llvm] [InstCombine] Fold copysign(floor(fabs(X)), X) to trunc(X) (PR #200836)

Aayush Shrivastava via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 3 05:15:01 PDT 2026


================
@@ -295,67 +295,59 @@ define <2 x bfloat> @copysign_simplify_demanded_bits_sign_bitcast_not_int_vec(<2
   ret <2 x bfloat> %result
 }
 
-; copysign(floor(fabs(X)), X) --> trunc(X)  (requires nnan)
+; copysign(floor(fabs(X)), X) --> copysign(trunc(X), X)
+; copysign ignores the sign of its magnitude arg, so trunc(X) is equivalent
+; to floor(fabs(X)) for the magnitude. Valid for all inputs including NaN.
 
 define double @copysign_floor_fabs_to_trunc_f64(double %x) {
 ; CHECK-LABEL: @copysign_floor_fabs_to_trunc_f64(
-; CHECK-NEXT:    [[RESULT:%.*]] = call nnan double @llvm.trunc.f64(double [[X:%.*]])
-; CHECK-NEXT:    ret double [[RESULT]]
+; CHECK-NEXT:    [[RESULT:%.*]] = call double @llvm.trunc.f64(double [[X:%.*]])
+; CHECK-NEXT:    [[RESULT1:%.*]] = call double @llvm.copysign.f64(double [[RESULT]], double [[X]])
+; CHECK-NEXT:    ret double [[RESULT1]]
 ;
   %abs = call double @llvm.fabs.f64(double %x)
   %fl = call double @llvm.floor.f64(double %abs)
-  %result = call nnan double @llvm.copysign.f64(double %fl, double %x)
+  %result = call double @llvm.copysign.f64(double %fl, double %x)
   ret double %result
 }
 
 define float @copysign_floor_fabs_to_trunc_f32(float %x) {
 ; CHECK-LABEL: @copysign_floor_fabs_to_trunc_f32(
-; CHECK-NEXT:    [[RESULT:%.*]] = call nnan float @llvm.trunc.f32(float [[X:%.*]])
-; CHECK-NEXT:    ret float [[RESULT]]
+; CHECK-NEXT:    [[RESULT:%.*]] = call float @llvm.trunc.f32(float [[X:%.*]])
+; CHECK-NEXT:    [[RESULT1:%.*]] = call float @llvm.copysign.f32(float [[RESULT]], float [[X]])
+; CHECK-NEXT:    ret float [[RESULT1]]
 ;
   %abs = call float @llvm.fabs.f32(float %x)
   %fl = call float @llvm.floor.f32(float %abs)
-  %result = call nnan float @llvm.copysign.f32(float %fl, float %x)
+  %result = call float @llvm.copysign.f32(float %fl, float %x)
   ret float %result
 }
 
 define <3 x double> @copysign_floor_fabs_to_trunc_vec(<3 x double> %x) {
 ; CHECK-LABEL: @copysign_floor_fabs_to_trunc_vec(
-; CHECK-NEXT:    [[RESULT:%.*]] = call nnan <3 x double> @llvm.trunc.v3f64(<3 x double> [[X:%.*]])
-; CHECK-NEXT:    ret <3 x double> [[RESULT]]
+; CHECK-NEXT:    [[RESULT:%.*]] = call <3 x double> @llvm.trunc.v3f64(<3 x double> [[X:%.*]])
+; CHECK-NEXT:    [[RESULT1:%.*]] = call <3 x double> @llvm.copysign.v3f64(<3 x double> [[RESULT]], <3 x double> [[X]])
+; CHECK-NEXT:    ret <3 x double> [[RESULT1]]
 ;
   %abs = call <3 x double> @llvm.fabs.v3f64(<3 x double> %x)
   %fl = call <3 x double> @llvm.floor.v3f64(<3 x double> %abs)
-  %result = call nnan <3 x double> @llvm.copysign.v3f64(<3 x double> %fl, <3 x double> %x)
+  %result = call <3 x double> @llvm.copysign.v3f64(<3 x double> %fl, <3 x double> %x)
   ret <3 x double> %result
 }
 
-; FMF flags from copysign propagate to the resulting trunc.
+; FMF flags from copysign propagate to the resulting instructions.
 define double @copysign_floor_fabs_to_trunc_fmf(double %x) {
 ; CHECK-LABEL: @copysign_floor_fabs_to_trunc_fmf(
 ; CHECK-NEXT:    [[RESULT:%.*]] = call nnan ninf double @llvm.trunc.f64(double [[X:%.*]])
-; CHECK-NEXT:    ret double [[RESULT]]
+; CHECK-NEXT:    [[RESULT1:%.*]] = call nnan ninf double @llvm.copysign.f64(double [[RESULT]], double [[X]])
+; CHECK-NEXT:    ret double [[RESULT1]]
 ;
   %abs = call double @llvm.fabs.f64(double %x)
   %fl = call double @llvm.floor.f64(double %abs)
   %result = call nnan ninf double @llvm.copysign.f64(double %fl, double %x)
   ret double %result
 }
 
-; Negative test: missing nnan -- NaN inputs would give different sign bits.
----------------
iamaayushrivastava wrote:

> Should preserve this test? Just change the name / comment

Done, added it back as `copysign_floor_fabs_to_trunc_no_fmf` with an updated comment.

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


More information about the llvm-commits mailing list