| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | |
| ; RUN: opt -S -passes=instcombine < %s | FileCheck %s | |
| declare float @llvm.fabs.f32(float) | |
| declare float @llvm.floor.f32(float) | |
| declare float @llvm.trunc.f32(float) | |
| declare float @llvm.copysign.f32(float, float) | |
| declare float @llvm.maxnum.f32(float, float) | |
| declare double @llvm.fabs.f64(double) | |
| declare double @llvm.floor.f64(double) | |
| declare double @llvm.trunc.f64(double) | |
| declare double @llvm.copysign.f64(double, double) | |
| declare <3 x double> @llvm.copysign.v3f64(<3 x double>, <3 x double>) | |
| declare <3 x double> @llvm.fabs.v3f64(<3 x double>) | |
| declare <3 x double> @llvm.floor.v3f64(<3 x double>) | |
| declare <3 x double> @llvm.trunc.v3f64(<3 x double>) | |
| define float @positive_sign_arg(float %x) { | |
| ; CHECK-LABEL: @positive_sign_arg( | |
| ; CHECK-NEXT: [[R:%.*]] = call arcp float @llvm.fabs.f32(float [[X:%.*]]) | |
| ; CHECK-NEXT: ret float [[R]] | |
| ; | |
| %r = call arcp float @llvm.copysign.f32(float %x, float 0.0) | |
| ret float %r | |
| } | |
| define <3 x double> @positive_sign_arg_vec_splat(<3 x double> %x) { | |
| ; CHECK-LABEL: @positive_sign_arg_vec_splat( | |
| ; CHECK-NEXT: [[R:%.*]] = call ninf <3 x double> @llvm.fabs.v3f64(<3 x double> [[X:%.*]]) | |
| ; CHECK-NEXT: ret <3 x double> [[R]] | |
| ; | |
| %r = call ninf <3 x double> @llvm.copysign.v3f64(<3 x double> %x, <3 x double> <double 42.0, double 42.0, double 42.0>) | |
| ret <3 x double> %r | |
| } | |
| define float @negative_sign_arg(float %x) { | |
| ; CHECK-LABEL: @negative_sign_arg( | |
| ; CHECK-NEXT: [[TMP1:%.*]] = call nnan float @llvm.fabs.f32(float [[X:%.*]]) | |
| ; CHECK-NEXT: [[R:%.*]] = fneg nnan float [[TMP1]] | |
| ; CHECK-NEXT: ret float [[R]] | |
| ; | |
| %r = call nnan float @llvm.copysign.f32(float %x, float -0.0) | |
| ret float %r | |
| } | |
| define <3 x double> @negative_sign_arg_vec_splat(<3 x double> %x) { | |
| ; CHECK-LABEL: @negative_sign_arg_vec_splat( | |
| ; CHECK-NEXT: [[TMP1:%.*]] = call fast <3 x double> @llvm.fabs.v3f64(<3 x double> [[X:%.*]]) | |
| ; CHECK-NEXT: [[R:%.*]] = fneg fast <3 x double> [[TMP1]] | |
| ; CHECK-NEXT: ret <3 x double> [[R]] | |
| ; | |
| %r = call fast <3 x double> @llvm.copysign.v3f64(<3 x double> %x, <3 x double> <double -42.0, double -42.0, double -42.0>) | |
| ret <3 x double> %r | |
| } | |
| define float @known_positive_sign_arg(float %x, float %y) { | |
| ; CHECK-LABEL: @known_positive_sign_arg( | |
| ; CHECK-NEXT: [[R:%.*]] = call ninf float @llvm.fabs.f32(float [[X:%.*]]) | |
| ; CHECK-NEXT: ret float [[R]] | |
| ; | |
| %fabs = call float @llvm.fabs.f32(float %y) | |
| %r = call ninf float @llvm.copysign.f32(float %x, float %fabs) | |
| ret float %r | |
| } | |
| define <3 x double> @known_positive_sign_arg_vec(<3 x double> %x, <3 x i32> %y) { | |
| ; CHECK-LABEL: @known_positive_sign_arg_vec( | |
| ; CHECK-NEXT: [[R:%.*]] = call arcp <3 x double> @llvm.fabs.v3f64(<3 x double> [[X:%.*]]) | |
| ; CHECK-NEXT: ret <3 x double> [[R]] | |
| ; | |
| %yf = uitofp <3 x i32> %y to <3 x double> | |
| %r = call arcp <3 x double> @llvm.copysign.v3f64(<3 x double> %x, <3 x double> %yf) | |
| ret <3 x double> %r | |
| } | |
| ; maxnum(-0.0, 0.0) can return -0.0. | |
| define float @not_known_positive_sign_arg(float %x, float %y) { | |
| ; CHECK-LABEL: @not_known_positive_sign_arg( | |
| ; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float 0.000000e+00) | |
| ; CHECK-NEXT: [[R:%.*]] = call ninf float @llvm.copysign.f32(float [[Y:%.*]], float [[MAX]]) | |
| ; CHECK-NEXT: ret float [[R]] | |
| ; | |
| %max = call float @llvm.maxnum.f32(float %x, float 0.0) | |
| %r = call ninf float @llvm.copysign.f32(float %y, float %max) | |
| ret float %r | |
| } | |
| ; The magnitude operand of the 1st copysign is irrelevant. | |
| ; copysign(x, copysign(y, z)) --> copysign(x, z) | |
| define float @copysign_sign_arg(float %x, float %y, float %z) { | |
| ; CHECK-LABEL: @copysign_sign_arg( | |
| ; CHECK-NEXT: [[R:%.*]] = call float @llvm.copysign.f32(float [[X:%.*]], float [[Z:%.*]]) | |
| ; CHECK-NEXT: ret float [[R]] | |
| ; | |
| %s = call reassoc float @llvm.copysign.f32(float %y, float %z) | |
| %r = call ninf float @llvm.copysign.f32(float %x, float %s) | |
| ret float %r | |
| } | |
| define float @copysign_sign_arg_nnan(float %x, float %y, float %z) { | |
| ; CHECK-LABEL: @copysign_sign_arg_nnan( | |
| ; CHECK-NEXT: [[R:%.*]] = call nnan float @llvm.copysign.f32(float [[X:%.*]], float [[Z:%.*]]) | |
| ; CHECK-NEXT: ret float [[R]] | |
| ; | |
| %s = call nnan float @llvm.copysign.f32(float %y, float %z) | |
| %r = call nnan float @llvm.copysign.f32(float %x, float %s) | |
| ret float %r | |
| } | |
| define float @copysign_sign_arg_mixed(float %x, float %y, float %z) { | |
| ; CHECK-LABEL: @copysign_sign_arg_mixed( | |
| ; CHECK-NEXT: [[R:%.*]] = call nsz float @llvm.copysign.f32(float [[X:%.*]], float [[Z:%.*]]) | |
| ; CHECK-NEXT: ret float [[R]] | |
| ; | |
| %s = call ninf nsz float @llvm.copysign.f32(float %y, float %z) | |
| %r = call nnan nsz float @llvm.copysign.f32(float %x, float %s) | |
| ret float %r | |
| } | |
| define float @fneg_mag(float %x, float %y) { | |
| ; CHECK-LABEL: @fneg_mag( | |
| ; CHECK-NEXT: [[R:%.*]] = call float @llvm.copysign.f32(float [[X:%.*]], float [[Y:%.*]]) | |
| ; CHECK-NEXT: ret float [[R]] | |
| ; | |
| %n = fneg float %x | |
| %r = call float @llvm.copysign.f32(float %n, float %y) | |
| ret float %r | |
| } | |
| define float @fabs_mag(float %x, float %y) { | |
| ; CHECK-LABEL: @fabs_mag( | |
| ; CHECK-NEXT: [[R:%.*]] = call float @llvm.copysign.f32(float [[X:%.*]], float [[Y:%.*]]) | |
| ; CHECK-NEXT: ret float [[R]] | |
| ; | |
| %a = call float @llvm.fabs.f32(float %x) | |
| %r = call float @llvm.copysign.f32(float %a, float %y) | |
| ret float %r | |
| } | |
| ; Issue 177932 | |
| define float @copysign_simplify_demanded_bits_sign(float %mag, float %sign) { | |
| ; CHECK-LABEL: @copysign_simplify_demanded_bits_sign( | |
| ; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.copysign.f32(float [[MAG:%.*]], float [[SIGN:%.*]]) | |
| ; CHECK-NEXT: ret float [[RESULT]] | |
| ; | |
| %sign.int = bitcast float %sign to i32 | |
| %and.sign = and i32 %sign.int, -2147483648 | |
| %cast.sign = bitcast i32 %and.sign to float | |
| %result = call float @llvm.copysign.f32(float %mag, float %cast.sign) | |
| ret float %result | |
| } | |
| define <2 x float> @copysign_simplify_demanded_bits_sign_vector(<2 x float> %mag, <2 x float> %sign) { | |
| ; CHECK-LABEL: @copysign_simplify_demanded_bits_sign_vector( | |
| ; CHECK-NEXT: [[RESULT:%.*]] = call <2 x float> @llvm.copysign.v2f32(<2 x float> [[MAG:%.*]], <2 x float> [[SIGN:%.*]]) | |
| ; CHECK-NEXT: ret <2 x float> [[RESULT]] | |
| ; | |
| %sign.int = bitcast <2 x float> %sign to <2 x i32> | |
| %and.sign = and <2 x i32> %sign.int, splat (i32 -2147483648) | |
| %cast.sign = bitcast <2 x i32> %and.sign to <2 x float> | |
| %result = call <2 x float> @llvm.copysign.v2f32(<2 x float> %mag, <2 x float> %cast.sign) | |
| ret <2 x float> %result | |
| } | |
| define float @copysign_simplify_demanded_bits_sign_multiple_use_cast(float %mag, float %sign, ptr %ptr) { | |
| ; CHECK-LABEL: @copysign_simplify_demanded_bits_sign_multiple_use_cast( | |
| ; CHECK-NEXT: [[SIGN_INT:%.*]] = bitcast float [[SIGN:%.*]] to i32 | |
| ; CHECK-NEXT: [[AND_SIGN:%.*]] = and i32 [[SIGN_INT]], -2147483648 | |
| ; CHECK-NEXT: [[CAST_SIGN:%.*]] = bitcast i32 [[AND_SIGN]] to float | |
| ; CHECK-NEXT: store i32 [[AND_SIGN]], ptr [[PTR:%.*]], align 4 | |
| ; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.copysign.f32(float [[MAG:%.*]], float [[CAST_SIGN]]) | |
| ; CHECK-NEXT: ret float [[RESULT]] | |
| ; | |
| %sign.int = bitcast float %sign to i32 | |
| %and.sign = and i32 %sign.int, -2147483648 | |
| %cast.sign = bitcast i32 %and.sign to float | |
| store float %cast.sign, ptr %ptr | |
| %result = call float @llvm.copysign.f32(float %mag, float %cast.sign) | |
| ret float %result | |
| } | |
| define float @copysign_simplify_demanded_bits_sign_multiple_use_cast_src(float %mag, float %sign, ptr %ptr) { | |
| ; CHECK-LABEL: @copysign_simplify_demanded_bits_sign_multiple_use_cast_src( | |
| ; CHECK-NEXT: [[SIGN_INT:%.*]] = bitcast float [[SIGN:%.*]] to i32 | |
| ; CHECK-NEXT: [[AND_SIGN:%.*]] = and i32 [[SIGN_INT]], -2147483648 | |
| ; CHECK-NEXT: store i32 [[AND_SIGN]], ptr [[PTR:%.*]], align 4 | |
| ; CHECK-NEXT: [[CAST_SIGN:%.*]] = bitcast i32 [[AND_SIGN]] to float | |
| ; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.copysign.f32(float [[MAG:%.*]], float [[CAST_SIGN]]) | |
| ; CHECK-NEXT: ret float [[RESULT]] | |
| ; | |
| %sign.int = bitcast float %sign to i32 | |
| %and.sign = and i32 %sign.int, -2147483648 | |
| store i32 %and.sign, ptr %ptr | |
| %cast.sign = bitcast i32 %and.sign to float | |
| %result = call float @llvm.copysign.f32(float %mag, float %cast.sign) | |
| ret float %result | |
| } | |
| ; Cannot simplify due to second use of %cast.sign | |
| define i32 @issue178245(i32 %i.0.i.i) { | |
| ; CHECK-LABEL: @issue178245( | |
| ; CHECK-NEXT: entry: | |
| ; CHECK-NEXT: [[TOBOOL104_I_I_NOT:%.*]] = icmp eq i32 [[I_0_I_I:%.*]], -1177359834 | |
| ; CHECK-NEXT: [[CAST_SIGN:%.*]] = select i1 [[TOBOOL104_I_I_NOT]], float 0.000000e+00, float -nan(0x3FFFFB) | |
| ; CHECK-NEXT: [[FCMP:%.*]] = fcmp uno float [[CAST_SIGN]], 0.000000e+00 | |
| ; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.copysign.f32(float 0.000000e+00, float [[CAST_SIGN]]) | |
| ; CHECK-NEXT: [[TMP0:%.*]] = bitcast float [[COPYSIGN]] to i32 | |
| ; CHECK-NEXT: [[RESULT:%.*]] = select i1 [[FCMP]], i32 0, i32 [[TMP0]] | |
| ; CHECK-NEXT: ret i32 [[RESULT]] | |
| ; | |
| entry: | |
| %tobool104.i.i.not = icmp eq i32 %i.0.i.i, -1177359834 | |
| %conv111.i.i = select i1 %tobool104.i.i.not, i32 0, i32 -5 | |
| %cast.sign = bitcast i32 %conv111.i.i to float | |
| %fcmp = fcmp uno float %cast.sign, 0.000000e+00 | |
| %copysign = call float @llvm.copysign.f32(float 0.000000e+00, float %cast.sign) | |
| %select = select i1 %fcmp, float 0.000000e+00, float %copysign | |
| %result = bitcast float %select to i32 | |
| ret i32 %result | |
| } | |
| define float @copysign_simplify_demanded_bits_sign_constexpr(float %mag, float %sign) { | |
| ; CHECK-LABEL: @copysign_simplify_demanded_bits_sign_constexpr( | |
| ; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.copysign.f32(float [[MAG:%.*]], float bitcast (i32 ptrtoint (ptr @copysign_simplify_demanded_bits_sign_constexpr to i32) to float)) | |
| ; CHECK-NEXT: ret float [[RESULT]] | |
| ; | |
| %result = call float @llvm.copysign.f32(float %mag, float bitcast (i32 ptrtoint (ptr @copysign_simplify_demanded_bits_sign_constexpr to i32) to float)) | |
| ret float %result | |
| } | |
| define <2 x half> @copysign_simplify_demanded_bits_sign_cast_not_elementwise_0(<2 x half> %mag, float %sign) { | |
| ; CHECK-LABEL: @copysign_simplify_demanded_bits_sign_cast_not_elementwise_0( | |
| ; CHECK-NEXT: [[SIGN_INT:%.*]] = bitcast float [[SIGN:%.*]] to i32 | |
| ; CHECK-NEXT: [[AND_SIGN:%.*]] = and i32 [[SIGN_INT]], -2147483648 | |
| ; CHECK-NEXT: [[CAST_SIGN:%.*]] = bitcast i32 [[AND_SIGN]] to <2 x half> | |
| ; CHECK-NEXT: [[RESULT:%.*]] = call <2 x half> @llvm.copysign.v2f16(<2 x half> [[MAG:%.*]], <2 x half> [[CAST_SIGN]]) | |
| ; CHECK-NEXT: ret <2 x half> [[RESULT]] | |
| ; | |
| %sign.int = bitcast float %sign to i32 | |
| %and.sign = and i32 %sign.int, -2147483648 | |
| %cast.sign = bitcast i32 %and.sign to <2 x half> | |
| %result = call <2 x half> @llvm.copysign.v2f16(<2 x half> %mag, <2 x half> %cast.sign) | |
| ret <2 x half> %result | |
| } | |
| define float @copysign_simplify_demanded_bits_sign_not_elementwise_1(float %mag, <2 x half> %sign) { | |
| ; CHECK-LABEL: @copysign_simplify_demanded_bits_sign_not_elementwise_1( | |
| ; CHECK-NEXT: [[SIGN_INT:%.*]] = bitcast <2 x half> [[SIGN:%.*]] to <2 x i16> | |
| ; CHECK-NEXT: [[AND_SIGN:%.*]] = and <2 x i16> [[SIGN_INT]], splat (i16 -32768) | |
| ; CHECK-NEXT: [[CAST_SIGN:%.*]] = bitcast <2 x i16> [[AND_SIGN]] to float | |
| ; CHECK-NEXT: [[RESULT:%.*]] = call float @llvm.copysign.f32(float [[MAG:%.*]], float [[CAST_SIGN]]) | |
| ; CHECK-NEXT: ret float [[RESULT]] | |
| ; | |
| %sign.int = bitcast <2 x half> %sign to <2 x i16> | |
| %and.sign = and <2 x i16> %sign.int, splat (i16 -32768) | |
| %cast.sign = bitcast <2 x i16> %and.sign to float | |
| %result = call float @llvm.copysign.f32(float %mag, float %cast.sign) | |
| ret float %result | |
| } | |
| define ppc_fp128 @copysign_simplify_demanded_bits_sign_ppcfp128(ppc_fp128 %mag, ppc_fp128 %sign) { | |
| ; CHECK-LABEL: @copysign_simplify_demanded_bits_sign_ppcfp128( | |
| ; CHECK-NEXT: [[RESULT:%.*]] = call ppc_fp128 @llvm.copysign.ppcf128(ppc_fp128 [[MAG:%.*]], ppc_fp128 [[SIGN:%.*]]) | |
| ; CHECK-NEXT: ret ppc_fp128 [[RESULT]] | |
| ; | |
| %sign.int = bitcast ppc_fp128 %sign to i128 | |
| %sign.mask = shl i128 1, 127 | |
| %and.sign = and i128 %sign.int, %sign.mask | |
| %cast.sign = bitcast i128 %and.sign to ppc_fp128 | |
| %result = call ppc_fp128 @llvm.copysign.ppcfp128(ppc_fp128 %mag, ppc_fp128 %cast.sign) | |
| ret ppc_fp128 %result | |
| } | |
| define bfloat @copysign_simplify_demanded_bits_sign_bitcast_not_int(bfloat %mag, half %sign) { | |
| ; CHECK-LABEL: @copysign_simplify_demanded_bits_sign_bitcast_not_int( | |
| ; CHECK-NEXT: [[CAST_SIGN:%.*]] = bitcast half [[SIGN:%.*]] to bfloat | |
| ; CHECK-NEXT: [[RESULT:%.*]] = call bfloat @llvm.copysign.bf16(bfloat [[MAG:%.*]], bfloat [[CAST_SIGN]]) | |
| ; CHECK-NEXT: ret bfloat [[RESULT]] | |
| ; | |
| %cast.sign = bitcast half %sign to bfloat | |
| %result = call bfloat @llvm.copysign.bf16(bfloat %mag, bfloat %cast.sign) | |
| ret bfloat %result | |
| } | |
| define <2 x bfloat> @copysign_simplify_demanded_bits_sign_bitcast_not_int_vec(<2 x bfloat> %mag, <2 x half> %sign) { | |
| ; CHECK-LABEL: @copysign_simplify_demanded_bits_sign_bitcast_not_int_vec( | |
| ; CHECK-NEXT: [[CAST_SIGN:%.*]] = bitcast <2 x half> [[SIGN:%.*]] to <2 x bfloat> | |
| ; CHECK-NEXT: [[RESULT:%.*]] = call <2 x bfloat> @llvm.copysign.v2bf16(<2 x bfloat> [[MAG:%.*]], <2 x bfloat> [[CAST_SIGN]]) | |
| ; CHECK-NEXT: ret <2 x bfloat> [[RESULT]] | |
| ; | |
| %cast.sign = bitcast <2 x half> %sign to <2 x bfloat> | |
| %result = call <2 x bfloat> @llvm.copysign.v2bf16(<2 x bfloat> %mag, <2 x bfloat> %cast.sign) | |
| ret <2 x bfloat> %result | |
| } | |
| ; 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 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 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 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 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 <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 <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 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: [[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 | |
| } | |
| ; Fold applies without any FMF -- copysign's implicit fabs handles NaN. | |
| define double @copysign_floor_fabs_to_trunc_no_fmf(double %x) { | |
| ; CHECK-LABEL: @copysign_floor_fabs_to_trunc_no_fmf( | |
| ; 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 double @llvm.copysign.f64(double %fl, double %x) | |
| ret double %result | |
| } | |
| ; Fold applies when fabs wraps a sign-only op: fabs(copysign(X, Y)). | |
| define double @copysign_floor_fabs_copysign_to_trunc(double %x, double %y) { | |
| ; CHECK-LABEL: @copysign_floor_fabs_copysign_to_trunc( | |
| ; 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]] | |
| ; | |
| %cs = call double @llvm.copysign.f64(double %x, double %y) | |
| %abs = call double @llvm.fabs.f64(double %cs) | |
| %fl = call double @llvm.floor.f64(double %abs) | |
| %result = call double @llvm.copysign.f64(double %fl, double %x) | |
| ret double %result | |
| } | |
| ; Negative test: fneg(fabs(X)) is not non-negative so floor differs from trunc. | |
| define double @copysign_floor_fneg_fabs_no_fold(double %x) { | |
| ; CHECK-LABEL: @copysign_floor_fneg_fabs_no_fold( | |
| ; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]]) | |
| ; CHECK-NEXT: [[FNEG:%.*]] = fneg double [[ABS]] | |
| ; CHECK-NEXT: [[FL:%.*]] = call double @llvm.floor.f64(double [[FNEG]]) | |
| ; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.copysign.f64(double [[FL]], double [[X]]) | |
| ; CHECK-NEXT: ret double [[RESULT]] | |
| ; | |
| %abs = call double @llvm.fabs.f64(double %x) | |
| %fneg = fneg double %abs | |
| %fl = call double @llvm.floor.f64(double %fneg) | |
| %result = call double @llvm.copysign.f64(double %fl, double %x) | |
| ret double %result | |
| } | |
| ; Negative test: sign argument differs from fabs argument -- must not fold. | |
| define double @copysign_floor_fabs_no_fold_different_sign(double %x, double %y) { | |
| ; CHECK-LABEL: @copysign_floor_fabs_no_fold_different_sign( | |
| ; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[X:%.*]]) | |
| ; CHECK-NEXT: [[FL:%.*]] = call double @llvm.floor.f64(double [[ABS]]) | |
| ; CHECK-NEXT: [[RESULT:%.*]] = call double @llvm.copysign.f64(double [[FL]], double [[Y:%.*]]) | |
| ; CHECK-NEXT: ret double [[RESULT]] | |
| ; | |
| %abs = call double @llvm.fabs.f64(double %x) | |
| %fl = call double @llvm.floor.f64(double %abs) | |
| %result = call double @llvm.copysign.f64(double %fl, double %y) | |
| ret double %result | |
| } |