Index: lib/Target/X86/X86InstructionSelector.cpp =================================================================== --- lib/Target/X86/X86InstructionSelector.cpp +++ lib/Target/X86/X86InstructionSelector.cpp @@ -91,6 +91,8 @@ bool materializeFP(MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) const; bool selectImplicitDefOrPHI(MachineInstr &I, MachineRegisterInfo &MRI) const; + bool selectShift(MachineInstr &I, MachineRegisterInfo &MRI, + MachineFunction &MF) const; // emit insert subreg instruction and insert it before MachineInstr &I bool emitInsertSubreg(unsigned DstReg, unsigned SrcReg, MachineInstr &I, @@ -349,6 +351,10 @@ case TargetOpcode::G_IMPLICIT_DEF: case TargetOpcode::G_PHI: return selectImplicitDefOrPHI(I, MRI); + case TargetOpcode::G_SHL: + case TargetOpcode::G_ASHR: + case TargetOpcode::G_LSHR: + return selectShift(I, MRI, MF); } return false; @@ -1291,6 +1297,85 @@ return true; } +bool X86InstructionSelector::selectShift(MachineInstr &I, + MachineRegisterInfo &MRI, + MachineFunction &MF) const { + + assert((I.getOpcode() == TargetOpcode::G_SHL || + I.getOpcode() == TargetOpcode::G_ASHR || + I.getOpcode() == TargetOpcode::G_LSHR) && + "unexpected instruction"); + + unsigned DstReg = I.getOperand(0).getReg(); + const LLT DstTy = MRI.getType(DstReg); + const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI); + + const static unsigned NumTypes = 4; // i8, i16, i32, i64 + const static struct ShiftEntry { + unsigned CReg; + unsigned OpLSHR; + unsigned OpASHR; + unsigned OpSHL; + } OpTable[NumTypes] = { + {X86::CL, X86::SHR8rCL, X86::SAR8rCL, X86::SHL8rCL}, // i8 + {X86::CX, X86::SHR16rCL, X86::SAR16rCL, X86::SHL16rCL}, // i16 + {X86::ECX, X86::SHR32rCL, X86::SAR32rCL, X86::SHL32rCL}, // i32 + {X86::RCX, X86::SHR64rCL, X86::SAR64rCL, X86::SHL64rCL} // i64 + }; + + if (DstRB.getID() != X86::GPRRegBankID) + return false; + + unsigned TypeIndex; + if (DstTy.getSizeInBits() == 8) + TypeIndex = 0; + else if (DstTy.getSizeInBits() == 16) + TypeIndex = 1; + else if (DstTy.getSizeInBits() == 32) + TypeIndex = 2; + else if (DstTy.getSizeInBits() == 64) + TypeIndex = 3; + else + return false; + + unsigned CReg = OpTable[TypeIndex].CReg, Opcode = 0; + switch (I.getOpcode()) { + case TargetOpcode::G_SHL: + Opcode = OpTable[TypeIndex].OpSHL; + break; + case TargetOpcode::G_ASHR: + Opcode = OpTable[TypeIndex].OpASHR; + break; + case TargetOpcode::G_LSHR: + Opcode = OpTable[TypeIndex].OpLSHR; + break; + default: + return false; + } + + unsigned Op0Reg = I.getOperand(1).getReg(); + unsigned Op1Reg = I.getOperand(2).getReg(); + + BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(TargetOpcode::COPY), + OpTable[TypeIndex].CReg) + .addReg(Op1Reg); + + // The shift instruction uses X86::CL. If we defined a super-register + // of X86::CL, emit a subreg KILL to precisely describe what we're doing here. + if (CReg != X86::CL) + BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(TargetOpcode::KILL), + X86::CL) + .addReg(CReg, RegState::Kill); + + MachineInstr &ShiftInst = + *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode), DstReg) + .addReg(Op0Reg); + + constrainSelectedInstRegOperands(ShiftInst, TII, TRI, RBI); + I.eraseFromParent(); + return true; +} + InstructionSelector * llvm::createX86InstructionSelector(const X86TargetMachine &TM, X86Subtarget &Subtarget, Index: lib/Target/X86/X86LegalizerInfo.cpp =================================================================== --- lib/Target/X86/X86LegalizerInfo.cpp +++ lib/Target/X86/X86LegalizerInfo.cpp @@ -116,6 +116,14 @@ for (auto Ty : {s8, s16, s32, p0}) setAction({G_ICMP, 1, Ty}, Legal); + + // Shifts + for (unsigned ShiftOp : {G_LSHR, G_ASHR, G_SHL}) { + for (auto Ty : {s8, s16, s32, s64}) + setAction({ShiftOp, Ty}, Legal); + + setAction({ShiftOp, s1}, WidenScalar); + } } void X86LegalizerInfo::setLegalizerInfo64bit() { @@ -150,6 +158,10 @@ // Comparison setAction({G_ICMP, 1, s64}, Legal); + + // Shifts + for (unsigned ShiftOp : {G_LSHR, G_ASHR, G_SHL}) + setAction({ShiftOp, s64}, Legal); } void X86LegalizerInfo::setLegalizerInfoSSE1() { Index: lib/Target/X86/X86RegisterBankInfo.cpp =================================================================== --- lib/Target/X86/X86RegisterBankInfo.cpp +++ lib/Target/X86/X86RegisterBankInfo.cpp @@ -169,6 +169,10 @@ switch (Opc) { case TargetOpcode::G_ADD: case TargetOpcode::G_SUB: + case TargetOpcode::G_MUL: + case TargetOpcode::G_SHL: + case TargetOpcode::G_LSHR: + case TargetOpcode::G_ASHR: return getSameOperandsMapping(MI, false); break; case TargetOpcode::G_FADD: Index: test/CodeGen/X86/GlobalISel/ashr-scalar.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/ashr-scalar.ll @@ -0,0 +1,182 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=X64 + +define i64 @test_ashr_i64(i64 %arg1, i64 %arg2) { +; X64-LABEL: test_ashr_i64: +; X64: # BB#0: +; X64-NEXT: movq %rsi, %rcx +; X64-NEXT: # kill: %CL %RCX +; X64-NEXT: sarq %cl, %rdi +; X64-NEXT: movq %rdi, %rax +; X64-NEXT: retq + %res = ashr i64 %arg1, %arg2 + ret i64 %res +} + +define i64 @test_ashr_i64_imm(i64 %arg1) { +; X64-LABEL: test_ashr_i64_imm: +; X64: # BB#0: +; X64-NEXT: movq $5, %rcx +; X64-NEXT: # kill: %CL %RCX +; X64-NEXT: sarq %cl, %rdi +; X64-NEXT: movq %rdi, %rax +; X64-NEXT: retq + %res = ashr i64 %arg1, 5 + ret i64 %res +} + +define i64 @test_ashr_i64_imm1(i64 %arg1) { +; X64-LABEL: test_ashr_i64_imm1: +; X64: # BB#0: +; X64-NEXT: movq $1, %rcx +; X64-NEXT: # kill: %CL %RCX +; X64-NEXT: sarq %cl, %rdi +; X64-NEXT: movq %rdi, %rax +; X64-NEXT: retq + %res = ashr i64 %arg1, 1 + ret i64 %res +} + +define i32 @test_ashr_i32(i32 %arg1, i32 %arg2) { +; X64-LABEL: test_ashr_i32: +; X64: # BB#0: +; X64-NEXT: movl %esi, %ecx +; X64-NEXT: # kill: %CL %ECX +; X64-NEXT: sarl %cl, %edi +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %res = ashr i32 %arg1, %arg2 + ret i32 %res +} + +define i32 @test_ashr_i32_imm(i32 %arg1) { +; X64-LABEL: test_ashr_i32_imm: +; X64: # BB#0: +; X64-NEXT: movl $5, %ecx +; X64-NEXT: # kill: %CL %ECX +; X64-NEXT: sarl %cl, %edi +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %res = ashr i32 %arg1, 5 + ret i32 %res +} + +define i32 @test_ashr_i32_imm1(i32 %arg1) { +; X64-LABEL: test_ashr_i32_imm1: +; X64: # BB#0: +; X64-NEXT: movl $1, %ecx +; X64-NEXT: # kill: %CL %ECX +; X64-NEXT: sarl %cl, %edi +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %res = ashr i32 %arg1, 1 + ret i32 %res +} + +define i16 @test_ashr_i16(i32 %arg1, i32 %arg2) { +; X64-LABEL: test_ashr_i16: +; X64: # BB#0: +; X64-NEXT: movl %esi, %ecx +; X64-NEXT: # kill: %CL %CX +; X64-NEXT: sarw %cl, %di +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i16 + %a2 = trunc i32 %arg2 to i16 + %res = ashr i16 %a, %a2 + ret i16 %res +} + +define i16 @test_ashr_i16_imm(i32 %arg1) { +; X64-LABEL: test_ashr_i16_imm: +; X64: # BB#0: +; X64-NEXT: movw $5, %cx +; X64-NEXT: # kill: %CL %CX +; X64-NEXT: sarw %cl, %di +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i16 + %res = ashr i16 %a, 5 + ret i16 %res +} + +define i16 @test_ashr_i16_imm1(i32 %arg1) { +; X64-LABEL: test_ashr_i16_imm1: +; X64: # BB#0: +; X64-NEXT: movw $1, %cx +; X64-NEXT: # kill: %CL %CX +; X64-NEXT: sarw %cl, %di +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i16 + %res = ashr i16 %a, 1 + ret i16 %res +} + +define i8 @test_ashr_i8(i32 %arg1, i32 %arg2) { +; X64-LABEL: test_ashr_i8: +; X64: # BB#0: +; X64-NEXT: movl %esi, %ecx +; X64-NEXT: sarb %cl, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i8 + %a2 = trunc i32 %arg2 to i8 + %res = ashr i8 %a, %a2 + ret i8 %res +} + +define i8 @test_ashr_i8_imm(i32 %arg1) { +; X64-LABEL: test_ashr_i8_imm: +; X64: # BB#0: +; X64-NEXT: sarb $5, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i8 + %res = ashr i8 %a, 5 + ret i8 %res +} + +define i8 @test_ashr_i8_imm1(i32 %arg1) { +; X64-LABEL: test_ashr_i8_imm1: +; X64: # BB#0: +; X64-NEXT: sarb %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i8 + %res = ashr i8 %a, 1 + ret i8 %res +} + +define i1 @test_ashr_i1(i32 %arg1, i32 %arg2) { +; X64-LABEL: test_ashr_i1: +; X64: # BB#0: +; X64-NEXT: shlb $7, %dil +; X64-NEXT: sarb $7, %dil +; X64-NEXT: shlb $7, %sil +; X64-NEXT: sarb $7, %sil +; X64-NEXT: movl %esi, %ecx +; X64-NEXT: sarb %cl, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i1 + %a2 = trunc i32 %arg2 to i1 + %res = ashr i1 %a, %a2 + ret i1 %res +} + +define i1 @test_ashr_i1_imm1(i32 %arg1) { +; X64-LABEL: test_ashr_i1_imm1: +; X64: # BB#0: +; X64-NEXT: movb $-1, %cl +; X64-NEXT: shlb $7, %dil +; X64-NEXT: sarb $7, %dil +; X64-NEXT: shlb $7, %cl +; X64-NEXT: sarb $7, %cl +; X64-NEXT: sarb %cl, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i1 + %res = ashr i1 %a, 1 + ret i1 %res +} Index: test/CodeGen/X86/GlobalISel/legalize-ashr-scalar.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/legalize-ashr-scalar.mir @@ -0,0 +1,101 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s +--- | + + define void @test_ashr() { ret void } + define void @test_ashr_i1() { ret void } +... +--- +name: test_ashr +# CHECK-LABEL: name: test_ashr +alignment: 4 +legalized: false +regBankSelected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _, preferred-register: '' } + - { id: 1, class: _, preferred-register: '' } + - { id: 2, class: _, preferred-register: '' } + - { id: 3, class: _, preferred-register: '' } + - { id: 4, class: _, preferred-register: '' } + - { id: 5, class: _, preferred-register: '' } + - { id: 6, class: _, preferred-register: '' } + - { id: 7, class: _, preferred-register: '' } + - { id: 8, class: _, preferred-register: '' } + - { id: 9, class: _, preferred-register: '' } + - { id: 10, class: _, preferred-register: '' } + - { id: 11, class: _, preferred-register: '' } +# CHECK: %0(s64) = COPY %rdi +# CHECK-NEXT: %1(s64) = COPY %rsi +# CHECK-NEXT: %2(s64) = G_ASHR %0, %1 +# CHECK-NEXT: %3(s32) = G_TRUNC %0(s64) +# CHECK-NEXT: %4(s32) = G_TRUNC %1(s64) +# CHECK-NEXT: %5(s32) = G_ASHR %3, %4 +# CHECK-NEXT: %6(s16) = G_TRUNC %0(s64) +# CHECK-NEXT: %7(s16) = G_TRUNC %1(s64) +# CHECK-NEXT: %8(s16) = G_ASHR %6, %7 +# CHECK-NEXT: %9(s8) = G_TRUNC %0(s64) +# CHECK-NEXT: %10(s8) = G_TRUNC %1(s64) +# CHECK-NEXT: %11(s8) = G_ASHR %9, %10 +# CHECK-NEXT: RET 0 +body: | + bb.1 (%ir-block.0): + liveins: %rdi, %rsi + + %0(s64) = COPY %rdi + %1(s64) = COPY %rsi + %2(s64) = G_ASHR %0, %1 + + %3(s32) = G_TRUNC %0 + %4(s32) = G_TRUNC %1 + %5(s32) = G_ASHR %3, %4 + + %6(s16) = G_TRUNC %0 + %7(s16) = G_TRUNC %1 + %8(s16) = G_ASHR %6, %7 + + %9(s8) = G_TRUNC %0 + %10(s8) = G_TRUNC %1 + %11(s8) = G_ASHR %9, %10 + + RET 0 + +... +--- +name: test_ashr_i1 +# CHECK-LABEL: name: test_ashr_i1 +alignment: 4 +legalized: false +regBankSelected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _, preferred-register: '' } + - { id: 1, class: _, preferred-register: '' } + - { id: 2, class: _, preferred-register: '' } + - { id: 3, class: _, preferred-register: '' } + - { id: 4, class: _, preferred-register: '' } +# CHECK: %0(s64) = COPY %rdi +# CHECK-NEXT: %1(s64) = COPY %rsi +# CHECK-NEXT: %11(s8) = G_CONSTANT i8 7 +# CHECK-NEXT: %12(s8) = G_TRUNC %0(s64) +# CHECK-NEXT: %13(s8) = G_SHL %12, %11 +# CHECK-NEXT: %5(s8) = G_ASHR %13, %11 +# CHECK-NEXT: %8(s8) = G_CONSTANT i8 7 +# CHECK-NEXT: %9(s8) = G_TRUNC %1(s64) +# CHECK-NEXT: %10(s8) = G_SHL %9, %8 +# CHECK-NEXT: %6(s8) = G_ASHR %10, %8 +# CHECK-NEXT: %7(s8) = G_ASHR %5, %6 +# CHECK-NEXT: %4(s1) = G_TRUNC %7(s8) +# CHECK-NEXT: RET 0 +body: | + bb.1 (%ir-block.0): + liveins: %rdi, %rsi + + %0(s64) = COPY %rdi + %1(s64) = COPY %rsi + %2(s1) = G_TRUNC %0 + %3(s1) = G_TRUNC %1 + %4(s1) = G_ASHR %2, %3 + + RET 0 + +... Index: test/CodeGen/X86/GlobalISel/legalize-lshr-scalar.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/legalize-lshr-scalar.mir @@ -0,0 +1,99 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s +--- | + + define void @test_lshr() { ret void } + define void @test_lshr_i1() { ret void } +... +--- +name: test_lshr +# CHECK-LABEL: name: test_lshr +alignment: 4 +legalized: false +regBankSelected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _, preferred-register: '' } + - { id: 1, class: _, preferred-register: '' } + - { id: 2, class: _, preferred-register: '' } + - { id: 3, class: _, preferred-register: '' } + - { id: 4, class: _, preferred-register: '' } + - { id: 5, class: _, preferred-register: '' } + - { id: 6, class: _, preferred-register: '' } + - { id: 7, class: _, preferred-register: '' } + - { id: 8, class: _, preferred-register: '' } + - { id: 9, class: _, preferred-register: '' } + - { id: 10, class: _, preferred-register: '' } + - { id: 11, class: _, preferred-register: '' } +# CHECK: %0(s64) = COPY %rdi +# CHECK-NEXT: %1(s64) = COPY %rsi +# CHECK-NEXT: %2(s64) = G_LSHR %0, %1 +# CHECK-NEXT: %3(s32) = G_TRUNC %0(s64) +# CHECK-NEXT: %4(s32) = G_TRUNC %1(s64) +# CHECK-NEXT: %5(s32) = G_LSHR %3, %4 +# CHECK-NEXT: %6(s16) = G_TRUNC %0(s64) +# CHECK-NEXT: %7(s16) = G_TRUNC %1(s64) +# CHECK-NEXT: %8(s16) = G_LSHR %6, %7 +# CHECK-NEXT: %9(s8) = G_TRUNC %0(s64) +# CHECK-NEXT: %10(s8) = G_TRUNC %1(s64) +# CHECK-NEXT: %11(s8) = G_LSHR %9, %10 +# CHECK-NEXT: RET 0 +body: | + bb.1 (%ir-block.0): + liveins: %rdi, %rsi + + %0(s64) = COPY %rdi + %1(s64) = COPY %rsi + %2(s64) = G_LSHR %0, %1 + + %3(s32) = G_TRUNC %0 + %4(s32) = G_TRUNC %1 + %5(s32) = G_LSHR %3, %4 + + %6(s16) = G_TRUNC %0 + %7(s16) = G_TRUNC %1 + %8(s16) = G_LSHR %6, %7 + + %9(s8) = G_TRUNC %0 + %10(s8) = G_TRUNC %1 + %11(s8) = G_LSHR %9, %10 + + RET 0 + +... +--- +name: test_lshr_i1 +# CHECK-LABEL: name: test_lshr_i1 +alignment: 4 +legalized: false +regBankSelected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _, preferred-register: '' } + - { id: 1, class: _, preferred-register: '' } + - { id: 2, class: _, preferred-register: '' } + - { id: 3, class: _, preferred-register: '' } + - { id: 4, class: _, preferred-register: '' } +# CHECK: %0(s64) = COPY %rdi +# CHECK-NEXT: %1(s64) = COPY %rsi +# CHECK-NEXT: %10(s8) = G_CONSTANT i8 1 +# CHECK-NEXT: %11(s8) = G_TRUNC %0(s64) +# CHECK-NEXT: %5(s8) = G_AND %11, %10 +# CHECK-NEXT: %8(s8) = G_CONSTANT i8 1 +# CHECK-NEXT: %9(s8) = G_TRUNC %1(s64) +# CHECK-NEXT: %6(s8) = G_AND %9, %8 +# CHECK-NEXT: %7(s8) = G_LSHR %5, %6 +# CHECK-NEXT: %4(s1) = G_TRUNC %7(s8) +# CHECK-NEXT: RET 0 +body: | + bb.1 (%ir-block.0): + liveins: %rdi, %rsi + + %0(s64) = COPY %rdi + %1(s64) = COPY %rsi + %2(s1) = G_TRUNC %0 + %3(s1) = G_TRUNC %1 + %4(s1) = G_LSHR %2, %3 + + RET 0 + +... Index: test/CodeGen/X86/GlobalISel/legalize-shl-scalar.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/legalize-shl-scalar.mir @@ -0,0 +1,95 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s +--- | + + define void @test_shl() { ret void } + define void @test_shl_i1() { ret void } +... +--- +name: test_shl +# CHECK-LABEL: name: test_shl +alignment: 4 +legalized: false +regBankSelected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _, preferred-register: '' } + - { id: 1, class: _, preferred-register: '' } + - { id: 2, class: _, preferred-register: '' } + - { id: 3, class: _, preferred-register: '' } + - { id: 4, class: _, preferred-register: '' } + - { id: 5, class: _, preferred-register: '' } + - { id: 6, class: _, preferred-register: '' } + - { id: 7, class: _, preferred-register: '' } + - { id: 8, class: _, preferred-register: '' } + - { id: 9, class: _, preferred-register: '' } + - { id: 10, class: _, preferred-register: '' } + - { id: 11, class: _, preferred-register: '' } +# CHECK: %0(s64) = COPY %rdi +# CHECK-NEXT: %1(s64) = COPY %rsi +# CHECK-NEXT: %2(s64) = G_SHL %0, %1 +# CHECK-NEXT: %3(s32) = G_TRUNC %0(s64) +# CHECK-NEXT: %4(s32) = G_TRUNC %1(s64) +# CHECK-NEXT: %5(s32) = G_SHL %3, %4 +# CHECK-NEXT: %6(s16) = G_TRUNC %0(s64) +# CHECK-NEXT: %7(s16) = G_TRUNC %1(s64) +# CHECK-NEXT: %8(s16) = G_SHL %6, %7 +# CHECK-NEXT: %9(s8) = G_TRUNC %0(s64) +# CHECK-NEXT: %10(s8) = G_TRUNC %1(s64) +# CHECK-NEXT: %11(s8) = G_SHL %9, %10 +# CHECK-NEXT: RET 0 +body: | + bb.1 (%ir-block.0): + liveins: %rdi, %rsi + + %0(s64) = COPY %rdi + %1(s64) = COPY %rsi + %2(s64) = G_SHL %0, %1 + + %3(s32) = G_TRUNC %0 + %4(s32) = G_TRUNC %1 + %5(s32) = G_SHL %3, %4 + + %6(s16) = G_TRUNC %0 + %7(s16) = G_TRUNC %1 + %8(s16) = G_SHL %6, %7 + + %9(s8) = G_TRUNC %0 + %10(s8) = G_TRUNC %1 + %11(s8) = G_SHL %9, %10 + + RET 0 + +... +--- +name: test_shl_i1 +# CHECK-LABEL: name: test_shl_i1 +alignment: 4 +legalized: false +regBankSelected: false +tracksRegLiveness: true +registers: + - { id: 0, class: _, preferred-register: '' } + - { id: 1, class: _, preferred-register: '' } + - { id: 2, class: _, preferred-register: '' } + - { id: 3, class: _, preferred-register: '' } + - { id: 4, class: _, preferred-register: '' } +# CHECK: %0(s64) = COPY %rdi +# CHECK-NEXT: %1(s64) = COPY %rsi +# CHECK-NEXT: %5(s8) = G_TRUNC %0(s64) +# CHECK-NEXT: %6(s8) = G_TRUNC %1(s64) +# CHECK-NEXT: %7(s8) = G_SHL %5, %6 +# CHECK-NEXT: %4(s1) = G_TRUNC %7(s8) +# CHECK-NEXT: RET 0 +body: | + bb.1 (%ir-block.0): + liveins: %rdi, %rsi + + %0(s64) = COPY %rdi + %1(s64) = COPY %rsi + %2(s1) = G_TRUNC %0 + %3(s1) = G_TRUNC %1 + %4(s1) = G_SHL %2, %3 + + RET 0 + +... Index: test/CodeGen/X86/GlobalISel/lshr-scalar.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/lshr-scalar.ll @@ -0,0 +1,178 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=X64 + +define i64 @test_lshr_i64(i64 %arg1, i64 %arg2) { +; X64-LABEL: test_lshr_i64: +; X64: # BB#0: +; X64-NEXT: movq %rsi, %rcx +; X64-NEXT: # kill: %CL %RCX +; X64-NEXT: shrq %cl, %rdi +; X64-NEXT: movq %rdi, %rax +; X64-NEXT: retq + %res = lshr i64 %arg1, %arg2 + ret i64 %res +} + +define i64 @test_lshr_i64_imm(i64 %arg1) { +; X64-LABEL: test_lshr_i64_imm: +; X64: # BB#0: +; X64-NEXT: movq $5, %rcx +; X64-NEXT: # kill: %CL %RCX +; X64-NEXT: shrq %cl, %rdi +; X64-NEXT: movq %rdi, %rax +; X64-NEXT: retq + %res = lshr i64 %arg1, 5 + ret i64 %res +} + +define i64 @test_lshr_i64_imm1(i64 %arg1) { +; X64-LABEL: test_lshr_i64_imm1: +; X64: # BB#0: +; X64-NEXT: movq $1, %rcx +; X64-NEXT: # kill: %CL %RCX +; X64-NEXT: shrq %cl, %rdi +; X64-NEXT: movq %rdi, %rax +; X64-NEXT: retq + %res = lshr i64 %arg1, 1 + ret i64 %res +} + +define i32 @test_lshr_i32(i32 %arg1, i32 %arg2) { +; X64-LABEL: test_lshr_i32: +; X64: # BB#0: +; X64-NEXT: movl %esi, %ecx +; X64-NEXT: # kill: %CL %ECX +; X64-NEXT: shrl %cl, %edi +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %res = lshr i32 %arg1, %arg2 + ret i32 %res +} + +define i32 @test_lshr_i32_imm(i32 %arg1) { +; X64-LABEL: test_lshr_i32_imm: +; X64: # BB#0: +; X64-NEXT: movl $5, %ecx +; X64-NEXT: # kill: %CL %ECX +; X64-NEXT: shrl %cl, %edi +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %res = lshr i32 %arg1, 5 + ret i32 %res +} + +define i32 @test_lshr_i32_imm1(i32 %arg1) { +; X64-LABEL: test_lshr_i32_imm1: +; X64: # BB#0: +; X64-NEXT: movl $1, %ecx +; X64-NEXT: # kill: %CL %ECX +; X64-NEXT: shrl %cl, %edi +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %res = lshr i32 %arg1, 1 + ret i32 %res +} + +define i16 @test_lshr_i16(i32 %arg1, i32 %arg2) { +; X64-LABEL: test_lshr_i16: +; X64: # BB#0: +; X64-NEXT: movl %esi, %ecx +; X64-NEXT: # kill: %CL %CX +; X64-NEXT: shrw %cl, %di +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i16 + %a2 = trunc i32 %arg2 to i16 + %res = lshr i16 %a, %a2 + ret i16 %res +} + +define i16 @test_lshr_i16_imm(i32 %arg1) { +; X64-LABEL: test_lshr_i16_imm: +; X64: # BB#0: +; X64-NEXT: movw $5, %cx +; X64-NEXT: # kill: %CL %CX +; X64-NEXT: shrw %cl, %di +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i16 + %res = lshr i16 %a, 5 + ret i16 %res +} + +define i16 @test_lshr_i16_imm1(i32 %arg1) { +; X64-LABEL: test_lshr_i16_imm1: +; X64: # BB#0: +; X64-NEXT: movw $1, %cx +; X64-NEXT: # kill: %CL %CX +; X64-NEXT: shrw %cl, %di +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i16 + %res = lshr i16 %a, 1 + ret i16 %res +} + +define i8 @test_lshr_i8(i32 %arg1, i32 %arg2) { +; X64-LABEL: test_lshr_i8: +; X64: # BB#0: +; X64-NEXT: movl %esi, %ecx +; X64-NEXT: shrb %cl, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i8 + %a2 = trunc i32 %arg2 to i8 + %res = lshr i8 %a, %a2 + ret i8 %res +} + +define i8 @test_lshr_i8_imm(i32 %arg1) { +; X64-LABEL: test_lshr_i8_imm: +; X64: # BB#0: +; X64-NEXT: shrb $5, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i8 + %res = lshr i8 %a, 5 + ret i8 %res +} + +define i8 @test_lshr_i8_imm1(i32 %arg1) { +; X64-LABEL: test_lshr_i8_imm1: +; X64: # BB#0: +; X64-NEXT: shrb %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i8 + %res = lshr i8 %a, 1 + ret i8 %res +} + +define i1 @test_lshr_i1(i32 %arg1, i32 %arg2) { +; X64-LABEL: test_lshr_i1: +; X64: # BB#0: +; X64-NEXT: andb $1, %dil +; X64-NEXT: andb $1, %sil +; X64-NEXT: movl %esi, %ecx +; X64-NEXT: shrb %cl, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i1 + %a2 = trunc i32 %arg2 to i1 + %res = lshr i1 %a, %a2 + ret i1 %res +} + +define i1 @test_lshr_i1_imm1(i32 %arg1) { +; X64-LABEL: test_lshr_i1_imm1: +; X64: # BB#0: +; X64-NEXT: movb $-1, %cl +; X64-NEXT: andb $1, %dil +; X64-NEXT: andb $1, %cl +; X64-NEXT: shrb %cl, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i1 + %res = lshr i1 %a, 1 + ret i1 %res +} Index: test/CodeGen/X86/GlobalISel/regbankselect-X86_64.mir =================================================================== --- test/CodeGen/X86/GlobalISel/regbankselect-X86_64.mir +++ test/CodeGen/X86/GlobalISel/regbankselect-X86_64.mir @@ -241,6 +241,13 @@ ret void } + define void @test_shl_i32(i32 %arg1, i32 %arg2) { + %res = shl i32 %arg1, %arg2 + %res1 = lshr i32 %arg1, %arg2 + %res2 = ashr i32 %arg1, %arg2 + ret void + } + ... --- name: test_add_i8 @@ -1430,4 +1437,40 @@ %0(s32) = G_FCONSTANT float 1.0 %1(s64) = G_FCONSTANT double 2.0 ... +--- +name: test_shl_i32 +# CHECK-LABEL: name: test_shl_i32 +alignment: 4 +legalized: true +regBankSelected: false +tracksRegLiveness: true +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gpr, preferred-register: '' } +# CHECK-NEXT: - { id: 1, class: gpr, preferred-register: '' } +# CHECK-NEXT: - { id: 2, class: gpr, preferred-register: '' } +# CHECK-NEXT: - { id: 3, class: gpr, preferred-register: '' } +# CHECK-NEXT: - { id: 4, class: gpr, preferred-register: '' } +registers: + - { id: 0, class: _, preferred-register: '' } + - { id: 1, class: _, preferred-register: '' } + - { id: 2, class: _, preferred-register: '' } + - { id: 3, class: _, preferred-register: '' } + - { id: 4, class: _, preferred-register: '' } +# CHECK: %0(s32) = COPY %edi +# CHECK-NEXT: %1(s32) = COPY %esi +# CHECK-NEXT: %2(s32) = G_SHL %0, %1 +# CHECK-NEXT: %3(s32) = G_LSHR %0, %1 +# CHECK-NEXT: %4(s32) = G_ASHR %0, %1 +# CHECK-NEXT: RET 0 +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s32) = G_SHL %0, %1 + %3(s32) = G_LSHR %0, %1 + %4(s32) = G_ASHR %0, %1 + RET 0 + +... Index: test/CodeGen/X86/GlobalISel/select-ashr-scalar.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/select-ashr-scalar.mir @@ -0,0 +1,540 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=ALL +--- | + + define i64 @test_ashr_i64(i64 %arg1, i64 %arg2) { + %res = ashr i64 %arg1, %arg2 + ret i64 %res + } + + define i64 @test_ashr_i64_imm(i64 %arg1) { + %res = ashr i64 %arg1, 5 + ret i64 %res + } + + define i64 @test_ashr_i64_imm1(i64 %arg1) { + %res = ashr i64 %arg1, 1 + ret i64 %res + } + + define i32 @test_ashr_i32(i32 %arg1, i32 %arg2) { + %res = ashr i32 %arg1, %arg2 + ret i32 %res + } + + define i32 @test_ashr_i32_imm(i32 %arg1) { + %res = ashr i32 %arg1, 5 + ret i32 %res + } + + define i32 @test_ashr_i32_imm1(i32 %arg1) { + %res = ashr i32 %arg1, 1 + ret i32 %res + } + + define i16 @test_ashr_i16(i32 %arg1, i32 %arg2) { + %a = trunc i32 %arg1 to i16 + %a2 = trunc i32 %arg2 to i16 + %res = ashr i16 %a, %a2 + ret i16 %res + } + + define i16 @test_ashr_i16_imm(i32 %arg1) { + %a = trunc i32 %arg1 to i16 + %res = ashr i16 %a, 5 + ret i16 %res + } + + define i16 @test_ashr_i16_imm1(i32 %arg1) { + %a = trunc i32 %arg1 to i16 + %res = ashr i16 %a, 1 + ret i16 %res + } + + define i8 @test_ashr_i8(i32 %arg1, i32 %arg2) { + %a = trunc i32 %arg1 to i8 + %a2 = trunc i32 %arg2 to i8 + %res = ashr i8 %a, %a2 + ret i8 %res + } + + define i8 @test_ashr_i8_imm(i32 %arg1) { + %a = trunc i32 %arg1 to i8 + %res = ashr i8 %a, 5 + ret i8 %res + } + + define i8 @test_ashr_i8_imm1(i32 %arg1) { + %a = trunc i32 %arg1 to i8 + %res = ashr i8 %a, 1 + ret i8 %res + } +... +--- +name: test_ashr_i64 +# ALL-LABEL: name: test_ashr_i64 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr64, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %rdi +# ALL-NEXT: %1 = COPY %rsi +# ALL-NEXT: %rcx = COPY %1 +# ALL-NEXT: %cl = KILL killed %rcx +# ALL-NEXT: %2 = SAR64rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %rax = COPY %2 +# ALL-NEXT: RET 0, implicit %rax +body: | + bb.1 (%ir-block.0): + liveins: %rdi, %rsi + + %0(s64) = COPY %rdi + %1(s64) = COPY %rsi + %2(s64) = G_ASHR %0, %1 + %rax = COPY %2(s64) + RET 0, implicit %rax + +... +--- +name: test_ashr_i64_imm +# ALL-LABEL: name: test_ashr_i64_imm +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr64, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %rdi +# ALL-NEXT: %1 = MOV64ri32 5 +# ALL-NEXT: %rcx = COPY %1 +# ALL-NEXT: %cl = KILL killed %rcx +# ALL-NEXT: %2 = SAR64rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %rax = COPY %2 +# ALL-NEXT: RET 0, implicit %rax +body: | + bb.1 (%ir-block.0): + liveins: %rdi + + %0(s64) = COPY %rdi + %1(s64) = G_CONSTANT i64 5 + %2(s64) = G_ASHR %0, %1 + %rax = COPY %2(s64) + RET 0, implicit %rax + +... +--- +name: test_ashr_i64_imm1 +# ALL-LABEL: name: test_ashr_i64_imm1 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr64, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %rdi +# ALL-NEXT: %1 = MOV64ri32 1 +# ALL-NEXT: %rcx = COPY %1 +# ALL-NEXT: %cl = KILL killed %rcx +# ALL-NEXT: %2 = SAR64rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %rax = COPY %2 +# ALL-NEXT: RET 0, implicit %rax +body: | + bb.1 (%ir-block.0): + liveins: %rdi + + %0(s64) = COPY %rdi + %1(s64) = G_CONSTANT i64 1 + %2(s64) = G_ASHR %0, %1 + %rax = COPY %2(s64) + RET 0, implicit %rax + +... +--- +name: test_ashr_i32 +# ALL-LABEL: name: test_ashr_i32 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %esi +# ALL-NEXT: %ecx = COPY %1 +# ALL-NEXT: %cl = KILL killed %ecx +# ALL-NEXT: %2 = SAR32rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %eax = COPY %2 +# ALL-NEXT: RET 0, implicit %eax +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s32) = G_ASHR %0, %1 + %eax = COPY %2(s32) + RET 0, implicit %eax + +... +--- +name: test_ashr_i32_imm +# ALL-LABEL: name: test_ashr_i32_imm +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = MOV32ri 5 +# ALL-NEXT: %ecx = COPY %1 +# ALL-NEXT: %cl = KILL killed %ecx +# ALL-NEXT: %2 = SAR32rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %eax = COPY %2 +# ALL-NEXT: RET 0, implicit %eax +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %1(s32) = G_CONSTANT i32 5 + %2(s32) = G_ASHR %0, %1 + %eax = COPY %2(s32) + RET 0, implicit %eax + +... +--- +name: test_ashr_i32_imm1 +# ALL-LABEL: name: test_ashr_i32_imm1 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = MOV32ri 1 +# ALL-NEXT: %ecx = COPY %1 +# ALL-NEXT: %cl = KILL killed %ecx +# ALL-NEXT: %2 = SAR32rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %eax = COPY %2 +# ALL-NEXT: RET 0, implicit %eax +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %1(s32) = G_CONSTANT i32 1 + %2(s32) = G_ASHR %0, %1 + %eax = COPY %2(s32) + RET 0, implicit %eax + +... +--- +name: test_ashr_i16 +# ALL-LABEL: name: test_ashr_i16 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 4, class: gr16, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } + - { id: 4, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %esi +# ALL-NEXT: %2 = COPY %0.sub_16bit +# ALL-NEXT: %3 = COPY %1.sub_16bit +# ALL-NEXT: %cx = COPY %3 +# ALL-NEXT: %cl = KILL killed %cx +# ALL-NEXT: %4 = SAR16rCL %2, implicit-def %eflags, implicit %cl +# ALL-NEXT: %ax = COPY %4 +# ALL-NEXT: RET 0, implicit %ax +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s16) = G_TRUNC %0(s32) + %3(s16) = G_TRUNC %1(s32) + %4(s16) = G_ASHR %2, %3 + %ax = COPY %4(s16) + RET 0, implicit %ax + +... +--- +name: test_ashr_i16_imm +# ALL-LABEL: name: test_ashr_i16_imm +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr16, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %2 = MOV16ri 5 +# ALL-NEXT: %1 = COPY %0.sub_16bit +# ALL-NEXT: %cx = COPY %2 +# ALL-NEXT: %cl = KILL killed %cx +# ALL-NEXT: %3 = SAR16rCL %1, implicit-def %eflags, implicit %cl +# ALL-NEXT: %ax = COPY %3 +# ALL-NEXT: RET 0, implicit %ax +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %2(s16) = G_CONSTANT i16 5 + %1(s16) = G_TRUNC %0(s32) + %3(s16) = G_ASHR %1, %2 + %ax = COPY %3(s16) + RET 0, implicit %ax + +... +--- +name: test_ashr_i16_imm1 +# ALL-LABEL: name: test_ashr_i16_imm1 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr16, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %2 = MOV16ri 1 +# ALL-NEXT: %1 = COPY %0.sub_16bit +# ALL-NEXT: %cx = COPY %2 +# ALL-NEXT: %cl = KILL killed %cx +# ALL-NEXT: %3 = SAR16rCL %1, implicit-def %eflags, implicit %cl +# ALL-NEXT: %ax = COPY %3 +# ALL-NEXT: RET 0, implicit %ax +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %2(s16) = G_CONSTANT i16 1 + %1(s16) = G_TRUNC %0(s32) + %3(s16) = G_ASHR %1, %2 + %ax = COPY %3(s16) + RET 0, implicit %ax + +... +--- +name: test_ashr_i8 +# ALL-LABEL: name: test_ashr_i8 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr8, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr8, preferred-register: '' } +# ALL-NEXT: - { id: 4, class: gr8, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } + - { id: 4, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %esi +# ALL-NEXT: %2 = COPY %0.sub_8bit +# ALL-NEXT: %3 = COPY %1.sub_8bit +# ALL-NEXT: %cl = COPY %3 +# ALL-NEXT: %4 = SAR8rCL %2, implicit-def %eflags, implicit %cl +# ALL-NEXT: %al = COPY %4 +# ALL-NEXT: RET 0, implicit %al +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s8) = G_TRUNC %0(s32) + %3(s8) = G_TRUNC %1(s32) + %4(s8) = G_ASHR %2, %3 + %al = COPY %4(s8) + RET 0, implicit %al + +... +--- +name: test_ashr_i8_imm +# ALL-LABEL: name: test_ashr_i8_imm +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr8, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gpr, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr8, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %0.sub_8bit +# ALL-NEXT: %3 = SAR8ri %1, 5, implicit-def %eflags +# ALL-NEXT: %al = COPY %3 +# ALL-NEXT: RET 0, implicit %al +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %2(s8) = G_CONSTANT i8 5 + %1(s8) = G_TRUNC %0(s32) + %3(s8) = G_ASHR %1, %2 + %al = COPY %3(s8) + RET 0, implicit %al + +... +--- +name: test_ashr_i8_imm1 +# ALL-LABEL: name: test_ashr_i8_imm1 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr8, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gpr, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr8, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %0.sub_8bit +# ALL-NEXT: %3 = SAR8r1 %1, implicit-def %eflags +# ALL-NEXT: %al = COPY %3 +# ALL-NEXT: RET 0, implicit %al +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %2(s8) = G_CONSTANT i8 1 + %1(s8) = G_TRUNC %0(s32) + %3(s8) = G_ASHR %1, %2 + %al = COPY %3(s8) + RET 0, implicit %al + +... Index: test/CodeGen/X86/GlobalISel/select-lshr-scalar.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/select-lshr-scalar.mir @@ -0,0 +1,540 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=ALL +--- | + + define i64 @test_lshr_i64(i64 %arg1, i64 %arg2) { + %res = lshr i64 %arg1, %arg2 + ret i64 %res + } + + define i64 @test_lshr_i64_imm(i64 %arg1) { + %res = lshr i64 %arg1, 5 + ret i64 %res + } + + define i64 @test_lshr_i64_imm1(i64 %arg1) { + %res = lshr i64 %arg1, 1 + ret i64 %res + } + + define i32 @test_lshr_i32(i32 %arg1, i32 %arg2) { + %res = lshr i32 %arg1, %arg2 + ret i32 %res + } + + define i32 @test_lshr_i32_imm(i32 %arg1) { + %res = lshr i32 %arg1, 5 + ret i32 %res + } + + define i32 @test_lshr_i32_imm1(i32 %arg1) { + %res = lshr i32 %arg1, 1 + ret i32 %res + } + + define i16 @test_lshr_i16(i32 %arg1, i32 %arg2) { + %a = trunc i32 %arg1 to i16 + %a2 = trunc i32 %arg2 to i16 + %res = lshr i16 %a, %a2 + ret i16 %res + } + + define i16 @test_lshr_i16_imm(i32 %arg1) { + %a = trunc i32 %arg1 to i16 + %res = lshr i16 %a, 5 + ret i16 %res + } + + define i16 @test_lshr_i16_imm1(i32 %arg1) { + %a = trunc i32 %arg1 to i16 + %res = lshr i16 %a, 1 + ret i16 %res + } + + define i8 @test_lshr_i8(i32 %arg1, i32 %arg2) { + %a = trunc i32 %arg1 to i8 + %a2 = trunc i32 %arg2 to i8 + %res = lshr i8 %a, %a2 + ret i8 %res + } + + define i8 @test_lshr_i8_imm(i32 %arg1) { + %a = trunc i32 %arg1 to i8 + %res = lshr i8 %a, 5 + ret i8 %res + } + + define i8 @test_lshr_i8_imm1(i32 %arg1) { + %a = trunc i32 %arg1 to i8 + %res = lshr i8 %a, 1 + ret i8 %res + } +... +--- +name: test_lshr_i64 +# ALL-LABEL: name: test_lshr_i64 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr64, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %rdi +# ALL-NEXT: %1 = COPY %rsi +# ALL-NEXT: %rcx = COPY %1 +# ALL-NEXT: %cl = KILL killed %rcx +# ALL-NEXT: %2 = SHR64rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %rax = COPY %2 +# ALL-NEXT: RET 0, implicit %rax +body: | + bb.1 (%ir-block.0): + liveins: %rdi, %rsi + + %0(s64) = COPY %rdi + %1(s64) = COPY %rsi + %2(s64) = G_LSHR %0, %1 + %rax = COPY %2(s64) + RET 0, implicit %rax + +... +--- +name: test_lshr_i64_imm +# ALL-LABEL: name: test_lshr_i64_imm +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr64, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %rdi +# ALL-NEXT: %1 = MOV64ri32 5 +# ALL-NEXT: %rcx = COPY %1 +# ALL-NEXT: %cl = KILL killed %rcx +# ALL-NEXT: %2 = SHR64rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %rax = COPY %2 +# ALL-NEXT: RET 0, implicit %rax +body: | + bb.1 (%ir-block.0): + liveins: %rdi + + %0(s64) = COPY %rdi + %1(s64) = G_CONSTANT i64 5 + %2(s64) = G_LSHR %0, %1 + %rax = COPY %2(s64) + RET 0, implicit %rax + +... +--- +name: test_lshr_i64_imm1 +# ALL-LABEL: name: test_lshr_i64_imm1 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr64, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %rdi +# ALL-NEXT: %1 = MOV64ri32 1 +# ALL-NEXT: %rcx = COPY %1 +# ALL-NEXT: %cl = KILL killed %rcx +# ALL-NEXT: %2 = SHR64rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %rax = COPY %2 +# ALL-NEXT: RET 0, implicit %rax +body: | + bb.1 (%ir-block.0): + liveins: %rdi + + %0(s64) = COPY %rdi + %1(s64) = G_CONSTANT i64 1 + %2(s64) = G_LSHR %0, %1 + %rax = COPY %2(s64) + RET 0, implicit %rax + +... +--- +name: test_lshr_i32 +# ALL-LABEL: name: test_lshr_i32 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %esi +# ALL-NEXT: %ecx = COPY %1 +# ALL-NEXT: %cl = KILL killed %ecx +# ALL-NEXT: %2 = SHR32rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %eax = COPY %2 +# ALL-NEXT: RET 0, implicit %eax +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s32) = G_LSHR %0, %1 + %eax = COPY %2(s32) + RET 0, implicit %eax + +... +--- +name: test_lshr_i32_imm +# ALL-LABEL: name: test_lshr_i32_imm +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = MOV32ri 5 +# ALL-NEXT: %ecx = COPY %1 +# ALL-NEXT: %cl = KILL killed %ecx +# ALL-NEXT: %2 = SHR32rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %eax = COPY %2 +# ALL-NEXT: RET 0, implicit %eax +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %1(s32) = G_CONSTANT i32 5 + %2(s32) = G_LSHR %0, %1 + %eax = COPY %2(s32) + RET 0, implicit %eax + +... +--- +name: test_lshr_i32_imm1 +# ALL-LABEL: name: test_lshr_i32_imm1 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = MOV32ri 1 +# ALL-NEXT: %ecx = COPY %1 +# ALL-NEXT: %cl = KILL killed %ecx +# ALL-NEXT: %2 = SHR32rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %eax = COPY %2 +# ALL-NEXT: RET 0, implicit %eax +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %1(s32) = G_CONSTANT i32 1 + %2(s32) = G_LSHR %0, %1 + %eax = COPY %2(s32) + RET 0, implicit %eax + +... +--- +name: test_lshr_i16 +# ALL-LABEL: name: test_lshr_i16 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 4, class: gr16, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } + - { id: 4, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %esi +# ALL-NEXT: %2 = COPY %0.sub_16bit +# ALL-NEXT: %3 = COPY %1.sub_16bit +# ALL-NEXT: %cx = COPY %3 +# ALL-NEXT: %cl = KILL killed %cx +# ALL-NEXT: %4 = SHR16rCL %2, implicit-def %eflags, implicit %cl +# ALL-NEXT: %ax = COPY %4 +# ALL-NEXT: RET 0, implicit %ax +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s16) = G_TRUNC %0(s32) + %3(s16) = G_TRUNC %1(s32) + %4(s16) = G_LSHR %2, %3 + %ax = COPY %4(s16) + RET 0, implicit %ax + +... +--- +name: test_lshr_i16_imm +# ALL-LABEL: name: test_lshr_i16_imm +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr16, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %2 = MOV16ri 5 +# ALL-NEXT: %1 = COPY %0.sub_16bit +# ALL-NEXT: %cx = COPY %2 +# ALL-NEXT: %cl = KILL killed %cx +# ALL-NEXT: %3 = SHR16rCL %1, implicit-def %eflags, implicit %cl +# ALL-NEXT: %ax = COPY %3 +# ALL-NEXT: RET 0, implicit %ax +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %2(s16) = G_CONSTANT i16 5 + %1(s16) = G_TRUNC %0(s32) + %3(s16) = G_LSHR %1, %2 + %ax = COPY %3(s16) + RET 0, implicit %ax + +... +--- +name: test_lshr_i16_imm1 +# ALL-LABEL: name: test_lshr_i16_imm1 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr16, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %2 = MOV16ri 1 +# ALL-NEXT: %1 = COPY %0.sub_16bit +# ALL-NEXT: %cx = COPY %2 +# ALL-NEXT: %cl = KILL killed %cx +# ALL-NEXT: %3 = SHR16rCL %1, implicit-def %eflags, implicit %cl +# ALL-NEXT: %ax = COPY %3 +# ALL-NEXT: RET 0, implicit %ax +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %2(s16) = G_CONSTANT i16 1 + %1(s16) = G_TRUNC %0(s32) + %3(s16) = G_LSHR %1, %2 + %ax = COPY %3(s16) + RET 0, implicit %ax + +... +--- +name: test_lshr_i8 +# ALL-LABEL: name: test_lshr_i8 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr8, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr8, preferred-register: '' } +# ALL-NEXT: - { id: 4, class: gr8, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } + - { id: 4, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %esi +# ALL-NEXT: %2 = COPY %0.sub_8bit +# ALL-NEXT: %3 = COPY %1.sub_8bit +# ALL-NEXT: %cl = COPY %3 +# ALL-NEXT: %4 = SHR8rCL %2, implicit-def %eflags, implicit %cl +# ALL-NEXT: %al = COPY %4 +# ALL-NEXT: RET 0, implicit %al +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s8) = G_TRUNC %0(s32) + %3(s8) = G_TRUNC %1(s32) + %4(s8) = G_LSHR %2, %3 + %al = COPY %4(s8) + RET 0, implicit %al + +... +--- +name: test_lshr_i8_imm +# ALL-LABEL: name: test_lshr_i8_imm +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr8, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gpr, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr8, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %0.sub_8bit +# ALL-NEXT: %3 = SHR8ri %1, 5, implicit-def %eflags +# ALL-NEXT: %al = COPY %3 +# ALL-NEXT: RET 0, implicit %al +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %2(s8) = G_CONSTANT i8 5 + %1(s8) = G_TRUNC %0(s32) + %3(s8) = G_LSHR %1, %2 + %al = COPY %3(s8) + RET 0, implicit %al + +... +--- +name: test_lshr_i8_imm1 +# ALL-LABEL: name: test_lshr_i8_imm1 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr8, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gpr, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr8, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %0.sub_8bit +# ALL-NEXT: %3 = SHR8r1 %1, implicit-def %eflags +# ALL-NEXT: %al = COPY %3 +# ALL-NEXT: RET 0, implicit %al +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %2(s8) = G_CONSTANT i8 1 + %1(s8) = G_TRUNC %0(s32) + %3(s8) = G_LSHR %1, %2 + %al = COPY %3(s8) + RET 0, implicit %al + +... Index: test/CodeGen/X86/GlobalISel/select-shl-scalar.mir =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/select-shl-scalar.mir @@ -0,0 +1,541 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=ALL +--- | + + define i64 @test_shl_i64(i64 %arg1, i64 %arg2) { + %res = shl i64 %arg1, %arg2 + ret i64 %res + } + + define i64 @test_shl_i64_imm(i64 %arg1) { + %res = shl i64 %arg1, 5 + ret i64 %res + } + + define i64 @test_shl_i64_imm1(i64 %arg1) { + %res = shl i64 %arg1, 1 + ret i64 %res + } + + define i32 @test_shl_i32(i32 %arg1, i32 %arg2) { + %res = shl i32 %arg1, %arg2 + ret i32 %res + } + + define i32 @test_shl_i32_imm(i32 %arg1) { + %res = shl i32 %arg1, 5 + ret i32 %res + } + + define i32 @test_shl_i32_imm1(i32 %arg1) { + %res = shl i32 %arg1, 1 + ret i32 %res + } + + define i16 @test_shl_i16(i32 %arg1, i32 %arg2) { + %a = trunc i32 %arg1 to i16 + %a2 = trunc i32 %arg2 to i16 + %res = shl i16 %a, %a2 + ret i16 %res + } + + define i16 @test_shl_i16_imm(i32 %arg1) { + %a = trunc i32 %arg1 to i16 + %res = shl i16 %a, 5 + ret i16 %res + } + + define i16 @test_shl_i16_imm1(i32 %arg1) { + %a = trunc i32 %arg1 to i16 + %res = shl i16 %a, 1 + ret i16 %res + } + + define i8 @test_shl_i8(i32 %arg1, i32 %arg2) { + %a = trunc i32 %arg1 to i8 + %a2 = trunc i32 %arg2 to i8 + %res = shl i8 %a, %a2 + ret i8 %res + } + + define i8 @test_shl_i8_imm(i32 %arg1) { + %a = trunc i32 %arg1 to i8 + %res = shl i8 %a, 5 + ret i8 %res + } + + define i8 @test_shl_i8_imm1(i32 %arg1) { + %a = trunc i32 %arg1 to i8 + %res = shl i8 %a, 1 + ret i8 %res + } + +... +--- +name: test_shl_i64 +# ALL-LABEL: name: test_shl_i64 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr64, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %rdi +# ALL-NEXT: %1 = COPY %rsi +# ALL-NEXT: %rcx = COPY %1 +# ALL-NEXT: %cl = KILL killed %rcx +# ALL-NEXT: %2 = SHL64rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %rax = COPY %2 +# ALL-NEXT: RET 0, implicit %rax +body: | + bb.1 (%ir-block.0): + liveins: %rdi, %rsi + + %0(s64) = COPY %rdi + %1(s64) = COPY %rsi + %2(s64) = G_SHL %0, %1 + %rax = COPY %2(s64) + RET 0, implicit %rax + +... +--- +name: test_shl_i64_imm +# ALL-LABEL: name: test_shl_i64_imm +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr64, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %rdi +# ALL-NEXT: %1 = MOV64ri32 5 +# ALL-NEXT: %rcx = COPY %1 +# ALL-NEXT: %cl = KILL killed %rcx +# ALL-NEXT: %2 = SHL64rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %rax = COPY %2 +# ALL-NEXT: RET 0, implicit %rax +body: | + bb.1 (%ir-block.0): + liveins: %rdi + + %0(s64) = COPY %rdi + %1(s64) = G_CONSTANT i64 5 + %2(s64) = G_SHL %0, %1 + %rax = COPY %2(s64) + RET 0, implicit %rax + +... +--- +name: test_shl_i64_imm1 +# ALL-LABEL: name: test_shl_i64_imm1 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr64, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr64, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %rdi +# ALL-NEXT: %1 = MOV64ri32 1 +# ALL-NEXT: %rcx = COPY %1 +# ALL-NEXT: %cl = KILL killed %rcx +# ALL-NEXT: %2 = SHL64rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %rax = COPY %2 +# ALL-NEXT: RET 0, implicit %rax +body: | + bb.1 (%ir-block.0): + liveins: %rdi + + %0(s64) = COPY %rdi + %1(s64) = G_CONSTANT i64 1 + %2(s64) = G_SHL %0, %1 + %rax = COPY %2(s64) + RET 0, implicit %rax + +... +--- +name: test_shl_i32 +# ALL-LABEL: name: test_shl_i32 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %esi +# ALL-NEXT: %ecx = COPY %1 +# ALL-NEXT: %cl = KILL killed %ecx +# ALL-NEXT: %2 = SHL32rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %eax = COPY %2 +# ALL-NEXT: RET 0, implicit %eax +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s32) = G_SHL %0, %1 + %eax = COPY %2(s32) + RET 0, implicit %eax + +... +--- +name: test_shl_i32_imm +# ALL-LABEL: name: test_shl_i32_imm +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = MOV32ri 5 +# ALL-NEXT: %ecx = COPY %1 +# ALL-NEXT: %cl = KILL killed %ecx +# ALL-NEXT: %2 = SHL32rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %eax = COPY %2 +# ALL-NEXT: RET 0, implicit %eax +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %1(s32) = G_CONSTANT i32 5 + %2(s32) = G_SHL %0, %1 + %eax = COPY %2(s32) + RET 0, implicit %eax + +... +--- +name: test_shl_i32_imm1 +# ALL-LABEL: name: test_shl_i32_imm1 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr32, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = MOV32ri 1 +# ALL-NEXT: %ecx = COPY %1 +# ALL-NEXT: %cl = KILL killed %ecx +# ALL-NEXT: %2 = SHL32rCL %0, implicit-def %eflags, implicit %cl +# ALL-NEXT: %eax = COPY %2 +# ALL-NEXT: RET 0, implicit %eax +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %1(s32) = G_CONSTANT i32 1 + %2(s32) = G_SHL %0, %1 + %eax = COPY %2(s32) + RET 0, implicit %eax + +... +--- +name: test_shl_i16 +# ALL-LABEL: name: test_shl_i16 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 4, class: gr16, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } + - { id: 4, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %esi +# ALL-NEXT: %2 = COPY %0.sub_16bit +# ALL-NEXT: %3 = COPY %1.sub_16bit +# ALL-NEXT: %cx = COPY %3 +# ALL-NEXT: %cl = KILL killed %cx +# ALL-NEXT: %4 = SHL16rCL %2, implicit-def %eflags, implicit %cl +# ALL-NEXT: %ax = COPY %4 +# ALL-NEXT: RET 0, implicit %ax +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s16) = G_TRUNC %0(s32) + %3(s16) = G_TRUNC %1(s32) + %4(s16) = G_SHL %2, %3 + %ax = COPY %4(s16) + RET 0, implicit %ax + +... +--- +name: test_shl_i16_imm +# ALL-LABEL: name: test_shl_i16_imm +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr16, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %2 = MOV16ri 5 +# ALL-NEXT: %1 = COPY %0.sub_16bit +# ALL-NEXT: %cx = COPY %2 +# ALL-NEXT: %cl = KILL killed %cx +# ALL-NEXT: %3 = SHL16rCL %1, implicit-def %eflags, implicit %cl +# ALL-NEXT: %ax = COPY %3 +# ALL-NEXT: RET 0, implicit %ax +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %2(s16) = G_CONSTANT i16 5 + %1(s16) = G_TRUNC %0(s32) + %3(s16) = G_SHL %1, %2 + %ax = COPY %3(s16) + RET 0, implicit %ax + +... +--- +name: test_shl_i16_imm1 +# ALL-LABEL: name: test_shl_i16_imm1 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr16, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr16, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %2 = MOV16ri 1 +# ALL-NEXT: %1 = COPY %0.sub_16bit +# ALL-NEXT: %cx = COPY %2 +# ALL-NEXT: %cl = KILL killed %cx +# ALL-NEXT: %3 = SHL16rCL %1, implicit-def %eflags, implicit %cl +# ALL-NEXT: %ax = COPY %3 +# ALL-NEXT: RET 0, implicit %ax +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %2(s16) = G_CONSTANT i16 1 + %1(s16) = G_TRUNC %0(s32) + %3(s16) = G_SHL %1, %2 + %ax = COPY %3(s16) + RET 0, implicit %ax + +... +--- +name: test_shl_i8 +# ALL-LABEL: name: test_shl_i8 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gr8, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr8, preferred-register: '' } +# ALL-NEXT: - { id: 4, class: gr8, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } + - { id: 4, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %esi +# ALL-NEXT: %2 = COPY %0.sub_8bit +# ALL-NEXT: %3 = COPY %1.sub_8bit +# ALL-NEXT: %cl = COPY %3 +# ALL-NEXT: %4 = SHL8rCL %2, implicit-def %eflags, implicit %cl +# ALL-NEXT: %al = COPY %4 +# ALL-NEXT: RET 0, implicit %al +body: | + bb.1 (%ir-block.0): + liveins: %edi, %esi + + %0(s32) = COPY %edi + %1(s32) = COPY %esi + %2(s8) = G_TRUNC %0(s32) + %3(s8) = G_TRUNC %1(s32) + %4(s8) = G_SHL %2, %3 + %al = COPY %4(s8) + RET 0, implicit %al + +... +--- +name: test_shl_i8_imm +# ALL-LABEL: name: test_shl_i8_imm +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr8, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gpr, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr8, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %0.sub_8bit +# ALL-NEXT: %3 = SHL8ri %1, 5, implicit-def %eflags +# ALL-NEXT: %al = COPY %3 +# ALL-NEXT: RET 0, implicit %al +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %2(s8) = G_CONSTANT i8 5 + %1(s8) = G_TRUNC %0(s32) + %3(s8) = G_SHL %1, %2 + %al = COPY %3(s8) + RET 0, implicit %al + +... +--- +name: test_shl_i8_imm1 +# ALL-LABEL: name: test_shl_i8_imm1 +alignment: 4 +legalized: true +regBankSelected: true +tracksRegLiveness: true +# ALL: registers: +# ALL-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# ALL-NEXT: - { id: 1, class: gr8, preferred-register: '' } +# ALL-NEXT: - { id: 2, class: gpr, preferred-register: '' } +# ALL-NEXT: - { id: 3, class: gr8, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +liveins: +fixedStack: +stack: +constants: +# ALL: %0 = COPY %edi +# ALL-NEXT: %1 = COPY %0.sub_8bit +# ALL-NEXT: %3 = ADD8rr %1, %1, implicit-def %eflags +# ALL-NEXT: %al = COPY %3 +# ALL-NEXT: RET 0, implicit %al +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %2(s8) = G_CONSTANT i8 1 + %1(s8) = G_TRUNC %0(s32) + %3(s8) = G_SHL %1, %2 + %al = COPY %3(s8) + RET 0, implicit %al + +... Index: test/CodeGen/X86/GlobalISel/shl-scalar.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/GlobalISel/shl-scalar.ll @@ -0,0 +1,174 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=X64 + +define i64 @test_shl_i64(i64 %arg1, i64 %arg2) { +; X64-LABEL: test_shl_i64: +; X64: # BB#0: +; X64-NEXT: movq %rsi, %rcx +; X64-NEXT: # kill: %CL %RCX +; X64-NEXT: shlq %cl, %rdi +; X64-NEXT: movq %rdi, %rax +; X64-NEXT: retq + %res = shl i64 %arg1, %arg2 + ret i64 %res +} + +define i64 @test_shl_i64_imm(i64 %arg1) { +; X64-LABEL: test_shl_i64_imm: +; X64: # BB#0: +; X64-NEXT: movq $5, %rcx +; X64-NEXT: # kill: %CL %RCX +; X64-NEXT: shlq %cl, %rdi +; X64-NEXT: movq %rdi, %rax +; X64-NEXT: retq + %res = shl i64 %arg1, 5 + ret i64 %res +} + +define i64 @test_shl_i64_imm1(i64 %arg1) { +; X64-LABEL: test_shl_i64_imm1: +; X64: # BB#0: +; X64-NEXT: movq $1, %rcx +; X64-NEXT: # kill: %CL %RCX +; X64-NEXT: shlq %cl, %rdi +; X64-NEXT: movq %rdi, %rax +; X64-NEXT: retq + %res = shl i64 %arg1, 1 + ret i64 %res +} + +define i32 @test_shl_i32(i32 %arg1, i32 %arg2) { +; X64-LABEL: test_shl_i32: +; X64: # BB#0: +; X64-NEXT: movl %esi, %ecx +; X64-NEXT: # kill: %CL %ECX +; X64-NEXT: shll %cl, %edi +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %res = shl i32 %arg1, %arg2 + ret i32 %res +} + +define i32 @test_shl_i32_imm(i32 %arg1) { +; X64-LABEL: test_shl_i32_imm: +; X64: # BB#0: +; X64-NEXT: movl $5, %ecx +; X64-NEXT: # kill: %CL %ECX +; X64-NEXT: shll %cl, %edi +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %res = shl i32 %arg1, 5 + ret i32 %res +} + +define i32 @test_shl_i32_imm1(i32 %arg1) { +; X64-LABEL: test_shl_i32_imm1: +; X64: # BB#0: +; X64-NEXT: movl $1, %ecx +; X64-NEXT: # kill: %CL %ECX +; X64-NEXT: shll %cl, %edi +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %res = shl i32 %arg1, 1 + ret i32 %res +} + +define i16 @test_shl_i16(i32 %arg1, i32 %arg2) { +; X64-LABEL: test_shl_i16: +; X64: # BB#0: +; X64-NEXT: movl %esi, %ecx +; X64-NEXT: # kill: %CL %CX +; X64-NEXT: shlw %cl, %di +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i16 + %a2 = trunc i32 %arg2 to i16 + %res = shl i16 %a, %a2 + ret i16 %res +} + +define i16 @test_shl_i16_imm(i32 %arg1) { +; X64-LABEL: test_shl_i16_imm: +; X64: # BB#0: +; X64-NEXT: movw $5, %cx +; X64-NEXT: # kill: %CL %CX +; X64-NEXT: shlw %cl, %di +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i16 + %res = shl i16 %a, 5 + ret i16 %res +} + +define i16 @test_shl_i16_imm1(i32 %arg1) { +; X64-LABEL: test_shl_i16_imm1: +; X64: # BB#0: +; X64-NEXT: movw $1, %cx +; X64-NEXT: # kill: %CL %CX +; X64-NEXT: shlw %cl, %di +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i16 + %res = shl i16 %a, 1 + ret i16 %res +} + +define i8 @test_shl_i8(i32 %arg1, i32 %arg2) { +; X64-LABEL: test_shl_i8: +; X64: # BB#0: +; X64-NEXT: movl %esi, %ecx +; X64-NEXT: shlb %cl, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i8 + %a2 = trunc i32 %arg2 to i8 + %res = shl i8 %a, %a2 + ret i8 %res +} + +define i8 @test_shl_i8_imm(i32 %arg1) { +; X64-LABEL: test_shl_i8_imm: +; X64: # BB#0: +; X64-NEXT: shlb $5, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i8 + %res = shl i8 %a, 5 + ret i8 %res +} + +define i8 @test_shl_i8_imm1(i32 %arg1) { +; X64-LABEL: test_shl_i8_imm1: +; X64: # BB#0: +; X64-NEXT: addb %dil, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i8 + %res = shl i8 %a, 1 + ret i8 %res +} + +define i1 @test_shl_i1(i32 %arg1, i32 %arg2) { +; X64-LABEL: test_shl_i1: +; X64: # BB#0: +; X64-NEXT: movl %esi, %ecx +; X64-NEXT: shlb %cl, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i1 + %a2 = trunc i32 %arg2 to i1 + %res = shl i1 %a, %a2 + ret i1 %res +} + +define i1 @test_shl_i1_imm1(i32 %arg1) { +; X64-LABEL: test_shl_i1_imm1: +; X64: # BB#0: +; X64-NEXT: movb $-1, %cl +; X64-NEXT: shlb %cl, %dil +; X64-NEXT: movl %edi, %eax +; X64-NEXT: retq + %a = trunc i32 %arg1 to i1 + %res = shl i1 %a, 1 + ret i1 %res +}