1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -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 allowed as long as we deal with -0.0 and -INF. 7 8define double @pow_libcall_half_no_FMF(double %x) { 9; CHECK-LABEL: @pow_libcall_half_no_FMF( 10; CHECK-NEXT: [[SQRT:%.*]] = call double @sqrt(double [[X:%.*]]) 11; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[SQRT]]) 12; CHECK-NEXT: [[ISINF:%.*]] = fcmp oeq double [[X]], 0xFFF0000000000000 13; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[ISINF]], double 0x7FF0000000000000, double [[ABS]] 14; CHECK-NEXT: ret double [[TMP1]] 15; 16 %pow = call double @pow(double %x, double 5.0e-01) 17 ret double %pow 18} 19 20define double @pow_intrinsic_half_no_FMF(double %x) { 21; CHECK-LABEL: @pow_intrinsic_half_no_FMF( 22; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[X:%.*]]) 23; CHECK-NEXT: [[ABS:%.*]] = call double @llvm.fabs.f64(double [[SQRT]]) 24; CHECK-NEXT: [[ISINF:%.*]] = fcmp oeq double [[X]], 0xFFF0000000000000 25; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[ISINF]], double 0x7FF0000000000000, double [[ABS]] 26; CHECK-NEXT: ret double [[TMP1]] 27; 28 %pow = call double @llvm.pow.f64(double %x, double 5.0e-01) 29 ret double %pow 30} 31 32; This makes no difference, but FMF are propagated. 33 34define double @pow_libcall_half_approx(double %x) { 35; CHECK-LABEL: @pow_libcall_half_approx( 36; CHECK-NEXT: [[SQRT:%.*]] = call afn double @sqrt(double [[X:%.*]]) 37; CHECK-NEXT: [[ABS:%.*]] = call afn double @llvm.fabs.f64(double [[SQRT]]) 38; CHECK-NEXT: [[ISINF:%.*]] = fcmp afn oeq double [[X]], 0xFFF0000000000000 39; CHECK-NEXT: [[TMP1:%.*]] = select afn i1 [[ISINF]], double 0x7FF0000000000000, double [[ABS]] 40; CHECK-NEXT: ret double [[TMP1]] 41; 42 %pow = call afn double @pow(double %x, double 5.0e-01) 43 ret double %pow 44} 45 46define <2 x double> @pow_intrinsic_half_approx(<2 x double> %x) { 47; CHECK-LABEL: @pow_intrinsic_half_approx( 48; CHECK-NEXT: [[SQRT:%.*]] = call afn <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]]) 49; CHECK-NEXT: [[ABS:%.*]] = call afn <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]]) 50; CHECK-NEXT: [[ISINF:%.*]] = fcmp afn oeq <2 x double> [[X]], <double 0xFFF0000000000000, double 0xFFF0000000000000> 51; CHECK-NEXT: [[TMP1:%.*]] = select afn <2 x i1> [[ISINF]], <2 x double> <double 0x7FF0000000000000, double 0x7FF0000000000000>, <2 x double> [[ABS]] 52; CHECK-NEXT: ret <2 x double> [[TMP1]] 53; 54 %pow = call afn <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double 5.0e-01, double 5.0e-01>) 55 ret <2 x double> %pow 56} 57 58define float @powf_intrinsic_half_fast(float %x) { 59; CHECK-LABEL: @powf_intrinsic_half_fast( 60; CHECK-NEXT: [[SQRT:%.*]] = call fast float @llvm.sqrt.f32(float [[X:%.*]]) 61; CHECK-NEXT: ret float [[SQRT]] 62; 63 %pow = call fast float @llvm.pow.f32(float %x, float 5.0e-01) 64 ret float %pow 65} 66 67; If we can disregard INFs, no need for a select. 68 69define double @pow_libcall_half_ninf(double %x) { 70; CHECK-LABEL: @pow_libcall_half_ninf( 71; CHECK-NEXT: [[SQRT:%.*]] = call ninf double @sqrt(double [[X:%.*]]) 72; CHECK-NEXT: [[ABS:%.*]] = call ninf double @llvm.fabs.f64(double [[SQRT]]) 73; CHECK-NEXT: ret double [[ABS]] 74; 75 %pow = call ninf double @pow(double %x, double 5.0e-01) 76 ret double %pow 77} 78 79define <2 x double> @pow_intrinsic_half_ninf(<2 x double> %x) { 80; CHECK-LABEL: @pow_intrinsic_half_ninf( 81; CHECK-NEXT: [[SQRT:%.*]] = call ninf <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]]) 82; CHECK-NEXT: [[ABS:%.*]] = call ninf <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]]) 83; CHECK-NEXT: ret <2 x double> [[ABS]] 84; 85 %pow = call ninf <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double 5.0e-01, double 5.0e-01>) 86 ret <2 x double> %pow 87} 88 89; If we can disregard -0.0, no need for fabs. 90 91define double @pow_libcall_half_nsz(double %x) { 92; CHECK-LABEL: @pow_libcall_half_nsz( 93; CHECK-NEXT: [[SQRT:%.*]] = call nsz double @sqrt(double [[X:%.*]]) 94; CHECK-NEXT: [[ISINF:%.*]] = fcmp nsz oeq double [[X]], 0xFFF0000000000000 95; CHECK-NEXT: [[TMP1:%.*]] = select nsz i1 [[ISINF]], double 0x7FF0000000000000, double [[SQRT]] 96; CHECK-NEXT: ret double [[TMP1]] 97; 98 %pow = call nsz double @pow(double %x, double 5.0e-01) 99 ret double %pow 100} 101 102define double @pow_intrinsic_half_nsz(double %x) { 103; CHECK-LABEL: @pow_intrinsic_half_nsz( 104; CHECK-NEXT: [[SQRT:%.*]] = call nsz double @llvm.sqrt.f64(double [[X:%.*]]) 105; CHECK-NEXT: [[ISINF:%.*]] = fcmp nsz oeq double [[X]], 0xFFF0000000000000 106; CHECK-NEXT: [[TMP1:%.*]] = select nsz i1 [[ISINF]], double 0x7FF0000000000000, double [[SQRT]] 107; CHECK-NEXT: ret double [[TMP1]] 108; 109 %pow = call nsz double @llvm.pow.f64(double %x, double 5.0e-01) 110 ret double %pow 111} 112 113; This is just sqrt. 114 115define float @pow_libcall_half_ninf_nsz(float %x) { 116; CHECK-LABEL: @pow_libcall_half_ninf_nsz( 117; CHECK-NEXT: [[SQRTF:%.*]] = call ninf nsz float @sqrtf(float [[X:%.*]]) 118; CHECK-NEXT: ret float [[SQRTF]] 119; 120 %pow = call ninf nsz float @powf(float %x, float 5.0e-01) 121 ret float %pow 122} 123 124define double @pow_intrinsic_half_ninf_nsz(double %x) { 125; CHECK-LABEL: @pow_intrinsic_half_ninf_nsz( 126; CHECK-NEXT: [[SQRT:%.*]] = call ninf nsz double @llvm.sqrt.f64(double [[X:%.*]]) 127; CHECK-NEXT: ret double [[SQRT]] 128; 129 %pow = call ninf nsz double @llvm.pow.f64(double %x, double 5.0e-01) 130 ret double %pow 131} 132 133; Overspecified FMF to test propagation to the new op(s). 134 135define float @pow_libcall_half_fast(float %x) { 136; CHECK-LABEL: @pow_libcall_half_fast( 137; CHECK-NEXT: [[SQRTF:%.*]] = call fast float @sqrtf(float [[X:%.*]]) 138; CHECK-NEXT: ret float [[SQRTF]] 139; 140 %pow = call fast float @powf(float %x, float 5.0e-01) 141 ret float %pow 142} 143 144define double @pow_intrinsic_half_fast(double %x) { 145; CHECK-LABEL: @pow_intrinsic_half_fast( 146; CHECK-NEXT: [[SQRT:%.*]] = call fast double @llvm.sqrt.f64(double [[X:%.*]]) 147; CHECK-NEXT: ret double [[SQRT]] 148; 149 %pow = call fast double @llvm.pow.f64(double %x, double 5.0e-01) 150 ret double %pow 151} 152 153; This should not be transformed without some kind of FMF. 154; -0.5 means take the reciprocal. 155 156define float @pow_libcall_neghalf_no_FMF(float %x) { 157; CHECK-LABEL: @pow_libcall_neghalf_no_FMF( 158; CHECK-NEXT: [[POW:%.*]] = call float @powf(float [[X:%.*]], float -5.000000e-01) 159; CHECK-NEXT: ret float [[POW]] 160; 161 %pow = call float @powf(float %x, float -5.0e-01) 162 ret float %pow 163} 164 165; Transform to sqrt+fdiv because 'reassoc' allows an extra rounding step. 166; Use 'fabs' to handle -0.0 correctly. 167; Use 'select' to handle -INF correctly. 168 169define float @pow_libcall_neghalf_reassoc(float %x) { 170; CHECK-LABEL: @pow_libcall_neghalf_reassoc( 171; CHECK-NEXT: [[SQRTF:%.*]] = call reassoc float @sqrtf(float [[X:%.*]]) 172; CHECK-NEXT: [[ABS:%.*]] = call reassoc float @llvm.fabs.f32(float [[SQRTF]]) 173; CHECK-NEXT: [[ISINF:%.*]] = fcmp reassoc oeq float [[X]], 0xFFF0000000000000 174; CHECK-NEXT: [[ABS_OP:%.*]] = fdiv reassoc float 1.000000e+00, [[ABS]] 175; CHECK-NEXT: [[RECIPROCAL:%.*]] = select i1 [[ISINF]], float 0.000000e+00, float [[ABS_OP]] 176; CHECK-NEXT: ret float [[RECIPROCAL]] 177; 178 %pow = call reassoc float @powf(float %x, float -5.0e-01) 179 ret float %pow 180} 181 182; Transform to sqrt+fdiv because 'afn' allows an extra rounding step. 183; Use 'fabs' to handle -0.0 correctly. 184; Use 'select' to handle -INF correctly. 185 186define float @pow_libcall_neghalf_afn(float %x) { 187; CHECK-LABEL: @pow_libcall_neghalf_afn( 188; CHECK-NEXT: [[SQRTF:%.*]] = call afn float @sqrtf(float [[X:%.*]]) 189; CHECK-NEXT: [[ABS:%.*]] = call afn float @llvm.fabs.f32(float [[SQRTF]]) 190; CHECK-NEXT: [[ISINF:%.*]] = fcmp afn oeq float [[X]], 0xFFF0000000000000 191; CHECK-NEXT: [[ABS_OP:%.*]] = fdiv afn float 1.000000e+00, [[ABS]] 192; CHECK-NEXT: [[RECIPROCAL:%.*]] = select i1 [[ISINF]], float 0.000000e+00, float [[ABS_OP]] 193; CHECK-NEXT: ret float [[RECIPROCAL]] 194; 195 %pow = call afn float @powf(float %x, float -5.0e-01) 196 ret float %pow 197} 198 199; This should not be transformed without some kind of FMF. 200 201define <2 x double> @pow_intrinsic_neghalf_no_FMF(<2 x double> %x) { 202; CHECK-LABEL: @pow_intrinsic_neghalf_no_FMF( 203; CHECK-NEXT: [[POW:%.*]] = call <2 x double> @llvm.pow.v2f64(<2 x double> [[X:%.*]], <2 x double> <double -5.000000e-01, double -5.000000e-01>) 204; CHECK-NEXT: ret <2 x double> [[POW]] 205; 206 %pow = call <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>) 207 ret <2 x double> %pow 208} 209 210; Transform to sqrt+fdiv because 'reassoc' allows an extra rounding step. 211; Use 'fabs' to handle -0.0 correctly. 212; Use 'select' to handle -INF correctly. 213 214define <2 x double> @pow_intrinsic_neghalf_reassoc(<2 x double> %x) { 215; CHECK-LABEL: @pow_intrinsic_neghalf_reassoc( 216; CHECK-NEXT: [[SQRT:%.*]] = call reassoc <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]]) 217; CHECK-NEXT: [[ABS:%.*]] = call reassoc <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]]) 218; CHECK-NEXT: [[ISINF:%.*]] = fcmp reassoc oeq <2 x double> [[X]], <double 0xFFF0000000000000, double 0xFFF0000000000000> 219; CHECK-NEXT: [[ABS_OP:%.*]] = fdiv reassoc <2 x double> <double 1.000000e+00, double 1.000000e+00>, [[ABS]] 220; CHECK-NEXT: [[RECIPROCAL:%.*]] = select <2 x i1> [[ISINF]], <2 x double> zeroinitializer, <2 x double> [[ABS_OP]] 221; CHECK-NEXT: ret <2 x double> [[RECIPROCAL]] 222; 223 %pow = call reassoc <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>) 224 ret <2 x double> %pow 225} 226 227; Transform to sqrt+fdiv because 'afn' allows an extra rounding step. 228; Use 'fabs' to handle -0.0 correctly. 229; Use 'select' to handle -INF correctly. 230 231define <2 x double> @pow_intrinsic_neghalf_afn(<2 x double> %x) { 232; CHECK-LABEL: @pow_intrinsic_neghalf_afn( 233; CHECK-NEXT: [[SQRT:%.*]] = call afn <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]]) 234; CHECK-NEXT: [[ABS:%.*]] = call afn <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]]) 235; CHECK-NEXT: [[ISINF:%.*]] = fcmp afn oeq <2 x double> [[X]], <double 0xFFF0000000000000, double 0xFFF0000000000000> 236; CHECK-NEXT: [[ABS_OP:%.*]] = fdiv afn <2 x double> <double 1.000000e+00, double 1.000000e+00>, [[ABS]] 237; CHECK-NEXT: [[RECIPROCAL:%.*]] = select <2 x i1> [[ISINF]], <2 x double> zeroinitializer, <2 x double> [[ABS_OP]] 238; CHECK-NEXT: ret <2 x double> [[RECIPROCAL]] 239; 240 %pow = call afn <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double -5.0e-01, double -5.0e-01>) 241 ret <2 x double> %pow 242} 243 244; If we can disregard INFs, no need for a select. 245 246define double @pow_libcall_neghalf_ninf(double %x) { 247; CHECK-LABEL: @pow_libcall_neghalf_ninf( 248; CHECK-NEXT: [[SQRT:%.*]] = call ninf afn double @sqrt(double [[X:%.*]]) 249; CHECK-NEXT: [[ABS:%.*]] = call ninf afn double @llvm.fabs.f64(double [[SQRT]]) 250; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv ninf afn double 1.000000e+00, [[ABS]] 251; CHECK-NEXT: ret double [[RECIPROCAL]] 252; 253 %pow = call afn ninf double @pow(double %x, double -5.0e-01) 254 ret double %pow 255} 256 257define <2 x double> @pow_intrinsic_neghalf_ninf(<2 x double> %x) { 258; CHECK-LABEL: @pow_intrinsic_neghalf_ninf( 259; CHECK-NEXT: [[SQRT:%.*]] = call ninf afn <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]]) 260; CHECK-NEXT: [[ABS:%.*]] = call ninf afn <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]]) 261; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv ninf afn <2 x double> <double 1.000000e+00, double 1.000000e+00>, [[ABS]] 262; CHECK-NEXT: ret <2 x double> [[RECIPROCAL]] 263; 264 %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>) 265 ret <2 x double> %pow 266} 267 268; If we can disregard -0.0, no need for fabs. 269 270define double @pow_libcall_neghalf_nsz(double %x) { 271; CHECK-LABEL: @pow_libcall_neghalf_nsz( 272; CHECK-NEXT: [[SQRT:%.*]] = call nsz afn double @sqrt(double [[X:%.*]]) 273; CHECK-NEXT: [[ISINF:%.*]] = fcmp nsz afn oeq double [[X]], 0xFFF0000000000000 274; CHECK-NEXT: [[SQRT_OP:%.*]] = fdiv nsz afn double 1.000000e+00, [[SQRT]] 275; CHECK-NEXT: [[RECIPROCAL:%.*]] = select i1 [[ISINF]], double 0.000000e+00, double [[SQRT_OP]] 276; CHECK-NEXT: ret double [[RECIPROCAL]] 277; 278 %pow = call afn nsz double @pow(double %x, double -5.0e-01) 279 ret double %pow 280} 281 282define double @pow_intrinsic_neghalf_nsz(double %x) { 283; CHECK-LABEL: @pow_intrinsic_neghalf_nsz( 284; CHECK-NEXT: [[SQRT:%.*]] = call nsz afn double @llvm.sqrt.f64(double [[X:%.*]]) 285; CHECK-NEXT: [[ISINF:%.*]] = fcmp nsz afn oeq double [[X]], 0xFFF0000000000000 286; CHECK-NEXT: [[SQRT_OP:%.*]] = fdiv nsz afn double 1.000000e+00, [[SQRT]] 287; CHECK-NEXT: [[RECIPROCAL:%.*]] = select i1 [[ISINF]], double 0.000000e+00, double [[SQRT_OP]] 288; CHECK-NEXT: ret double [[RECIPROCAL]] 289; 290 %pow = call afn nsz double @llvm.pow.f64(double %x, double -5.0e-01) 291 ret double %pow 292} 293 294; This is just recip-sqrt. 295 296define double @pow_intrinsic_neghalf_ninf_nsz(double %x) { 297; CHECK-LABEL: @pow_intrinsic_neghalf_ninf_nsz( 298; CHECK-NEXT: [[SQRT:%.*]] = call ninf nsz afn double @llvm.sqrt.f64(double [[X:%.*]]) 299; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv ninf nsz afn double 1.000000e+00, [[SQRT]] 300; CHECK-NEXT: ret double [[RECIPROCAL]] 301; 302 %pow = call afn ninf nsz double @llvm.pow.f64(double %x, double -5.0e-01) 303 ret double %pow 304} 305 306define float @pow_libcall_neghalf_ninf_nsz(float %x) { 307; CHECK-LABEL: @pow_libcall_neghalf_ninf_nsz( 308; CHECK-NEXT: [[SQRTF:%.*]] = call ninf nsz afn float @sqrtf(float [[X:%.*]]) 309; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv ninf nsz afn float 1.000000e+00, [[SQRTF]] 310; CHECK-NEXT: ret float [[RECIPROCAL]] 311; 312 %pow = call afn ninf nsz float @powf(float %x, float -5.0e-01) 313 ret float %pow 314} 315 316; Overspecified FMF to test propagation to the new op(s). 317 318define float @pow_libcall_neghalf_fast(float %x) { 319; CHECK-LABEL: @pow_libcall_neghalf_fast( 320; CHECK-NEXT: [[SQRTF:%.*]] = call fast float @sqrtf(float [[X:%.*]]) 321; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv fast float 1.000000e+00, [[SQRTF]] 322; CHECK-NEXT: ret float [[RECIPROCAL]] 323; 324 %pow = call fast float @powf(float %x, float -5.0e-01) 325 ret float %pow 326} 327 328define double @pow_intrinsic_neghalf_fast(double %x) { 329; CHECK-LABEL: @pow_intrinsic_neghalf_fast( 330; CHECK-NEXT: [[SQRT:%.*]] = call fast double @llvm.sqrt.f64(double [[X:%.*]]) 331; CHECK-NEXT: [[RECIPROCAL:%.*]] = fdiv fast double 1.000000e+00, [[SQRT]] 332; CHECK-NEXT: ret double [[RECIPROCAL]] 333; 334 %pow = call fast double @llvm.pow.f64(double %x, double -5.0e-01) 335 ret double %pow 336} 337 338declare double @llvm.pow.f64(double, double) #0 339declare float @llvm.pow.f32(float, float) #0 340declare <2 x double> @llvm.pow.v2f64(<2 x double>, <2 x double>) #0 341declare <2 x float> @llvm.pow.v2f32(<2 x float>, <2 x float>) #0 342declare <4 x float> @llvm.pow.v4f32(<4 x float>, <4 x float>) #0 343declare double @pow(double, double) 344declare float @powf(float, float) 345 346attributes #0 = { nounwind readnone speculatable } 347attributes #1 = { nounwind readnone } 348