1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -instcombine -S | FileCheck %s 3 4declare void @use(float) 5 6define float @fneg_fneg(float %a) { 7; 8; CHECK-LABEL: @fneg_fneg( 9; CHECK-NEXT: ret float [[A:%.*]] 10; 11 %f = fneg float %a 12 %r = fneg float %f 13 ret float %r 14} 15 16; -(X * C) --> X * (-C) 17 18define float @fmul_fsub(float %x) { 19; CHECK-LABEL: @fmul_fsub( 20; CHECK-NEXT: [[R:%.*]] = fmul float [[X:%.*]], -4.200000e+01 21; CHECK-NEXT: ret float [[R]] 22; 23 %m = fmul float %x, 42.0 24 %r = fsub float -0.0, %m 25 ret float %r 26} 27 28define float @fmul_fneg(float %x) { 29; CHECK-LABEL: @fmul_fneg( 30; CHECK-NEXT: [[R:%.*]] = fmul float [[X:%.*]], -4.200000e+01 31; CHECK-NEXT: ret float [[R]] 32; 33 %m = fmul float %x, 42.0 34 %r = fneg float %m 35 ret float %r 36} 37 38; Fast math is not required, but it should be propagated. 39 40define float @fmul_fsub_fmf(float %x) { 41; CHECK-LABEL: @fmul_fsub_fmf( 42; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], -4.200000e+01 43; CHECK-NEXT: ret float [[R]] 44; 45 %m = fmul float %x, 42.0 46 %r = fsub reassoc nsz float -0.0, %m 47 ret float %r 48} 49 50define float @fmul_fneg_fmf(float %x) { 51; CHECK-LABEL: @fmul_fneg_fmf( 52; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], -4.200000e+01 53; CHECK-NEXT: ret float [[R]] 54; 55 %m = fmul float %x, 42.0 56 %r = fneg reassoc nsz float %m 57 ret float %r 58} 59 60; Extra use prevents the fold. We don't want to replace the fneg with an fmul. 61 62define float @fmul_fsub_extra_use(float %x) { 63; CHECK-LABEL: @fmul_fsub_extra_use( 64; CHECK-NEXT: [[M:%.*]] = fmul float [[X:%.*]], 4.200000e+01 65; CHECK-NEXT: [[R:%.*]] = fneg float [[M]] 66; CHECK-NEXT: call void @use(float [[M]]) 67; CHECK-NEXT: ret float [[R]] 68; 69 %m = fmul float %x, 42.0 70 %r = fsub float -0.0, %m 71 call void @use(float %m) 72 ret float %r 73} 74 75define float @fmul_fneg_extra_use(float %x) { 76; CHECK-LABEL: @fmul_fneg_extra_use( 77; CHECK-NEXT: [[M:%.*]] = fmul float [[X:%.*]], 4.200000e+01 78; CHECK-NEXT: [[R:%.*]] = fneg float [[M]] 79; CHECK-NEXT: call void @use(float [[M]]) 80; CHECK-NEXT: ret float [[R]] 81; 82 %m = fmul float %x, 42.0 83 %r = fneg float %m 84 call void @use(float %m) 85 ret float %r 86} 87 88; Try a vector. Use special constants (NaN, INF, undef) because they don't change anything. 89 90define <4 x double> @fmul_fsub_vec(<4 x double> %x) { 91; CHECK-LABEL: @fmul_fsub_vec( 92; CHECK-NEXT: [[R:%.*]] = fmul <4 x double> [[X:%.*]], <double -4.200000e+01, double 0xFFF8000000000000, double 0xFFF0000000000000, double undef> 93; CHECK-NEXT: ret <4 x double> [[R]] 94; 95 %m = fmul <4 x double> %x, <double 42.0, double 0x7FF8000000000000, double 0x7FF0000000000000, double undef> 96 %r = fsub <4 x double> <double -0.0, double -0.0, double -0.0, double -0.0>, %m 97 ret <4 x double> %r 98} 99 100define <4 x double> @fmul_fneg_vec(<4 x double> %x) { 101; CHECK-LABEL: @fmul_fneg_vec( 102; CHECK-NEXT: [[R:%.*]] = fmul <4 x double> [[X:%.*]], <double -4.200000e+01, double 0xFFF8000000000000, double 0xFFF0000000000000, double undef> 103; CHECK-NEXT: ret <4 x double> [[R]] 104; 105 %m = fmul <4 x double> %x, <double 42.0, double 0x7FF8000000000000, double 0x7FF0000000000000, double undef> 106 %r = fneg <4 x double> %m 107 ret <4 x double> %r 108} 109 110; -(X / C) --> X / (-C) 111 112define float @fdiv_op1_constant_fsub(float %x) { 113; CHECK-LABEL: @fdiv_op1_constant_fsub( 114; CHECK-NEXT: [[R:%.*]] = fdiv float [[X:%.*]], 4.200000e+01 115; CHECK-NEXT: ret float [[R]] 116; 117 %d = fdiv float %x, -42.0 118 %r = fsub float -0.0, %d 119 ret float %r 120} 121 122define float @fdiv_op1_constant_fneg(float %x) { 123; CHECK-LABEL: @fdiv_op1_constant_fneg( 124; CHECK-NEXT: [[R:%.*]] = fdiv float [[X:%.*]], 4.200000e+01 125; CHECK-NEXT: ret float [[R]] 126; 127 %d = fdiv float %x, -42.0 128 %r = fneg float %d 129 ret float %r 130} 131 132; Fast math is not required, but it should be propagated. 133 134define float @fdiv_op1_constant_fsub_fmf(float %x) { 135; CHECK-LABEL: @fdiv_op1_constant_fsub_fmf( 136; CHECK-NEXT: [[R:%.*]] = fdiv nnan float [[X:%.*]], 4.200000e+01 137; CHECK-NEXT: ret float [[R]] 138; 139 %d = fdiv float %x, -42.0 140 %r = fsub nnan float -0.0, %d 141 ret float %r 142} 143 144define float @fdiv_op1_constant_fneg_fmf(float %x) { 145; CHECK-LABEL: @fdiv_op1_constant_fneg_fmf( 146; CHECK-NEXT: [[R:%.*]] = fdiv nnan float [[X:%.*]], 4.200000e+01 147; CHECK-NEXT: ret float [[R]] 148; 149 %d = fdiv float %x, -42.0 150 %r = fneg nnan float %d 151 ret float %r 152} 153 154; Extra use prevents the fold. We don't want to replace the fneg with an fdiv. 155 156define float @fdiv_op1_constant_fsub_extra_use(float %x) { 157; CHECK-LABEL: @fdiv_op1_constant_fsub_extra_use( 158; CHECK-NEXT: [[D:%.*]] = fdiv float [[X:%.*]], 4.200000e+01 159; CHECK-NEXT: [[R:%.*]] = fneg float [[D]] 160; CHECK-NEXT: call void @use(float [[D]]) 161; CHECK-NEXT: ret float [[R]] 162; 163 %d = fdiv float %x, 42.0 164 %r = fsub float -0.0, %d 165 call void @use(float %d) 166 ret float %r 167} 168 169define float @fdiv_op1_constant_fneg_extra_use(float %x) { 170; CHECK-LABEL: @fdiv_op1_constant_fneg_extra_use( 171; CHECK-NEXT: [[D:%.*]] = fdiv float [[X:%.*]], 4.200000e+01 172; CHECK-NEXT: [[R:%.*]] = fneg float [[D]] 173; CHECK-NEXT: call void @use(float [[D]]) 174; CHECK-NEXT: ret float [[R]] 175; 176 %d = fdiv float %x, 42.0 177 %r = fneg float %d 178 call void @use(float %d) 179 ret float %r 180} 181 182; Try a vector. Use special constants (NaN, INF, undef) because they don't change anything. 183 184define <4 x double> @fdiv_op1_constant_fsub_vec(<4 x double> %x) { 185; CHECK-LABEL: @fdiv_op1_constant_fsub_vec( 186; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> [[X:%.*]], <double 4.200000e+01, double 0x7FF800000ABCD000, double 0x7FF0000000000000, double undef> 187; CHECK-NEXT: ret <4 x double> [[R]] 188; 189 %d = fdiv <4 x double> %x, <double -42.0, double 0xFFF800000ABCD000, double 0xFFF0000000000000, double undef> 190 %r = fsub <4 x double> <double -0.0, double -0.0, double -0.0, double -0.0>, %d 191 ret <4 x double> %r 192} 193 194define <4 x double> @fdiv_op1_constant_fneg_vec(<4 x double> %x) { 195; CHECK-LABEL: @fdiv_op1_constant_fneg_vec( 196; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> [[X:%.*]], <double 4.200000e+01, double 0x7FF800000ABCD000, double 0x7FF0000000000000, double undef> 197; CHECK-NEXT: ret <4 x double> [[R]] 198; 199 %d = fdiv <4 x double> %x, <double -42.0, double 0xFFF800000ABCD000, double 0xFFF0000000000000, double undef> 200 %r = fneg <4 x double> %d 201 ret <4 x double> %r 202} 203 204; -(C / X) --> (-C) / X 205 206define float @fdiv_op0_constant_fsub(float %x) { 207; CHECK-LABEL: @fdiv_op0_constant_fsub( 208; CHECK-NEXT: [[R:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] 209; CHECK-NEXT: ret float [[R]] 210; 211 %d = fdiv float 42.0, %x 212 %r = fsub float -0.0, %d 213 ret float %r 214} 215 216define float @fdiv_op0_constant_fneg(float %x) { 217; CHECK-LABEL: @fdiv_op0_constant_fneg( 218; CHECK-NEXT: [[R:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] 219; CHECK-NEXT: ret float [[R]] 220; 221 %d = fdiv float 42.0, %x 222 %r = fneg float %d 223 ret float %r 224} 225 226; Fast math is not required, but it should be propagated. 227 228define float @fdiv_op0_constant_fsub_fmf(float %x) { 229; CHECK-LABEL: @fdiv_op0_constant_fsub_fmf( 230; CHECK-NEXT: [[R:%.*]] = fdiv fast float -4.200000e+01, [[X:%.*]] 231; CHECK-NEXT: ret float [[R]] 232; 233 %d = fdiv float 42.0, %x 234 %r = fsub fast float -0.0, %d 235 ret float %r 236} 237 238define float @fdiv_op0_constant_fneg_fmf(float %x) { 239; CHECK-LABEL: @fdiv_op0_constant_fneg_fmf( 240; CHECK-NEXT: [[R:%.*]] = fdiv fast float -4.200000e+01, [[X:%.*]] 241; CHECK-NEXT: ret float [[R]] 242; 243 %d = fdiv float 42.0, %x 244 %r = fneg fast float %d 245 ret float %r 246} 247 248; Extra use prevents the fold. We don't want to replace the fneg with an fdiv. 249 250define float @fdiv_op0_constant_fsub_extra_use(float %x) { 251; CHECK-LABEL: @fdiv_op0_constant_fsub_extra_use( 252; CHECK-NEXT: [[D:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] 253; CHECK-NEXT: [[R:%.*]] = fneg float [[D]] 254; CHECK-NEXT: call void @use(float [[D]]) 255; CHECK-NEXT: ret float [[R]] 256; 257 %d = fdiv float -42.0, %x 258 %r = fsub float -0.0, %d 259 call void @use(float %d) 260 ret float %r 261} 262 263define float @fdiv_op0_constant_fneg_extra_use(float %x) { 264; CHECK-LABEL: @fdiv_op0_constant_fneg_extra_use( 265; CHECK-NEXT: [[D:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] 266; CHECK-NEXT: [[R:%.*]] = fneg float [[D]] 267; CHECK-NEXT: call void @use(float [[D]]) 268; CHECK-NEXT: ret float [[R]] 269; 270 %d = fdiv float -42.0, %x 271 %r = fneg float %d 272 call void @use(float %d) 273 ret float %r 274} 275 276; Try a vector. Use special constants (NaN, INF, undef) because they don't change anything. 277 278define <4 x double> @fdiv_op0_constant_fsub_vec(<4 x double> %x) { 279; CHECK-LABEL: @fdiv_op0_constant_fsub_vec( 280; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> <double 4.200000e+01, double 0xFFF8000000000000, double 0x7FF0000000000000, double undef>, [[X:%.*]] 281; CHECK-NEXT: ret <4 x double> [[R]] 282; 283 %d = fdiv <4 x double> <double -42.0, double 0x7FF8000000000000, double 0xFFF0000000000000, double undef>, %x 284 %r = fsub <4 x double> <double -0.0, double -0.0, double -0.0, double -0.0>, %d 285 ret <4 x double> %r 286} 287 288define <4 x double> @fdiv_op0_constant_fneg_vec(<4 x double> %x) { 289; CHECK-LABEL: @fdiv_op0_constant_fneg_vec( 290; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> <double 4.200000e+01, double 0xFFF8000000000000, double 0x7FF0000000000000, double undef>, [[X:%.*]] 291; CHECK-NEXT: ret <4 x double> [[R]] 292; 293 %d = fdiv <4 x double> <double -42.0, double 0x7FF8000000000000, double 0xFFF0000000000000, double undef>, %x 294 %r = fneg <4 x double> %d 295 ret <4 x double> %r 296} 297 298; Sink FP negation through a select: 299; c ? -x : -y --> -(c ? x : y) 300 301define <2 x double> @fneg_fneg_sel(<2 x double> %x, <2 x double> %y, i1 %cond) { 302; CHECK-LABEL: @fneg_fneg_sel( 303; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], <2 x double> [[X:%.*]], <2 x double> [[Y:%.*]] 304; CHECK-NEXT: [[SEL:%.*]] = fneg <2 x double> [[SEL_V]] 305; CHECK-NEXT: ret <2 x double> [[SEL]] 306; 307 %n1 = fneg <2 x double> %x 308 %n2 = fneg <2 x double> %y 309 %sel = select i1 %cond, <2 x double> %n1, <2 x double> %n2 310 ret <2 x double> %sel 311} 312 313; An extra use is allowed. 314 315define float @fneg_fneg_sel_extra_use1(float %x, float %y, i1 %cond) { 316; CHECK-LABEL: @fneg_fneg_sel_extra_use1( 317; CHECK-NEXT: [[N1:%.*]] = fneg float [[X:%.*]] 318; CHECK-NEXT: call void @use(float [[N1]]) 319; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], float [[X]], float [[Y:%.*]] 320; CHECK-NEXT: [[SEL:%.*]] = fneg float [[SEL_V]] 321; CHECK-NEXT: ret float [[SEL]] 322; 323 %n1 = fneg float %x 324 call void @use(float %n1) 325 %n2 = fneg float %y 326 %sel = select i1 %cond, float %n1, float %n2 327 ret float %sel 328} 329 330define float @fneg_fneg_sel_extra_use2(float %x, float %y, i1 %cond) { 331; CHECK-LABEL: @fneg_fneg_sel_extra_use2( 332; CHECK-NEXT: [[N2:%.*]] = fneg float [[Y:%.*]] 333; CHECK-NEXT: call void @use(float [[N2]]) 334; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], float [[X:%.*]], float [[Y]] 335; CHECK-NEXT: [[SEL:%.*]] = fneg float [[SEL_V]] 336; CHECK-NEXT: ret float [[SEL]] 337; 338 %n1 = fneg float %x 339 %n2 = fneg float %y 340 call void @use(float %n2) 341 %sel = select i1 %cond, float %n1, float %n2 342 ret float %sel 343} 344 345; Legacy form of fneg should work too. 346 347define float @fsub_fsub_sel_extra_use1(float %x, float %y, i1 %cond) { 348; CHECK-LABEL: @fsub_fsub_sel_extra_use1( 349; CHECK-NEXT: [[N1:%.*]] = fneg float [[X:%.*]] 350; CHECK-NEXT: call void @use(float [[N1]]) 351; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], float [[X]], float [[Y:%.*]] 352; CHECK-NEXT: [[SEL:%.*]] = fneg float [[SEL_V]] 353; CHECK-NEXT: ret float [[SEL]] 354; 355 %n1 = fsub float -0.0, %x 356 call void @use(float %n1) 357 %n2 = fsub float -0.0, %y 358 %sel = select i1 %cond, float %n1, float %n2 359 ret float %sel 360} 361 362; Negative test: but 2 extra uses would require an extra instruction. 363 364define float @fneg_fneg_sel_extra_use3(float %x, float %y, i1 %cond) { 365; CHECK-LABEL: @fneg_fneg_sel_extra_use3( 366; CHECK-NEXT: [[N1:%.*]] = fneg float [[X:%.*]] 367; CHECK-NEXT: call void @use(float [[N1]]) 368; CHECK-NEXT: [[N2:%.*]] = fneg float [[Y:%.*]] 369; CHECK-NEXT: call void @use(float [[N2]]) 370; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], float [[N1]], float [[N2]] 371; CHECK-NEXT: ret float [[SEL]] 372; 373 %n1 = fneg float %x 374 call void @use(float %n1) 375 %n2 = fneg float %y 376 call void @use(float %n2) 377 %sel = select i1 %cond, float %n1, float %n2 378 ret float %sel 379} 380 381; Negative test 382 383define float @fneg_fadd_constant(float %x) { 384; CHECK-LABEL: @fneg_fadd_constant( 385; CHECK-NEXT: [[A:%.*]] = fadd float [[X:%.*]], 4.200000e+01 386; CHECK-NEXT: [[R:%.*]] = fneg float [[A]] 387; CHECK-NEXT: ret float [[R]] 388; 389 %a = fadd float %x, 42.0 390 %r = fneg float %a 391 ret float %r 392} 393 394; Negative test 395 396define float @fake_nsz_fadd_constant(float %x) { 397; CHECK-LABEL: @fake_nsz_fadd_constant( 398; CHECK-NEXT: [[A:%.*]] = fadd float [[X:%.*]], 4.200000e+01 399; CHECK-NEXT: [[R:%.*]] = fneg float [[A]] 400; CHECK-NEXT: ret float [[R]] 401; 402 %a = fadd float %x, 42.0 403 %r = fsub float -0.0, %a 404 ret float %r 405} 406 407; -(X + C) --> -C - X 408 409define float @fneg_nsz_fadd_constant(float %x) { 410; CHECK-LABEL: @fneg_nsz_fadd_constant( 411; CHECK-NEXT: [[R:%.*]] = fsub nsz float -4.200000e+01, [[X:%.*]] 412; CHECK-NEXT: ret float [[R]] 413; 414 %a = fadd float %x, 42.0 415 %r = fneg nsz float %a 416 ret float %r 417} 418 419; -(X + C) --> -C - X 420 421define float @fake_fneg_nsz_fadd_constant(float %x) { 422; CHECK-LABEL: @fake_fneg_nsz_fadd_constant( 423; CHECK-NEXT: [[R:%.*]] = fsub fast float -4.200000e+01, [[X:%.*]] 424; CHECK-NEXT: ret float [[R]] 425; 426 %a = fadd float %x, 42.0 427 %r = fsub fast float -0.0, %a 428 ret float %r 429} 430 431; Negative test 432 433define float @fneg_nsz_fadd_constant_extra_use(float %x) { 434; CHECK-LABEL: @fneg_nsz_fadd_constant_extra_use( 435; CHECK-NEXT: [[A:%.*]] = fadd float [[X:%.*]], 4.200000e+01 436; CHECK-NEXT: call void @use(float [[A]]) 437; CHECK-NEXT: [[R:%.*]] = fneg nsz float [[A]] 438; CHECK-NEXT: ret float [[R]] 439; 440 %a = fadd float %x, 42.0 441 call void @use(float %a) 442 %r = fneg nsz float %a 443 ret float %r 444} 445 446; Negative test 447 448define float @fake_fneg_nsz_fadd_constant_extra_use(float %x) { 449; CHECK-LABEL: @fake_fneg_nsz_fadd_constant_extra_use( 450; CHECK-NEXT: [[A:%.*]] = fadd float [[X:%.*]], 4.200000e+01 451; CHECK-NEXT: call void @use(float [[A]]) 452; CHECK-NEXT: [[R:%.*]] = fneg fast float [[A]] 453; CHECK-NEXT: ret float [[R]] 454; 455 %a = fadd float %x, 42.0 456 call void @use(float %a) 457 %r = fsub fast float -0.0, %a 458 ret float %r 459} 460 461; -(X + C) --> -C - X 462 463define <2 x float> @fneg_nsz_fadd_constant_vec(<2 x float> %x) { 464; CHECK-LABEL: @fneg_nsz_fadd_constant_vec( 465; CHECK-NEXT: [[R:%.*]] = fsub reassoc nnan nsz <2 x float> <float -4.200000e+01, float -4.300000e+01>, [[X:%.*]] 466; CHECK-NEXT: ret <2 x float> [[R]] 467; 468 %a = fadd <2 x float> %x, <float 42.0, float 43.0> 469 %r = fneg nsz nnan reassoc <2 x float> %a 470 ret <2 x float> %r 471} 472 473; -(X + C) --> -C - X 474 475define <2 x float> @fake_fneg_nsz_fadd_constant_vec(<2 x float> %x) { 476; CHECK-LABEL: @fake_fneg_nsz_fadd_constant_vec( 477; CHECK-NEXT: [[R:%.*]] = fsub nsz <2 x float> <float -4.200000e+01, float undef>, [[X:%.*]] 478; CHECK-NEXT: ret <2 x float> [[R]] 479; 480 %a = fadd <2 x float> %x, <float 42.0, float undef> 481 %r = fsub nsz <2 x float> <float undef, float -0.0>, %a 482 ret <2 x float> %r 483} 484 485@g = external global i16, align 1 486 487define float @fneg_nsz_fadd_constant_expr(float %x) { 488; CHECK-LABEL: @fneg_nsz_fadd_constant_expr( 489; CHECK-NEXT: [[R:%.*]] = fsub nsz float fneg (float bitcast (i32 ptrtoint (i16* @g to i32) to float)), [[X:%.*]] 490; CHECK-NEXT: ret float [[R]] 491; 492 %a = fadd float %x, bitcast (i32 ptrtoint (i16* @g to i32) to float) 493 %r = fneg nsz float %a 494 ret float %r 495} 496 497define float @fake_fneg_nsz_fadd_constant_expr(float %x) { 498; CHECK-LABEL: @fake_fneg_nsz_fadd_constant_expr( 499; CHECK-NEXT: [[R:%.*]] = fsub nsz float fneg (float bitcast (i32 ptrtoint (i16* @g to i32) to float)), [[X:%.*]] 500; CHECK-NEXT: ret float [[R]] 501; 502 %a = fadd float %x, bitcast (i32 ptrtoint (i16* @g to i32) to float) 503 %r = fsub nsz float -0.0, %a 504 ret float %r 505} 506