From c0199e4844a798d255d562539cfe6ddbf38caeee Mon Sep 17 00:00:00 2001 From: Igor Breger Date: Wed, 19 Apr 2017 11:34:59 +0000 Subject: [PATCH] [GlobalIsel][X86] support G_TRUNC selection. Summary: [GlobalIsel][X86] support G_TRUNC selection. Add regbank-select and legalizer tests. Currently legalization of trunc i64 on 32bit platform not supported. Reviewers: ab, zvi, rovka Reviewed By: zvi Subscribers: dberris, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D32115 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300678 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/X86InstructionSelector.cpp | 61 ++++++ lib/Target/X86/X86RegisterBankInfo.cpp | 1 + .../X86/GlobalISel/X86-regbankselect.mir | 28 +++ .../CodeGen/X86/GlobalISel/legalize-trunc.mir | 31 +++ test/CodeGen/X86/GlobalISel/select-trunc.mir | 183 ++++++++++++++++++ test/CodeGen/X86/GlobalISel/trunc.ll | 57 ++++++ 6 files changed, 361 insertions(+) create mode 100644 test/CodeGen/X86/GlobalISel/legalize-trunc.mir create mode 100644 test/CodeGen/X86/GlobalISel/select-trunc.mir create mode 100644 test/CodeGen/X86/GlobalISel/trunc.ll diff --git a/lib/Target/X86/X86InstructionSelector.cpp b/lib/Target/X86/X86InstructionSelector.cpp index 6cc5e8b6359..fb931579289 100644 --- a/lib/Target/X86/X86InstructionSelector.cpp +++ b/lib/Target/X86/X86InstructionSelector.cpp @@ -67,6 +67,8 @@ private: MachineFunction &MF) const; bool selectConstant(MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) const; + bool selectTrunc(MachineInstr &I, MachineRegisterInfo &MRI, + MachineFunction &MF) const; const X86Subtarget &STI; const X86InstrInfo &TII; @@ -99,6 +101,10 @@ X86InstructionSelector::X86InstructionSelector(const X86Subtarget &STI, static const TargetRegisterClass * getRegClassForTypeOnBank(LLT Ty, const RegisterBank &RB) { if (RB.getID() == X86::GPRRegBankID) { + if (Ty.getSizeInBits() <= 8) + return &X86::GR8RegClass; + if (Ty.getSizeInBits() == 16) + return &X86::GR16RegClass; if (Ty.getSizeInBits() == 32) return &X86::GR32RegClass; if (Ty.getSizeInBits() == 64) @@ -207,6 +213,8 @@ bool X86InstructionSelector::select(MachineInstr &I) const { return true; if (selectConstant(I, MRI, MF)) return true; + if (selectTrunc(I, MRI, MF)) + return true; return selectImpl(I); } @@ -509,6 +517,59 @@ bool X86InstructionSelector::selectConstant(MachineInstr &I, return constrainSelectedInstRegOperands(I, TII, TRI, RBI); } +bool X86InstructionSelector::selectTrunc(MachineInstr &I, + MachineRegisterInfo &MRI, + MachineFunction &MF) const { + if (I.getOpcode() != TargetOpcode::G_TRUNC) + return false; + + const unsigned DstReg = I.getOperand(0).getReg(); + const unsigned SrcReg = I.getOperand(1).getReg(); + + const LLT DstTy = MRI.getType(DstReg); + const LLT SrcTy = MRI.getType(SrcReg); + + const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI); + const RegisterBank &SrcRB = *RBI.getRegBank(SrcReg, MRI, TRI); + + if (DstRB.getID() != SrcRB.getID()) { + DEBUG(dbgs() << "G_TRUNC input/output on different banks\n"); + return false; + } + + if (DstRB.getID() != X86::GPRRegBankID) + return false; + + const TargetRegisterClass *DstRC = getRegClassForTypeOnBank(DstTy, DstRB); + if (!DstRC) + return false; + + const TargetRegisterClass *SrcRC = getRegClassForTypeOnBank(SrcTy, SrcRB); + if (!SrcRC) + return false; + + if (!RBI.constrainGenericRegister(SrcReg, *SrcRC, MRI) || + !RBI.constrainGenericRegister(DstReg, *DstRC, MRI)) { + DEBUG(dbgs() << "Failed to constrain G_TRUNC\n"); + return false; + } + + if (DstRC == SrcRC) { + // Nothing to be done + } else if (DstRC == &X86::GR32RegClass) { + I.getOperand(1).setSubReg(X86::sub_32bit); + } else if (DstRC == &X86::GR16RegClass) { + I.getOperand(1).setSubReg(X86::sub_16bit); + } else if (DstRC == &X86::GR8RegClass) { + I.getOperand(1).setSubReg(X86::sub_8bit); + } else { + return false; + } + + I.setDesc(TII.get(X86::COPY)); + return true; +} + InstructionSelector * llvm::createX86InstructionSelector(X86Subtarget &Subtarget, X86RegisterBankInfo &RBI) { diff --git a/lib/Target/X86/X86RegisterBankInfo.cpp b/lib/Target/X86/X86RegisterBankInfo.cpp index d395c826e6b..0f8a750a023 100644 --- a/lib/Target/X86/X86RegisterBankInfo.cpp +++ b/lib/Target/X86/X86RegisterBankInfo.cpp @@ -68,6 +68,7 @@ X86GenRegisterBankInfo::PartialMappingIdx X86GenRegisterBankInfo::getPartialMappingIdx(const LLT &Ty, bool isFP) { if ((Ty.isScalar() && !isFP) || Ty.isPointer()) { switch (Ty.getSizeInBits()) { + case 1: case 8: return PMI_GPR8; case 16: diff --git a/test/CodeGen/X86/GlobalISel/X86-regbankselect.mir b/test/CodeGen/X86/GlobalISel/X86-regbankselect.mir index c4e5fb2d05f..8e04239041a 100644 --- a/test/CodeGen/X86/GlobalISel/X86-regbankselect.mir +++ b/test/CodeGen/X86/GlobalISel/X86-regbankselect.mir @@ -106,6 +106,10 @@ ret void } + define void @trunc_check() { + ret void + } + ... --- name: test_add_i8 @@ -632,3 +636,27 @@ body: | RET 0 ... +--- +name: trunc_check +alignment: 4 +legalized: true +# CHECK-LABEL: name: trunc_check +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gpr } +# CHECK-NEXT: - { id: 1, class: gpr } +# CHECK-NEXT: - { id: 2, class: gpr } +# CHECK-NEXT: - { id: 3, class: gpr } +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } + - { id: 3, class: _ } +body: | + bb.0 (%ir-block.0): + %0(s32) = IMPLICIT_DEF + %1(s1) = G_TRUNC %0(s32) + %2(s8) = G_TRUNC %0(s32) + %3(s16) = G_TRUNC %0(s32) + RET 0 + +... diff --git a/test/CodeGen/X86/GlobalISel/legalize-trunc.mir b/test/CodeGen/X86/GlobalISel/legalize-trunc.mir new file mode 100644 index 00000000000..6b390d990ec --- /dev/null +++ b/test/CodeGen/X86/GlobalISel/legalize-trunc.mir @@ -0,0 +1,31 @@ +# RUN: llc -mtriple=i386-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X32 +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X64 +--- | + define void @trunc_check() { + ret void + } + +... +--- +name: trunc_check +# ALL-LABEL: name: trunc_check +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } + - { id: 3, class: _ } +body: | + bb.1 (%ir-block.0): + %0(s32) = IMPLICIT_DEF + ; ALL: %1(s1) = G_TRUNC %0(s32) + %1(s1) = G_TRUNC %0(s32) + + ; ALL: %2(s8) = G_TRUNC %0(s32) + %2(s8) = G_TRUNC %0(s32) + + ; ALL: %3(s16) = G_TRUNC %0(s32) + %3(s16) = G_TRUNC %0(s32) + RET 0 + +... + diff --git a/test/CodeGen/X86/GlobalISel/select-trunc.mir b/test/CodeGen/X86/GlobalISel/select-trunc.mir new file mode 100644 index 00000000000..714340248ff --- /dev/null +++ b/test/CodeGen/X86/GlobalISel/select-trunc.mir @@ -0,0 +1,183 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=instruction-select %s -o - | FileCheck %s --check-prefix=CHECK +--- | + define i1 @trunc_i32toi1(i32 %a) { + %r = trunc i32 %a to i1 + ret i1 %r + } + + define i8 @trunc_i32toi8(i32 %a) { + %r = trunc i32 %a to i8 + ret i8 %r + } + + define i16 @trunc_i32toi16(i32 %a) { + %r = trunc i32 %a to i16 + ret i16 %r + } + + define i8 @trunc_i64toi8(i64 %a) { + %r = trunc i64 %a to i8 + ret i8 %r + } + + define i16 @trunc_i64toi16(i64 %a) { + %r = trunc i64 %a to i16 + ret i16 %r + } + + define i32 @trunc_i64toi32(i64 %a) { + %r = trunc i64 %a to i32 + ret i32 %r + } + +... +--- +name: trunc_i32toi1 +alignment: 4 +legalized: true +regBankSelected: true +selected: false +# CHECK-LABEL: name: trunc_i32toi1 +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gr32 } +# CHECK-NEXT: - { id: 1, class: gr8 } +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } +# CHECK: body: +# CHECK: %1 = COPY %0.sub_8 +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %1(s1) = G_TRUNC %0(s32) + %al = COPY %1(s1) + RET 0, implicit %al + +... +--- +name: trunc_i32toi8 +alignment: 4 +legalized: true +regBankSelected: true +selected: false +# CHECK-LABEL: name: trunc_i32toi8 +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gr32 } +# CHECK-NEXT: - { id: 1, class: gr8 } +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } +# CHECK: body: +# CHECK: %1 = COPY %0.sub_8 +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %1(s8) = G_TRUNC %0(s32) + %al = COPY %1(s8) + RET 0, implicit %al + +... +--- +name: trunc_i32toi16 +alignment: 4 +legalized: true +regBankSelected: true +selected: false +# CHECK-LABEL: name: trunc_i32toi16 +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gr32 } +# CHECK-NEXT: - { id: 1, class: gr16 } +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } +# CHECK: body: +# CHECK: %1 = COPY %0.sub_16 +body: | + bb.1 (%ir-block.0): + liveins: %edi + + %0(s32) = COPY %edi + %1(s16) = G_TRUNC %0(s32) + %ax = COPY %1(s16) + RET 0, implicit %ax + +... +--- +name: trunc_i64toi8 +alignment: 4 +legalized: true +regBankSelected: true +selected: false +# CHECK-LABEL: name: trunc_i64toi8 +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gr64 } +# CHECK-NEXT: - { id: 1, class: gr8 } +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } +# CHECK: body: +# CHECK: %1 = COPY %0.sub_8 +body: | + bb.1 (%ir-block.0): + liveins: %rdi + + %0(s64) = COPY %rdi + %1(s8) = G_TRUNC %0(s64) + %al = COPY %1(s8) + RET 0, implicit %al + +... +--- +name: trunc_i64toi16 +alignment: 4 +legalized: true +regBankSelected: true +selected: false +# CHECK-LABEL: name: trunc_i64toi16 +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gr64 } +# CHECK-NEXT: - { id: 1, class: gr16 } +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } +# CHECK: body: +# CHECK: %1 = COPY %0.sub_16 +body: | + bb.1 (%ir-block.0): + liveins: %rdi + + %0(s64) = COPY %rdi + %1(s16) = G_TRUNC %0(s64) + %ax = COPY %1(s16) + RET 0, implicit %ax + +... +--- +name: trunc_i64toi32 +alignment: 4 +legalized: true +regBankSelected: true +selected: false +# CHECK-LABEL: name: trunc_i64toi32 +# CHECK: registers: +# CHECK-NEXT: - { id: 0, class: gr64 } +# CHECK-NEXT: - { id: 1, class: gr32 } +registers: + - { id: 0, class: gpr } + - { id: 1, class: gpr } +# CHECK: body: +# CHECK: %1 = COPY %0.sub_32 +body: | + bb.1 (%ir-block.0): + liveins: %rdi + + %0(s64) = COPY %rdi + %1(s32) = G_TRUNC %0(s64) + %eax = COPY %1(s32) + RET 0, implicit %eax + +... diff --git a/test/CodeGen/X86/GlobalISel/trunc.ll b/test/CodeGen/X86/GlobalISel/trunc.ll new file mode 100644 index 00000000000..a56fc3b5a87 --- /dev/null +++ b/test/CodeGen/X86/GlobalISel/trunc.ll @@ -0,0 +1,57 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=x86_64-linux-gnu -global-isel < %s -o - | FileCheck %s --check-prefix=CHECK + +define i1 @trunc_i32toi1(i32 %a) { +; CHECK-LABEL: trunc_i32toi1: +; CHECK: # BB#0: +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %r = trunc i32 %a to i1 + ret i1 %r +} + +define i8 @trunc_i32toi8(i32 %a) { +; CHECK-LABEL: trunc_i32toi8: +; CHECK: # BB#0: +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %r = trunc i32 %a to i8 + ret i8 %r +} + +define i16 @trunc_i32toi16(i32 %a) { +; CHECK-LABEL: trunc_i32toi16: +; CHECK: # BB#0: +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %r = trunc i32 %a to i16 + ret i16 %r +} + +define i8 @trunc_i64toi8(i64 %a) { +; CHECK-LABEL: trunc_i64toi8: +; CHECK: # BB#0: +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %r = trunc i64 %a to i8 + ret i8 %r +} + +define i16 @trunc_i64toi16(i64 %a) { +; CHECK-LABEL: trunc_i64toi16: +; CHECK: # BB#0: +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %r = trunc i64 %a to i16 + ret i16 %r +} + +define i32 @trunc_i64toi32(i64 %a) { +; CHECK-LABEL: trunc_i64toi32: +; CHECK: # BB#0: +; CHECK-NEXT: movl %edi, %eax +; CHECK-NEXT: retq + %r = trunc i64 %a to i32 + ret i32 %r +} + -- 2.50.1