351 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py2; RUN: opt < %s -passes=instcombine -S | FileCheck %s3 4; Check the libcall and the intrinsic for each case with differing FMF.5 6; The transform to sqrt is not allowed if we risk setting errno due to -INF.7 8define double @pow_libcall_half_no_FMF(double %x) {9; CHECK-LABEL: @pow_libcall_half_no_FMF(10; CHECK-NEXT: [[POW:%.*]] = call double @pow(double [[X:%.*]], double 5.000000e-01)11; CHECK-NEXT: ret double [[POW]]12;13 %pow = call double @pow(double %x, double 5.0e-01)14 ret double %pow15}16 17; The transform to (non-errno setting) sqrt is allowed as long as we deal with -0.0 and -INF.18 19define double @pow_intrinsic_half_no_FMF(double %x) {20; CHECK-LABEL: @pow_intrinsic_half_no_FMF(21; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[X:%.*]])22; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[SQRT]])23; CHECK-NEXT: [[ISINF:%.*]] = fcmp oeq double [[X]], 0xFFF000000000000024; CHECK-NEXT: [[POW:%.*]] = select i1 [[ISINF]], double 0x7FF0000000000000, double [[ABS]]25; CHECK-NEXT: ret double [[POW]]26;27 %pow = call double @llvm.pow.f64(double %x, double 5.0e-01)28 ret double %pow29}30 31; `afn` makes no difference, but FMF are propagated/retained.32 33; (As above) the transform to sqrt may generate EDOM due to -INF. Generally, EDOM implies34; formation of a NaN (which then propagates). `afn` may justify returning NaN (along with35; setting EDOM); however, the conservatively correct approach is to avoid both the NaN and36; the EDOM.37 38define double @pow_libcall_half_approx(double %x) {39; CHECK-LABEL: @pow_libcall_half_approx(40; CHECK-NEXT: [[POW:%.*]] = call afn double @pow(double [[X:%.*]], double 5.000000e-01)41; CHECK-NEXT: ret double [[POW]]42;43 %pow = call afn double @pow(double %x, double 5.0e-01)44 ret double %pow45}46 47; (As above) the transform to (non-errno setting) sqrt is allowed as long as we deal with -0.048; and -INF.49 50define <2 x double> @pow_intrinsic_half_approx(<2 x double> %x) {51; CHECK-LABEL: @pow_intrinsic_half_approx(52; CHECK-NEXT: [[SQRT:%.*]] = call afn <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])53; CHECK-NEXT: [[ABS:%.*]] = call afn <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])54; CHECK-NEXT: [[ISINF:%.*]] = fcmp afn oeq <2 x double> [[X]], splat (double 0xFFF0000000000000)55; CHECK-NEXT: [[POW:%.*]] = select afn <2 x i1> [[ISINF]], <2 x double> splat (double 0x7FF0000000000000), <2 x double> [[ABS]]56; CHECK-NEXT: ret <2 x double> [[POW]]57;58 %pow = call afn <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double 5.0e-01, double 5.0e-01>)59 ret <2 x double> %pow60}61 62define float @powf_intrinsic_half_fast(float %x) {63; CHECK-LABEL: @powf_intrinsic_half_fast(64; CHECK-NEXT: [[SQRT:%.*]] = call fast float @llvm.sqrt.f32(float [[X:%.*]])65; CHECK-NEXT: ret float [[SQRT]]66;67 %pow = call fast float @llvm.pow.f32(float %x, float 5.0e-01)68 ret float %pow69}70 71; If we can disregard INFs, no need for a select.72 73define double @pow_libcall_half_no_FMF_base_ninf(i32 %x) {74; CHECK-LABEL: @pow_libcall_half_no_FMF_base_ninf(75; CHECK-NEXT: [[CONV:%.*]] = uitofp i32 [[X:%.*]] to double76; CHECK-NEXT: [[SQRT:%.*]] = call double @sqrt(double [[CONV]])77; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[SQRT]])78; CHECK-NEXT: ret double [[ABS]]79;80 %conv = uitofp i32 %x to double81 %pow = call double @pow(double %conv, double 5.0e-01)82 ret double %pow83}84 85define double @pow_libcall_half_ninf(double %x) {86; CHECK-LABEL: @pow_libcall_half_ninf(87; CHECK-NEXT: [[SQRT:%.*]] = call ninf double @sqrt(double [[X:%.*]])88; CHECK-NEXT: [[ABS:%.*]] = call ninf double @llvm.fabs.f64(double [[SQRT]])89; CHECK-NEXT: ret double [[ABS]]90;91 %pow = call ninf double @pow(double %x, double 5.0e-01)92 ret double %pow93}94 95define <2 x double> @pow_intrinsic_half_ninf(<2 x double> %x) {96; CHECK-LABEL: @pow_intrinsic_half_ninf(97; CHECK-NEXT: [[SQRT:%.*]] = call ninf <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])98; CHECK-NEXT: [[ABS:%.*]] = call ninf <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])99; CHECK-NEXT: ret <2 x double> [[ABS]]100;101 %pow = call ninf <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double 5.0e-01, double 5.0e-01>)102 ret <2 x double> %pow103}104 105; If we can disregard -0.0, no need for fabs, but still (because of -INF) cannot use library sqrt.106 107define double @pow_libcall_half_nsz(double %x) {108; CHECK-LABEL: @pow_libcall_half_nsz(109; CHECK-NEXT: [[POW:%.*]] = call nsz double @pow(double [[X:%.*]], double 5.000000e-01)110; CHECK-NEXT: ret double [[POW]]111;112 %pow = call nsz double @pow(double %x, double 5.0e-01)113 ret double %pow114}115 116define double @pow_intrinsic_half_nsz(double %x) {117; CHECK-LABEL: @pow_intrinsic_half_nsz(118; CHECK-NEXT: [[SQRT:%.*]] = call nsz double @llvm.sqrt.f64(double [[X:%.*]])119; CHECK-NEXT: [[ISINF:%.*]] = fcmp nsz oeq double [[X]], 0xFFF0000000000000120; CHECK-NEXT: [[POW:%.*]] = select nsz i1 [[ISINF]], double 0x7FF0000000000000, double [[SQRT]]121; CHECK-NEXT: ret double [[POW]]122;123 %pow = call nsz double @llvm.pow.f64(double %x, double 5.0e-01)124 ret double %pow125}126 127; This is just sqrt.128 129define float @pow_libcall_half_ninf_nsz(float %x) {130; CHECK-LABEL: @pow_libcall_half_ninf_nsz(131; CHECK-NEXT: [[SQRTF:%.*]] = call ninf nsz float @sqrtf(float [[X:%.*]])132; CHECK-NEXT: ret float [[SQRTF]]133;134 %pow = call ninf nsz float @powf(float %x, float 5.0e-01)135 ret float %pow136}137 138define double @pow_intrinsic_half_ninf_nsz(double %x) {139; CHECK-LABEL: @pow_intrinsic_half_ninf_nsz(140; CHECK-NEXT: [[SQRT:%.*]] = call ninf nsz double @llvm.sqrt.f64(double [[X:%.*]])141; CHECK-NEXT: ret double [[SQRT]]142;143 %pow = call ninf nsz double @llvm.pow.f64(double %x, double 5.0e-01)144 ret double %pow145}146 147; Overspecified FMF to test propagation to the new op(s).148 149define float @pow_libcall_half_fast(float %x) {150; CHECK-LABEL: @pow_libcall_half_fast(151; CHECK-NEXT: [[SQRTF:%.*]] = call fast float @sqrtf(float [[X:%.*]])152; CHECK-NEXT: ret float [[SQRTF]]153;154 %pow = call fast float @powf(float %x, float 5.0e-01)155 ret float %pow156}157 158define double @pow_intrinsic_half_fast(double %x) {159; CHECK-LABEL: @pow_intrinsic_half_fast(160; CHECK-NEXT: [[SQRT:%.*]] = call fast double @llvm.sqrt.f64(double [[X:%.*]])161; CHECK-NEXT: ret double [[SQRT]]162;163 %pow = call fast double @llvm.pow.f64(double %x, double 5.0e-01)164 ret double %pow165}166 167; This should not be transformed without some kind of FMF.168; -0.5 means take the reciprocal.169 170define float @pow_libcall_neghalf_no_FMF(float %x) {171; CHECK-LABEL: @pow_libcall_neghalf_no_FMF(172; CHECK-NEXT: [[POW:%.*]] = call float @powf(float [[X:%.*]], float -5.000000e-01)173; CHECK-NEXT: ret float [[POW]]174;175 %pow = call float @powf(float %x, float -5.0e-01)176 ret float %pow177}178 179; If we can disregard INFs, a call to a library sqrt is okay.180; Transform to sqrt+fdiv because 'reassoc' allows an extra rounding step.181; Use 'fabs' to handle -0.0 correctly.182 183define float @pow_libcall_neghalf_reassoc_ninf(float %x) {184; CHECK-LABEL: @pow_libcall_neghalf_reassoc_ninf(185; CHECK-NEXT: [[SQRTF:%.*]] = call reassoc ninf float @sqrtf(float [[X:%.*]])186; CHECK-NEXT: [[ABS:%.*]] = call reassoc ninf float @llvm.fabs.f32(float [[SQRTF]])187; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv reassoc ninf float 1.000000e+00, [[ABS]]188; CHECK-NEXT: ret float [[RECIPROCAL]]189;190 %pow = call reassoc ninf float @powf(float %x, float -5.0e-01)191 ret float %pow192}193 194; If we cannot disregard INFs, a call to a library sqrt is not okay.195 196define float @pow_libcall_neghalf_afn(float %x) {197; CHECK-LABEL: @pow_libcall_neghalf_afn(198; CHECK-NEXT: [[POW:%.*]] = call afn float @powf(float [[X:%.*]], float -5.000000e-01)199; CHECK-NEXT: ret float [[POW]]200;201 %pow = call afn float @powf(float %x, float -5.0e-01)202 ret float %pow203}204 205; This should not be transformed without some kind of FMF.206 207define <2 x double> @pow_intrinsic_neghalf_no_FMF(<2 x double> %x) {208; CHECK-LABEL: @pow_intrinsic_neghalf_no_FMF(209; CHECK-NEXT: [[POW:%.*]] = call <2 x double> @llvm.pow.v2f64(<2 x double> [[X:%.*]], <2 x double> splat (double -5.000000e-01))210; CHECK-NEXT: ret <2 x double> [[POW]]211;212 %pow = call <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>)213 ret <2 x double> %pow214}215 216; Transform to sqrt+fdiv because 'reassoc' allows an extra rounding step.217; Use 'fabs' to handle -0.0 correctly.218; Use 'select' to handle -INF correctly.219 220define <2 x double> @pow_intrinsic_neghalf_reassoc(<2 x double> %x) {221; CHECK-LABEL: @pow_intrinsic_neghalf_reassoc(222; CHECK-NEXT: [[SQRT:%.*]] = call reassoc <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])223; CHECK-NEXT: [[ABS:%.*]] = call reassoc <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])224; CHECK-NEXT: [[ISINF:%.*]] = fcmp reassoc oeq <2 x double> [[X]], splat (double 0xFFF0000000000000)225; CHECK-NEXT: [[TMP1:%.*]] = fdiv reassoc <2 x double> splat (double 1.000000e+00), [[ABS]]226; CHECK-NEXT: [[RECIPROCAL:%.*]] = select <2 x i1> [[ISINF]], <2 x double> zeroinitializer, <2 x double> [[TMP1]]227; CHECK-NEXT: ret <2 x double> [[RECIPROCAL]]228;229 %pow = call reassoc <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>)230 ret <2 x double> %pow231}232 233; Transform to sqrt+fdiv because 'afn' allows an extra rounding step.234; Use 'fabs' to handle -0.0 correctly.235; Use 'select' to handle -INF correctly.236 237define <2 x double> @pow_intrinsic_neghalf_afn(<2 x double> %x) {238; CHECK-LABEL: @pow_intrinsic_neghalf_afn(239; CHECK-NEXT: [[SQRT:%.*]] = call afn <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])240; CHECK-NEXT: [[ABS:%.*]] = call afn <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])241; CHECK-NEXT: [[ISINF:%.*]] = fcmp afn oeq <2 x double> [[X]], splat (double 0xFFF0000000000000)242; CHECK-NEXT: [[TMP1:%.*]] = fdiv afn <2 x double> splat (double 1.000000e+00), [[ABS]]243; CHECK-NEXT: [[RECIPROCAL:%.*]] = select <2 x i1> [[ISINF]], <2 x double> zeroinitializer, <2 x double> [[TMP1]]244; CHECK-NEXT: ret <2 x double> [[RECIPROCAL]]245;246 %pow = call afn <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>)247 ret <2 x double> %pow248}249 250; If we can disregard INFs, no need for a select.251 252define double @pow_libcall_neghalf_ninf(double %x) {253; CHECK-LABEL: @pow_libcall_neghalf_ninf(254; CHECK-NEXT: [[SQRT:%.*]] = call ninf afn double @sqrt(double [[X:%.*]])255; CHECK-NEXT: [[ABS:%.*]] = call ninf afn double @llvm.fabs.f64(double [[SQRT]])256; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv ninf afn double 1.000000e+00, [[ABS]]257; CHECK-NEXT: ret double [[RECIPROCAL]]258;259 %pow = call afn ninf double @pow(double %x, double -5.0e-01)260 ret double %pow261}262 263define <2 x double> @pow_intrinsic_neghalf_ninf(<2 x double> %x) {264; CHECK-LABEL: @pow_intrinsic_neghalf_ninf(265; CHECK-NEXT: [[SQRT:%.*]] = call ninf afn <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])266; CHECK-NEXT: [[ABS:%.*]] = call ninf afn <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])267; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv ninf afn <2 x double> splat (double 1.000000e+00), [[ABS]]268; CHECK-NEXT: ret <2 x double> [[RECIPROCAL]]269;270 %pow = call afn ninf <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>)271 ret <2 x double> %pow272}273 274; If we can disregard -0.0, no need for fabs, but still (because of -INF) cannot use library sqrt.275 276define double @pow_libcall_neghalf_nsz(double %x) {277; CHECK-LABEL: @pow_libcall_neghalf_nsz(278; CHECK-NEXT: [[POW:%.*]] = call nsz afn double @pow(double [[X:%.*]], double -5.000000e-01)279; CHECK-NEXT: ret double [[POW]]280;281 %pow = call afn nsz double @pow(double %x, double -5.0e-01)282 ret double %pow283}284 285define double @pow_intrinsic_neghalf_nsz(double %x) {286; CHECK-LABEL: @pow_intrinsic_neghalf_nsz(287; CHECK-NEXT: [[SQRT:%.*]] = call nsz afn double @llvm.sqrt.f64(double [[X:%.*]])288; CHECK-NEXT: [[ISINF:%.*]] = fcmp nsz afn oeq double [[X]], 0xFFF0000000000000289; CHECK-NEXT: [[TMP1:%.*]] = fdiv nsz afn double 1.000000e+00, [[SQRT]]290; CHECK-NEXT: [[RECIPROCAL:%.*]] = select i1 [[ISINF]], double 0.000000e+00, double [[TMP1]]291; CHECK-NEXT: ret double [[RECIPROCAL]]292;293 %pow = call afn nsz double @llvm.pow.f64(double %x, double -5.0e-01)294 ret double %pow295}296 297; This is just recip-sqrt.298 299define double @pow_intrinsic_neghalf_ninf_nsz(double %x) {300; CHECK-LABEL: @pow_intrinsic_neghalf_ninf_nsz(301; CHECK-NEXT: [[SQRT:%.*]] = call ninf nsz afn double @llvm.sqrt.f64(double [[X:%.*]])302; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv ninf nsz afn double 1.000000e+00, [[SQRT]]303; CHECK-NEXT: ret double [[RECIPROCAL]]304;305 %pow = call afn ninf nsz double @llvm.pow.f64(double %x, double -5.0e-01)306 ret double %pow307}308 309define float @pow_libcall_neghalf_ninf_nsz(float %x) {310; CHECK-LABEL: @pow_libcall_neghalf_ninf_nsz(311; CHECK-NEXT: [[SQRTF:%.*]] = call ninf nsz afn float @sqrtf(float [[X:%.*]])312; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv ninf nsz afn float 1.000000e+00, [[SQRTF]]313; CHECK-NEXT: ret float [[RECIPROCAL]]314;315 %pow = call afn ninf nsz float @powf(float %x, float -5.0e-01)316 ret float %pow317}318 319; Overspecified FMF to test propagation to the new op(s).320 321define float @pow_libcall_neghalf_fast(float %x) {322; CHECK-LABEL: @pow_libcall_neghalf_fast(323; CHECK-NEXT: [[SQRTF:%.*]] = call fast float @sqrtf(float [[X:%.*]])324; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv fast float 1.000000e+00, [[SQRTF]]325; CHECK-NEXT: ret float [[RECIPROCAL]]326;327 %pow = call fast float @powf(float %x, float -5.0e-01)328 ret float %pow329}330 331define double @pow_intrinsic_neghalf_fast(double %x) {332; CHECK-LABEL: @pow_intrinsic_neghalf_fast(333; CHECK-NEXT: [[SQRT:%.*]] = call fast double @llvm.sqrt.f64(double [[X:%.*]])334; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv fast double 1.000000e+00, [[SQRT]]335; CHECK-NEXT: ret double [[RECIPROCAL]]336;337 %pow = call fast double @llvm.pow.f64(double %x, double -5.0e-01)338 ret double %pow339}340 341declare double @llvm.pow.f64(double, double) #0342declare float @llvm.pow.f32(float, float) #0343declare <2 x double> @llvm.pow.v2f64(<2 x double>, <2 x double>) #0344declare <2 x float> @llvm.pow.v2f32(<2 x float>, <2 x float>) #0345declare <4 x float> @llvm.pow.v4f32(<4 x float>, <4 x float>) #0346declare double @pow(double, double)347declare float @powf(float, float)348 349attributes #0 = { nounwind readnone speculatable }350attributes #1 = { nounwind readnone }351