1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=instcombine -S | FileCheck %s 3 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 %pow 15} 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]], 0xFFF0000000000000 24; 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 %pow 29} 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 implies 34; formation of a NaN (which then propagates). `afn` may justify returning NaN (along with 35; setting EDOM); however, the conservatively correct approach is to avoid both the NaN and 36; 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 %pow 45} 46 47; (As above) the transform to (non-errno setting) sqrt is allowed as long as we deal with -0.0 48; 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> %pow 60} 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 %pow 69} 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 double 76; 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 double 81 %pow = call double @pow(double %conv, double 5.0e-01) 82 ret double %pow 83} 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 %pow 93} 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> %pow 103} 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 %pow 114} 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]], 0xFFF0000000000000 120; 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 %pow 125} 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 %pow 136} 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 %pow 145} 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 %pow 156} 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 %pow 165} 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 %pow 177} 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 %pow 192} 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 %pow 203} 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> %pow 214} 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> %pow 231} 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> %pow 248} 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 %pow 261} 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> %pow 272} 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 %pow 283} 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]], 0xFFF0000000000000 289; 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 %pow 295} 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 %pow 307} 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 %pow 317} 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 %pow 329} 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 %pow 339} 340 341declare double @llvm.pow.f64(double, double) #0 342declare float @llvm.pow.f32(float, float) #0 343declare <2 x double> @llvm.pow.v2f64(<2 x double>, <2 x double>) #0 344declare <2 x float> @llvm.pow.v2f32(<2 x float>, <2 x float>) #0 345declare <4 x float> @llvm.pow.v4f32(<4 x float>, <4 x float>) #0 346declare double @pow(double, double) 347declare float @powf(float, float) 348 349attributes #0 = { nounwind readnone speculatable } 350attributes #1 = { nounwind readnone } 351