]> granicus.if.org Git - llvm/commitdiff
[GlobalIsel][X86] support G_TRUNC selection.
authorIgor Breger <igor.breger@intel.com>
Wed, 19 Apr 2017 11:34:59 +0000 (11:34 +0000)
committerIgor Breger <igor.breger@intel.com>
Wed, 19 Apr 2017 11:34:59 +0000 (11:34 +0000)
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
lib/Target/X86/X86RegisterBankInfo.cpp
test/CodeGen/X86/GlobalISel/X86-regbankselect.mir
test/CodeGen/X86/GlobalISel/legalize-trunc.mir [new file with mode: 0644]
test/CodeGen/X86/GlobalISel/select-trunc.mir [new file with mode: 0644]
test/CodeGen/X86/GlobalISel/trunc.ll [new file with mode: 0644]

index 6cc5e8b63597502644483cb0e4eec7826e0b6e98..fb93157928922521fc2463d5868c8d5151d85bd4 100644 (file)
@@ -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) {
index d395c826e6bf7a050bdd8b5ffdd9b65eb32bf3c6..0f8a750a0235215b5112804d866d77ceeb85b07e 100644 (file)
@@ -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:
index c4e5fb2d05fc0348ccd39e0640063a099589ca8d..8e04239041a87d2f17b1d20db0c7ea504c9324ac 100644 (file)
     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 (file)
index 0000000..6b390d9
--- /dev/null
@@ -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 (file)
index 0000000..7143402
--- /dev/null
@@ -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 (file)
index 0000000..a56fc3b
--- /dev/null
@@ -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
+}
+