1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -instcombine -S | FileCheck %s 3 4; PR4374 5 6define float @test1(float %x, float %y) { 7; CHECK-LABEL: @test1( 8; CHECK-NEXT: [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]] 9; CHECK-NEXT: [[T2:%.*]] = fneg float [[T1]] 10; CHECK-NEXT: ret float [[T2]] 11; 12 %t1 = fsub float %x, %y 13 %t2 = fsub float -0.0, %t1 14 ret float %t2 15} 16 17define float @test1_unary(float %x, float %y) { 18; CHECK-LABEL: @test1_unary( 19; CHECK-NEXT: [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]] 20; CHECK-NEXT: [[T2:%.*]] = fneg float [[T1]] 21; CHECK-NEXT: ret float [[T2]] 22; 23 %t1 = fsub float %x, %y 24 %t2 = fneg float %t1 25 ret float %t2 26} 27 28; Can't do anything with the test above because -0.0 - 0.0 = -0.0, but if we have nsz: 29; -(X - Y) --> Y - X 30 31define float @neg_sub_nsz(float %x, float %y) { 32; CHECK-LABEL: @neg_sub_nsz( 33; CHECK-NEXT: [[T2:%.*]] = fsub nsz float [[Y:%.*]], [[X:%.*]] 34; CHECK-NEXT: ret float [[T2]] 35; 36 %t1 = fsub float %x, %y 37 %t2 = fsub nsz float -0.0, %t1 38 ret float %t2 39} 40 41define float @unary_neg_sub_nsz(float %x, float %y) { 42; CHECK-LABEL: @unary_neg_sub_nsz( 43; CHECK-NEXT: [[T2:%.*]] = fsub nsz float [[Y:%.*]], [[X:%.*]] 44; CHECK-NEXT: ret float [[T2]] 45; 46 %t1 = fsub float %x, %y 47 %t2 = fneg nsz float %t1 48 ret float %t2 49} 50 51; If the subtract has another use, we don't do the transform (even though it 52; doesn't increase the IR instruction count) because we assume that fneg is 53; easier to analyze and generally cheaper than generic fsub. 54 55declare void @use(float) 56declare void @use2(float, double) 57 58define float @neg_sub_nsz_extra_use(float %x, float %y) { 59; CHECK-LABEL: @neg_sub_nsz_extra_use( 60; CHECK-NEXT: [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]] 61; CHECK-NEXT: [[T2:%.*]] = fneg nsz float [[T1]] 62; CHECK-NEXT: call void @use(float [[T1]]) 63; CHECK-NEXT: ret float [[T2]] 64; 65 %t1 = fsub float %x, %y 66 %t2 = fsub nsz float -0.0, %t1 67 call void @use(float %t1) 68 ret float %t2 69} 70 71define float @unary_neg_sub_nsz_extra_use(float %x, float %y) { 72; CHECK-LABEL: @unary_neg_sub_nsz_extra_use( 73; CHECK-NEXT: [[T1:%.*]] = fsub float [[X:%.*]], [[Y:%.*]] 74; CHECK-NEXT: [[T2:%.*]] = fneg nsz float [[T1]] 75; CHECK-NEXT: call void @use(float [[T1]]) 76; CHECK-NEXT: ret float [[T2]] 77; 78 %t1 = fsub float %x, %y 79 %t2 = fneg nsz float %t1 80 call void @use(float %t1) 81 ret float %t2 82} 83 84; With nsz: Z - (X - Y) --> Z + (Y - X) 85 86define float @sub_sub_nsz(float %x, float %y, float %z) { 87; CHECK-LABEL: @sub_sub_nsz( 88; CHECK-NEXT: [[TMP1:%.*]] = fsub nsz float [[Y:%.*]], [[X:%.*]] 89; CHECK-NEXT: [[T2:%.*]] = fadd nsz float [[TMP1]], [[Z:%.*]] 90; CHECK-NEXT: ret float [[T2]] 91; 92 %t1 = fsub float %x, %y 93 %t2 = fsub nsz float %z, %t1 94 ret float %t2 95} 96 97; With nsz and reassoc: Y - ((X * 5) + Y) --> X * -5 98 99define float @sub_add_neg_x(float %x, float %y) { 100; CHECK-LABEL: @sub_add_neg_x( 101; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], -5.000000e+00 102; CHECK-NEXT: ret float [[R]] 103; 104 %mul = fmul float %x, 5.000000e+00 105 %add = fadd float %mul, %y 106 %r = fsub nsz reassoc float %y, %add 107 ret float %r 108} 109 110; Same as above: if 'Z' is not -0.0, swap fsub operands and convert to fadd. 111 112define float @sub_sub_known_not_negzero(float %x, float %y) { 113; CHECK-LABEL: @sub_sub_known_not_negzero( 114; CHECK-NEXT: [[TMP1:%.*]] = fsub float [[Y:%.*]], [[X:%.*]] 115; CHECK-NEXT: [[T2:%.*]] = fadd float [[TMP1]], 4.200000e+01 116; CHECK-NEXT: ret float [[T2]] 117; 118 %t1 = fsub float %x, %y 119 %t2 = fsub float 42.0, %t1 120 ret float %t2 121} 122 123; <rdar://problem/7530098> 124 125define double @test2(double %x, double %y) { 126; CHECK-LABEL: @test2( 127; CHECK-NEXT: [[T1:%.*]] = fadd double [[X:%.*]], [[Y:%.*]] 128; CHECK-NEXT: [[T2:%.*]] = fsub double [[X]], [[T1]] 129; CHECK-NEXT: ret double [[T2]] 130; 131 %t1 = fadd double %x, %y 132 %t2 = fsub double %x, %t1 133 ret double %t2 134} 135 136; X - C --> X + (-C) 137 138define float @constant_op1(float %x, float %y) { 139; CHECK-LABEL: @constant_op1( 140; CHECK-NEXT: [[R:%.*]] = fadd float [[X:%.*]], -4.200000e+01 141; CHECK-NEXT: ret float [[R]] 142; 143 %r = fsub float %x, 42.0 144 ret float %r 145} 146 147define <2 x float> @constant_op1_vec(<2 x float> %x, <2 x float> %y) { 148; CHECK-LABEL: @constant_op1_vec( 149; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], <float -4.200000e+01, float 4.200000e+01> 150; CHECK-NEXT: ret <2 x float> [[R]] 151; 152 %r = fsub <2 x float> %x, <float 42.0, float -42.0> 153 ret <2 x float> %r 154} 155 156define <2 x float> @constant_op1_vec_undef(<2 x float> %x, <2 x float> %y) { 157; CHECK-LABEL: @constant_op1_vec_undef( 158; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], <float undef, float 4.200000e+01> 159; CHECK-NEXT: ret <2 x float> [[R]] 160; 161 %r = fsub <2 x float> %x, <float undef, float -42.0> 162 ret <2 x float> %r 163} 164 165; X - (-Y) --> X + Y 166 167define float @neg_op1(float %x, float %y) { 168; CHECK-LABEL: @neg_op1( 169; CHECK-NEXT: [[R:%.*]] = fadd float [[X:%.*]], [[Y:%.*]] 170; CHECK-NEXT: ret float [[R]] 171; 172 %negy = fsub float -0.0, %y 173 %r = fsub float %x, %negy 174 ret float %r 175} 176 177define float @unary_neg_op1(float %x, float %y) { 178; CHECK-LABEL: @unary_neg_op1( 179; CHECK-NEXT: [[R:%.*]] = fadd float [[X:%.*]], [[Y:%.*]] 180; CHECK-NEXT: ret float [[R]] 181; 182 %negy = fneg float %y 183 %r = fsub float %x, %negy 184 ret float %r 185} 186 187define <2 x float> @neg_op1_vec(<2 x float> %x, <2 x float> %y) { 188; CHECK-LABEL: @neg_op1_vec( 189; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], [[Y:%.*]] 190; CHECK-NEXT: ret <2 x float> [[R]] 191; 192 %negy = fsub <2 x float> <float -0.0, float -0.0>, %y 193 %r = fsub <2 x float> %x, %negy 194 ret <2 x float> %r 195} 196 197define <2 x float> @unary_neg_op1_vec(<2 x float> %x, <2 x float> %y) { 198; CHECK-LABEL: @unary_neg_op1_vec( 199; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], [[Y:%.*]] 200; CHECK-NEXT: ret <2 x float> [[R]] 201; 202 %negy = fneg <2 x float> %y 203 %r = fsub <2 x float> %x, %negy 204 ret <2 x float> %r 205} 206 207define <2 x float> @neg_op1_vec_undef(<2 x float> %x, <2 x float> %y) { 208; CHECK-LABEL: @neg_op1_vec_undef( 209; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[X:%.*]], [[Y:%.*]] 210; CHECK-NEXT: ret <2 x float> [[R]] 211; 212 %negy = fsub <2 x float> <float -0.0, float undef>, %y 213 %r = fsub <2 x float> %x, %negy 214 ret <2 x float> %r 215} 216 217; Similar to above - but look through fpext/fptrunc casts to find the fneg. 218 219define double @neg_ext_op1(float %a, double %b) { 220; CHECK-LABEL: @neg_ext_op1( 221; CHECK-NEXT: [[TMP1:%.*]] = fpext float [[A:%.*]] to double 222; CHECK-NEXT: [[T3:%.*]] = fadd double [[TMP1]], [[B:%.*]] 223; CHECK-NEXT: ret double [[T3]] 224; 225 %t1 = fsub float -0.0, %a 226 %t2 = fpext float %t1 to double 227 %t3 = fsub double %b, %t2 228 ret double %t3 229} 230 231define double @unary_neg_ext_op1(float %a, double %b) { 232; CHECK-LABEL: @unary_neg_ext_op1( 233; CHECK-NEXT: [[TMP1:%.*]] = fpext float [[A:%.*]] to double 234; CHECK-NEXT: [[T3:%.*]] = fadd double [[TMP1]], [[B:%.*]] 235; CHECK-NEXT: ret double [[T3]] 236; 237 %t1 = fneg float %a 238 %t2 = fpext float %t1 to double 239 %t3 = fsub double %b, %t2 240 ret double %t3 241} 242 243; Verify that vectors work too. 244 245define <2 x float> @neg_trunc_op1(<2 x double> %a, <2 x float> %b) { 246; CHECK-LABEL: @neg_trunc_op1( 247; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x double> [[A:%.*]] to <2 x float> 248; CHECK-NEXT: [[T3:%.*]] = fadd <2 x float> [[TMP1]], [[B:%.*]] 249; CHECK-NEXT: ret <2 x float> [[T3]] 250; 251 %t1 = fsub <2 x double> <double -0.0, double -0.0>, %a 252 %t2 = fptrunc <2 x double> %t1 to <2 x float> 253 %t3 = fsub <2 x float> %b, %t2 254 ret <2 x float> %t3 255} 256 257define <2 x float> @unary_neg_trunc_op1(<2 x double> %a, <2 x float> %b) { 258; CHECK-LABEL: @unary_neg_trunc_op1( 259; CHECK-NEXT: [[TMP1:%.*]] = fptrunc <2 x double> [[A:%.*]] to <2 x float> 260; CHECK-NEXT: [[T3:%.*]] = fadd <2 x float> [[TMP1]], [[B:%.*]] 261; CHECK-NEXT: ret <2 x float> [[T3]] 262; 263 %t1 = fneg <2 x double> %a 264 %t2 = fptrunc <2 x double> %t1 to <2 x float> 265 %t3 = fsub <2 x float> %b, %t2 266 ret <2 x float> %t3 267} 268 269; No FMF needed, but they should propagate to the fadd. 270 271define double @neg_ext_op1_fast(float %a, double %b) { 272; CHECK-LABEL: @neg_ext_op1_fast( 273; CHECK-NEXT: [[TMP1:%.*]] = fpext float [[A:%.*]] to double 274; CHECK-NEXT: [[T3:%.*]] = fadd fast double [[TMP1]], [[B:%.*]] 275; CHECK-NEXT: ret double [[T3]] 276; 277 %t1 = fsub float -0.0, %a 278 %t2 = fpext float %t1 to double 279 %t3 = fsub fast double %b, %t2 280 ret double %t3 281} 282 283define double @unary_neg_ext_op1_fast(float %a, double %b) { 284; CHECK-LABEL: @unary_neg_ext_op1_fast( 285; CHECK-NEXT: [[TMP1:%.*]] = fpext float [[A:%.*]] to double 286; CHECK-NEXT: [[T3:%.*]] = fadd fast double [[TMP1]], [[B:%.*]] 287; CHECK-NEXT: ret double [[T3]] 288; 289 %t1 = fneg float %a 290 %t2 = fpext float %t1 to double 291 %t3 = fsub fast double %b, %t2 292 ret double %t3 293} 294 295; Extra use should prevent the transform. 296 297define float @neg_ext_op1_extra_use(half %a, float %b) { 298; CHECK-LABEL: @neg_ext_op1_extra_use( 299; CHECK-NEXT: [[T1:%.*]] = fneg half [[A:%.*]] 300; CHECK-NEXT: [[T2:%.*]] = fpext half [[T1]] to float 301; CHECK-NEXT: [[T3:%.*]] = fsub float [[B:%.*]], [[T2]] 302; CHECK-NEXT: call void @use(float [[T2]]) 303; CHECK-NEXT: ret float [[T3]] 304; 305 %t1 = fsub half -0.0, %a 306 %t2 = fpext half %t1 to float 307 %t3 = fsub float %b, %t2 308 call void @use(float %t2) 309 ret float %t3 310} 311 312define float @unary_neg_ext_op1_extra_use(half %a, float %b) { 313; CHECK-LABEL: @unary_neg_ext_op1_extra_use( 314; CHECK-NEXT: [[T1:%.*]] = fneg half [[A:%.*]] 315; CHECK-NEXT: [[T2:%.*]] = fpext half [[T1]] to float 316; CHECK-NEXT: [[T3:%.*]] = fsub float [[B:%.*]], [[T2]] 317; CHECK-NEXT: call void @use(float [[T2]]) 318; CHECK-NEXT: ret float [[T3]] 319; 320 %t1 = fneg half %a 321 %t2 = fpext half %t1 to float 322 %t3 = fsub float %b, %t2 323 call void @use(float %t2) 324 ret float %t3 325} 326 327; One-use fptrunc is always hoisted above fneg, so the corresponding 328; multi-use bug for fptrunc isn't visible with a fold starting from 329; the last fsub. 330 331define float @neg_trunc_op1_extra_use(double %a, float %b) { 332; CHECK-LABEL: @neg_trunc_op1_extra_use( 333; CHECK-NEXT: [[TMP1:%.*]] = fptrunc double [[A:%.*]] to float 334; CHECK-NEXT: [[T2:%.*]] = fneg float [[TMP1]] 335; CHECK-NEXT: [[T3:%.*]] = fadd float [[TMP1]], [[B:%.*]] 336; CHECK-NEXT: call void @use(float [[T2]]) 337; CHECK-NEXT: ret float [[T3]] 338; 339 %t1 = fsub double -0.0, %a 340 %t2 = fptrunc double %t1 to float 341 %t3 = fsub float %b, %t2 342 call void @use(float %t2) 343 ret float %t3 344} 345 346define float @unary_neg_trunc_op1_extra_use(double %a, float %b) { 347; CHECK-LABEL: @unary_neg_trunc_op1_extra_use( 348; CHECK-NEXT: [[TMP1:%.*]] = fptrunc double [[A:%.*]] to float 349; CHECK-NEXT: [[T2:%.*]] = fneg float [[TMP1]] 350; CHECK-NEXT: [[T3:%.*]] = fadd float [[TMP1]], [[B:%.*]] 351; CHECK-NEXT: call void @use(float [[T2]]) 352; CHECK-NEXT: ret float [[T3]] 353; 354 %t1 = fneg double %a 355 %t2 = fptrunc double %t1 to float 356 %t3 = fsub float %b, %t2 357 call void @use(float %t2) 358 ret float %t3 359} 360 361; Extra uses should prevent the transform. 362 363define float @neg_trunc_op1_extra_uses(double %a, float %b) { 364; CHECK-LABEL: @neg_trunc_op1_extra_uses( 365; CHECK-NEXT: [[T1:%.*]] = fneg double [[A:%.*]] 366; CHECK-NEXT: [[T2:%.*]] = fptrunc double [[T1]] to float 367; CHECK-NEXT: [[T3:%.*]] = fsub float [[B:%.*]], [[T2]] 368; CHECK-NEXT: call void @use2(float [[T2]], double [[T1]]) 369; CHECK-NEXT: ret float [[T3]] 370; 371 %t1 = fsub double -0.0, %a 372 %t2 = fptrunc double %t1 to float 373 %t3 = fsub float %b, %t2 374 call void @use2(float %t2, double %t1) 375 ret float %t3 376} 377 378define float @unary_neg_trunc_op1_extra_uses(double %a, float %b) { 379; CHECK-LABEL: @unary_neg_trunc_op1_extra_uses( 380; CHECK-NEXT: [[T1:%.*]] = fneg double [[A:%.*]] 381; CHECK-NEXT: [[T2:%.*]] = fptrunc double [[T1]] to float 382; CHECK-NEXT: [[T3:%.*]] = fsub float [[B:%.*]], [[T2]] 383; CHECK-NEXT: call void @use2(float [[T2]], double [[T1]]) 384; CHECK-NEXT: ret float [[T3]] 385; 386 %t1 = fneg double %a 387 %t2 = fptrunc double %t1 to float 388 %t3 = fsub float %b, %t2 389 call void @use2(float %t2, double %t1) 390 ret float %t3 391} 392 393; Don't negate a constant expression to form fadd and induce infinite looping: 394; https://bugs.llvm.org/show_bug.cgi?id=37605 395 396@b = external global i16, align 1 397 398define float @PR37605(float %conv) { 399; CHECK-LABEL: @PR37605( 400; CHECK-NEXT: [[SUB:%.*]] = fsub float [[CONV:%.*]], bitcast (i32 ptrtoint (i16* @b to i32) to float) 401; CHECK-NEXT: ret float [[SUB]] 402; 403 %sub = fsub float %conv, bitcast (i32 ptrtoint (i16* @b to i32) to float) 404 ret float %sub 405} 406 407define double @fsub_fdiv_fneg1(double %x, double %y, double %z) { 408; CHECK-LABEL: @fsub_fdiv_fneg1( 409; CHECK-NEXT: [[TMP1:%.*]] = fdiv double [[X:%.*]], [[Y:%.*]] 410; CHECK-NEXT: [[R:%.*]] = fadd double [[TMP1]], [[Z:%.*]] 411; CHECK-NEXT: ret double [[R]] 412; 413 %neg = fsub double -0.000000e+00, %x 414 %div = fdiv double %neg, %y 415 %r = fsub double %z, %div 416 ret double %r 417} 418 419define <2 x double> @fsub_fdiv_fneg2(<2 x double> %x, <2 x double> %y, <2 x double> %z) { 420; CHECK-LABEL: @fsub_fdiv_fneg2( 421; CHECK-NEXT: [[TMP1:%.*]] = fdiv <2 x double> [[Y:%.*]], [[X:%.*]] 422; CHECK-NEXT: [[R:%.*]] = fadd <2 x double> [[TMP1]], [[Z:%.*]] 423; CHECK-NEXT: ret <2 x double> [[R]] 424; 425 %neg = fsub <2 x double> <double -0.0, double -0.0>, %x 426 %div = fdiv <2 x double> %y, %neg 427 %r = fsub <2 x double> %z, %div 428 ret <2 x double> %r 429} 430 431define double @fsub_fmul_fneg1(double %x, double %y, double %z) { 432; CHECK-LABEL: @fsub_fmul_fneg1( 433; CHECK-NEXT: [[TMP1:%.*]] = fmul double [[X:%.*]], [[Y:%.*]] 434; CHECK-NEXT: [[R:%.*]] = fadd double [[TMP1]], [[Z:%.*]] 435; CHECK-NEXT: ret double [[R]] 436; 437 %neg = fsub double -0.000000e+00, %x 438 %mul = fmul double %neg, %y 439 %r = fsub double %z, %mul 440 ret double %r 441} 442 443define double @fsub_fmul_fneg2(double %x, double %y, double %z) { 444; CHECK-LABEL: @fsub_fmul_fneg2( 445; CHECK-NEXT: [[TMP1:%.*]] = fmul double [[X:%.*]], [[Y:%.*]] 446; CHECK-NEXT: [[R:%.*]] = fadd double [[TMP1]], [[Z:%.*]] 447; CHECK-NEXT: ret double [[R]] 448; 449 %neg = fsub double -0.000000e+00, %x 450 %mul = fmul double %y, %neg 451 %r = fsub double %z, %mul 452 ret double %r 453} 454 455define float @fsub_fdiv_fneg1_extra_use(float %x, float %y, float %z) { 456; CHECK-LABEL: @fsub_fdiv_fneg1_extra_use( 457; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]] 458; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[NEG]], [[Y:%.*]] 459; CHECK-NEXT: call void @use(float [[DIV]]) 460; CHECK-NEXT: [[R:%.*]] = fsub float [[Z:%.*]], [[DIV]] 461; CHECK-NEXT: ret float [[R]] 462; 463 %neg = fsub float -0.000000e+00, %x 464 %div = fdiv float %neg, %y 465 call void @use(float %div) 466 %r = fsub float %z, %div 467 ret float %r 468} 469 470define float @fsub_fdiv_fneg2_extra_use(float %x, float %y, float %z) { 471; CHECK-LABEL: @fsub_fdiv_fneg2_extra_use( 472; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]] 473; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[Y:%.*]], [[NEG]] 474; CHECK-NEXT: call void @use(float [[DIV]]) 475; CHECK-NEXT: [[R:%.*]] = fsub float [[Z:%.*]], [[DIV]] 476; CHECK-NEXT: ret float [[R]] 477; 478 %neg = fsub float -0.000000e+00, %x 479 %div = fdiv float %y, %neg 480 call void @use(float %div) 481 %r = fsub float %z, %div 482 ret float %r 483} 484 485declare void @use_vec(<2 x float>) 486 487define <2 x float> @fsub_fmul_fneg1_extra_use(<2 x float> %x, <2 x float> %y, <2 x float> %z) { 488; CHECK-LABEL: @fsub_fmul_fneg1_extra_use( 489; CHECK-NEXT: [[NEG:%.*]] = fneg <2 x float> [[X:%.*]] 490; CHECK-NEXT: [[MUL:%.*]] = fmul <2 x float> [[NEG]], [[Y:%.*]] 491; CHECK-NEXT: call void @use_vec(<2 x float> [[MUL]]) 492; CHECK-NEXT: [[R:%.*]] = fsub <2 x float> [[Z:%.*]], [[MUL]] 493; CHECK-NEXT: ret <2 x float> [[R]] 494; 495 %neg = fsub <2 x float> <float -0.0, float -0.0>, %x 496 %mul = fmul <2 x float> %neg, %y 497 call void @use_vec(<2 x float> %mul) 498 %r = fsub <2 x float> %z, %mul 499 ret <2 x float> %r 500} 501 502define float @fsub_fmul_fneg2_extra_use(float %x, float %y, float %z) { 503; CHECK-LABEL: @fsub_fmul_fneg2_extra_use( 504; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]] 505; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NEG]], [[Y:%.*]] 506; CHECK-NEXT: call void @use(float [[MUL]]) 507; CHECK-NEXT: [[R:%.*]] = fsub float [[Z:%.*]], [[MUL]] 508; CHECK-NEXT: ret float [[R]] 509; 510 %neg = fsub float -0.000000e+00, %x 511 %mul = fmul float %y, %neg 512 call void @use(float %mul) 513 %r = fsub float %z, %mul 514 ret float %r 515} 516 517define float @fsub_fdiv_fneg1_extra_use2(float %x, float %y, float %z) { 518; CHECK-LABEL: @fsub_fdiv_fneg1_extra_use2( 519; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]] 520; CHECK-NEXT: call void @use(float [[NEG]]) 521; CHECK-NEXT: [[TMP1:%.*]] = fdiv float [[X]], [[Y:%.*]] 522; CHECK-NEXT: [[R:%.*]] = fadd float [[TMP1]], [[Z:%.*]] 523; CHECK-NEXT: ret float [[R]] 524; 525 %neg = fsub float -0.000000e+00, %x 526 call void @use(float %neg) 527 %div = fdiv float %neg, %y 528 %r = fsub float %z, %div 529 ret float %r 530} 531 532define float @fsub_fdiv_fneg2_extra_use2(float %x, float %y, float %z) { 533; CHECK-LABEL: @fsub_fdiv_fneg2_extra_use2( 534; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]] 535; CHECK-NEXT: call void @use(float [[NEG]]) 536; CHECK-NEXT: [[TMP1:%.*]] = fdiv float [[Y:%.*]], [[X]] 537; CHECK-NEXT: [[R:%.*]] = fadd float [[TMP1]], [[Z:%.*]] 538; CHECK-NEXT: ret float [[R]] 539; 540 %neg = fsub float -0.000000e+00, %x 541 call void @use(float %neg) 542 %div = fdiv float %y, %neg 543 %r = fsub float %z, %div 544 ret float %r 545} 546 547define <2 x float> @fsub_fmul_fneg1_extra_use2(<2 x float> %x, <2 x float> %y, <2 x float> %z) { 548; CHECK-LABEL: @fsub_fmul_fneg1_extra_use2( 549; CHECK-NEXT: [[NEG:%.*]] = fneg <2 x float> [[X:%.*]] 550; CHECK-NEXT: call void @use_vec(<2 x float> [[NEG]]) 551; CHECK-NEXT: [[TMP1:%.*]] = fmul <2 x float> [[X]], [[Y:%.*]] 552; CHECK-NEXT: [[R:%.*]] = fadd <2 x float> [[TMP1]], [[Z:%.*]] 553; CHECK-NEXT: ret <2 x float> [[R]] 554; 555 %neg = fsub <2 x float> <float -0.0, float -0.0>, %x 556 call void @use_vec(<2 x float> %neg) 557 %mul = fmul <2 x float> %neg, %y 558 %r = fsub <2 x float> %z, %mul 559 ret <2 x float> %r 560} 561 562define float @fsub_fmul_fneg2_extra_use2(float %x, float %y, float %z) { 563; CHECK-LABEL: @fsub_fmul_fneg2_extra_use2( 564; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]] 565; CHECK-NEXT: call void @use(float [[NEG]]) 566; CHECK-NEXT: [[TMP1:%.*]] = fmul float [[X]], [[Y:%.*]] 567; CHECK-NEXT: [[R:%.*]] = fadd float [[TMP1]], [[Z:%.*]] 568; CHECK-NEXT: ret float [[R]] 569; 570 %neg = fsub float -0.000000e+00, %x 571 call void @use(float %neg) 572 %mul = fmul float %y, %neg 573 %r = fsub float %z, %mul 574 ret float %r 575} 576 577define float @fsub_fdiv_fneg1_extra_use3(float %x, float %y, float %z) { 578; CHECK-LABEL: @fsub_fdiv_fneg1_extra_use3( 579; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]] 580; CHECK-NEXT: call void @use(float [[NEG]]) 581; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[NEG]], [[Y:%.*]] 582; CHECK-NEXT: call void @use(float [[DIV]]) 583; CHECK-NEXT: [[R:%.*]] = fsub float [[Z:%.*]], [[DIV]] 584; CHECK-NEXT: ret float [[R]] 585; 586 %neg = fsub float -0.000000e+00, %x 587 call void @use(float %neg) 588 %div = fdiv float %neg, %y 589 call void @use(float %div) 590 %r = fsub float %z, %div 591 ret float %r 592} 593 594define float @fsub_fdiv_fneg2_extra_use3(float %x, float %y, float %z) { 595; CHECK-LABEL: @fsub_fdiv_fneg2_extra_use3( 596; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]] 597; CHECK-NEXT: call void @use(float [[NEG]]) 598; CHECK-NEXT: [[DIV:%.*]] = fdiv float [[Y:%.*]], [[NEG]] 599; CHECK-NEXT: call void @use(float [[DIV]]) 600; CHECK-NEXT: [[R:%.*]] = fsub float [[Z:%.*]], [[DIV]] 601; CHECK-NEXT: ret float [[R]] 602; 603 %neg = fsub float -0.000000e+00, %x 604 call void @use(float %neg) 605 %div = fdiv float %y, %neg 606 call void @use(float %div) 607 %r = fsub float %z, %div 608 ret float %r 609} 610 611define <2 x float> @fsub_fmul_fneg1_extra_use3(<2 x float> %x, <2 x float> %y, <2 x float> %z) { 612; CHECK-LABEL: @fsub_fmul_fneg1_extra_use3( 613; CHECK-NEXT: [[NEG:%.*]] = fneg <2 x float> [[X:%.*]] 614; CHECK-NEXT: call void @use_vec(<2 x float> [[NEG]]) 615; CHECK-NEXT: [[MUL:%.*]] = fmul <2 x float> [[NEG]], [[Y:%.*]] 616; CHECK-NEXT: call void @use_vec(<2 x float> [[MUL]]) 617; CHECK-NEXT: [[R:%.*]] = fsub <2 x float> [[Z:%.*]], [[MUL]] 618; CHECK-NEXT: ret <2 x float> [[R]] 619; 620 %neg = fsub <2 x float> <float -0.0, float -0.0>, %x 621 call void @use_vec(<2 x float> %neg) 622 %mul = fmul <2 x float> %neg, %y 623 call void @use_vec(<2 x float> %mul) 624 %r = fsub <2 x float> %z, %mul 625 ret <2 x float> %r 626} 627 628define float @fsub_fmul_fneg2_extra_use3(float %x, float %y, float %z) { 629; CHECK-LABEL: @fsub_fmul_fneg2_extra_use3( 630; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]] 631; CHECK-NEXT: call void @use(float [[NEG]]) 632; CHECK-NEXT: [[MUL:%.*]] = fmul float [[NEG]], [[Y:%.*]] 633; CHECK-NEXT: call void @use(float [[MUL]]) 634; CHECK-NEXT: [[R:%.*]] = fsub float [[Z:%.*]], [[MUL]] 635; CHECK-NEXT: ret float [[R]] 636; 637 %neg = fsub float -0.000000e+00, %x 638 call void @use(float %neg) 639 %mul = fmul float %y, %neg 640 call void @use(float %mul) 641 %r = fsub float %z, %mul 642 ret float %r 643} 644 645; Negative test - can't reassociate without FMF. 646 647define float @fsub_fsub(float %x, float %y, float %z) { 648; CHECK-LABEL: @fsub_fsub( 649; CHECK-NEXT: [[XY:%.*]] = fsub float [[X:%.*]], [[Y:%.*]] 650; CHECK-NEXT: [[XYZ:%.*]] = fsub float [[XY]], [[Z:%.*]] 651; CHECK-NEXT: ret float [[XYZ]] 652; 653 %xy = fsub float %x, %y 654 %xyz = fsub float %xy, %z 655 ret float %xyz 656} 657 658; Negative test - can't reassociate without enough FMF. 659 660define float @fsub_fsub_nsz(float %x, float %y, float %z) { 661; CHECK-LABEL: @fsub_fsub_nsz( 662; CHECK-NEXT: [[XY:%.*]] = fsub float [[X:%.*]], [[Y:%.*]] 663; CHECK-NEXT: [[XYZ:%.*]] = fsub nsz float [[XY]], [[Z:%.*]] 664; CHECK-NEXT: ret float [[XYZ]] 665; 666 %xy = fsub float %x, %y 667 %xyz = fsub nsz float %xy, %z 668 ret float %xyz 669} 670 671; Negative test - can't reassociate without enough FMF. 672 673define float @fsub_fsub_reassoc(float %x, float %y, float %z) { 674; CHECK-LABEL: @fsub_fsub_reassoc( 675; CHECK-NEXT: [[XY:%.*]] = fsub float [[X:%.*]], [[Y:%.*]] 676; CHECK-NEXT: [[XYZ:%.*]] = fsub reassoc float [[XY]], [[Z:%.*]] 677; CHECK-NEXT: ret float [[XYZ]] 678; 679 %xy = fsub float %x, %y 680 %xyz = fsub reassoc float %xy, %z 681 ret float %xyz 682} 683 684define float @fsub_fsub_nsz_reassoc(float %x, float %y, float %z) { 685; CHECK-LABEL: @fsub_fsub_nsz_reassoc( 686; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz float [[Y:%.*]], [[Z:%.*]] 687; CHECK-NEXT: [[XYZ:%.*]] = fsub reassoc nsz float [[X:%.*]], [[TMP1]] 688; CHECK-NEXT: ret float [[XYZ]] 689; 690 %xy = fsub float %x, %y 691 %xyz = fsub nsz reassoc float %xy, %z 692 ret float %xyz 693} 694 695define <2 x double> @fsub_fsub_fast_vec(<2 x double> %x, <2 x double> %y, <2 x double> %z) { 696; CHECK-LABEL: @fsub_fsub_fast_vec( 697; CHECK-NEXT: [[TMP1:%.*]] = fadd fast <2 x double> [[Y:%.*]], [[Z:%.*]] 698; CHECK-NEXT: [[XYZ:%.*]] = fsub fast <2 x double> [[X:%.*]], [[TMP1]] 699; CHECK-NEXT: ret <2 x double> [[XYZ]] 700; 701 %xy = fsub fast <2 x double> %x, %y 702 %xyz = fsub fast reassoc <2 x double> %xy, %z 703 ret <2 x double> %xyz 704} 705 706; Negative test - don't reassociate and increase instructions. 707 708define float @fsub_fsub_nsz_reassoc_extra_use(float %x, float %y, float %z) { 709; CHECK-LABEL: @fsub_fsub_nsz_reassoc_extra_use( 710; CHECK-NEXT: [[XY:%.*]] = fsub float [[X:%.*]], [[Y:%.*]] 711; CHECK-NEXT: call void @use(float [[XY]]) 712; CHECK-NEXT: [[XYZ:%.*]] = fsub reassoc nsz float [[XY]], [[Z:%.*]] 713; CHECK-NEXT: ret float [[XYZ]] 714; 715 %xy = fsub float %x, %y 716 call void @use(float %xy) 717 %xyz = fsub nsz reassoc float %xy, %z 718 ret float %xyz 719} 720 721define float @fneg_fsub(float %x, float %y) { 722; CHECK-LABEL: @fneg_fsub( 723; CHECK-NEXT: [[NEGX:%.*]] = fneg float [[X:%.*]] 724; CHECK-NEXT: [[SUB:%.*]] = fsub float [[NEGX]], [[Y:%.*]] 725; CHECK-NEXT: ret float [[SUB]] 726; 727 %negx = fneg float %x 728 %sub = fsub float %negx, %y 729 ret float %sub 730} 731 732define float @fneg_fsub_nsz(float %x, float %y) { 733; CHECK-LABEL: @fneg_fsub_nsz( 734; CHECK-NEXT: [[TMP1:%.*]] = fadd nsz float [[X:%.*]], [[Y:%.*]] 735; CHECK-NEXT: [[SUB:%.*]] = fneg nsz float [[TMP1]] 736; CHECK-NEXT: ret float [[SUB]] 737; 738 %negx = fneg float %x 739 %sub = fsub nsz float %negx, %y 740 ret float %sub 741} 742 743define float @fake_fneg_fsub_fast(float %x, float %y) { 744; CHECK-LABEL: @fake_fneg_fsub_fast( 745; CHECK-NEXT: [[TMP1:%.*]] = fadd fast float [[X:%.*]], [[Y:%.*]] 746; CHECK-NEXT: [[SUB:%.*]] = fneg fast float [[TMP1]] 747; CHECK-NEXT: ret float [[SUB]] 748; 749 %negx = fsub float -0.0, %x 750 %sub = fsub fast float %negx, %y 751 ret float %sub 752} 753 754define float @fake_fneg_fsub_fast_extra_use(float %x, float %y) { 755; CHECK-LABEL: @fake_fneg_fsub_fast_extra_use( 756; CHECK-NEXT: [[NEGX:%.*]] = fneg float [[X:%.*]] 757; CHECK-NEXT: call void @use(float [[NEGX]]) 758; CHECK-NEXT: [[SUB:%.*]] = fsub fast float [[NEGX]], [[Y:%.*]] 759; CHECK-NEXT: ret float [[SUB]] 760; 761 %negx = fsub float -0.0, %x 762 call void @use(float %negx) 763 %sub = fsub fast float %negx, %y 764 ret float %sub 765} 766 767define <2 x float> @fake_fneg_fsub_vec(<2 x float> %x, <2 x float> %y) { 768; CHECK-LABEL: @fake_fneg_fsub_vec( 769; CHECK-NEXT: [[TMP1:%.*]] = fadd nsz <2 x float> [[X:%.*]], [[Y:%.*]] 770; CHECK-NEXT: [[SUB:%.*]] = fneg nsz <2 x float> [[TMP1]] 771; CHECK-NEXT: ret <2 x float> [[SUB]] 772; 773 %negx = fsub <2 x float> <float -0.0, float -0.0>, %x 774 %sub = fsub nsz <2 x float> %negx, %y 775 ret <2 x float> %sub 776} 777 778define float @fneg_fsub_constant(float %x) { 779; CHECK-LABEL: @fneg_fsub_constant( 780; CHECK-NEXT: [[SUB:%.*]] = fsub nsz float -4.200000e+01, [[X:%.*]] 781; CHECK-NEXT: ret float [[SUB]] 782; 783 %negx = fneg float %x 784 %sub = fsub nsz float %negx, 42.0 785 ret float %sub 786} 787 788; ((w-x) + y) - z --> (w+y) - (x+z) 789 790define float @fsub_fadd_fsub_reassoc(float %w, float %x, float %y, float %z) { 791; CHECK-LABEL: @fsub_fadd_fsub_reassoc( 792; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz float [[W:%.*]], [[Y:%.*]] 793; CHECK-NEXT: [[TMP2:%.*]] = fadd reassoc nsz float [[X:%.*]], [[Z:%.*]] 794; CHECK-NEXT: [[S2:%.*]] = fsub reassoc nsz float [[TMP1]], [[TMP2]] 795; CHECK-NEXT: ret float [[S2]] 796; 797 %s1 = fsub reassoc nsz float %w, %x 798 %a = fadd reassoc nsz float %s1, %y 799 %s2 = fsub reassoc nsz float %a, %z 800 ret float %s2 801} 802 803; FMF on the last op is enough to do the transform; vectors work too. 804 805define <2 x float> @fsub_fadd_fsub_reassoc_commute(<2 x float> %w, <2 x float> %x, <2 x float> %y, <2 x float> %z) { 806; CHECK-LABEL: @fsub_fadd_fsub_reassoc_commute( 807; CHECK-NEXT: [[D:%.*]] = fdiv <2 x float> [[Y:%.*]], <float 4.200000e+01, float -4.200000e+01> 808; CHECK-NEXT: [[TMP1:%.*]] = fadd fast <2 x float> [[D]], [[W:%.*]] 809; CHECK-NEXT: [[TMP2:%.*]] = fadd fast <2 x float> [[X:%.*]], [[Z:%.*]] 810; CHECK-NEXT: [[S2:%.*]] = fsub fast <2 x float> [[TMP1]], [[TMP2]] 811; CHECK-NEXT: ret <2 x float> [[S2]] 812; 813 %d = fdiv <2 x float> %y, <float 42.0, float -42.0> ; thwart complexity-based canonicalization 814 %s1 = fsub <2 x float> %w, %x 815 %a = fadd <2 x float> %d, %s1 816 %s2 = fsub fast <2 x float> %a, %z 817 ret <2 x float> %s2 818} 819 820; (v-w) + (x-y) - z --> (v+x) - (w+y+z) 821 822define float @fsub_fadd_fsub_reassoc_twice(float %v, float %w, float %x, float %y, float %z) { 823; CHECK-LABEL: @fsub_fadd_fsub_reassoc_twice( 824; CHECK-NEXT: [[TMP1:%.*]] = fadd reassoc nsz float [[W:%.*]], [[Z:%.*]] 825; CHECK-NEXT: [[TMP2:%.*]] = fadd reassoc nsz float [[X:%.*]], [[V:%.*]] 826; CHECK-NEXT: [[TMP3:%.*]] = fadd reassoc nsz float [[TMP1]], [[Y:%.*]] 827; CHECK-NEXT: [[S3:%.*]] = fsub reassoc nsz float [[TMP2]], [[TMP3]] 828; CHECK-NEXT: ret float [[S3]] 829; 830 %s1 = fsub reassoc nsz float %v, %w 831 %s2 = fsub reassoc nsz float %x, %y 832 %a = fadd reassoc nsz float %s1, %s2 833 %s3 = fsub reassoc nsz float %a, %z 834 ret float %s3 835} 836 837; negative test - FMF 838 839define float @fsub_fadd_fsub_not_reassoc(float %w, float %x, float %y, float %z) { 840; CHECK-LABEL: @fsub_fadd_fsub_not_reassoc( 841; CHECK-NEXT: [[S1:%.*]] = fsub fast float [[W:%.*]], [[X:%.*]] 842; CHECK-NEXT: [[A:%.*]] = fadd fast float [[S1]], [[Y:%.*]] 843; CHECK-NEXT: [[S2:%.*]] = fsub nsz float [[A]], [[Z:%.*]] 844; CHECK-NEXT: ret float [[S2]] 845; 846 %s1 = fsub fast float %w, %x 847 %a = fadd fast float %s1, %y 848 %s2 = fsub nsz float %a, %z 849 ret float %s2 850} 851 852; negative test - uses 853 854define float @fsub_fadd_fsub_reassoc_use1(float %w, float %x, float %y, float %z) { 855; CHECK-LABEL: @fsub_fadd_fsub_reassoc_use1( 856; CHECK-NEXT: [[S1:%.*]] = fsub fast float [[W:%.*]], [[X:%.*]] 857; CHECK-NEXT: call void @use(float [[S1]]) 858; CHECK-NEXT: [[A:%.*]] = fadd fast float [[S1]], [[Y:%.*]] 859; CHECK-NEXT: [[S2:%.*]] = fsub fast float [[A]], [[Z:%.*]] 860; CHECK-NEXT: ret float [[S2]] 861; 862 %s1 = fsub fast float %w, %x 863 call void @use(float %s1) 864 %a = fadd fast float %s1, %y 865 %s2 = fsub fast float %a, %z 866 ret float %s2 867} 868 869; negative test - uses 870 871define float @fsub_fadd_fsub_reassoc_use2(float %w, float %x, float %y, float %z) { 872; CHECK-LABEL: @fsub_fadd_fsub_reassoc_use2( 873; CHECK-NEXT: [[S1:%.*]] = fsub fast float [[W:%.*]], [[X:%.*]] 874; CHECK-NEXT: [[A:%.*]] = fadd fast float [[S1]], [[Y:%.*]] 875; CHECK-NEXT: call void @use(float [[A]]) 876; CHECK-NEXT: [[S2:%.*]] = fsub fast float [[A]], [[Z:%.*]] 877; CHECK-NEXT: ret float [[S2]] 878; 879 %s1 = fsub fast float %w, %x 880 %a = fadd fast float %s1, %y 881 call void @use(float %a) 882 %s2 = fsub fast float %a, %z 883 ret float %s2 884} 885