1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -instcombine < %s | FileCheck %s 3 4; (-0.0 - X) * C => X * -C 5define float @neg_constant(float %x) { 6; CHECK-LABEL: @neg_constant( 7; CHECK-NEXT: [[MUL:%.*]] = fmul ninf float [[X:%.*]], -2.000000e+01 8; CHECK-NEXT: ret float [[MUL]] 9; 10 %sub = fsub float -0.0, %x 11 %mul = fmul ninf float %sub, 2.0e+1 12 ret float %mul 13} 14 15define <2 x float> @neg_constant_vec(<2 x float> %x) { 16; CHECK-LABEL: @neg_constant_vec( 17; CHECK-NEXT: [[MUL:%.*]] = fmul ninf <2 x float> [[X:%.*]], <float -2.000000e+00, float -3.000000e+00> 18; CHECK-NEXT: ret <2 x float> [[MUL]] 19; 20 %sub = fsub <2 x float> <float -0.0, float -0.0>, %x 21 %mul = fmul ninf <2 x float> %sub, <float 2.0, float 3.0> 22 ret <2 x float> %mul 23} 24 25define <2 x float> @neg_constant_vec_undef(<2 x float> %x) { 26; CHECK-LABEL: @neg_constant_vec_undef( 27; CHECK-NEXT: [[MUL:%.*]] = fmul ninf <2 x float> [[X:%.*]], <float -2.000000e+00, float -3.000000e+00> 28; CHECK-NEXT: ret <2 x float> [[MUL]] 29; 30 %sub = fsub <2 x float> <float undef, float -0.0>, %x 31 %mul = fmul ninf <2 x float> %sub, <float 2.0, float 3.0> 32 ret <2 x float> %mul 33} 34 35; (0.0 - X) * C => X * -C 36define float @neg_nsz_constant(float %x) { 37; CHECK-LABEL: @neg_nsz_constant( 38; CHECK-NEXT: [[MUL:%.*]] = fmul nnan float [[X:%.*]], -2.000000e+01 39; CHECK-NEXT: ret float [[MUL]] 40; 41 %sub = fsub nsz float 0.0, %x 42 %mul = fmul nnan float %sub, 2.0e+1 43 ret float %mul 44} 45 46; (-0.0 - X) * (-0.0 - Y) => X * Y 47define float @neg_neg(float %x, float %y) { 48; CHECK-LABEL: @neg_neg( 49; CHECK-NEXT: [[MUL:%.*]] = fmul arcp float [[X:%.*]], [[Y:%.*]] 50; CHECK-NEXT: ret float [[MUL]] 51; 52 %sub1 = fsub float -0.0, %x 53 %sub2 = fsub float -0.0, %y 54 %mul = fmul arcp float %sub1, %sub2 55 ret float %mul 56} 57 58define <2 x float> @neg_neg_vec(<2 x float> %x, <2 x float> %y) { 59; CHECK-LABEL: @neg_neg_vec( 60; CHECK-NEXT: [[MUL:%.*]] = fmul arcp <2 x float> [[X:%.*]], [[Y:%.*]] 61; CHECK-NEXT: ret <2 x float> [[MUL]] 62; 63 %sub1 = fsub <2 x float> <float -0.0, float -0.0>, %x 64 %sub2 = fsub <2 x float> <float -0.0, float -0.0>, %y 65 %mul = fmul arcp <2 x float> %sub1, %sub2 66 ret <2 x float> %mul 67} 68 69define <2 x float> @neg_neg_vec_undef(<2 x float> %x, <2 x float> %y) { 70; CHECK-LABEL: @neg_neg_vec_undef( 71; CHECK-NEXT: [[MUL:%.*]] = fmul arcp <2 x float> [[X:%.*]], [[Y:%.*]] 72; CHECK-NEXT: ret <2 x float> [[MUL]] 73; 74 %sub1 = fsub <2 x float> <float -0.0, float undef>, %x 75 %sub2 = fsub <2 x float> <float undef, float -0.0>, %y 76 %mul = fmul arcp <2 x float> %sub1, %sub2 77 ret <2 x float> %mul 78} 79 80; (0.0 - X) * (0.0 - Y) => X * Y 81define float @neg_neg_nsz(float %x, float %y) { 82; CHECK-LABEL: @neg_neg_nsz( 83; CHECK-NEXT: [[MUL:%.*]] = fmul afn float [[X:%.*]], [[Y:%.*]] 84; CHECK-NEXT: ret float [[MUL]] 85; 86 %sub1 = fsub nsz float 0.0, %x 87 %sub2 = fsub nsz float 0.0, %y 88 %mul = fmul afn float %sub1, %sub2 89 ret float %mul 90} 91 92declare void @use_f32(float) 93 94define float @neg_neg_multi_use(float %x, float %y) { 95; CHECK-LABEL: @neg_neg_multi_use( 96; CHECK-NEXT: [[NX:%.*]] = fsub float -0.000000e+00, [[X:%.*]] 97; CHECK-NEXT: [[NY:%.*]] = fsub float -0.000000e+00, [[Y:%.*]] 98; CHECK-NEXT: [[MUL:%.*]] = fmul afn float [[X]], [[Y]] 99; CHECK-NEXT: call void @use_f32(float [[NX]]) 100; CHECK-NEXT: call void @use_f32(float [[NY]]) 101; CHECK-NEXT: ret float [[MUL]] 102; 103 %nx = fsub float -0.0, %x 104 %ny = fsub float -0.0, %y 105 %mul = fmul afn float %nx, %ny 106 call void @use_f32(float %nx) 107 call void @use_f32(float %ny) 108 ret float %mul 109} 110 111; (-0.0 - X) * Y => -0.0 - (X * Y) 112define float @neg_sink(float %x, float %y) { 113; CHECK-LABEL: @neg_sink( 114; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X:%.*]], [[Y:%.*]] 115; CHECK-NEXT: [[MUL:%.*]] = fsub float -0.000000e+00, [[TMP1]] 116; CHECK-NEXT: ret float [[MUL]] 117; 118 %sub = fsub float -0.0, %x 119 %mul = fmul float %sub, %y 120 ret float %mul 121} 122 123define <2 x float> @neg_sink_vec(<2 x float> %x, <2 x float> %y) { 124; CHECK-LABEL: @neg_sink_vec( 125; CHECK-NEXT: [[TMP1:%.*]] = fmul <2 x float> [[X:%.*]], [[Y:%.*]] 126; CHECK-NEXT: [[MUL:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]] 127; CHECK-NEXT: ret <2 x float> [[MUL]] 128; 129 %sub = fsub <2 x float> <float -0.0, float -0.0>, %x 130 %mul = fmul <2 x float> %sub, %y 131 ret <2 x float> %mul 132} 133 134define <2 x float> @neg_sink_vec_undef(<2 x float> %x, <2 x float> %y) { 135; CHECK-LABEL: @neg_sink_vec_undef( 136; CHECK-NEXT: [[TMP1:%.*]] = fmul <2 x float> [[X:%.*]], [[Y:%.*]] 137; CHECK-NEXT: [[MUL:%.*]] = fsub <2 x float> <float -0.000000e+00, float -0.000000e+00>, [[TMP1]] 138; CHECK-NEXT: ret <2 x float> [[MUL]] 139; 140 %sub = fsub <2 x float> <float undef, float -0.0>, %x 141 %mul = fmul <2 x float> %sub, %y 142 ret <2 x float> %mul 143} 144 145; (0.0 - X) * Y => 0.0 - (X * Y) 146define float @neg_sink_nsz(float %x, float %y) { 147; CHECK-LABEL: @neg_sink_nsz( 148; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X:%.*]], [[Y:%.*]] 149; CHECK-NEXT: [[MUL:%.*]] = fsub float -0.000000e+00, [[TMP1]] 150; CHECK-NEXT: ret float [[MUL]] 151; 152 %sub1 = fsub nsz float 0.0, %x 153 %mul = fmul float %sub1, %y 154 ret float %mul 155} 156 157; "(-0.0 - X) * Y => -0.0 - (X * Y)" is disabled if expression "-0.0 - X" 158; has multiple uses. 159define float @neg_sink_multi_use(float %x, float %y) { 160; CHECK-LABEL: @neg_sink_multi_use( 161; CHECK-NEXT: [[SUB1:%.*]] = fsub float -0.000000e+00, [[X:%.*]] 162; CHECK-NEXT: [[MUL:%.*]] = fmul float [[SUB1]], [[Y:%.*]] 163; CHECK-NEXT: [[MUL2:%.*]] = fmul float [[MUL]], [[SUB1]] 164; CHECK-NEXT: ret float [[MUL2]] 165; 166 %sub1 = fsub float -0.0, %x 167 %mul = fmul float %sub1, %y 168 %mul2 = fmul float %mul, %sub1 169 ret float %mul2 170} 171 172; Don't crash when attempting to cast a constant FMul to an instruction. 173define void @test8(i32* %inout) { 174; CHECK-LABEL: @test8( 175; CHECK-NEXT: entry: 176; CHECK-NEXT: br label [[FOR_COND:%.*]] 177; CHECK: for.cond: 178; CHECK-NEXT: [[LOCAL_VAR_7_0:%.*]] = phi <4 x float> [ <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[ENTRY:%.*]] ], [ [[TMP0:%.*]], [[FOR_BODY:%.*]] ] 179; CHECK-NEXT: br i1 undef, label [[FOR_BODY]], label [[FOR_END:%.*]] 180; CHECK: for.body: 181; CHECK-NEXT: [[TMP0]] = insertelement <4 x float> [[LOCAL_VAR_7_0]], float 0.000000e+00, i32 2 182; CHECK-NEXT: br label [[FOR_COND]] 183; CHECK: for.end: 184; CHECK-NEXT: ret void 185; 186entry: 187 %0 = load i32, i32* %inout, align 4 188 %conv = uitofp i32 %0 to float 189 %vecinit = insertelement <4 x float> <float 0.000000e+00, float 0.000000e+00, float 0.000000e+00, float undef>, float %conv, i32 3 190 %sub = fsub <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, %vecinit 191 %1 = shufflevector <4 x float> %sub, <4 x float> undef, <4 x i32> <i32 1, i32 1, i32 1, i32 1> 192 %mul = fmul <4 x float> zeroinitializer, %1 193 br label %for.cond 194 195for.cond: ; preds = %for.body, %entry 196 %local_var_7.0 = phi <4 x float> [ %mul, %entry ], [ %2, %for.body ] 197 br i1 undef, label %for.body, label %for.end 198 199for.body: ; preds = %for.cond 200 %2 = insertelement <4 x float> %local_var_7.0, float 0.000000e+00, i32 2 201 br label %for.cond 202 203for.end: ; preds = %for.cond 204 ret void 205} 206 207; X * -1.0 => -0.0 - X 208define float @test9(float %x) { 209; CHECK-LABEL: @test9( 210; CHECK-NEXT: [[MUL:%.*]] = fsub float -0.000000e+00, [[X:%.*]] 211; CHECK-NEXT: ret float [[MUL]] 212; 213 %mul = fmul float %x, -1.0 214 ret float %mul 215} 216 217; PR18532 218define <4 x float> @test10(<4 x float> %x) { 219; CHECK-LABEL: @test10( 220; CHECK-NEXT: [[MUL:%.*]] = fsub arcp afn <4 x float> <float -0.000000e+00, float -0.000000e+00, float -0.000000e+00, float -0.000000e+00>, [[X:%.*]] 221; CHECK-NEXT: ret <4 x float> [[MUL]] 222; 223 %mul = fmul arcp afn <4 x float> %x, <float -1.0, float -1.0, float -1.0, float -1.0> 224 ret <4 x float> %mul 225} 226 227define float @test11(float %x, float %y) { 228; CHECK-LABEL: @test11( 229; CHECK-NEXT: [[B:%.*]] = fadd fast float [[X:%.*]], [[Y:%.*]] 230; CHECK-NEXT: [[C:%.*]] = fadd fast float [[B]], 3.000000e+00 231; CHECK-NEXT: ret float [[C]] 232; 233 %a = fadd fast float %x, 1.0 234 %b = fadd fast float %y, 2.0 235 %c = fadd fast float %a, %b 236 ret float %c 237} 238 239declare double @llvm.sqrt.f64(double) 240 241; With unsafe/fast math, sqrt(X) * sqrt(X) is just X, 242; but make sure another use of the sqrt is intact. 243; Note that the remaining fmul is altered but is not 'fast' 244; itself because it was not marked 'fast' originally. 245; Thus, we have an overall fast result, but no more indication of 246; 'fast'ness in the code. 247define double @sqrt_squared2(double %f) { 248; CHECK-LABEL: @sqrt_squared2( 249; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.sqrt.f64(double [[F:%.*]]) 250; CHECK-NEXT: [[MUL2:%.*]] = fmul double [[SQRT]], [[F]] 251; CHECK-NEXT: ret double [[MUL2]] 252; 253 %sqrt = call double @llvm.sqrt.f64(double %f) 254 %mul1 = fmul fast double %sqrt, %sqrt 255 %mul2 = fmul double %mul1, %sqrt 256 ret double %mul2 257} 258 259declare float @llvm.fabs.f32(float) nounwind readnone 260 261define float @fabs_squared(float %x) { 262; CHECK-LABEL: @fabs_squared( 263; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X:%.*]], [[X]] 264; CHECK-NEXT: ret float [[MUL]] 265; 266 %x.fabs = call float @llvm.fabs.f32(float %x) 267 %mul = fmul float %x.fabs, %x.fabs 268 ret float %mul 269} 270 271define float @fabs_squared_fast(float %x) { 272; CHECK-LABEL: @fabs_squared_fast( 273; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[X:%.*]], [[X]] 274; CHECK-NEXT: ret float [[MUL]] 275; 276 %x.fabs = call float @llvm.fabs.f32(float %x) 277 %mul = fmul fast float %x.fabs, %x.fabs 278 ret float %mul 279} 280 281define float @fabs_x_fabs(float %x, float %y) { 282; CHECK-LABEL: @fabs_x_fabs( 283; CHECK-NEXT: [[X_FABS:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]]) 284; CHECK-NEXT: [[Y_FABS:%.*]] = call float @llvm.fabs.f32(float [[Y:%.*]]) 285; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X_FABS]], [[Y_FABS]] 286; CHECK-NEXT: ret float [[MUL]] 287; 288 %x.fabs = call float @llvm.fabs.f32(float %x) 289 %y.fabs = call float @llvm.fabs.f32(float %y) 290 %mul = fmul float %x.fabs, %y.fabs 291 ret float %mul 292} 293 294; (X*Y) * X => (X*X) * Y 295; The transform only requires 'reassoc', but test other FMF in 296; the commuted variants to make sure FMF propagates as expected. 297 298define float @reassoc_common_operand1(float %x, float %y) { 299; CHECK-LABEL: @reassoc_common_operand1( 300; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc float [[X:%.*]], [[X]] 301; CHECK-NEXT: [[MUL2:%.*]] = fmul reassoc float [[TMP1]], [[Y:%.*]] 302; CHECK-NEXT: ret float [[MUL2]] 303; 304 %mul1 = fmul float %x, %y 305 %mul2 = fmul reassoc float %mul1, %x 306 ret float %mul2 307} 308 309; (Y*X) * X => (X*X) * Y 310 311define float @reassoc_common_operand2(float %x, float %y) { 312; CHECK-LABEL: @reassoc_common_operand2( 313; CHECK-NEXT: [[TMP1:%.*]] = fmul fast float [[X:%.*]], [[X]] 314; CHECK-NEXT: [[MUL2:%.*]] = fmul fast float [[TMP1]], [[Y:%.*]] 315; CHECK-NEXT: ret float [[MUL2]] 316; 317 %mul1 = fmul float %y, %x 318 %mul2 = fmul fast float %mul1, %x 319 ret float %mul2 320} 321 322; X * (X*Y) => (X*X) * Y 323 324define float @reassoc_common_operand3(float %x1, float %y) { 325; CHECK-LABEL: @reassoc_common_operand3( 326; CHECK-NEXT: [[X:%.*]] = fdiv float [[X1:%.*]], 3.000000e+00 327; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc nnan float [[X]], [[X]] 328; CHECK-NEXT: [[MUL2:%.*]] = fmul reassoc nnan float [[TMP1]], [[Y:%.*]] 329; CHECK-NEXT: ret float [[MUL2]] 330; 331 %x = fdiv float %x1, 3.0 ; thwart complexity-based canonicalization 332 %mul1 = fmul float %x, %y 333 %mul2 = fmul reassoc nnan float %x, %mul1 334 ret float %mul2 335} 336 337; X * (Y*X) => (X*X) * Y 338 339define float @reassoc_common_operand4(float %x1, float %y) { 340; CHECK-LABEL: @reassoc_common_operand4( 341; CHECK-NEXT: [[X:%.*]] = fdiv float [[X1:%.*]], 3.000000e+00 342; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc ninf float [[X]], [[X]] 343; CHECK-NEXT: [[MUL2:%.*]] = fmul reassoc ninf float [[TMP1]], [[Y:%.*]] 344; CHECK-NEXT: ret float [[MUL2]] 345; 346 %x = fdiv float %x1, 3.0 ; thwart complexity-based canonicalization 347 %mul1 = fmul float %y, %x 348 %mul2 = fmul reassoc ninf float %x, %mul1 349 ret float %mul2 350} 351 352; No change if the first fmul has another use. 353 354define float @reassoc_common_operand_multi_use(float %x, float %y) { 355; CHECK-LABEL: @reassoc_common_operand_multi_use( 356; CHECK-NEXT: [[MUL1:%.*]] = fmul float [[X:%.*]], [[Y:%.*]] 357; CHECK-NEXT: [[MUL2:%.*]] = fmul fast float [[MUL1]], [[X]] 358; CHECK-NEXT: call void @use_f32(float [[MUL1]]) 359; CHECK-NEXT: ret float [[MUL2]] 360; 361 %mul1 = fmul float %x, %y 362 %mul2 = fmul fast float %mul1, %x 363 call void @use_f32(float %mul1) 364 ret float %mul2 365} 366 367declare float @llvm.log2.f32(float) 368 369; log2(Y * 0.5) * X = log2(Y) * X - X 370 371define float @log2half(float %x, float %y) { 372; CHECK-LABEL: @log2half( 373; CHECK-NEXT: [[LOG2:%.*]] = call fast float @llvm.log2.f32(float [[Y:%.*]]) 374; CHECK-NEXT: [[TMP1:%.*]] = fmul fast float [[LOG2]], [[X:%.*]] 375; CHECK-NEXT: [[MUL:%.*]] = fsub fast float [[TMP1]], [[X]] 376; CHECK-NEXT: ret float [[MUL]] 377; 378 %halfy = fmul float %y, 0.5 379 %log2 = call float @llvm.log2.f32(float %halfy) 380 %mul = fmul fast float %log2, %x 381 ret float %mul 382} 383 384define float @log2half_commute(float %x1, float %y) { 385; CHECK-LABEL: @log2half_commute( 386; CHECK-NEXT: [[X:%.*]] = fdiv float [[X1:%.*]], 7.000000e+00 387; CHECK-NEXT: [[LOG2:%.*]] = call fast float @llvm.log2.f32(float [[Y:%.*]]) 388; CHECK-NEXT: [[TMP1:%.*]] = fmul fast float [[LOG2]], [[X]] 389; CHECK-NEXT: [[MUL:%.*]] = fsub fast float [[TMP1]], [[X]] 390; CHECK-NEXT: ret float [[MUL]] 391; 392 %x = fdiv float %x1, 7.0 ; thwart complexity-based canonicalization 393 %halfy = fmul float %y, 0.5 394 %log2 = call float @llvm.log2.f32(float %halfy) 395 %mul = fmul fast float %x, %log2 396 ret float %mul 397} 398 399; C1/X * C2 => (C1*C2) / X 400 401define float @fdiv_constant_numerator_fmul(float %x) { 402; CHECK-LABEL: @fdiv_constant_numerator_fmul( 403; CHECK-NEXT: [[T3:%.*]] = fdiv reassoc float 1.200000e+07, [[X:%.*]] 404; CHECK-NEXT: ret float [[T3]] 405; 406 %t1 = fdiv float 2.0e+3, %x 407 %t3 = fmul reassoc float %t1, 6.0e+3 408 ret float %t3 409} 410 411; C1/X * C2 => (C1*C2) / X is disabled if C1/X has multiple uses 412 413@fmul2_external = external global float 414 415define float @fdiv_constant_numerator_fmul_extra_use(float %x) { 416; CHECK-LABEL: @fdiv_constant_numerator_fmul_extra_use( 417; CHECK-NEXT: [[DIV:%.*]] = fdiv fast float 1.000000e+00, [[X:%.*]] 418; CHECK-NEXT: store float [[DIV]], float* @fmul2_external, align 4 419; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[DIV]], 2.000000e+00 420; CHECK-NEXT: ret float [[MUL]] 421; 422 %div = fdiv fast float 1.0, %x 423 store float %div, float* @fmul2_external 424 %mul = fmul fast float %div, 2.0 425 ret float %mul 426} 427 428; X/C1 * C2 => X * (C2/C1) (if C2/C1 is normal FP) 429 430define float @fdiv_constant_denominator_fmul(float %x) { 431; CHECK-LABEL: @fdiv_constant_denominator_fmul( 432; CHECK-NEXT: [[T3:%.*]] = fmul reassoc float [[X:%.*]], 3.000000e+00 433; CHECK-NEXT: ret float [[T3]] 434; 435 %t1 = fdiv float %x, 2.0e+3 436 %t3 = fmul reassoc float %t1, 6.0e+3 437 ret float %t3 438} 439 440define <4 x float> @fdiv_constant_denominator_fmul_vec(<4 x float> %x) { 441; CHECK-LABEL: @fdiv_constant_denominator_fmul_vec( 442; CHECK-NEXT: [[T3:%.*]] = fmul reassoc <4 x float> [[X:%.*]], <float 3.000000e+00, float 2.000000e+00, float 1.000000e+00, float 1.000000e+00> 443; CHECK-NEXT: ret <4 x float> [[T3]] 444; 445 %t1 = fdiv <4 x float> %x, <float 2.0e+3, float 3.0e+3, float 2.0e+3, float 1.0e+3> 446 %t3 = fmul reassoc <4 x float> %t1, <float 6.0e+3, float 6.0e+3, float 2.0e+3, float 1.0e+3> 447 ret <4 x float> %t3 448} 449 450; Make sure fmul with constant expression doesn't assert. 451 452define <4 x float> @fdiv_constant_denominator_fmul_vec_constexpr(<4 x float> %x) { 453; CHECK-LABEL: @fdiv_constant_denominator_fmul_vec_constexpr( 454; CHECK-NEXT: [[T3:%.*]] = fmul reassoc <4 x float> [[X:%.*]], <float 3.000000e+00, float 2.000000e+00, float 1.000000e+00, float 1.000000e+00> 455; CHECK-NEXT: ret <4 x float> [[T3]] 456; 457 %constExprMul = bitcast i128 trunc (i160 bitcast (<5 x float> <float 6.0e+3, float 6.0e+3, float 2.0e+3, float 1.0e+3, float undef> to i160) to i128) to <4 x float> 458 %t1 = fdiv <4 x float> %x, <float 2.0e+3, float 3.0e+3, float 2.0e+3, float 1.0e+3> 459 %t3 = fmul reassoc <4 x float> %t1, %constExprMul 460 ret <4 x float> %t3 461} 462 463; Rule "X/C1 * C2 => X * (C2/C1) is not applicable if C2/C1 is abnormal 464; 0x3810000000000000 == FLT_MIN 465 466define float @fdiv_constant_denominator_fmul_denorm(float %x) { 467; CHECK-LABEL: @fdiv_constant_denominator_fmul_denorm( 468; CHECK-NEXT: [[T1:%.*]] = fdiv float [[X:%.*]], 2.000000e+03 469; CHECK-NEXT: [[T3:%.*]] = fmul fast float [[T1]], 0x3810000000000000 470; CHECK-NEXT: ret float [[T3]] 471; 472 %t1 = fdiv float %x, 2.0e+3 473 %t3 = fmul fast float %t1, 0x3810000000000000 474 ret float %t3 475} 476 477; X / C1 * C2 => X / (C2/C1) if C1/C2 is abnormal, but C2/C1 is a normal value. 478; TODO: We don't convert the fast fdiv to fmul because that would be multiplication 479; by a denormal, but we could do better when we know that denormals are not a problem. 480 481define float @fdiv_constant_denominator_fmul_denorm_try_harder(float %x) { 482; CHECK-LABEL: @fdiv_constant_denominator_fmul_denorm_try_harder( 483; CHECK-NEXT: [[T3:%.*]] = fdiv reassoc float [[X:%.*]], 0x47E8000000000000 484; CHECK-NEXT: ret float [[T3]] 485; 486 %t1 = fdiv float %x, 3.0 487 %t3 = fmul reassoc float %t1, 0x3810000000000000 488 ret float %t3 489} 490 491; Negative test: we should not have 2 divisions instead of the 1 we started with. 492 493define float @fdiv_constant_denominator_fmul_denorm_try_harder_extra_use(float %x) { 494; CHECK-LABEL: @fdiv_constant_denominator_fmul_denorm_try_harder_extra_use( 495; CHECK-NEXT: [[T1:%.*]] = fdiv float [[X:%.*]], 3.000000e+00 496; CHECK-NEXT: [[T3:%.*]] = fmul fast float [[T1]], 0x3810000000000000 497; CHECK-NEXT: [[R:%.*]] = fadd float [[T1]], [[T3]] 498; CHECK-NEXT: ret float [[R]] 499; 500 %t1 = fdiv float %x, 3.0e+0 501 %t3 = fmul fast float %t1, 0x3810000000000000 502 %r = fadd float %t1, %t3 503 ret float %r 504} 505 506; (X + C1) * C2 --> (X * C2) + C1*C2 507 508define float @fmul_fadd_distribute(float %x) { 509; CHECK-LABEL: @fmul_fadd_distribute( 510; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc float [[X:%.*]], 3.000000e+00 511; CHECK-NEXT: [[T3:%.*]] = fadd reassoc float [[TMP1]], 6.000000e+00 512; CHECK-NEXT: ret float [[T3]] 513; 514 %t2 = fadd float %x, 2.0 515 %t3 = fmul reassoc float %t2, 3.0 516 ret float %t3 517} 518 519; (X - C1) * C2 --> (X * C2) - C1*C2 520 521define float @fmul_fsub_distribute1(float %x) { 522; CHECK-LABEL: @fmul_fsub_distribute1( 523; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc float [[X:%.*]], 3.000000e+00 524; CHECK-NEXT: [[T3:%.*]] = fadd reassoc float [[TMP1]], -6.000000e+00 525; CHECK-NEXT: ret float [[T3]] 526; 527 %t2 = fsub float %x, 2.0 528 %t3 = fmul reassoc float %t2, 3.0 529 ret float %t3 530} 531 532; (C1 - X) * C2 --> C1*C2 - (X * C2) 533 534define float @fmul_fsub_distribute2(float %x) { 535; CHECK-LABEL: @fmul_fsub_distribute2( 536; CHECK-NEXT: [[TMP1:%.*]] = fmul reassoc float [[X:%.*]], 3.000000e+00 537; CHECK-NEXT: [[T3:%.*]] = fsub reassoc float 6.000000e+00, [[TMP1]] 538; CHECK-NEXT: ret float [[T3]] 539; 540 %t2 = fsub float 2.0, %x 541 %t3 = fmul reassoc float %t2, 3.0 542 ret float %t3 543} 544 545; FIXME: This should only need 'reassoc'. 546; ((X*C1) + C2) * C3 => (X * (C1*C3)) + (C2*C3) 547 548define float @fmul_fadd_fmul_distribute(float %x) { 549; CHECK-LABEL: @fmul_fadd_fmul_distribute( 550; CHECK-NEXT: [[TMP1:%.*]] = fmul fast float [[X:%.*]], 3.000000e+01 551; CHECK-NEXT: [[T3:%.*]] = fadd fast float [[TMP1]], 1.000000e+01 552; CHECK-NEXT: ret float [[T3]] 553; 554 %t1 = fmul float %x, 6.0 555 %t2 = fadd float %t1, 2.0 556 %t3 = fmul fast float %t2, 5.0 557 ret float %t3 558} 559 560define float @fmul_fadd_distribute_extra_use(float %x) { 561; CHECK-LABEL: @fmul_fadd_distribute_extra_use( 562; CHECK-NEXT: [[T1:%.*]] = fmul float [[X:%.*]], 6.000000e+00 563; CHECK-NEXT: [[T2:%.*]] = fadd float [[T1]], 2.000000e+00 564; CHECK-NEXT: [[T3:%.*]] = fmul fast float [[T2]], 5.000000e+00 565; CHECK-NEXT: call void @use_f32(float [[T2]]) 566; CHECK-NEXT: ret float [[T3]] 567; 568 %t1 = fmul float %x, 6.0 569 %t2 = fadd float %t1, 2.0 570 %t3 = fmul fast float %t2, 5.0 571 call void @use_f32(float %t2) 572 ret float %t3 573} 574 575; (X/C1 + C2) * C3 => X/(C1/C3) + C2*C3 576; 0x10000000000000 = DBL_MIN 577; TODO: We don't convert the fast fdiv to fmul because that would be multiplication 578; by a denormal, but we could do better when we know that denormals are not a problem. 579 580define double @fmul_fadd_fdiv_distribute2(double %x) { 581; CHECK-LABEL: @fmul_fadd_fdiv_distribute2( 582; CHECK-NEXT: [[TMP1:%.*]] = fdiv reassoc double [[X:%.*]], 0x7FE8000000000000 583; CHECK-NEXT: [[T3:%.*]] = fadd reassoc double [[TMP1]], 0x34000000000000 584; CHECK-NEXT: ret double [[T3]] 585; 586 %t1 = fdiv double %x, 3.0 587 %t2 = fadd double %t1, 5.0 588 %t3 = fmul reassoc double %t2, 0x10000000000000 589 ret double %t3 590} 591 592; 5.0e-1 * DBL_MIN yields denormal, so "(f1*3.0 + 5.0e-1) * DBL_MIN" cannot 593; be simplified into f1 * (3.0*DBL_MIN) + (5.0e-1*DBL_MIN) 594 595define double @fmul_fadd_fdiv_distribute3(double %x) { 596; CHECK-LABEL: @fmul_fadd_fdiv_distribute3( 597; CHECK-NEXT: [[TMP1:%.*]] = fdiv reassoc double [[X:%.*]], 0x7FE8000000000000 598; CHECK-NEXT: [[T3:%.*]] = fadd reassoc double [[TMP1]], 0x34000000000000 599; CHECK-NEXT: ret double [[T3]] 600; 601 %t1 = fdiv double %x, 3.0 602 %t2 = fadd double %t1, 5.0 603 %t3 = fmul reassoc double %t2, 0x10000000000000 604 ret double %t3 605} 606 607; FIXME: This should only need 'reassoc'. 608; (C2 - (X*C1)) * C3 => (C2*C3) - (X * (C1*C3)) 609 610define float @fmul_fsub_fmul_distribute(float %x) { 611; CHECK-LABEL: @fmul_fsub_fmul_distribute( 612; CHECK-NEXT: [[TMP1:%.*]] = fmul fast float [[X:%.*]], 3.000000e+01 613; CHECK-NEXT: [[T3:%.*]] = fsub fast float 1.000000e+01, [[TMP1]] 614; CHECK-NEXT: ret float [[T3]] 615; 616 %t1 = fmul float %x, 6.0 617 %t2 = fsub float 2.0, %t1 618 %t3 = fmul fast float %t2, 5.0 619 ret float %t3 620} 621 622define float @fmul_fsub_fmul_distribute_extra_use(float %x) { 623; CHECK-LABEL: @fmul_fsub_fmul_distribute_extra_use( 624; CHECK-NEXT: [[T1:%.*]] = fmul float [[X:%.*]], 6.000000e+00 625; CHECK-NEXT: [[T2:%.*]] = fsub float 2.000000e+00, [[T1]] 626; CHECK-NEXT: [[T3:%.*]] = fmul fast float [[T2]], 5.000000e+00 627; CHECK-NEXT: call void @use_f32(float [[T2]]) 628; CHECK-NEXT: ret float [[T3]] 629; 630 %t1 = fmul float %x, 6.0 631 %t2 = fsub float 2.0, %t1 632 %t3 = fmul fast float %t2, 5.0 633 call void @use_f32(float %t2) 634 ret float %t3 635} 636 637; FIXME: This should only need 'reassoc'. 638; ((X*C1) - C2) * C3 => (X * (C1*C3)) - C2*C3 639 640define float @fmul_fsub_fmul_distribute2(float %x) { 641; CHECK-LABEL: @fmul_fsub_fmul_distribute2( 642; CHECK-NEXT: [[TMP1:%.*]] = fmul fast float [[X:%.*]], 3.000000e+01 643; CHECK-NEXT: [[T3:%.*]] = fadd fast float [[TMP1]], -1.000000e+01 644; CHECK-NEXT: ret float [[T3]] 645; 646 %t1 = fmul float %x, 6.0 647 %t2 = fsub float %t1, 2.0 648 %t3 = fmul fast float %t2, 5.0 649 ret float %t3 650} 651 652define float @fmul_fsub_fmul_distribute2_extra_use(float %x) { 653; CHECK-LABEL: @fmul_fsub_fmul_distribute2_extra_use( 654; CHECK-NEXT: [[T1:%.*]] = fmul float [[X:%.*]], 6.000000e+00 655; CHECK-NEXT: [[T2:%.*]] = fsub float 2.000000e+00, [[T1]] 656; CHECK-NEXT: [[T3:%.*]] = fmul fast float [[T2]], 5.000000e+00 657; CHECK-NEXT: call void @use_f32(float [[T2]]) 658; CHECK-NEXT: ret float [[T3]] 659; 660 %t1 = fmul float %x, 6.0 661 %t2 = fsub float 2.0, %t1 662 %t3 = fmul fast float %t2, 5.0 663 call void @use_f32(float %t2) 664 ret float %t3 665} 666 667; "(X*Y) * X => (X*X) * Y" is disabled if "X*Y" has multiple uses 668 669define float @common_factor(float %x, float %y) { 670; CHECK-LABEL: @common_factor( 671; CHECK-NEXT: [[MUL:%.*]] = fmul float [[X:%.*]], [[Y:%.*]] 672; CHECK-NEXT: [[MUL1:%.*]] = fmul fast float [[MUL]], [[X]] 673; CHECK-NEXT: [[ADD:%.*]] = fadd float [[MUL1]], [[MUL]] 674; CHECK-NEXT: ret float [[ADD]] 675; 676 %mul = fmul float %x, %y 677 %mul1 = fmul fast float %mul, %x 678 %add = fadd float %mul1, %mul 679 ret float %add 680} 681 682