1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=instcombine -S | FileCheck %s 3; RUN: opt < %s -passes=instcombine -use-constant-fp-for-fixed-length-splat -S | FileCheck %s 4 5declare float @llvm.ldexp.f32.i32(float, i32) 6declare <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float>, <2 x i32>) 7declare void @use(float) 8 9define float @fneg_fneg(float %a) { 10; 11; CHECK-LABEL: @fneg_fneg( 12; CHECK-NEXT: ret float [[A:%.*]] 13; 14 %f = fneg float %a 15 %r = fneg float %f 16 ret float %r 17} 18 19; -(X * C) --> X * (-C) 20 21define float @fmul_fsub(float %x) { 22; CHECK-LABEL: @fmul_fsub( 23; CHECK-NEXT: [[R:%.*]] = fmul float [[X:%.*]], -4.200000e+01 24; CHECK-NEXT: ret float [[R]] 25; 26 %m = fmul float %x, 42.0 27 %r = fsub float -0.0, %m 28 ret float %r 29} 30 31define float @fmul_fneg(float %x) { 32; CHECK-LABEL: @fmul_fneg( 33; CHECK-NEXT: [[R:%.*]] = fmul float [[X:%.*]], -4.200000e+01 34; CHECK-NEXT: ret float [[R]] 35; 36 %m = fmul float %x, 42.0 37 %r = fneg float %m 38 ret float %r 39} 40 41; Fast math is not required, but it should be propagated. 42 43define float @fmul_fsub_fmf(float %x) { 44; CHECK-LABEL: @fmul_fsub_fmf( 45; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], -4.200000e+01 46; CHECK-NEXT: ret float [[R]] 47; 48 %m = fmul float %x, 42.0 49 %r = fsub reassoc nsz float -0.0, %m 50 ret float %r 51} 52 53define float @fmul_fneg_fmf(float %x) { 54; CHECK-LABEL: @fmul_fneg_fmf( 55; CHECK-NEXT: [[R:%.*]] = fmul reassoc nsz float [[X:%.*]], -4.200000e+01 56; CHECK-NEXT: ret float [[R]] 57; 58 %m = fmul float %x, 42.0 59 %r = fneg reassoc nsz float %m 60 ret float %r 61} 62 63; Extra use prevents the fold. We don't want to replace the fneg with an fmul. 64 65define float @fmul_fsub_extra_use(float %x) { 66; CHECK-LABEL: @fmul_fsub_extra_use( 67; CHECK-NEXT: [[M:%.*]] = fmul float [[X:%.*]], 4.200000e+01 68; CHECK-NEXT: [[R:%.*]] = fneg float [[M]] 69; CHECK-NEXT: call void @use(float [[M]]) 70; CHECK-NEXT: ret float [[R]] 71; 72 %m = fmul float %x, 42.0 73 %r = fsub float -0.0, %m 74 call void @use(float %m) 75 ret float %r 76} 77 78define float @fmul_fneg_extra_use(float %x) { 79; CHECK-LABEL: @fmul_fneg_extra_use( 80; CHECK-NEXT: [[M:%.*]] = fmul float [[X:%.*]], 4.200000e+01 81; CHECK-NEXT: [[R:%.*]] = fneg float [[M]] 82; CHECK-NEXT: call void @use(float [[M]]) 83; CHECK-NEXT: ret float [[R]] 84; 85 %m = fmul float %x, 42.0 86 %r = fneg float %m 87 call void @use(float %m) 88 ret float %r 89} 90 91; Try a vector. Use special constants (NaN, INF, poison) because they don't change anything. 92 93define <4 x double> @fmul_fsub_vec(<4 x double> %x) { 94; CHECK-LABEL: @fmul_fsub_vec( 95; CHECK-NEXT: [[R:%.*]] = fmul <4 x double> [[X:%.*]], <double -4.200000e+01, double 0xFFF8000000000000, double 0xFFF0000000000000, double poison> 96; CHECK-NEXT: ret <4 x double> [[R]] 97; 98 %m = fmul <4 x double> %x, <double 42.0, double 0x7FF8000000000000, double 0x7FF0000000000000, double poison> 99 %r = fsub <4 x double> <double -0.0, double -0.0, double -0.0, double -0.0>, %m 100 ret <4 x double> %r 101} 102 103define <4 x double> @fmul_fneg_vec(<4 x double> %x) { 104; CHECK-LABEL: @fmul_fneg_vec( 105; CHECK-NEXT: [[R:%.*]] = fmul <4 x double> [[X:%.*]], <double -4.200000e+01, double 0xFFF8000000000000, double 0xFFF0000000000000, double poison> 106; CHECK-NEXT: ret <4 x double> [[R]] 107; 108 %m = fmul <4 x double> %x, <double 42.0, double 0x7FF8000000000000, double 0x7FF0000000000000, double poison> 109 %r = fneg <4 x double> %m 110 ret <4 x double> %r 111} 112 113; -(X / C) --> X / (-C) 114 115define float @fdiv_op1_constant_fsub(float %x) { 116; CHECK-LABEL: @fdiv_op1_constant_fsub( 117; CHECK-NEXT: [[R:%.*]] = fdiv float [[X:%.*]], 4.200000e+01 118; CHECK-NEXT: ret float [[R]] 119; 120 %d = fdiv float %x, -42.0 121 %r = fsub float -0.0, %d 122 ret float %r 123} 124 125define float @fdiv_op1_constant_fneg(float %x) { 126; CHECK-LABEL: @fdiv_op1_constant_fneg( 127; CHECK-NEXT: [[R:%.*]] = fdiv float [[X:%.*]], 4.200000e+01 128; CHECK-NEXT: ret float [[R]] 129; 130 %d = fdiv float %x, -42.0 131 %r = fneg float %d 132 ret float %r 133} 134 135; Fast math is not required, but it should be propagated. 136 137define float @fdiv_op1_constant_fsub_fmf(float %x) { 138; CHECK-LABEL: @fdiv_op1_constant_fsub_fmf( 139; CHECK-NEXT: [[R:%.*]] = fdiv nnan float [[X:%.*]], 4.200000e+01 140; CHECK-NEXT: ret float [[R]] 141; 142 %d = fdiv float %x, -42.0 143 %r = fsub nnan float -0.0, %d 144 ret float %r 145} 146 147define float @fdiv_op1_constant_fneg_fmf(float %x) { 148; CHECK-LABEL: @fdiv_op1_constant_fneg_fmf( 149; CHECK-NEXT: [[R:%.*]] = fdiv nnan float [[X:%.*]], 4.200000e+01 150; CHECK-NEXT: ret float [[R]] 151; 152 %d = fdiv float %x, -42.0 153 %r = fneg nnan float %d 154 ret float %r 155} 156 157; Extra use prevents the fold. We don't want to replace the fneg with an fdiv. 158 159define float @fdiv_op1_constant_fsub_extra_use(float %x) { 160; CHECK-LABEL: @fdiv_op1_constant_fsub_extra_use( 161; CHECK-NEXT: [[D:%.*]] = fdiv float [[X:%.*]], 4.200000e+01 162; CHECK-NEXT: [[R:%.*]] = fneg float [[D]] 163; CHECK-NEXT: call void @use(float [[D]]) 164; CHECK-NEXT: ret float [[R]] 165; 166 %d = fdiv float %x, 42.0 167 %r = fsub float -0.0, %d 168 call void @use(float %d) 169 ret float %r 170} 171 172define float @fdiv_op1_constant_fneg_extra_use(float %x) { 173; CHECK-LABEL: @fdiv_op1_constant_fneg_extra_use( 174; CHECK-NEXT: [[D:%.*]] = fdiv float [[X:%.*]], 4.200000e+01 175; CHECK-NEXT: [[R:%.*]] = fneg float [[D]] 176; CHECK-NEXT: call void @use(float [[D]]) 177; CHECK-NEXT: ret float [[R]] 178; 179 %d = fdiv float %x, 42.0 180 %r = fneg float %d 181 call void @use(float %d) 182 ret float %r 183} 184 185; Try a vector. Use special constants (NaN, INF, poison) because they don't change anything. 186 187define <4 x double> @fdiv_op1_constant_fsub_vec(<4 x double> %x) { 188; CHECK-LABEL: @fdiv_op1_constant_fsub_vec( 189; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> [[X:%.*]], <double 4.200000e+01, double 0x7FF800000ABCD000, double 0x7FF0000000000000, double poison> 190; CHECK-NEXT: ret <4 x double> [[R]] 191; 192 %d = fdiv <4 x double> %x, <double -42.0, double 0xFFF800000ABCD000, double 0xFFF0000000000000, double poison> 193 %r = fsub <4 x double> <double -0.0, double -0.0, double -0.0, double -0.0>, %d 194 ret <4 x double> %r 195} 196 197define <4 x double> @fdiv_op1_constant_fneg_vec(<4 x double> %x) { 198; CHECK-LABEL: @fdiv_op1_constant_fneg_vec( 199; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> [[X:%.*]], <double 4.200000e+01, double 0x7FF800000ABCD000, double 0x7FF0000000000000, double poison> 200; CHECK-NEXT: ret <4 x double> [[R]] 201; 202 %d = fdiv <4 x double> %x, <double -42.0, double 0xFFF800000ABCD000, double 0xFFF0000000000000, double poison> 203 %r = fneg <4 x double> %d 204 ret <4 x double> %r 205} 206 207; -(C / X) --> (-C) / X 208 209define float @fdiv_op0_constant_fsub(float %x) { 210; CHECK-LABEL: @fdiv_op0_constant_fsub( 211; CHECK-NEXT: [[R:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] 212; CHECK-NEXT: ret float [[R]] 213; 214 %d = fdiv float 42.0, %x 215 %r = fsub float -0.0, %d 216 ret float %r 217} 218 219define float @fdiv_op0_constant_fneg(float %x) { 220; CHECK-LABEL: @fdiv_op0_constant_fneg( 221; CHECK-NEXT: [[R:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] 222; CHECK-NEXT: ret float [[R]] 223; 224 %d = fdiv float 42.0, %x 225 %r = fneg float %d 226 ret float %r 227} 228 229; Fast math is not required, but it should be propagated. 230 231define float @fdiv_op0_constant_fneg_fast_fast(float %x) { 232; CHECK-LABEL: @fdiv_op0_constant_fneg_fast_fast( 233; CHECK-NEXT: [[R:%.*]] = fdiv fast float -4.200000e+01, [[X:%.*]] 234; CHECK-NEXT: ret float [[R]] 235; 236 %d = fdiv fast float 42.0, %x 237 %r = fneg fast float %d 238 ret float %r 239} 240 241define float @fdiv_op0_constant_fneg_fast(float %x) { 242; CHECK-LABEL: @fdiv_op0_constant_fneg_fast( 243; CHECK-NEXT: [[R:%.*]] = fdiv reassoc nnan arcp contract afn float -4.200000e+01, [[X:%.*]] 244; CHECK-NEXT: ret float [[R]] 245; 246 %d = fdiv float 42.0, %x 247 %r = fneg fast float %d 248 ret float %r 249} 250 251define float @fdiv_op0_constant_fneg_nsz_nsz(float %x) { 252; CHECK-LABEL: @fdiv_op0_constant_fneg_nsz_nsz( 253; CHECK-NEXT: [[R:%.*]] = fdiv nsz float -4.200000e+01, [[X:%.*]] 254; CHECK-NEXT: ret float [[R]] 255; 256 %d = fdiv nsz float 42.0, %x 257 %r = fneg nsz float %d 258 ret float %r 259} 260 261define float @fdiv_op0_constant_fneg_nsz(float %x) { 262; CHECK-LABEL: @fdiv_op0_constant_fneg_nsz( 263; CHECK-NEXT: [[R:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] 264; CHECK-NEXT: ret float [[R]] 265; 266 %d = fdiv float 42.0, %x 267 %r = fneg nsz float %d 268 ret float %r 269} 270 271define float @fdiv_op0_constant_fneg_ninf_ninf(float %x) { 272; CHECK-LABEL: @fdiv_op0_constant_fneg_ninf_ninf( 273; CHECK-NEXT: [[R:%.*]] = fdiv ninf float -4.200000e+01, [[X:%.*]] 274; CHECK-NEXT: ret float [[R]] 275; 276 %d = fdiv ninf float 42.0, %x 277 %r = fneg ninf float %d 278 ret float %r 279} 280 281define float @fdiv_op0_constant_fneg_ninf(float %x) { 282; CHECK-LABEL: @fdiv_op0_constant_fneg_ninf( 283; CHECK-NEXT: [[R:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] 284; CHECK-NEXT: ret float [[R]] 285; 286 %d = fdiv float 42.0, %x 287 %r = fneg ninf float %d 288 ret float %r 289} 290 291define float @fdiv_op0_constant_fneg_nnan_nnan(float %x) { 292; CHECK-LABEL: @fdiv_op0_constant_fneg_nnan_nnan( 293; CHECK-NEXT: [[R:%.*]] = fdiv nnan float -4.200000e+01, [[X:%.*]] 294; CHECK-NEXT: ret float [[R]] 295; 296 %d = fdiv nnan float 42.0, %x 297 %r = fneg nnan float %d 298 ret float %r 299} 300 301define float @fdiv_op0_constant_fneg_nnan(float %x) { 302; CHECK-LABEL: @fdiv_op0_constant_fneg_nnan( 303; CHECK-NEXT: [[R:%.*]] = fdiv nnan float -4.200000e+01, [[X:%.*]] 304; CHECK-NEXT: ret float [[R]] 305; 306 %d = fdiv float 42.0, %x 307 %r = fneg nnan float %d 308 ret float %r 309} 310 311; Extra use prevents the fold. We don't want to replace the fneg with an fdiv. 312 313define float @fdiv_op0_constant_fsub_extra_use(float %x) { 314; CHECK-LABEL: @fdiv_op0_constant_fsub_extra_use( 315; CHECK-NEXT: [[D:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] 316; CHECK-NEXT: [[R:%.*]] = fneg float [[D]] 317; CHECK-NEXT: call void @use(float [[D]]) 318; CHECK-NEXT: ret float [[R]] 319; 320 %d = fdiv float -42.0, %x 321 %r = fsub float -0.0, %d 322 call void @use(float %d) 323 ret float %r 324} 325 326define float @fdiv_op0_constant_fneg_extra_use(float %x) { 327; CHECK-LABEL: @fdiv_op0_constant_fneg_extra_use( 328; CHECK-NEXT: [[D:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] 329; CHECK-NEXT: [[R:%.*]] = fneg float [[D]] 330; CHECK-NEXT: call void @use(float [[D]]) 331; CHECK-NEXT: ret float [[R]] 332; 333 %d = fdiv float -42.0, %x 334 %r = fneg float %d 335 call void @use(float %d) 336 ret float %r 337} 338 339; Try a vector. Use special constants (NaN, INF, poison) because they don't change anything. 340 341define <4 x double> @fdiv_op0_constant_fsub_vec(<4 x double> %x) { 342; CHECK-LABEL: @fdiv_op0_constant_fsub_vec( 343; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> <double 4.200000e+01, double 0xFFF8000000000000, double 0x7FF0000000000000, double poison>, [[X:%.*]] 344; CHECK-NEXT: ret <4 x double> [[R]] 345; 346 %d = fdiv <4 x double> <double -42.0, double 0x7FF8000000000000, double 0xFFF0000000000000, double poison>, %x 347 %r = fsub <4 x double> <double -0.0, double -0.0, double -0.0, double -0.0>, %d 348 ret <4 x double> %r 349} 350 351define <4 x double> @fdiv_op0_constant_fneg_vec(<4 x double> %x) { 352; CHECK-LABEL: @fdiv_op0_constant_fneg_vec( 353; CHECK-NEXT: [[R:%.*]] = fdiv <4 x double> <double 4.200000e+01, double 0xFFF8000000000000, double 0x7FF0000000000000, double poison>, [[X:%.*]] 354; CHECK-NEXT: ret <4 x double> [[R]] 355; 356 %d = fdiv <4 x double> <double -42.0, double 0x7FF8000000000000, double 0xFFF0000000000000, double poison>, %x 357 %r = fneg <4 x double> %d 358 ret <4 x double> %r 359} 360 361; Sink FP negation through a select: 362; c ? -x : -y --> -(c ? x : y) 363 364define <2 x double> @fneg_fneg_sel(<2 x double> %x, <2 x double> %y, i1 %cond) { 365; CHECK-LABEL: @fneg_fneg_sel( 366; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], <2 x double> [[X:%.*]], <2 x double> [[Y:%.*]] 367; CHECK-NEXT: [[SEL:%.*]] = fneg <2 x double> [[SEL_V]] 368; CHECK-NEXT: ret <2 x double> [[SEL]] 369; 370 %n1 = fneg <2 x double> %x 371 %n2 = fneg <2 x double> %y 372 %sel = select i1 %cond, <2 x double> %n1, <2 x double> %n2 373 ret <2 x double> %sel 374} 375 376; An extra use is allowed. 377 378define float @fneg_fneg_sel_extra_use1(float %x, float %y, i1 %cond) { 379; CHECK-LABEL: @fneg_fneg_sel_extra_use1( 380; CHECK-NEXT: [[N1:%.*]] = fneg float [[X:%.*]] 381; CHECK-NEXT: call void @use(float [[N1]]) 382; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], float [[X]], float [[Y:%.*]] 383; CHECK-NEXT: [[SEL:%.*]] = fneg float [[SEL_V]] 384; CHECK-NEXT: ret float [[SEL]] 385; 386 %n1 = fneg float %x 387 call void @use(float %n1) 388 %n2 = fneg float %y 389 %sel = select i1 %cond, float %n1, float %n2 390 ret float %sel 391} 392 393define float @fneg_fneg_sel_extra_use2(float %x, float %y, i1 %cond) { 394; CHECK-LABEL: @fneg_fneg_sel_extra_use2( 395; CHECK-NEXT: [[N2:%.*]] = fneg float [[Y:%.*]] 396; CHECK-NEXT: call void @use(float [[N2]]) 397; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], float [[X:%.*]], float [[Y]] 398; CHECK-NEXT: [[SEL:%.*]] = fneg float [[SEL_V]] 399; CHECK-NEXT: ret float [[SEL]] 400; 401 %n1 = fneg float %x 402 %n2 = fneg float %y 403 call void @use(float %n2) 404 %sel = select i1 %cond, float %n1, float %n2 405 ret float %sel 406} 407 408; Legacy form of fneg should work too. 409 410define float @fsub_fsub_sel_extra_use1(float %x, float %y, i1 %cond) { 411; CHECK-LABEL: @fsub_fsub_sel_extra_use1( 412; CHECK-NEXT: [[N1:%.*]] = fneg float [[X:%.*]] 413; CHECK-NEXT: call void @use(float [[N1]]) 414; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], float [[X]], float [[Y:%.*]] 415; CHECK-NEXT: [[SEL:%.*]] = fneg float [[SEL_V]] 416; CHECK-NEXT: ret float [[SEL]] 417; 418 %n1 = fsub float -0.0, %x 419 call void @use(float %n1) 420 %n2 = fsub float -0.0, %y 421 %sel = select i1 %cond, float %n1, float %n2 422 ret float %sel 423} 424 425; Negative test: but 2 extra uses would require an extra instruction. 426 427define float @fneg_fneg_sel_extra_use3(float %x, float %y, i1 %cond) { 428; CHECK-LABEL: @fneg_fneg_sel_extra_use3( 429; CHECK-NEXT: [[N1:%.*]] = fneg float [[X:%.*]] 430; CHECK-NEXT: call void @use(float [[N1]]) 431; CHECK-NEXT: [[N2:%.*]] = fneg float [[Y:%.*]] 432; CHECK-NEXT: call void @use(float [[N2]]) 433; CHECK-NEXT: [[SEL:%.*]] = select i1 [[COND:%.*]], float [[N1]], float [[N2]] 434; CHECK-NEXT: ret float [[SEL]] 435; 436 %n1 = fneg float %x 437 call void @use(float %n1) 438 %n2 = fneg float %y 439 call void @use(float %n2) 440 %sel = select i1 %cond, float %n1, float %n2 441 ret float %sel 442} 443 444define double @fneg_fneg_sel_fmf1(double %x, double %y, i1 %cond) { 445; CHECK-LABEL: @fneg_fneg_sel_fmf1( 446; CHECK-NEXT: [[SEL_V:%.*]] = select i1 [[COND:%.*]], double [[X:%.*]], double [[Y:%.*]] 447; CHECK-NEXT: [[SEL:%.*]] = fneg double [[SEL_V]] 448; CHECK-NEXT: ret double [[SEL]] 449; 450 %n1 = fneg nnan double %x 451 %n2 = fneg ninf double %y 452 %sel = select i1 %cond, double %n1, double %n2 453 ret double %sel 454} 455 456define double @fneg_fneg_sel_fmf2(double %x, double %y, i1 %cond) { 457; CHECK-LABEL: @fneg_fneg_sel_fmf2( 458; CHECK-NEXT: [[SEL_V:%.*]] = select ninf i1 [[COND:%.*]], double [[X:%.*]], double [[Y:%.*]] 459; CHECK-NEXT: [[SEL:%.*]] = fneg ninf double [[SEL_V]] 460; CHECK-NEXT: ret double [[SEL]] 461; 462 %n1 = fneg nnan ninf double %x 463 %n2 = fneg ninf double %y 464 %sel = select i1 %cond, double %n1, double %n2 465 ret double %sel 466} 467 468define double @fneg_fneg_sel_fmf3(double %x, double %y, i1 %cond) { 469; CHECK-LABEL: @fneg_fneg_sel_fmf3( 470; CHECK-NEXT: [[SEL_V:%.*]] = select ninf i1 [[COND:%.*]], double [[X:%.*]], double [[Y:%.*]] 471; CHECK-NEXT: [[SEL:%.*]] = fneg ninf double [[SEL_V]] 472; CHECK-NEXT: ret double [[SEL]] 473; 474 %n1 = fneg nnan ninf double %x 475 %n2 = fneg ninf double %y 476 %sel = select ninf i1 %cond, double %n1, double %n2 477 ret double %sel 478} 479 480define double @fneg_fneg_sel_fmf4(double %x, double %y, i1 %cond) { 481; CHECK-LABEL: @fneg_fneg_sel_fmf4( 482; CHECK-NEXT: [[SEL_V:%.*]] = select nnan ninf nsz i1 [[COND:%.*]], double [[X:%.*]], double [[Y:%.*]] 483; CHECK-NEXT: [[SEL:%.*]] = fneg nnan ninf nsz double [[SEL_V]] 484; CHECK-NEXT: ret double [[SEL]] 485; 486 %n1 = fneg nnan double %x 487 %n2 = fneg ninf double %y 488 %sel = select nsz nnan ninf i1 %cond, double %n1, double %n2 489 ret double %sel 490} 491 492; Negative test 493 494define float @fneg_fadd_constant(float %x) { 495; CHECK-LABEL: @fneg_fadd_constant( 496; CHECK-NEXT: [[A:%.*]] = fadd float [[X:%.*]], 4.200000e+01 497; CHECK-NEXT: [[R:%.*]] = fneg float [[A]] 498; CHECK-NEXT: ret float [[R]] 499; 500 %a = fadd float %x, 42.0 501 %r = fneg float %a 502 ret float %r 503} 504 505; Negative test 506 507define float @fake_nsz_fadd_constant(float %x) { 508; CHECK-LABEL: @fake_nsz_fadd_constant( 509; CHECK-NEXT: [[A:%.*]] = fadd float [[X:%.*]], 4.200000e+01 510; CHECK-NEXT: [[R:%.*]] = fneg float [[A]] 511; CHECK-NEXT: ret float [[R]] 512; 513 %a = fadd float %x, 42.0 514 %r = fsub float -0.0, %a 515 ret float %r 516} 517 518; -(X + C) --> -C - X 519 520define float @fneg_nsz_fadd_constant(float %x) { 521; CHECK-LABEL: @fneg_nsz_fadd_constant( 522; CHECK-NEXT: [[R:%.*]] = fsub nsz float -4.200000e+01, [[X:%.*]] 523; CHECK-NEXT: ret float [[R]] 524; 525 %a = fadd float %x, 42.0 526 %r = fneg nsz float %a 527 ret float %r 528} 529 530; -(X + C) --> -C - X 531 532define float @fake_fneg_nsz_fadd_constant(float %x) { 533; CHECK-LABEL: @fake_fneg_nsz_fadd_constant( 534; CHECK-NEXT: [[R:%.*]] = fsub fast float -4.200000e+01, [[X:%.*]] 535; CHECK-NEXT: ret float [[R]] 536; 537 %a = fadd float %x, 42.0 538 %r = fsub fast float -0.0, %a 539 ret float %r 540} 541 542; Negative test 543 544define float @fneg_nsz_fadd_constant_extra_use(float %x) { 545; CHECK-LABEL: @fneg_nsz_fadd_constant_extra_use( 546; CHECK-NEXT: [[A:%.*]] = fadd float [[X:%.*]], 4.200000e+01 547; CHECK-NEXT: call void @use(float [[A]]) 548; CHECK-NEXT: [[R:%.*]] = fneg nsz float [[A]] 549; CHECK-NEXT: ret float [[R]] 550; 551 %a = fadd float %x, 42.0 552 call void @use(float %a) 553 %r = fneg nsz float %a 554 ret float %r 555} 556 557; Negative test 558 559define float @fake_fneg_nsz_fadd_constant_extra_use(float %x) { 560; CHECK-LABEL: @fake_fneg_nsz_fadd_constant_extra_use( 561; CHECK-NEXT: [[A:%.*]] = fadd float [[X:%.*]], 4.200000e+01 562; CHECK-NEXT: call void @use(float [[A]]) 563; CHECK-NEXT: [[R:%.*]] = fneg fast float [[A]] 564; CHECK-NEXT: ret float [[R]] 565; 566 %a = fadd float %x, 42.0 567 call void @use(float %a) 568 %r = fsub fast float -0.0, %a 569 ret float %r 570} 571 572; -(X + C) --> -C - X 573 574define <2 x float> @fneg_nsz_fadd_constant_vec(<2 x float> %x) { 575; CHECK-LABEL: @fneg_nsz_fadd_constant_vec( 576; CHECK-NEXT: [[R:%.*]] = fsub reassoc nnan nsz <2 x float> <float -4.200000e+01, float -4.300000e+01>, [[X:%.*]] 577; CHECK-NEXT: ret <2 x float> [[R]] 578; 579 %a = fadd <2 x float> %x, <float 42.0, float 43.0> 580 %r = fneg nsz nnan reassoc <2 x float> %a 581 ret <2 x float> %r 582} 583 584; -(X + C) --> -C - X 585 586define <2 x float> @fake_fneg_nsz_fadd_constant_vec(<2 x float> %x) { 587; CHECK-LABEL: @fake_fneg_nsz_fadd_constant_vec( 588; CHECK-NEXT: [[R:%.*]] = fsub nsz <2 x float> <float -4.200000e+01, float poison>, [[X:%.*]] 589; CHECK-NEXT: ret <2 x float> [[R]] 590; 591 %a = fadd <2 x float> %x, <float 42.0, float poison> 592 %r = fsub nsz <2 x float> <float poison, float -0.0>, %a 593 ret <2 x float> %r 594} 595 596@g = external global i16, align 1 597 598define float @fneg_nsz_fadd_constant_expr(float %x) { 599; CHECK-LABEL: @fneg_nsz_fadd_constant_expr( 600; CHECK-NEXT: [[A:%.*]] = fadd float [[X:%.*]], bitcast (i32 ptrtoint (ptr @g to i32) to float) 601; CHECK-NEXT: [[R:%.*]] = fneg nsz float [[A]] 602; CHECK-NEXT: ret float [[R]] 603; 604 %a = fadd float %x, bitcast (i32 ptrtoint (ptr @g to i32) to float) 605 %r = fneg nsz float %a 606 ret float %r 607} 608 609define float @fake_fneg_nsz_fadd_constant_expr(float %x) { 610; CHECK-LABEL: @fake_fneg_nsz_fadd_constant_expr( 611; CHECK-NEXT: [[A:%.*]] = fadd float [[X:%.*]], bitcast (i32 ptrtoint (ptr @g to i32) to float) 612; CHECK-NEXT: [[R:%.*]] = fneg nsz float [[A]] 613; CHECK-NEXT: ret float [[R]] 614; 615 %a = fadd float %x, bitcast (i32 ptrtoint (ptr @g to i32) to float) 616 %r = fsub nsz float -0.0, %a 617 ret float %r 618} 619 620define float @select_fneg_true(float %x, float %y, i1 %b) { 621; CHECK-LABEL: @select_fneg_true( 622; CHECK-NEXT: [[Y_NEG:%.*]] = fneg float [[Y:%.*]] 623; CHECK-NEXT: [[R:%.*]] = select i1 [[B:%.*]], float [[X:%.*]], float [[Y_NEG]] 624; CHECK-NEXT: ret float [[R]] 625; 626 %nx = fneg float %x 627 %s = select i1 %b, float %nx, float %y 628 %r = fneg float %s 629 ret float %r 630} 631 632define <2 x float> @select_fneg_false(<2 x float> %x, <2 x float> %y, <2 x i1> %b) { 633; CHECK-LABEL: @select_fneg_false( 634; CHECK-NEXT: [[X_NEG:%.*]] = fneg nnan nsz <2 x float> [[X:%.*]] 635; CHECK-NEXT: [[R:%.*]] = select nnan ninf <2 x i1> [[B:%.*]], <2 x float> [[X_NEG]], <2 x float> [[Y:%.*]] 636; CHECK-NEXT: ret <2 x float> [[R]] 637; 638 %ny = fneg nnan <2 x float> %y 639 %s = select ninf <2 x i1> %b, <2 x float> %x, <2 x float> %ny 640 %r = fneg nsz nnan <2 x float> %s 641 ret <2 x float> %r 642} 643 644define float @select_fneg_false_no_nsz(float %x, float %y, i1 %b) { 645; CHECK-LABEL: @select_fneg_false_no_nsz( 646; CHECK-NEXT: [[X_NEG:%.*]] = fneg nnan ninf nsz float [[X:%.*]] 647; CHECK-NEXT: [[R:%.*]] = select nnan ninf i1 [[B:%.*]], float [[X_NEG]], float [[Y:%.*]] 648; CHECK-NEXT: ret float [[R]] 649; 650 %ny = fneg float %y 651 %s = select i1 %b, float %x, float %ny 652 %r = fneg ninf nnan nsz float %s 653 ret float %r 654} 655 656; The removal of nsz in this pattern is not needed if the select condition can't be poison. 657 658define float @select_fneg_false_nsz_ok(float %x, float %y, i1 noundef %b) { 659; CHECK-LABEL: @select_fneg_false_nsz_ok( 660; CHECK-NEXT: [[X_NEG:%.*]] = fneg nnan ninf nsz float [[X:%.*]] 661; CHECK-NEXT: [[R:%.*]] = select nnan ninf nsz i1 [[B:%.*]], float [[X_NEG]], float [[Y:%.*]] 662; CHECK-NEXT: ret float [[R]] 663; 664 %ny = fneg float %y 665 %s = select i1 %b, float %x, float %ny 666 %r = fneg nsz ninf nnan float %s 667 ret float %r 668} 669 670define float @select_fneg_false_nsz(float %x, float %y, i1 %b) { 671; CHECK-LABEL: @select_fneg_false_nsz( 672; CHECK-NEXT: [[X_NEG:%.*]] = fneg nnan ninf nsz float [[X:%.*]] 673; CHECK-NEXT: [[R:%.*]] = select nnan ninf nsz i1 [[B:%.*]], float [[X_NEG]], float [[Y:%.*]] 674; CHECK-NEXT: ret float [[R]] 675; 676 %ny = fneg float %y 677 %s = select nsz i1 %b, float %x, float %ny 678 %r = fneg ninf nnan nsz float %s 679 ret float %r 680} 681 682; Special-case for propagating nsz: it's ok when selecting between an operand and its negation. 683 684define float @select_common_op_fneg_true(float %x, i1 %b) { 685; CHECK-LABEL: @select_common_op_fneg_true( 686; CHECK-NEXT: [[X_NEG:%.*]] = fneg nnan ninf nsz float [[X:%.*]] 687; CHECK-NEXT: [[R:%.*]] = select nnan ninf nsz i1 [[B:%.*]], float [[X_NEG]], float [[X]] 688; CHECK-NEXT: ret float [[R]] 689; 690 %nx = fneg float %x 691 %s = select i1 %b, float %x, float %nx 692 %r = fneg nsz ninf nnan float %s 693 ret float %r 694} 695 696define float @select_common_op_fneg_false(float %x, i1 %b) { 697; CHECK-LABEL: @select_common_op_fneg_false( 698; CHECK-NEXT: [[X_NEG:%.*]] = fneg nnan ninf nsz float [[X:%.*]] 699; CHECK-NEXT: [[R:%.*]] = select nnan ninf nsz i1 [[B:%.*]], float [[X_NEG]], float [[X]] 700; CHECK-NEXT: ret float [[R]] 701; 702 %nx = fneg float %x 703 %s = select i1 %b, float %x, float %nx 704 %r = fneg nsz ninf nnan float %s 705 ret float %r 706} 707 708; The transform above allows follow-on folds to convert to fabs. 709 710define float @fabs(float %a) { 711; CHECK-LABEL: @fabs( 712; CHECK-NEXT: [[FNEG1:%.*]] = call nnan ninf nsz float @llvm.fabs.f32(float [[A:%.*]]) 713; CHECK-NEXT: ret float [[FNEG1]] 714; 715 %fneg = fneg float %a 716 %cmp = fcmp ogt float %a, %fneg 717 %sel = select i1 %cmp, float %fneg, float %a 718 %fneg1 = fneg nnan ninf nsz float %sel 719 ret float %fneg1 720} 721 722define float @fnabs(float %a) { 723; CHECK-LABEL: @fnabs( 724; CHECK-NEXT: [[TMP1:%.*]] = call fast float @llvm.fabs.f32(float [[A:%.*]]) 725; CHECK-NEXT: [[FNEG1:%.*]] = fneg fast float [[TMP1]] 726; CHECK-NEXT: ret float [[FNEG1]] 727; 728 %fneg = fneg float %a 729 %cmp = fcmp olt float %a, %fneg 730 %sel = select i1 %cmp, float %fneg, float %a 731 %fneg1 = fneg fast float %sel 732 ret float %fneg1 733} 734 735define float @fnabs_1(float %a) { 736; CHECK-LABEL: @fnabs_1( 737; CHECK-NEXT: [[TMP1:%.*]] = call fast float @llvm.fabs.f32(float [[A:%.*]]) 738; CHECK-NEXT: [[FNEG1:%.*]] = fneg fast float [[TMP1]] 739; CHECK-NEXT: ret float [[FNEG1]] 740; 741 %fneg = fneg float %a 742 %cmp = fcmp ogt float %a, %fneg 743 %sel = select i1 %cmp, float %a, float %fneg 744 %fneg1 = fneg fast float %sel 745 ret float %fneg1 746} 747 748; This is not fabs because that could produce a different signbit for a NAN input. 749; PR59279 750 751define float @fnabs_2_nsz(float %a) { 752; CHECK-LABEL: @fnabs_2_nsz( 753; CHECK-NEXT: [[CMP:%.*]] = fcmp olt float [[A:%.*]], 0.000000e+00 754; CHECK-NEXT: [[A_NEG:%.*]] = fneg float [[A]] 755; CHECK-NEXT: [[FNEG1:%.*]] = select nsz i1 [[CMP]], float [[A]], float [[A_NEG]] 756; CHECK-NEXT: ret float [[FNEG1]] 757; 758 %fneg = fneg float %a 759 %cmp = fcmp olt float %a, %fneg 760 %sel = select nsz i1 %cmp, float %fneg, float %a 761 %fneg1 = fneg float %sel 762 ret float %fneg1 763} 764 765define float @fnabs_2_nsz_nnan(float %a) { 766; CHECK-LABEL: @fnabs_2_nsz_nnan( 767; CHECK-NEXT: [[SEL:%.*]] = call nnan nsz float @llvm.fabs.f32(float [[A:%.*]]) 768; CHECK-NEXT: [[FNEG1:%.*]] = fneg float [[SEL]] 769; CHECK-NEXT: ret float [[FNEG1]] 770; 771 %fneg = fneg float %a 772 %cmp = fcmp olt float %a, %fneg 773 %sel = select nsz nnan i1 %cmp, float %fneg, float %a 774 %fneg1 = fneg float %sel 775 ret float %fneg1 776} 777 778define float @select_fneg_both(float %x, float %y, i1 %b) { 779; CHECK-LABEL: @select_fneg_both( 780; CHECK-NEXT: [[S_V:%.*]] = select i1 [[B:%.*]], float [[X:%.*]], float [[Y:%.*]] 781; CHECK-NEXT: ret float [[S_V]] 782; 783 %nx = fneg float %x 784 %ny = fneg float %y 785 %s = select i1 %b, float %nx, float %ny 786 %r = fneg float %s 787 ret float %r 788} 789 790define float @select_fneg_use1(float %x, float %y, i1 %b) { 791; CHECK-LABEL: @select_fneg_use1( 792; CHECK-NEXT: [[NX:%.*]] = fneg ninf float [[X:%.*]] 793; CHECK-NEXT: call void @use(float [[NX]]) 794; CHECK-NEXT: [[Y_NEG:%.*]] = fneg float [[Y:%.*]] 795; CHECK-NEXT: [[R:%.*]] = select fast i1 [[B:%.*]], float [[X]], float [[Y_NEG]] 796; CHECK-NEXT: ret float [[R]] 797; 798 %nx = fneg ninf float %x 799 call void @use(float %nx) 800 %s = select fast i1 %b, float %nx, float %y 801 %r = fneg float %s 802 ret float %r 803} 804 805define float @select_fneg_use2(float %x, float %y, i1 %b) { 806; CHECK-LABEL: @select_fneg_use2( 807; CHECK-NEXT: call void @use(float [[Y:%.*]]) 808; CHECK-NEXT: [[Y_NEG:%.*]] = fneg fast float [[Y]] 809; CHECK-NEXT: [[R:%.*]] = select reassoc nnan ninf arcp contract afn i1 [[B:%.*]], float [[X:%.*]], float [[Y_NEG]] 810; CHECK-NEXT: ret float [[R]] 811; 812 call void @use(float %y) 813 %nx = fneg nsz float %x 814 %s = select ninf i1 %b, float %nx, float %y 815 %r = fneg fast float %s 816 ret float %r 817} 818 819; Negative test 820 821define float @select_fneg_use3(float %x, float %y, i1 %b) { 822; CHECK-LABEL: @select_fneg_use3( 823; CHECK-NEXT: [[NX:%.*]] = fneg float [[X:%.*]] 824; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], float [[NX]], float [[Y:%.*]] 825; CHECK-NEXT: call void @use(float [[S]]) 826; CHECK-NEXT: [[R:%.*]] = fneg float [[S]] 827; CHECK-NEXT: ret float [[R]] 828; 829 %nx = fneg float %x 830 %s = select i1 %b, float %nx, float %y 831 call void @use(float %s) 832 %r = fneg float %s 833 ret float %r 834} 835 836define float @fneg_ldexp(float %x, i32 %n) { 837; CHECK-LABEL: @fneg_ldexp( 838; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[X:%.*]] 839; CHECK-NEXT: [[NEG:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]) 840; CHECK-NEXT: ret float [[NEG]] 841; 842 %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n) 843 %neg = fneg float %ldexp 844 ret float %neg 845} 846 847define float @fsub_fneg_ldexp(float %x, i32 %n) { 848; CHECK-LABEL: @fsub_fneg_ldexp( 849; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[X:%.*]] 850; CHECK-NEXT: [[NEG:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]) 851; CHECK-NEXT: ret float [[NEG]] 852; 853 %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n) 854 %neg = fsub float -0.0, %ldexp 855 ret float %neg 856} 857 858define float @fsub_fneg_ldexp_nsz(float %x, i32 %n) { 859; CHECK-LABEL: @fsub_fneg_ldexp_nsz( 860; CHECK-NEXT: [[TMP1:%.*]] = fneg nsz float [[X:%.*]] 861; CHECK-NEXT: [[NEG:%.*]] = call nsz float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]) 862; CHECK-NEXT: ret float [[NEG]] 863; 864 %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n) 865 %neg = fsub nsz float -0.0, %ldexp 866 ret float %neg 867} 868 869define float @fsub_fneg_ldexp_p0_nsz(float %x, i32 %n) { 870; CHECK-LABEL: @fsub_fneg_ldexp_p0_nsz( 871; CHECK-NEXT: [[TMP1:%.*]] = fneg nsz float [[X:%.*]] 872; CHECK-NEXT: [[NEG:%.*]] = call nsz float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]) 873; CHECK-NEXT: ret float [[NEG]] 874; 875 %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n) 876 %neg = fsub nsz float 0.0, %ldexp 877 ret float %neg 878} 879 880define float @fsub_fneg_ldexp_p0(float %x, i32 %n) { 881; CHECK-LABEL: @fsub_fneg_ldexp_p0( 882; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]]) 883; CHECK-NEXT: [[NEG:%.*]] = fsub float 0.000000e+00, [[LDEXP]] 884; CHECK-NEXT: ret float [[NEG]] 885; 886 %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n) 887 %neg = fsub float 0.0, %ldexp 888 ret float %neg 889} 890 891define <2 x float> @fneg_ldexp_vector(<2 x float> %x, <2 x i32> %n) { 892; CHECK-LABEL: @fneg_ldexp_vector( 893; CHECK-NEXT: [[TMP1:%.*]] = fneg <2 x float> [[X:%.*]] 894; CHECK-NEXT: [[NEG:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[TMP1]], <2 x i32> [[N:%.*]]) 895; CHECK-NEXT: ret <2 x float> [[NEG]] 896; 897 %ldexp = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %x, <2 x i32> %n) 898 %neg = fneg <2 x float> %ldexp 899 ret <2 x float> %neg 900} 901 902define float @fneg_ldexp_multiuse(float %x, i32 %n, ptr %ptr) { 903; CHECK-LABEL: @fneg_ldexp_multiuse( 904; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]]) 905; CHECK-NEXT: store float [[LDEXP]], ptr [[PTR:%.*]], align 4 906; CHECK-NEXT: [[NEG:%.*]] = fneg float [[LDEXP]] 907; CHECK-NEXT: ret float [[NEG]] 908; 909 %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n) 910 store float %ldexp, ptr %ptr 911 %neg = fneg float %ldexp 912 ret float %neg 913} 914 915define float @fneg_ldexp_fmf_ldexp(float %x, i32 %n) { 916; CHECK-LABEL: @fneg_ldexp_fmf_ldexp( 917; CHECK-NEXT: [[TMP1:%.*]] = fneg nnan float [[X:%.*]] 918; CHECK-NEXT: [[NEG:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]) 919; CHECK-NEXT: ret float [[NEG]] 920; 921 %ldexp = call nnan float @llvm.ldexp.f32.i32(float %x, i32 %n) 922 %neg = fneg float %ldexp 923 ret float %neg 924} 925 926define float @fneg_ldexp_fmf_neg(float %x, i32 %n) { 927; CHECK-LABEL: @fneg_ldexp_fmf_neg( 928; CHECK-NEXT: [[TMP1:%.*]] = fneg nnan float [[X:%.*]] 929; CHECK-NEXT: [[NEG:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]) 930; CHECK-NEXT: ret float [[NEG]] 931; 932 %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n) 933 %neg = fneg nnan float %ldexp 934 ret float %neg 935} 936 937define float @fneg_ldexp_fmf(float %x, i32 %n) { 938; CHECK-LABEL: @fneg_ldexp_fmf( 939; CHECK-NEXT: [[TMP1:%.*]] = fneg nnan ninf float [[X:%.*]] 940; CHECK-NEXT: [[NEG:%.*]] = call nnan ninf float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]) 941; CHECK-NEXT: ret float [[NEG]] 942; 943 %ldexp = call ninf float @llvm.ldexp.f32.i32(float %x, i32 %n) 944 %neg = fneg nnan float %ldexp 945 ret float %neg 946} 947 948define float @fneg_ldexp_contract0(float %x, i32 %n) { 949; CHECK-LABEL: @fneg_ldexp_contract0( 950; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[X:%.*]] 951; CHECK-NEXT: [[NEG:%.*]] = call contract float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]) 952; CHECK-NEXT: ret float [[NEG]] 953; 954 %ldexp = call contract float @llvm.ldexp.f32.i32(float %x, i32 %n) 955 %neg = fneg float %ldexp 956 ret float %neg 957} 958 959define float @fneg_ldexp_contract1(float %x, i32 %n) { 960; CHECK-LABEL: @fneg_ldexp_contract1( 961; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[X:%.*]] 962; CHECK-NEXT: [[NEG:%.*]] = call contract float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]) 963; CHECK-NEXT: ret float [[NEG]] 964; 965 %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n) 966 %neg = fneg contract float %ldexp 967 ret float %neg 968} 969 970define float @fneg_ldexp_contract(float %x, i32 %n) { 971; CHECK-LABEL: @fneg_ldexp_contract( 972; CHECK-NEXT: [[TMP1:%.*]] = fneg contract float [[X:%.*]] 973; CHECK-NEXT: [[NEG:%.*]] = call contract float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]) 974; CHECK-NEXT: ret float [[NEG]] 975; 976 %ldexp = call contract float @llvm.ldexp.f32.i32(float %x, i32 %n) 977 %neg = fneg contract float %ldexp 978 ret float %neg 979} 980 981define float @fneg_ldexp_metadata(float %x, i32 %n) { 982; CHECK-LABEL: @fneg_ldexp_metadata( 983; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[X:%.*]] 984; CHECK-NEXT: [[NEG:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]), !arst [[META0:![0-9]+]] 985; CHECK-NEXT: ret float [[NEG]] 986; 987 %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n), !arst !0 988 %neg = fneg float %ldexp 989 ret float %neg 990} 991 992define float @test_fneg_select_constants(i1 %cond) { 993; CHECK-LABEL: @test_fneg_select_constants( 994; CHECK-NEXT: [[NEG:%.*]] = select i1 [[COND:%.*]], float -0.000000e+00, float 0.000000e+00 995; CHECK-NEXT: ret float [[NEG]] 996; 997 %sel1 = select i1 %cond, float 0.0, float -0.0 998 %neg = fneg float %sel1 999 ret float %neg 1000} 1001 1002define <2 x float> @test_fneg_vec(<2 x i1> %cond) { 1003; CHECK-LABEL: @test_fneg_vec( 1004; CHECK-NEXT: [[NEG:%.*]] = select <2 x i1> [[COND:%.*]], <2 x float> <float -0.000000e+00, float 0.000000e+00>, <2 x float> <float 0.000000e+00, float -0.000000e+00> 1005; CHECK-NEXT: ret <2 x float> [[NEG]] 1006; 1007 %sel1 = select <2 x i1> %cond, <2 x float> <float 0.0, float -0.0>, <2 x float> <float -0.0, float 0.0> 1008 %neg = fneg <2 x float> %sel1 1009 ret <2 x float> %neg 1010} 1011 1012define float @test_fneg_select_var_constant(i1 %cond, float %x) { 1013; CHECK-LABEL: @test_fneg_select_var_constant( 1014; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X:%.*]] 1015; CHECK-NEXT: [[NEG:%.*]] = select i1 [[COND:%.*]], float [[X_NEG]], float 0.000000e+00 1016; CHECK-NEXT: ret float [[NEG]] 1017; 1018 %sel1 = select i1 %cond, float %x, float -0.0 1019 %neg = fneg float %sel1 1020 ret float %neg 1021} 1022 1023; nsz can be preserved. 1024 1025define float @test_fneg_select_var_constant_fmf1(i1 %cond, float %x) { 1026; CHECK-LABEL: @test_fneg_select_var_constant_fmf1( 1027; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X:%.*]] 1028; CHECK-NEXT: [[NEG:%.*]] = select nnan ninf nsz i1 [[COND:%.*]], float [[X_NEG]], float -1.000000e+00 1029; CHECK-NEXT: ret float [[NEG]] 1030; 1031 %sel1 = select nnan ninf nsz i1 %cond, float %x, float 1.0 1032 %neg = fneg float %sel1 1033 ret float %neg 1034} 1035 1036define float @test_fneg_select_var_constant_fmf2(i1 %cond, float %x) { 1037; CHECK-LABEL: @test_fneg_select_var_constant_fmf2( 1038; CHECK-NEXT: [[X_NEG:%.*]] = fneg nnan ninf nsz float [[X:%.*]] 1039; CHECK-NEXT: [[NEG:%.*]] = select nnan ninf nsz i1 [[COND:%.*]], float [[X_NEG]], float -1.000000e+00 1040; CHECK-NEXT: ret float [[NEG]] 1041; 1042 %sel1 = select i1 %cond, float %x, float 1.0 1043 %neg = fneg nnan ninf nsz float %sel1 1044 ret float %neg 1045} 1046 1047define float @test_fneg_select_constant_var(i1 %cond, float %x) { 1048; CHECK-LABEL: @test_fneg_select_constant_var( 1049; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X:%.*]] 1050; CHECK-NEXT: [[NEG:%.*]] = select i1 [[COND:%.*]], float -0.000000e+00, float [[X_NEG]] 1051; CHECK-NEXT: ret float [[NEG]] 1052; 1053 %sel1 = select i1 %cond, float 0.0, float %x 1054 %neg = fneg float %sel1 1055 ret float %neg 1056} 1057 1058; Make sure nabs is generated. 1059 1060define float @test_fneg_select_abs(i1 %cond, float %x) { 1061; CHECK-LABEL: @test_fneg_select_abs( 1062; CHECK-NEXT: [[ABSX:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]]) 1063; CHECK-NEXT: [[ABSX_NEG:%.*]] = fneg float [[ABSX]] 1064; CHECK-NEXT: [[NEG:%.*]] = select i1 [[COND:%.*]], float -0.000000e+00, float [[ABSX_NEG]] 1065; CHECK-NEXT: ret float [[NEG]] 1066; 1067 %absx = call float @llvm.fabs.f32(float %x) 1068 %sel1 = select i1 %cond, float 0.0, float %absx 1069 %neg = fneg float %sel1 1070 ret float %neg 1071} 1072 1073define float @test_fneg_fabs_select(i1 %cond, float %x) { 1074; CHECK-LABEL: @test_fneg_fabs_select( 1075; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]]) 1076; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]] 1077; CHECK-NEXT: [[NEG:%.*]] = select i1 [[COND:%.*]], float -0.000000e+00, float [[DOTNEG]] 1078; CHECK-NEXT: ret float [[NEG]] 1079; 1080 %sel1 = select i1 %cond, float 0.0, float %x 1081 %abs = call float @llvm.fabs.f32(float %sel1) 1082 %neg = fneg float %abs 1083 ret float %neg 1084} 1085 1086define float @test_fneg_select_constant_var_multiuse(i1 %cond, float %x) { 1087; CHECK-LABEL: @test_fneg_select_constant_var_multiuse( 1088; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[COND:%.*]], float 0.000000e+00, float [[X:%.*]] 1089; CHECK-NEXT: call void @use(float [[SEL1]]) 1090; CHECK-NEXT: [[NEG:%.*]] = fneg float [[SEL1]] 1091; CHECK-NEXT: ret float [[NEG]] 1092; 1093 %sel1 = select i1 %cond, float 0.0, float %x 1094 call void @use(float %sel1) 1095 %neg = fneg float %sel1 1096 ret float %neg 1097} 1098 1099; Don't break fmax idioms. 1100 1101define float @test_fneg_select_maxnum(float %x) { 1102; CHECK-LABEL: @test_fneg_select_maxnum( 1103; CHECK-NEXT: [[SEL1:%.*]] = call nsz float @llvm.maxnum.f32(float [[X:%.*]], float 1.000000e+00) 1104; CHECK-NEXT: [[NEG:%.*]] = fneg float [[SEL1]] 1105; CHECK-NEXT: ret float [[NEG]] 1106; 1107 %cmp1 = fcmp ogt float %x, 1.0 1108 %sel1 = select nnan nsz i1 %cmp1, float %x, float 1.0 1109 %neg = fneg float %sel1 1110 ret float %neg 1111} 1112 1113; Check that there's no infinite loop. 1114define <vscale x 2 x double> @test_fneg_select_svec(<vscale x 2 x i1> %cond, <vscale x 2 x double> %b) { 1115; CHECK-LABEL: @test_fneg_select_svec( 1116; CHECK-NEXT: [[TMP2:%.*]] = fneg fast <vscale x 2 x double> [[TMP1:%.*]] 1117; CHECK-NEXT: [[TMP3:%.*]] = select fast <vscale x 2 x i1> [[COND:%.*]], <vscale x 2 x double> splat (double -0.000000e+00), <vscale x 2 x double> [[TMP2]] 1118; CHECK-NEXT: ret <vscale x 2 x double> [[TMP3]] 1119; 1120 %1 = select <vscale x 2 x i1> %cond, <vscale x 2 x double> zeroinitializer, <vscale x 2 x double> %b 1121 %2 = fneg fast <vscale x 2 x double> %1 1122 ret <vscale x 2 x double> %2 1123} 1124 1125define <vscale x 2 x double> @test_fneg_select_svec_2(<vscale x 2 x i1> %cond, <vscale x 2 x double> %a) { 1126; CHECK-LABEL: @test_fneg_select_svec_2( 1127; CHECK-NEXT: [[A_NEG:%.*]] = fneg fast <vscale x 2 x double> [[A:%.*]] 1128; CHECK-NEXT: [[TMP1:%.*]] = select fast <vscale x 2 x i1> [[COND:%.*]], <vscale x 2 x double> [[A_NEG]], <vscale x 2 x double> splat (double -0.000000e+00) 1129; CHECK-NEXT: ret <vscale x 2 x double> [[TMP1]] 1130; 1131 %1 = select <vscale x 2 x i1> %cond, <vscale x 2 x double> %a, <vscale x 2 x double> zeroinitializer 1132 %2 = fneg fast <vscale x 2 x double> %1 1133 ret <vscale x 2 x double> %2 1134} 1135 1136define <vscale x 2 x double> @test_fneg_select_svec_3(<vscale x 2 x i1> %cond, <vscale x 2 x double> %b) { 1137; CHECK-LABEL: @test_fneg_select_svec_3( 1138; CHECK-NEXT: ret <vscale x 2 x double> splat (double -0.000000e+00) 1139; 1140 %1 = select <vscale x 2 x i1> %cond, <vscale x 2 x double> zeroinitializer, <vscale x 2 x double> zeroinitializer 1141 %2 = fneg fast <vscale x 2 x double> %1 1142 ret <vscale x 2 x double> %2 1143} 1144 1145!0 = !{} 1146