1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers | FileCheck %s 3 4; Test that basic 64-bit floating-point comparison operations assemble as 5; expected. 6 7target triple = "wasm32-unknown-unknown" 8 9define i32 @ord_f64(double %x, double %y) { 10; CHECK-LABEL: ord_f64: 11; CHECK: .functype ord_f64 (f64, f64) -> (i32) 12; CHECK-NEXT: # %bb.0: 13; CHECK-NEXT: local.get $push4=, 0 14; CHECK-NEXT: local.get $push3=, 0 15; CHECK-NEXT: f64.eq $push1=, $pop4, $pop3 16; CHECK-NEXT: local.get $push6=, 1 17; CHECK-NEXT: local.get $push5=, 1 18; CHECK-NEXT: f64.eq $push0=, $pop6, $pop5 19; CHECK-NEXT: i32.and $push2=, $pop1, $pop0 20; CHECK-NEXT: return $pop2 21 %a = fcmp ord double %x, %y 22 %b = zext i1 %a to i32 23 ret i32 %b 24} 25 26define i32 @uno_f64(double %x, double %y) { 27; CHECK-LABEL: uno_f64: 28; CHECK: .functype uno_f64 (f64, f64) -> (i32) 29; CHECK-NEXT: # %bb.0: 30; CHECK-NEXT: local.get $push4=, 0 31; CHECK-NEXT: local.get $push3=, 0 32; CHECK-NEXT: f64.ne $push1=, $pop4, $pop3 33; CHECK-NEXT: local.get $push6=, 1 34; CHECK-NEXT: local.get $push5=, 1 35; CHECK-NEXT: f64.ne $push0=, $pop6, $pop5 36; CHECK-NEXT: i32.or $push2=, $pop1, $pop0 37; CHECK-NEXT: return $pop2 38 %a = fcmp uno double %x, %y 39 %b = zext i1 %a to i32 40 ret i32 %b 41} 42 43define i32 @oeq_f64(double %x, double %y) { 44; CHECK-LABEL: oeq_f64: 45; CHECK: .functype oeq_f64 (f64, f64) -> (i32) 46; CHECK-NEXT: # %bb.0: 47; CHECK-NEXT: local.get $push2=, 0 48; CHECK-NEXT: local.get $push1=, 1 49; CHECK-NEXT: f64.eq $push0=, $pop2, $pop1 50; CHECK-NEXT: return $pop0 51 %a = fcmp oeq double %x, %y 52 %b = zext i1 %a to i32 53 ret i32 %b 54} 55 56define i32 @une_f64(double %x, double %y) { 57; CHECK-LABEL: une_f64: 58; CHECK: .functype une_f64 (f64, f64) -> (i32) 59; CHECK-NEXT: # %bb.0: 60; CHECK-NEXT: local.get $push2=, 0 61; CHECK-NEXT: local.get $push1=, 1 62; CHECK-NEXT: f64.ne $push0=, $pop2, $pop1 63; CHECK-NEXT: return $pop0 64 %a = fcmp une double %x, %y 65 %b = zext i1 %a to i32 66 ret i32 %b 67} 68 69define i32 @olt_f64(double %x, double %y) { 70; CHECK-LABEL: olt_f64: 71; CHECK: .functype olt_f64 (f64, f64) -> (i32) 72; CHECK-NEXT: # %bb.0: 73; CHECK-NEXT: local.get $push2=, 0 74; CHECK-NEXT: local.get $push1=, 1 75; CHECK-NEXT: f64.lt $push0=, $pop2, $pop1 76; CHECK-NEXT: return $pop0 77 %a = fcmp olt double %x, %y 78 %b = zext i1 %a to i32 79 ret i32 %b 80} 81 82define i32 @ole_f64(double %x, double %y) { 83; CHECK-LABEL: ole_f64: 84; CHECK: .functype ole_f64 (f64, f64) -> (i32) 85; CHECK-NEXT: # %bb.0: 86; CHECK-NEXT: local.get $push2=, 0 87; CHECK-NEXT: local.get $push1=, 1 88; CHECK-NEXT: f64.le $push0=, $pop2, $pop1 89; CHECK-NEXT: return $pop0 90 %a = fcmp ole double %x, %y 91 %b = zext i1 %a to i32 92 ret i32 %b 93} 94 95define i32 @ogt_f64(double %x, double %y) { 96; CHECK-LABEL: ogt_f64: 97; CHECK: .functype ogt_f64 (f64, f64) -> (i32) 98; CHECK-NEXT: # %bb.0: 99; CHECK-NEXT: local.get $push2=, 0 100; CHECK-NEXT: local.get $push1=, 1 101; CHECK-NEXT: f64.gt $push0=, $pop2, $pop1 102; CHECK-NEXT: return $pop0 103 %a = fcmp ogt double %x, %y 104 %b = zext i1 %a to i32 105 ret i32 %b 106} 107 108define i32 @oge_f64(double %x, double %y) { 109; CHECK-LABEL: oge_f64: 110; CHECK: .functype oge_f64 (f64, f64) -> (i32) 111; CHECK-NEXT: # %bb.0: 112; CHECK-NEXT: local.get $push2=, 0 113; CHECK-NEXT: local.get $push1=, 1 114; CHECK-NEXT: f64.ge $push0=, $pop2, $pop1 115; CHECK-NEXT: return $pop0 116 %a = fcmp oge double %x, %y 117 %b = zext i1 %a to i32 118 ret i32 %b 119} 120 121; Expanded comparisons, which also check for NaN. 122 123define i32 @ueq_f64(double %x, double %y) { 124; CHECK-LABEL: ueq_f64: 125; CHECK: .functype ueq_f64 (f64, f64) -> (i32) 126; CHECK-NEXT: # %bb.0: 127; CHECK-NEXT: local.get $push6=, 0 128; CHECK-NEXT: local.get $push5=, 1 129; CHECK-NEXT: f64.gt $push1=, $pop6, $pop5 130; CHECK-NEXT: local.get $push8=, 0 131; CHECK-NEXT: local.get $push7=, 1 132; CHECK-NEXT: f64.lt $push0=, $pop8, $pop7 133; CHECK-NEXT: i32.or $push2=, $pop1, $pop0 134; CHECK-NEXT: i32.const $push3=, 1 135; CHECK-NEXT: i32.xor $push4=, $pop2, $pop3 136; CHECK-NEXT: return $pop4 137 %a = fcmp ueq double %x, %y 138 %b = zext i1 %a to i32 139 ret i32 %b 140} 141 142define i32 @one_f64(double %x, double %y) { 143; CHECK-LABEL: one_f64: 144; CHECK: .functype one_f64 (f64, f64) -> (i32) 145; CHECK-NEXT: # %bb.0: 146; CHECK-NEXT: local.get $push4=, 0 147; CHECK-NEXT: local.get $push3=, 1 148; CHECK-NEXT: f64.gt $push1=, $pop4, $pop3 149; CHECK-NEXT: local.get $push6=, 0 150; CHECK-NEXT: local.get $push5=, 1 151; CHECK-NEXT: f64.lt $push0=, $pop6, $pop5 152; CHECK-NEXT: i32.or $push2=, $pop1, $pop0 153; CHECK-NEXT: return $pop2 154 %a = fcmp one double %x, %y 155 %b = zext i1 %a to i32 156 ret i32 %b 157} 158 159define i32 @ult_f64(double %x, double %y) { 160; CHECK-LABEL: ult_f64: 161; CHECK: .functype ult_f64 (f64, f64) -> (i32) 162; CHECK-NEXT: # %bb.0: 163; CHECK-NEXT: local.get $push4=, 0 164; CHECK-NEXT: local.get $push3=, 1 165; CHECK-NEXT: f64.ge $push0=, $pop4, $pop3 166; CHECK-NEXT: i32.const $push1=, 1 167; CHECK-NEXT: i32.xor $push2=, $pop0, $pop1 168; CHECK-NEXT: return $pop2 169 %a = fcmp ult double %x, %y 170 %b = zext i1 %a to i32 171 ret i32 %b 172} 173 174define i32 @ule_f64(double %x, double %y) { 175; CHECK-LABEL: ule_f64: 176; CHECK: .functype ule_f64 (f64, f64) -> (i32) 177; CHECK-NEXT: # %bb.0: 178; CHECK-NEXT: local.get $push4=, 0 179; CHECK-NEXT: local.get $push3=, 1 180; CHECK-NEXT: f64.gt $push0=, $pop4, $pop3 181; CHECK-NEXT: i32.const $push1=, 1 182; CHECK-NEXT: i32.xor $push2=, $pop0, $pop1 183; CHECK-NEXT: return $pop2 184 %a = fcmp ule double %x, %y 185 %b = zext i1 %a to i32 186 ret i32 %b 187} 188 189define i32 @ugt_f64(double %x, double %y) { 190; CHECK-LABEL: ugt_f64: 191; CHECK: .functype ugt_f64 (f64, f64) -> (i32) 192; CHECK-NEXT: # %bb.0: 193; CHECK-NEXT: local.get $push4=, 0 194; CHECK-NEXT: local.get $push3=, 1 195; CHECK-NEXT: f64.le $push0=, $pop4, $pop3 196; CHECK-NEXT: i32.const $push1=, 1 197; CHECK-NEXT: i32.xor $push2=, $pop0, $pop1 198; CHECK-NEXT: return $pop2 199 %a = fcmp ugt double %x, %y 200 %b = zext i1 %a to i32 201 ret i32 %b 202} 203 204define i32 @uge_f64(double %x, double %y) { 205; CHECK-LABEL: uge_f64: 206; CHECK: .functype uge_f64 (f64, f64) -> (i32) 207; CHECK-NEXT: # %bb.0: 208; CHECK-NEXT: local.get $push4=, 0 209; CHECK-NEXT: local.get $push3=, 1 210; CHECK-NEXT: f64.lt $push0=, $pop4, $pop3 211; CHECK-NEXT: i32.const $push1=, 1 212; CHECK-NEXT: i32.xor $push2=, $pop0, $pop1 213; CHECK-NEXT: return $pop2 214 %a = fcmp uge double %x, %y 215 %b = zext i1 %a to i32 216 ret i32 %b 217} 218 219define void @olt_f64_branch(double %a, double %b) { 220; CHECK-LABEL: olt_f64_branch: 221; CHECK: .functype olt_f64_branch (f64, f64) -> () 222; CHECK-NEXT: # %bb.0: # %entry 223; CHECK-NEXT: block 224; CHECK-NEXT: local.get $push2=, 0 225; CHECK-NEXT: local.get $push1=, 1 226; CHECK-NEXT: f64.lt $push0=, $pop2, $pop1 227; CHECK-NEXT: i32.eqz $push3=, $pop0 228; CHECK-NEXT: br_if 0, $pop3 # 0: down to label0 229; CHECK-NEXT: # %bb.1: # %if.then 230; CHECK-NEXT: call call1 231; CHECK-NEXT: .LBB14_2: # %if.end 232; CHECK-NEXT: end_block # label0: 233; CHECK-NEXT: return 234entry: 235 %cmp = fcmp olt double %a, %b 236 br i1 %cmp, label %if.then, label %if.end 237 238if.then: 239 tail call void @call1() 240 br label %if.end 241 242if.end: 243 ret void 244} 245 246define void @ole_f64_branch(double %a, double %b) { 247; CHECK-LABEL: ole_f64_branch: 248; CHECK: .functype ole_f64_branch (f64, f64) -> () 249; CHECK-NEXT: # %bb.0: # %entry 250; CHECK-NEXT: block 251; CHECK-NEXT: local.get $push2=, 0 252; CHECK-NEXT: local.get $push1=, 1 253; CHECK-NEXT: f64.le $push0=, $pop2, $pop1 254; CHECK-NEXT: i32.eqz $push3=, $pop0 255; CHECK-NEXT: br_if 0, $pop3 # 0: down to label1 256; CHECK-NEXT: # %bb.1: # %if.then 257; CHECK-NEXT: call call1 258; CHECK-NEXT: .LBB15_2: # %if.end 259; CHECK-NEXT: end_block # label1: 260; CHECK-NEXT: return 261entry: 262 %cmp = fcmp ole double %a, %b 263 br i1 %cmp, label %if.then, label %if.end 264 265if.then: 266 tail call void @call1() 267 br label %if.end 268 269if.end: 270 ret void 271} 272 273define void @ugt_f64_branch(double %a, double %b) { 274; CHECK-LABEL: ugt_f64_branch: 275; CHECK: .functype ugt_f64_branch (f64, f64) -> () 276; CHECK-NEXT: # %bb.0: # %entry 277; CHECK-NEXT: block 278; CHECK-NEXT: local.get $push2=, 0 279; CHECK-NEXT: local.get $push1=, 1 280; CHECK-NEXT: f64.le $push0=, $pop2, $pop1 281; CHECK-NEXT: i32.eqz $push3=, $pop0 282; CHECK-NEXT: br_if 0, $pop3 # 0: down to label2 283; CHECK-NEXT: # %bb.1: # %if.then 284; CHECK-NEXT: call call1 285; CHECK-NEXT: .LBB16_2: # %if.end 286; CHECK-NEXT: end_block # label2: 287; CHECK-NEXT: return 288entry: 289 %cmp = fcmp ugt double %a, %b 290 br i1 %cmp, label %if.end, label %if.then 291 292if.then: 293 tail call void @call1() 294 br label %if.end 295 296if.end: 297 ret void 298} 299 300define void @ogt_f64_branch(double %a, double %b) { 301; CHECK-LABEL: ogt_f64_branch: 302; CHECK: .functype ogt_f64_branch (f64, f64) -> () 303; CHECK-NEXT: # %bb.0: # %entry 304; CHECK-NEXT: block 305; CHECK-NEXT: local.get $push2=, 0 306; CHECK-NEXT: local.get $push1=, 1 307; CHECK-NEXT: f64.gt $push0=, $pop2, $pop1 308; CHECK-NEXT: i32.eqz $push3=, $pop0 309; CHECK-NEXT: br_if 0, $pop3 # 0: down to label3 310; CHECK-NEXT: # %bb.1: # %if.then 311; CHECK-NEXT: call call1 312; CHECK-NEXT: .LBB17_2: # %if.end 313; CHECK-NEXT: end_block # label3: 314; CHECK-NEXT: return 315entry: 316 %cmp = fcmp ogt double %a, %b 317 br i1 %cmp, label %if.then, label %if.end 318 319if.then: 320 tail call void @call1() 321 br label %if.end 322 323if.end: 324 ret void 325} 326 327define void @ult_f64_branch(double %a, double %b) { 328; CHECK-LABEL: ult_f64_branch: 329; CHECK: .functype ult_f64_branch (f64, f64) -> () 330; CHECK-NEXT: # %bb.0: # %entry 331; CHECK-NEXT: block 332; CHECK-NEXT: local.get $push2=, 0 333; CHECK-NEXT: local.get $push1=, 1 334; CHECK-NEXT: f64.ge $push0=, $pop2, $pop1 335; CHECK-NEXT: i32.eqz $push3=, $pop0 336; CHECK-NEXT: br_if 0, $pop3 # 0: down to label4 337; CHECK-NEXT: # %bb.1: # %if.then 338; CHECK-NEXT: call call1 339; CHECK-NEXT: .LBB18_2: # %if.end 340; CHECK-NEXT: end_block # label4: 341; CHECK-NEXT: return 342entry: 343 %cmp = fcmp ult double %a, %b 344 br i1 %cmp, label %if.end, label %if.then 345 346if.then: 347 tail call void @call1() 348 br label %if.end 349 350if.end: 351 ret void 352} 353 354define void @ule_f64_branch(double %a, double %b) { 355; CHECK-LABEL: ule_f64_branch: 356; CHECK: .functype ule_f64_branch (f64, f64) -> () 357; CHECK-NEXT: # %bb.0: # %entry 358; CHECK-NEXT: block 359; CHECK-NEXT: local.get $push2=, 0 360; CHECK-NEXT: local.get $push1=, 1 361; CHECK-NEXT: f64.gt $push0=, $pop2, $pop1 362; CHECK-NEXT: i32.eqz $push3=, $pop0 363; CHECK-NEXT: br_if 0, $pop3 # 0: down to label5 364; CHECK-NEXT: # %bb.1: # %if.then 365; CHECK-NEXT: call call1 366; CHECK-NEXT: .LBB19_2: # %if.end 367; CHECK-NEXT: end_block # label5: 368; CHECK-NEXT: return 369entry: 370 %cmp = fcmp ule double %a, %b 371 br i1 %cmp, label %if.end, label %if.then 372 373if.then: 374 tail call void @call1() 375 br label %if.end 376 377if.end: 378 ret void 379} 380 381define void @xor_zext_switch(double %a, double %b) { 382; CHECK-LABEL: xor_zext_switch: 383; CHECK: .functype xor_zext_switch (f64, f64) -> () 384; CHECK-NEXT: # %bb.0: # %entry 385; CHECK-NEXT: block 386; CHECK-NEXT: i32.const $push1=, 0 387; CHECK-NEXT: br_if 0, $pop1 # 0: down to label6 388; CHECK-NEXT: # %bb.1: # %entry 389; CHECK-NEXT: block 390; CHECK-NEXT: block 391; CHECK-NEXT: local.get $push3=, 0 392; CHECK-NEXT: local.get $push2=, 1 393; CHECK-NEXT: f64.ge $push0=, $pop3, $pop2 394; CHECK-NEXT: br_table $pop0, 0, 1, 0 # 0: down to label8 395; CHECK-NEXT: # 1: down to label7 396; CHECK-NEXT: .LBB20_2: # %sw.bb.1 397; CHECK-NEXT: end_block # label8: 398; CHECK-NEXT: call foo1 399; CHECK-NEXT: return 400; CHECK-NEXT: .LBB20_3: # %sw.bb.2 401; CHECK-NEXT: end_block # label7: 402; CHECK-NEXT: call foo2 403; CHECK-NEXT: .LBB20_4: # %exit 404; CHECK-NEXT: end_block # label6: 405; CHECK-NEXT: return 406entry: 407 %cmp = fcmp ult double %a, %b 408 %zext = zext i1 %cmp to i32 409 %xor = xor i32 %zext, 1 410 switch i32 %xor, label %exit [ 411 i32 0, label %sw.bb.1 412 i32 1, label %sw.bb.2 413 ] 414 415sw.bb.1: 416 tail call void @foo1() 417 br label %exit 418 419sw.bb.2: 420 tail call void @foo2() 421 br label %exit 422 423exit: 424 ret void 425} 426 427define void @xor_add_switch(double %a, double %b) { 428; CHECK-LABEL: xor_add_switch: 429; CHECK: .functype xor_add_switch (f64, f64) -> () 430; CHECK-NEXT: # %bb.0: # %entry 431; CHECK-NEXT: block 432; CHECK-NEXT: block 433; CHECK-NEXT: block 434; CHECK-NEXT: block 435; CHECK-NEXT: local.get $push8=, 0 436; CHECK-NEXT: local.get $push7=, 1 437; CHECK-NEXT: f64.ge $push1=, $pop8, $pop7 438; CHECK-NEXT: i32.const $push2=, 1 439; CHECK-NEXT: i32.xor $push3=, $pop1, $pop2 440; CHECK-NEXT: i32.const $push6=, 1 441; CHECK-NEXT: i32.add $push4=, $pop3, $pop6 442; CHECK-NEXT: i32.const $push5=, 1 443; CHECK-NEXT: i32.xor $push0=, $pop4, $pop5 444; CHECK-NEXT: br_table $pop0, 0, 1, 2, 3 # 0: down to label12 445; CHECK-NEXT: # 1: down to label11 446; CHECK-NEXT: # 2: down to label10 447; CHECK-NEXT: # 3: down to label9 448; CHECK-NEXT: .LBB21_1: # %sw.bb.1 449; CHECK-NEXT: end_block # label12: 450; CHECK-NEXT: call foo1 451; CHECK-NEXT: return 452; CHECK-NEXT: .LBB21_2: # %sw.bb.2 453; CHECK-NEXT: end_block # label11: 454; CHECK-NEXT: call foo2 455; CHECK-NEXT: return 456; CHECK-NEXT: .LBB21_3: # %sw.bb.3 457; CHECK-NEXT: end_block # label10: 458; CHECK-NEXT: call foo3 459; CHECK-NEXT: .LBB21_4: # %exit 460; CHECK-NEXT: end_block # label9: 461; CHECK-NEXT: return 462entry: 463 %cmp = fcmp ult double %a, %b 464 %zext = zext i1 %cmp to i32 465 %add = add nsw nuw i32 %zext, 1 466 %xor = xor i32 %add, 1 467 switch i32 %xor, label %exit [ 468 i32 0, label %sw.bb.1 469 i32 1, label %sw.bb.2 470 i32 2, label %sw.bb.3 471 ] 472 473sw.bb.1: 474 tail call void @foo1() 475 br label %exit 476 477sw.bb.2: 478 tail call void @foo2() 479 br label %exit 480 481sw.bb.3: 482 tail call void @foo3() 483 br label %exit 484 485exit: 486 ret void 487} 488 489declare void @foo1() 490declare void @foo2() 491declare void @foo3() 492declare void @call1() 493