]> granicus.if.org Git - llvm/commitdiff
[ARM] GlobalISel: Support i8/i16 ABI extensions
authorDiana Picus <diana.picus@linaro.org>
Wed, 25 Jan 2017 08:10:40 +0000 (08:10 +0000)
committerDiana Picus <diana.picus@linaro.org>
Wed, 25 Jan 2017 08:10:40 +0000 (08:10 +0000)
At the moment, this means supporting the signext/zeroext attribute on the return
type of the function. For function arguments, signext/zeroext should be handled
by the caller, so there's nothing for us to do until we start lowering calls.

Note that this does not include support for other extensions (i8 to i16), those
will be added later.

Differential Revision: https://reviews.llvm.org/D27705

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@293034 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMCallLowering.cpp
lib/Target/ARM/ARMInstructionSelector.cpp
lib/Target/ARM/ARMLegalizerInfo.cpp
lib/Target/ARM/ARMRegisterBankInfo.cpp
test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir
test/CodeGen/ARM/GlobalISel/arm-irtranslator.ll
test/CodeGen/ARM/GlobalISel/arm-isel.ll
test/CodeGen/ARM/GlobalISel/arm-legalizer.mir

index 165095648008537c358f7cf05f49689c376e7750..7c298cee3eddaf20519e747d3197b2e868845807 100644 (file)
@@ -60,11 +60,8 @@ struct FuncReturnHandler : public CallLowering::ValueHandler {
     assert(VA.getValVT().getSizeInBits() <= 32 && "Unsupported value size");
     assert(VA.getLocVT().getSizeInBits() == 32 && "Unsupported location size");
 
-    assert(VA.getLocInfo() != CCValAssign::SExt &&
-           VA.getLocInfo() != CCValAssign::ZExt &&
-           "ABI extensions not supported yet");
-
-    MIRBuilder.buildCopy(PhysReg, ValVReg);
+    unsigned ExtReg = extendRegister(ValVReg, VA);
+    MIRBuilder.buildCopy(PhysReg, ExtReg);
     MIB.addUse(PhysReg, RegState::Implicit);
   }
 
@@ -156,6 +153,7 @@ struct FormalArgHandler : public CallLowering::ValueHandler {
     assert(VA.getValVT().getSizeInBits() <= 32 && "Unsupported value size");
     assert(VA.getLocVT().getSizeInBits() == 32 && "Unsupported location size");
 
+    // The caller should handle all necesary extensions.
     MIRBuilder.getMBB().addLiveIn(PhysReg);
     MIRBuilder.buildCopy(ValVReg, PhysReg);
   }
index 55d4f41e252a9f7c5108fac66f8fa0e1aacf82d3..dccb8578acd4029983dc8362b4ac53f17cd5559e 100644 (file)
@@ -68,6 +68,23 @@ static bool selectCopy(MachineInstr &I, const TargetInstrInfo &TII,
   return true;
 }
 
+/// Select the opcode for simple extensions (that translate to a single SXT/UXT
+/// instruction). Extension operations more complicated than that should not
+/// invoke this.
+static unsigned selectSimpleExtOpc(unsigned Opc, unsigned Size) {
+  using namespace TargetOpcode;
+
+  assert((Size == 8 || Size == 16) && "Unsupported size");
+
+  if (Opc == G_SEXT)
+    return Size == 8 ? ARM::SXTB : ARM::SXTH;
+
+  if (Opc == G_ZEXT)
+    return Size == 8 ? ARM::UXTB : ARM::UXTH;
+
+  llvm_unreachable("Unsupported opcode");
+}
+
 bool ARMInstructionSelector::select(MachineInstr &I) const {
   assert(I.getParent() && "Instruction should be in a basic block!");
   assert(I.getParent()->getParent() && "Instruction should be in a function!");
@@ -87,6 +104,31 @@ bool ARMInstructionSelector::select(MachineInstr &I) const {
 
   using namespace TargetOpcode;
   switch (I.getOpcode()) {
+  case G_SEXT:
+  case G_ZEXT: {
+    LLT DstTy = MRI.getType(I.getOperand(0).getReg());
+    // FIXME: Smaller destination sizes coming soon!
+    if (DstTy.getSizeInBits() != 32) {
+      DEBUG(dbgs() << "Unsupported destination size for extension");
+      return false;
+    }
+
+    LLT SrcTy = MRI.getType(I.getOperand(1).getReg());
+    unsigned SrcSize = SrcTy.getSizeInBits();
+    switch (SrcSize) {
+    case 8:
+    case 16: {
+      unsigned NewOpc = selectSimpleExtOpc(I.getOpcode(), SrcSize);
+      I.setDesc(TII.get(NewOpc));
+      MIB.addImm(0).add(predOps(ARMCC::AL));
+      break;
+    }
+    default:
+      DEBUG(dbgs() << "Unsupported source size for extension");
+      return false;
+    }
+    break;
+  }
   case G_ADD:
     I.setDesc(TII.get(ARM::ADDrr));
     MIB.add(predOps(ARMCC::AL)).add(condCodeOp());
index 255ea4bc71984c1e4ac15f3cfdbd10b4c38267db..0dfddf1bfc13c6de4056c0bd54323a771acc8090 100644 (file)
@@ -40,5 +40,11 @@ ARMLegalizerInfo::ARMLegalizerInfo() {
   for (auto Ty : {s8, s16, s32})
     setAction({G_ADD, Ty}, Legal);
 
+  for (auto Op : {G_SEXT, G_ZEXT}) {
+    setAction({Op, s32}, Legal);
+    for (auto Ty : {s8, s16})
+      setAction({Op, 1, Ty}, Legal);
+  }
+
   computeTables();
 }
index b40a9ddb65890c4fdc01537710e530ac8fea0038..ee2daa756f09ce2c0b750acf8e7cee0471216c62 100644 (file)
@@ -107,6 +107,7 @@ const RegisterBank &ARMRegisterBankInfo::getRegBankFromRegClass(
 
   switch (RC.getID()) {
   case GPRRegClassID:
+  case GPRnopcRegClassID:
   case tGPR_and_tcGPRRegClassID:
     return getRegBank(ARM::GPRRegBankID);
   default:
@@ -136,6 +137,8 @@ ARMRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
   switch (Opc) {
   case G_ADD:
   case G_LOAD:
+  case G_SEXT:
+  case G_ZEXT:
     // FIXME: We're abusing the fact that everything lives in a GPR for now; in
     // the real world we would use different mappings.
     OperandsMapping = &ARM::ValueMappings[0];
index 5c0853cfaab4563a0dddc0cf6a62ea6eb31b5646..6407b9ac780195fb88327e41af6321b0571c9be7 100644 (file)
@@ -1,5 +1,8 @@
 # RUN: llc -O0 -mtriple arm-- -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
 --- |
+  define void @test_sext_s8() { ret void }
+  define void @test_zext_s16() { ret void }
+
   define void @test_add_s8() { ret void }
   define void @test_add_s16() { ret void }
   define void @test_add_s32() { ret void }
@@ -7,6 +10,59 @@
   define void @test_load_from_stack() { ret void }
 ...
 ---
+---
+name:            test_sext_s8
+# CHECK-LABEL: name: test_sext_s8
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: gprb }
+  - { id: 1, class: gprb }
+body:             |
+  bb.0:
+    liveins: %r0
+
+    %0(s8) = COPY %r0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %r0
+
+    %1(s32) = G_SEXT %0(s8)
+    ; CHECK: [[VREGEXT:%[0-9]+]] = SXTB [[VREGX]], 0, 14, _
+
+    %r0 = COPY %1(s32)
+    ; CHECK: %r0 = COPY [[VREGEXT]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
+name:            test_zext_s16
+# CHECK-LABEL: name: test_zext_s16
+legalized:       true
+regBankSelected: true
+selected:        false
+# CHECK: selected: true
+registers:
+  - { id: 0, class: gprb }
+  - { id: 1, class: gprb }
+body:             |
+  bb.0:
+    liveins: %r0
+
+    %0(s16) = COPY %r0
+    ; CHECK: [[VREGX:%[0-9]+]] = COPY %r0
+
+    %1(s32) = G_ZEXT %0(s16)
+    ; CHECK: [[VREGEXT:%[0-9]+]] = UXTH [[VREGX]], 0, 14, _
+
+    %r0 = COPY %1(s32)
+    ; CHECK: %r0 = COPY [[VREGEXT]]
+
+    BX_RET 14, _, implicit %r0
+    ; CHECK: BX_RET 14, _, implicit %r0
+...
+---
 name:            test_add_s8
 # CHECK-LABEL: name: test_add_s8
 legalized:       true
index f863ed5a6849be79cab9ff733c57d8650678a7f3..425544f84273b676cb8c19a96a8cffd7a920122d 100644 (file)
@@ -20,6 +20,17 @@ entry:
   ret i8 %sum
 }
 
+define signext i8 @test_return_sext_i8(i8 %x) {
+; CHECK-LABEL: name: test_return_sext_i8
+; CHECK: liveins: %r0
+; CHECK: [[VREG:%[0-9]+]](s8) = COPY %r0
+; CHECK: [[VREGEXT:%[0-9]+]](s32) = G_SEXT [[VREG]]
+; CHECK: %r0 = COPY [[VREGEXT]](s32)
+; CHECK: BX_RET 14, _, implicit %r0
+entry:
+  ret i8 %x
+}
+
 define i16 @test_add_i16(i16 %x, i16 %y) {
 ; CHECK-LABEL: name: test_add_i16
 ; CHECK: liveins: %r0, %r1
@@ -33,6 +44,17 @@ entry:
   ret i16 %sum
 }
 
+define zeroext i16 @test_return_zext_i16(i16 %x) {
+; CHECK-LABEL: name: test_return_zext_i16
+; CHECK: liveins: %r0
+; CHECK: [[VREG:%[0-9]+]](s16) = COPY %r0
+; CHECK: [[VREGEXT:%[0-9]+]](s32) = G_ZEXT [[VREG]]
+; CHECK: %r0 = COPY [[VREGEXT]](s32)
+; CHECK: BX_RET 14, _, implicit %r0
+entry:
+  ret i16 %x
+}
+
 define i32 @test_add_i32(i32 %x, i32 %y) {
 ; CHECK-LABEL: name: test_add_i32
 ; CHECK: liveins: %r0, %r1
index 3f01b6dd3a8309b1584c08a3f953bb1d8af3c1d0..2c0c17c7eec857326bf5d41259115d001a4a2d92 100644 (file)
@@ -7,6 +7,22 @@ entry:
   ret void
 }
 
+define zeroext i8 @test_ext_i8(i8 %x) {
+; CHECK-LABEL: test_ext_i8:
+; CHECK: uxtb r0, r0
+; CHECK: bx lr
+entry:
+  ret i8 %x
+}
+
+define signext i16 @test_ext_i16(i16 %x) {
+; CHECK-LABEL: test_ext_i16:
+; CHECK: sxth r0, r0
+; CHECK: bx lr
+entry:
+  ret i16 %x
+}
+
 define i8 @test_add_i8(i8 %x, i8 %y) {
 ; CHECK-LABEL: test_add_i8:
 ; CHECK: add r0, r0, r1
index 98d71c09e63baa7790f4a1dc3c1861bcee683b5a..d1e8ec3d18824d84c014fac81875cb335a5ad175 100644 (file)
@@ -1,5 +1,8 @@
 # RUN: llc -mtriple arm-- -global-isel -run-pass=legalizer %s -o - | FileCheck %s
 --- |
+  define void @test_sext_s8() { ret void }
+  define void @test_zext_s16() { ret void }
+
   define void @test_add_s8() { ret void }
   define void @test_add_s16() { ret void }
   define void @test_add_s32() { ret void }
@@ -7,6 +10,50 @@
   define void @test_load_from_stack() { ret void }
 ...
 ---
+name:            test_sext_s8
+# CHECK-LABEL: name: test_sext_s8
+legalized:       false
+# CHECK: legalized: true
+regBankSelected: false
+selected:        false
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: _ }
+  - { id: 1, class: _ }
+body:             |
+  bb.0:
+    liveins: %r0
+
+    %0(s8) = COPY %r0
+    %1(s32) = G_SEXT %0
+    ; G_SEXT with s8 is legal, so we should find it unchanged in the output
+    ; CHECK: {{%[0-9]+}}(s32) = G_SEXT {{%[0-9]+}}
+    %r0 = COPY %1(s32)
+    BX_RET 14, _, implicit %r0
+...
+---
+name:            test_zext_s16
+# CHECK-LABEL: name: test_zext_s16
+legalized:       false
+# CHECK: legalized: true
+regBankSelected: false
+selected:        false
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: _ }
+  - { id: 1, class: _ }
+body:             |
+  bb.0:
+    liveins: %r0
+
+    %0(s16) = COPY %r0
+    %1(s32) = G_ZEXT %0
+    ; G_ZEXT with s16 is legal, so we should find it unchanged in the output
+    ; CHECK: {{%[0-9]+}}(s32) = G_ZEXT {{%[0-9]+}}
+    %r0 = COPY %1(s32)
+    BX_RET 14, _, implicit %r0
+...
+---
 name:            test_add_s8
 # CHECK-LABEL: name: test_add_s8
 legalized:       false