1; This tries to be a comprehensive test of i8 operations. 2 3; RUN: %p2i --filetype=obj --disassemble -i %s --args -O2 \ 4; RUN: -allow-externally-defined-symbols | FileCheck %s 5; RUN: %p2i --filetype=obj --disassemble -i %s --args -Om1 \ 6; RUN: -allow-externally-defined-symbols | FileCheck %s 7 8; The following tests i8 srem/urem lowering on x86-64, specifically that the %ah 9; result gets copied into %al/%bl/%cl/%dl before moved into its final register. 10; This extra copy is forced by excluding al/bl/cl/dl by default (-reg-exclude), 11; but allowing them to be used if absolutely necessary (-reg-reserve). 12 13; RUN: %p2i --target=x8664 --filetype=obj --disassemble -i %s --args -O2 \ 14; RUN: -reg-exclude=al,bl,cl,dl -reg-reserve \ 15; RUN: -allow-externally-defined-symbols | FileCheck %s --check-prefix=REM 16 17; RUN: %if --need=target_MIPS32 --need=allow_dump \ 18; RUN: --command %p2i --filetype=asm --assemble --disassemble --target \ 19; RUN: mips32 -i %s --args -O2 -allow-externally-defined-symbols \ 20; RUN: | %if --need=target_MIPS32 --need=allow_dump \ 21; RUN: --command FileCheck --check-prefix MIPS32 %s 22 23declare void @useInt(i32 %x) 24 25define internal i32 @add8Bit(i32 %a, i32 %b) { 26entry: 27 %a_8 = trunc i32 %a to i8 28 %b_8 = trunc i32 %b to i8 29 %add = add i8 %b_8, %a_8 30 %ret = zext i8 %add to i32 31 ret i32 %ret 32} 33; CHECK-LABEL: add8Bit 34; CHECK: add {{[abcd]l}} 35; MIPS32-LABEL: add8Bit 36; MIPS32: addu 37; MIPS32: andi {{.*}},0xff 38; MIPS32: move 39; MIPS32: jr 40; MIPS32: nop 41 42define internal i32 @add8BitConst(i32 %a) { 43entry: 44 %a_8 = trunc i32 %a to i8 45 %add = add i8 %a_8, 123 46 %ret = zext i8 %add to i32 47 ret i32 %ret 48} 49; CHECK-LABEL: add8BitConst 50; CHECK: add {{[abcd]l}} 51; MIPS32-LABEL: add8BitConst 52; MIPS32: addiu 53; MIPS32: andi {{.*}},0xff 54; MIPS32: move 55; MIPS32: jr 56; MIPS32: nop 57 58define internal i32 @sub8Bit(i32 %a, i32 %b) { 59entry: 60 %a_8 = trunc i32 %a to i8 61 %b_8 = trunc i32 %b to i8 62 %sub = sub i8 %b_8, %a_8 63 %ret = zext i8 %sub to i32 64 ret i32 %ret 65} 66; CHECK-LABEL: sub8Bit 67; CHECK: sub {{[abcd]l}} 68; MIPS32-LABEL: sub8Bit 69; MIPS32: subu 70; MIPS32: andi {{.*}},0xff 71; MIPS32: move 72; MIPS32: jr 73; MIPS32: nop 74 75define internal i32 @sub8BitConst(i32 %a) { 76entry: 77 %a_8 = trunc i32 %a to i8 78 %sub = sub i8 %a_8, 123 79 %ret = zext i8 %sub to i32 80 ret i32 %ret 81} 82; CHECK-LABEL: sub8BitConst 83; CHECK: sub {{[abcd]l}} 84; MIPS32-LABEL: sub8BitConst 85; MIPS32: addiu {{.*}},-123 86; MIPS32: andi {{.*}},0xff 87; MIPS32: move 88; MIPS32: jr 89; MIPS32: nop 90 91define internal i32 @mul8Bit(i32 %a, i32 %b) { 92entry: 93 %a_8 = trunc i32 %a to i8 94 %b_8 = trunc i32 %b to i8 95 %mul = mul i8 %b_8, %a_8 96 %ret = zext i8 %mul to i32 97 ret i32 %ret 98} 99; CHECK-LABEL: mul8Bit 100; CHECK: mul {{[abcd]l|BYTE PTR}} 101; MIPS32-LABEL: mul8Bit 102; MIPS32: mul 103; MIPS32: andi {{.*}},0xff 104; MIPS32: move 105; MIPS32: jr 106; MIPS32: nop 107 108define internal i32 @mul8BitConst(i32 %a) { 109entry: 110 %a_8 = trunc i32 %a to i8 111 %mul = mul i8 %a_8, 56 112 %ret = zext i8 %mul to i32 113 ret i32 %ret 114} 115; CHECK-LABEL: mul8BitConst 116; 8-bit imul only accepts r/m, not imm 117; CHECK: mov {{.*}},0x38 118; CHECK: mul {{[abcd]l|BYTE PTR}} 119; MIPS32-LABEL: mul8BitConst 120; MIPS32: li 121; MIPS32: mul 122; MIPS32: andi {{.*}},0xff 123; MIPS32: move 124; MIPS32: jr 125; MIPS32: nop 126 127define internal i32 @udiv8Bit(i32 %a, i32 %b) { 128entry: 129 %a_8 = trunc i32 %a to i8 130 %b_8 = trunc i32 %b to i8 131 %udiv = udiv i8 %b_8, %a_8 132 %ret = zext i8 %udiv to i32 133 ret i32 %ret 134} 135; CHECK-LABEL: udiv8Bit 136; CHECK: div {{[abcd]l|BYTE PTR}} 137; MIPS32-LABEL: udiv8Bit 138; MIPS32: divu 139; MIPS32: teq 140; MIPS32: mflo 141; MIPS32: andi {{.*}},0xff 142; MIPS32: jr 143; MIPS32: nop 144 145define internal i32 @udiv8BitConst(i32 %a) { 146entry: 147 %a_8 = trunc i32 %a to i8 148 %udiv = udiv i8 %a_8, 123 149 %ret = zext i8 %udiv to i32 150 ret i32 %ret 151} 152; CHECK-LABEL: udiv8BitConst 153; CHECK: div {{[abcd]l|BYTE PTR}} 154; MIPS32-LABEL: udiv8BitConst 155; MIPS32: li 156; MIPS32: divu 157; MIPS32: teq 158; MIPS32: mflo 159; MIPS32: andi {{.*}},0xff 160; MIPS32: jr 161; MIPS32: nop 162 163define internal i32 @urem8Bit(i32 %a, i32 %b) { 164entry: 165 %a_8 = trunc i32 %a to i8 166 %b_8 = trunc i32 %b to i8 167 %urem = urem i8 %b_8, %a_8 168 %ret = zext i8 %urem to i32 169 ret i32 %ret 170} 171; CHECK-LABEL: urem8Bit 172; CHECK: div {{[abcd]l|BYTE PTR}} 173; REM-LABEL: urem8Bit 174; REM: div 175; REM-NEXT: mov {{[abcd]}}l,ah 176; MIPS32-LABEL: urem8Bit 177; MIPS32: divu 178; MIPS32: teq 179; MIPS32: mfhi 180; MIPS32: andi {{.*}},0xff 181; MIPS32: jr 182; MIPS32: nop 183 184define internal i32 @urem8BitConst(i32 %a) { 185entry: 186 %a_8 = trunc i32 %a to i8 187 %urem = urem i8 %a_8, 123 188 %ret = zext i8 %urem to i32 189 ret i32 %ret 190} 191; CHECK-LABEL: urem8BitConst 192; CHECK: div {{[abcd]l|BYTE PTR}} 193; REM-LABEL: urem8BitConst 194; MIPS32-LABEL: urem8BitConst 195; MIPS32: li 196; MIPS32: divu 197; MIPS32: teq 198; MIPS32: mfhi 199; MIPS32: andi {{.*}},0xff 200; MIPS32: jr 201; MIPS32: nop 202 203 204define internal i32 @sdiv8Bit(i32 %a, i32 %b) { 205entry: 206 %a_8 = trunc i32 %a to i8 207 %b_8 = trunc i32 %b to i8 208 %sdiv = sdiv i8 %b_8, %a_8 209 %ret = zext i8 %sdiv to i32 210 ret i32 %ret 211} 212; CHECK-LABEL: sdiv8Bit 213; CHECK: idiv {{[abcd]l|BYTE PTR}} 214; MIPS32-LABEL: sdiv8Bit 215; MIPS32: div 216; MIPS32: teq 217; MIPS32: mflo 218; MIPS32: andi {{.*}},0xff 219; MIPS32: jr 220; MIPS32: nop 221 222define internal i32 @sdiv8BitConst(i32 %a) { 223entry: 224 %a_8 = trunc i32 %a to i8 225 %sdiv = sdiv i8 %a_8, 123 226 %ret = zext i8 %sdiv to i32 227 ret i32 %ret 228} 229; CHECK-LABEL: sdiv8BitConst 230; CHECK: idiv {{[abcd]l|BYTE PTR}} 231; MIPS32-LABEL: sdiv8BitConst 232; MIPS32: li 233; MIPS32: div 234; MIPS32: teq 235; MIPS32: mflo 236; MIPS32: andi {{.*}},0xff 237; MIPS32: jr 238; MIPS32: nop 239 240define internal i32 @srem8Bit(i32 %a, i32 %b) { 241entry: 242 %a_8 = trunc i32 %a to i8 243 %b_8 = trunc i32 %b to i8 244 %srem = srem i8 %b_8, %a_8 245 %ret = zext i8 %srem to i32 246 ret i32 %ret 247} 248; CHECK-LABEL: srem8Bit 249; CHECK: idiv {{[abcd]l|BYTE PTR}} 250; REM-LABEL: srem8Bit 251; REM: idiv 252; REM-NEXT: mov {{[abcd]}}l,ah 253; MIPS32-LABEL: srem8Bit 254; MIPS32: div 255; MIPS32: teq 256; MIPS32: mfhi 257; MIPS32: andi {{.*}},0xff 258; MIPS32: jr 259; MIPS32: nop 260 261define internal i32 @srem8BitConst(i32 %a) { 262entry: 263 %a_8 = trunc i32 %a to i8 264 %srem = srem i8 %a_8, 123 265 %ret = zext i8 %srem to i32 266 ret i32 %ret 267} 268; CHECK-LABEL: srem8BitConst 269; CHECK: idiv {{[abcd]l|BYTE PTR}} 270; REM-LABEL: srem8BitConst 271; MIPS32-LABEL: srem8BitConst 272; MIPS32: li 273; MIPS32: div 274; MIPS32: teq 275; MIPS32: mfhi 276; MIPS32: andi {{.*}},0xff 277; MIPS32: jr 278; MIPS32: nop 279 280define internal i32 @shl8Bit(i32 %a, i32 %b) { 281entry: 282 %a_8 = trunc i32 %a to i8 283 %b_8 = trunc i32 %b to i8 284 %shl = shl i8 %b_8, %a_8 285 %ret = zext i8 %shl to i32 286 ret i32 %ret 287} 288; CHECK-LABEL: shl8Bit 289; CHECK: shl {{[abd]l|BYTE PTR}},cl 290; MIPS32-LABEL: shl8Bit 291; MIPS32: sllv 292; MIPS32: andi {{.*}},0xff 293; MIPS32: move 294; MIPS32: jr 295; MIPS32: nop 296 297define internal i32 @shl8BitConst(i32 %a, i32 %b) { 298entry: 299 %a_8 = trunc i32 %a to i8 300 %shl = shl i8 %a_8, 6 301 %ret = zext i8 %shl to i32 302 ret i32 %ret 303} 304; CHECK-LABEL: shl8BitConst 305; CHECK: shl {{[abcd]l|BYTE PTR}},0x6 306; MIPS32-LABEL: shl8BitConst 307; MIPS32: sll 308; MIPS32: andi {{.*}},0xff 309; MIPS32: move 310; MIPS32: jr 311; MIPS32: nop 312 313define internal i32 @lshr8Bit(i32 %a, i32 %b) { 314entry: 315 %a_8 = trunc i32 %a to i8 316 %b_8 = trunc i32 %b to i8 317 %lshr = lshr i8 %b_8, %a_8 318 %ret = zext i8 %lshr to i32 319 ret i32 %ret 320} 321; CHECK-LABEL: lshr8Bit 322; CHECK: shr {{[abd]l|BYTE PTR}},cl 323; MIPS32-LABEL: lshr8Bit 324; MIPS32: srlv 325; MIPS32: andi {{.*}},0xff 326; MIPS32: move 327; MIPS32: jr 328; MIPS32: nop 329 330define internal i32 @lshr8BitConst(i32 %a, i32 %b) { 331entry: 332 %a_8 = trunc i32 %a to i8 333 %lshr = lshr i8 %a_8, 6 334 %ret = zext i8 %lshr to i32 335 ret i32 %ret 336} 337; CHECK-LABEL: lshr8BitConst 338; CHECK: shr {{[abcd]l|BYTE PTR}},0x6 339; MIPS32-LABEL: lshr8BitConst 340; MIPS32: srl 341; MIPS32: andi {{.*}},0xff 342; MIPS32: move 343; MIPS32: jr 344; MIPS32: nop 345 346define internal i32 @ashr8Bit(i32 %a, i32 %b) { 347entry: 348 %a_8 = trunc i32 %a to i8 349 %b_8 = trunc i32 %b to i8 350 %ashr = ashr i8 %b_8, %a_8 351 %ret = zext i8 %ashr to i32 352 ret i32 %ret 353} 354; CHECK-LABEL: ashr8Bit 355; CHECK: sar {{[abd]l|BYTE PTR}},cl 356; MIPS32-LABEL: ashr8Bit 357; MIPS32: sra 358; MIPS32: andi {{.*}},0xff 359; MIPS32: move 360; MIPS32: jr 361; MIPS32: nop 362 363define internal i32 @ashr8BitConst(i32 %a, i32 %b) { 364entry: 365 %a_8 = trunc i32 %a to i8 366 %ashr = ashr i8 %a_8, 6 367 %ret = zext i8 %ashr to i32 368 ret i32 %ret 369} 370; CHECK-LABEL: ashr8BitConst 371; CHECK: sar {{[abcd]l|BYTE PTR}},0x6 372; MIPS32-LABEL: ashr8BitConst 373; MIPS32: sra 374; MIPS32: andi {{.*}},0xff 375; MIPS32: move 376; MIPS32: jr 377; MIPS32: nop 378 379define internal i32 @icmp8Bit(i32 %a, i32 %b) { 380entry: 381 %a_8 = trunc i32 %a to i8 382 %b_8 = trunc i32 %b to i8 383 %icmp = icmp ne i8 %b_8, %a_8 384 %ret = zext i1 %icmp to i32 385 ret i32 %ret 386} 387; CHECK-LABEL: icmp8Bit 388; CHECK: cmp {{[abcd]l|BYTE PTR}} 389; MIPS32-LABEL: icmp8Bit 390; MIPS32: sll {{.*}},0x18 391; MIPS32: sll {{.*}},0x18 392; MIPS32: xor 393; MIPS32: sltu 394; MIPS32: andi {{.*}},0x1 395; MIPS32: move 396; MIPS32: jr 397; MIPS32: nop 398 399define internal i32 @icmp8BitConst(i32 %a) { 400entry: 401 %a_8 = trunc i32 %a to i8 402 %icmp = icmp ne i8 %a_8, 123 403 %ret = zext i1 %icmp to i32 404 ret i32 %ret 405} 406; CHECK-LABEL: icmp8BitConst 407; CHECK: cmp {{[abcd]l|BYTE PTR}} 408; MIPS32-LABEL: icmp8BitConst 409; MIPS32: li 410; MIPS32: sll {{.*}},0x18 411; MIPS32: sll {{.*}},0x18 412; MIPS32: xor 413; MIPS32: sltu 414; MIPS32: andi {{.*}},0x1 415; MIPS32: move 416; MIPS32: jr 417; MIPS32: nop 418 419define internal i32 @icmp8BitConstSwapped(i32 %a) { 420entry: 421 %a_8 = trunc i32 %a to i8 422 %icmp = icmp ne i8 123, %a_8 423 %ret = zext i1 %icmp to i32 424 ret i32 %ret 425} 426; CHECK-LABEL: icmp8BitConstSwapped 427; CHECK: cmp {{[abcd]l|BYTE PTR}} 428; MIPS32-LABEL: icmp8BitConstSwapped 429; MIPS32: li 430; MIPS32: sll {{.*}},0x18 431; MIPS32: sll {{.*}},0x18 432; MIPS32: xor v0,v0,a0 433; MIPS32: sltu 434; MIPS32: andi {{.*}},0x1 435; MIPS32: jr 436; MIPS32: nop 437 438define internal i32 @icmp8BitMem(i32 %a, i32 %b_iptr) { 439entry: 440 %a_8 = trunc i32 %a to i8 441 %bptr = inttoptr i32 %b_iptr to i8* 442 %b_8 = load i8, i8* %bptr, align 1 443 %icmp = icmp ne i8 %b_8, %a_8 444 %ret = zext i1 %icmp to i32 445 ret i32 %ret 446} 447; CHECK-LABEL: icmp8BitMem 448; CHECK: cmp {{[abcd]l|BYTE PTR}} 449; MIPS32-LABEL: icmp8BitMem 450; MIPS32: lb 451; MIPS32: sll {{.*}},0x18 452; MIPS32: sll {{.*}},0x18 453; MIPS32: xor 454; MIPS32: sltu 455; MIPS32: andi {{.*}},0x1 456; MIPS32: move 457; MIPS32: jr 458; MIPS32: nop 459 460define internal i32 @icmp8BitMemSwapped(i32 %a, i32 %b_iptr) { 461entry: 462 %a_8 = trunc i32 %a to i8 463 %bptr = inttoptr i32 %b_iptr to i8* 464 %b_8 = load i8, i8* %bptr, align 1 465 %icmp = icmp ne i8 %a_8, %b_8 466 %ret = zext i1 %icmp to i32 467 ret i32 %ret 468} 469; CHECK-LABEL: icmp8BitMemSwapped 470; CHECK: cmp {{[abcd]l|BYTE PTR}} 471; MIPS32-LABEL: icmp8BitMemSwapped 472; MIPS32: lb 473; MIPS32: sll {{.*}},0x18 474; MIPS32: sll {{.*}},0x18 475; MIPS32: xor 476; MIPS32: sltu 477; MIPS32: andi {{.*}},0x1 478; MIPS32: move 479; MIPS32: jr 480; MIPS32: nop 481 482define internal i32 @selectI8Var(i32 %a, i32 %b) { 483entry: 484 %a_8 = trunc i32 %a to i8 485 %b_8 = trunc i32 %b to i8 486 %cmp = icmp slt i8 %a_8, %b_8 487 %ret = select i1 %cmp, i8 %a_8, i8 %b_8 488 %ret_ext = zext i8 %ret to i32 489 ; Create a "fake" use of %cmp to prevent O2 bool folding. 490 %d1 = zext i1 %cmp to i32 491 call void @useInt(i32 %d1) 492 ret i32 %ret_ext 493} 494; CHECK-LABEL: selectI8Var 495; CHECK: cmp 496; CHECK: setl 497; CHECK: mov {{[a-d]l}} 498; MIPS32-LABEL: selectI8Var 499; MIPS32: addiu 500; MIPS32: sw 501; MIPS32: sw 502; MIPS32: move 503; MIPS32: move 504; MIPS32: sll {{.*}},0x18 505; MIPS32: sll {{.*}},0x18 506; MIPS32: slt 507; MIPS32: move 508; MIPS32: movn 509; MIPS32: andi {{.*}},0xff 510; MIPS32: move 511; MIPS32: andi {{.*}},0x1 512; MIPS32: move 513; MIPS32: jal 514; MIPS32: nop 515; MIPS32: move 516; MIPS32: lw 517; MIPS32: lw 518; MIPS32: addiu 519; MIPS32: jr 520; MIPS32: nop 521 522define internal i32 @testPhi8(i32 %arg, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7, i32 %arg8, i32 %arg9, i32 %arg10) { 523entry: 524 %trunc = trunc i32 %arg to i8 525 %trunc2 = trunc i32 %arg2 to i8 526 %trunc3 = trunc i32 %arg3 to i8 527 %trunc4 = trunc i32 %arg4 to i8 528 %trunc5 = trunc i32 %arg5 to i8 529 %cmp1 = icmp sgt i32 %arg, 0 530 br i1 %cmp1, label %next, label %target 531next: 532 %trunc6_16 = trunc i32 %arg6 to i16 533 %trunc7_16 = trunc i32 %arg7 to i16 534 %trunc8_16 = trunc i32 %arg8 to i16 535 %trunc9 = trunc i32 %arg9 to i8 536 %trunc10 = trunc i32 %arg10 to i8 537 %trunc7_8 = trunc i16 %trunc7_16 to i8 538 %trunc6_8 = trunc i16 %trunc6_16 to i8 539 %trunc8_8 = trunc i16 %trunc8_16 to i8 540 br label %target 541target: 542 %merge1 = phi i1 [ %cmp1, %entry ], [ false, %next ] 543 %merge2 = phi i8 [ %trunc, %entry ], [ %trunc6_8, %next ] 544 %merge3 = phi i8 [ %trunc2, %entry ], [ %trunc7_8, %next ] 545 %merge5 = phi i8 [ %trunc4, %entry ], [ %trunc9, %next ] 546 %merge6 = phi i8 [ %trunc5, %entry ], [ %trunc10, %next ] 547 %merge4 = phi i8 [ %trunc3, %entry ], [ %trunc8_8, %next ] 548 %res1 = select i1 %merge1, i8 %merge2, i8 %merge3 549 %res2 = select i1 %merge1, i8 %merge4, i8 %merge5 550 %res1_2 = select i1 %merge1, i8 %res1, i8 %res2 551 %res123 = select i1 %merge1, i8 %merge6, i8 %res1_2 552 %result = zext i8 %res123 to i32 553 ret i32 %result 554} 555; CHECK-LABEL: testPhi8 556; This assumes there will be some copy from an 8-bit register / stack slot. 557; CHECK-DAG: mov {{.*}},{{[a-d]}}l 558; CHECK-DAG: mov {{.*}},BYTE PTR 559; CHECK-DAG: mov BYTE PTR {{.*}} 560 561@global8 = internal global [1 x i8] c"\01", align 4 562 563define i32 @load_i8(i32 %addr_arg) { 564entry: 565 %addr = inttoptr i32 %addr_arg to i8* 566 %ret = load i8, i8* %addr, align 1 567 %ret2 = sub i8 %ret, 0 568 %ret_ext = zext i8 %ret2 to i32 569 ret i32 %ret_ext 570} 571; CHECK-LABEL: load_i8 572; CHECK: mov {{[a-d]l}},BYTE PTR 573; MIPS32-LABEL: load_i8 574; MIPS32: lb 575; MIPS32: addiu {{.*}},0 576; MIPS32: andi {{.*}},0xff 577; MIPS32: move 578; MIPS32: jr 579; MIPS32: nop 580 581define i32 @load_i8_global(i32 %addr_arg) { 582entry: 583 %addr = bitcast [1 x i8]* @global8 to i8* 584 %ret = load i8, i8* %addr, align 1 585 %ret2 = sub i8 %ret, 0 586 %ret_ext = zext i8 %ret2 to i32 587 ret i32 %ret_ext 588} 589; CHECK-LABEL: load_i8_global 590; CHECK: mov {{[a-d]l}},{{(BYTE PTR)?}} 591; MIPS32-LABEL: load_i8_global 592; MIPS32: lui 593; MIPS32: addiu 594; MIPS32: lb 595; MIPS32: addiu {{.*}},0 596; MIPS32: andi {{.*}},0xff 597; MIPS32: jr 598; MIPS32: nop 599 600define void @store_i8(i32 %addr_arg, i32 %val) { 601entry: 602 %val_trunc = trunc i32 %val to i8 603 %addr = inttoptr i32 %addr_arg to i8* 604 store i8 %val_trunc, i8* %addr, align 1 605 ret void 606} 607; CHECK-LABEL: store_i8 608; CHECK: mov BYTE PTR {{.*}},{{[a-d]l}} 609; MIPS32-LABEL: store_i8 610; MIPS32: sb 611; MIPS32: jr 612; MIPS32: nop 613 614define void @store_i8_const(i32 %addr_arg) { 615entry: 616 %addr = inttoptr i32 %addr_arg to i8* 617 store i8 123, i8* %addr, align 1 618 ret void 619} 620; CHECK-LABEL: store_i8_const 621; CHECK: mov BYTE PTR {{.*}},0x7b 622; MIPS32-LABEL: store_i8_const 623; MIPS32: li 624; MIPS32: sb 625; MIPS32: jr 626; MIPS32: nop 627