]> granicus.if.org Git - llvm/commitdiff
[ARM] GlobalISel: Load i1, i8 and i16 args from stack
authorDiana Picus <diana.picus@linaro.org>
Thu, 26 Jan 2017 09:20:47 +0000 (09:20 +0000)
committerDiana Picus <diana.picus@linaro.org>
Thu, 26 Jan 2017 09:20:47 +0000 (09:20 +0000)
Add support for loading i1, i8 and i16 arguments from the stack, with or without
the ABI extension flags.

When the ABI extension flags are present, we load a 4-byte value, otherwise we
preserve the size of the load and let the instruction selector replace it with a
LDRB/LDRH. This generates the same thing as DAGISel.

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

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

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

index dcd26341db0c3aff7502f5c28e6c4440de998e2b..5a2ded2e4b7f54e01c702e7361816bc4c287b000 100644 (file)
@@ -122,7 +122,7 @@ struct FormalArgHandler : public CallLowering::ValueHandler {
 
   unsigned getStackAddress(uint64_t Size, int64_t Offset,
                            MachinePointerInfo &MPO) override {
-    assert(Size == 4 && "Unsupported size");
+    assert((Size == 1 || Size == 2 || Size == 4) && "Unsupported size");
 
     auto &MFI = MIRBuilder.getMF().getFrameInfo();
 
@@ -138,7 +138,16 @@ struct FormalArgHandler : public CallLowering::ValueHandler {
 
   void assignValueToAddress(unsigned ValVReg, unsigned Addr, uint64_t Size,
                             MachinePointerInfo &MPO, CCValAssign &VA) override {
-    assert(Size == 4 && "Unsupported size");
+    assert((Size == 1 || Size == 2 || Size == 4) && "Unsupported size");
+
+    if (VA.getLocInfo() == CCValAssign::SExt ||
+        VA.getLocInfo() == CCValAssign::ZExt) {
+      // If the argument is zero- or sign-extended by the caller, its size
+      // becomes 4 bytes, so that's what we should load.
+      Size = 4;
+      assert(MRI.getType(ValVReg).isScalar() && "Only scalars supported atm");
+      MRI.setType(ValVReg, LLT::scalar(32));
+    }
 
     auto MMO = MIRBuilder.getMF().getMachineMemOperand(
         MPO, MachineMemOperand::MOLoad, Size, /* Alignment */ 0);
@@ -177,18 +186,10 @@ bool ARMCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
     return false;
 
   auto &Args = F.getArgumentList();
-  unsigned ArgIdx = 0;
-  for (auto &Arg : Args) {
-    ArgIdx++;
+  for (auto &Arg : Args)
     if (!isSupportedType(DL, TLI, Arg.getType()))
       return false;
 
-    // FIXME: This check as well as ArgIdx are going away as soon as we support
-    // loading values < 32 bits.
-    if (ArgIdx > 4 && Arg.getType()->getIntegerBitWidth() != 32)
-      return false;
-  }
-
   CCAssignFn *AssignFn =
       TLI.CCAssignFnForCall(F.getCallingConv(), F.isVarArg());
 
index 4167344337d4216916d5d53b2d29c646347f414a..538060d4334b250751fcc98c11d8d690a136aeea 100644 (file)
@@ -85,6 +85,22 @@ static unsigned selectSimpleExtOpc(unsigned Opc, unsigned Size) {
   llvm_unreachable("Unsupported opcode");
 }
 
+/// Select the opcode for simple loads. For types smaller than 32 bits, the
+/// value will be zero extended.
+static unsigned selectLoadOpCode(unsigned Size) {
+  switch (Size) {
+  case 1:
+  case 8:
+    return ARM::LDRBi12;
+  case 16:
+    return ARM::LDRH;
+  case 32:
+    return ARM::LDRi12;
+  }
+
+  llvm_unreachable("Unsupported size");
+}
+
 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!");
@@ -167,10 +183,22 @@ bool ARMInstructionSelector::select(MachineInstr &I) const {
     I.setDesc(TII.get(ARM::ADDri));
     MIB.addImm(0).add(predOps(ARMCC::AL)).add(condCodeOp());
     break;
-  case G_LOAD:
-    I.setDesc(TII.get(ARM::LDRi12));
+  case G_LOAD: {
+    LLT ValTy = MRI.getType(I.getOperand(0).getReg());
+    const auto ValSize = ValTy.getSizeInBits();
+
+    if (ValSize != 32 && ValSize != 16 && ValSize != 8 && ValSize != 1)
+      return false;
+
+    const auto NewOpc = selectLoadOpCode(ValSize);
+    I.setDesc(TII.get(NewOpc));
+
+    if (NewOpc == ARM::LDRH)
+      // LDRH has a funny addressing mode (there's already a FIXME for it).
+      MIB.addReg(0);
     MIB.addImm(0).add(predOps(ARMCC::AL));
     break;
+  }
   default:
     return false;
   }
index 7157af1ec16d244cbdb1843d3fd3d70e6bf1ef4d..5f4a549565e10c4fdd478f8c08d41d16c0b44f5a 100644 (file)
@@ -35,7 +35,8 @@ ARMLegalizerInfo::ARMLegalizerInfo() {
 
   setAction({G_FRAME_INDEX, p0}, Legal);
 
-  setAction({G_LOAD, s32}, Legal);
+  for (auto Ty : {s1, s8, s16, s32})
+    setAction({G_LOAD, Ty}, Legal);
   setAction({G_LOAD, 1, p0}, Legal);
 
   for (auto Ty : {s1, s8, s16, s32})
index 1d1a3e69b81622ba7c121a6e5ffe5d69fe1ef829..ab2ddf88ff390b36b6a1ec5aae8a255b3e0e799e 100644 (file)
@@ -233,19 +233,26 @@ registers:
 # CHECK-DAG: id: 2, class: gpr
 # CHECK-DAG: id: 3, class: gpr
 fixedStack:
-  - { id: 0, offset: 0, size: 4, alignment: 4, isImmutable: true, isAliased: false }
+  - { id: 0, offset: 0, size: 1, alignment: 4, isImmutable: true, isAliased: false }
   - { id: 1, offset: 4, size: 4, alignment: 4, isImmutable: true, isAliased: false }
   - { id: 2, offset: 8, size: 4, alignment: 4, isImmutable: true, isAliased: false }
-# CHECK: id: [[FRAME_INDEX:[0-9]+]], offset: 8
+# CHECK-DAG: id: [[FI1:[0-9]+]], offset: 0
+# CHECK-DAG: id: [[FI32:[0-9]+]], offset: 8
 body:             |
   bb.0:
     liveins: %r0, %r1, %r2, %r3
 
     %0(p0) = G_FRAME_INDEX %fixed-stack.2
-    ; CHECK: [[FIVREG:%[0-9]+]] = ADDri %fixed-stack.[[FRAME_INDEX]], 0, 14, _, _
+    ; CHECK: [[FI32VREG:%[0-9]+]] = ADDri %fixed-stack.[[FI32]], 0, 14, _, _
 
     %1(s32) = G_LOAD %0(p0)
-    ; CHECK: {{%[0-9]+}} = LDRi12 [[FIVREG]], 0, 14, _
+    ; CHECK: {{%[0-9]+}} = LDRi12 [[FI32VREG]], 0, 14, _
+
+    %2(p0) = G_FRAME_INDEX %fixed-stack.0
+    ; CHECK: [[FI1VREG:%[0-9]+]] = ADDri %fixed-stack.[[FI1]], 0, 14, _, _
+
+    %3(s1) = G_LOAD %2(p0)
+    ; CHECK: {{%[0-9]+}} = LDRBi12 [[FI1VREG]], 0, 14, _
 
     BX_RET 14, _
     ; CHECK: BX_RET 14, _
index e01d89cdf7a68238050c987fbdf41ec1316d0541..a20a108d8a92b231236538380d081048acbc2272 100644 (file)
@@ -82,8 +82,8 @@ entry:
   ret i32 %sum
 }
 
-define i32 @test_many_args(i32 %p0, i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5) {
-; CHECK-LABEL: name: test_many_args
+define i32 @test_stack_args(i32 %p0, i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5) {
+; CHECK-LABEL: name: test_stack_args
 ; CHECK: fixedStack:
 ; CHECK-DAG: id: [[P4:[0-9]]]{{.*}}offset: 0{{.*}}size: 4
 ; CHECK-DAG: id: [[P5:[0-9]]]{{.*}}offset: 4{{.*}}size: 4
@@ -98,3 +98,39 @@ entry:
   %sum = add i32 %p2, %p5
   ret i32 %sum
 }
+
+define i16 @test_stack_args_signext(i32 %p0, i16 %p1, i8 %p2, i1 %p3,
+                                    i8 signext %p4, i16 signext %p5) {
+; CHECK-LABEL: name: test_stack_args_signext
+; CHECK: fixedStack:
+; CHECK-DAG: id: [[P4:[0-9]]]{{.*}}offset: 0{{.*}}size: 1
+; CHECK-DAG: id: [[P5:[0-9]]]{{.*}}offset: 4{{.*}}size: 2
+; CHECK: liveins: %r0, %r1, %r2, %r3
+; CHECK: [[VREGP1:%[0-9]+]]{{.*}} = COPY %r1
+; CHECK: [[FIP5:%[0-9]+]]{{.*}} = G_FRAME_INDEX %fixed-stack.[[P5]]
+; CHECK: [[VREGP5:%[0-9]+]]{{.*}} = G_LOAD [[FIP5]](p0)
+; CHECK: [[SUM:%[0-9]+]]{{.*}} = G_ADD [[VREGP1]], [[VREGP5]]
+; CHECK: %r0 = COPY [[SUM]]
+; CHECK: BX_RET 14, _, implicit %r0
+entry:
+  %sum = add i16 %p1, %p5
+  ret i16 %sum
+}
+
+define i8 @test_stack_args_zeroext(i32 %p0, i16 %p1, i8 %p2, i1 %p3,
+                                    i8 zeroext %p4, i16 zeroext %p5) {
+; CHECK-LABEL: name: test_stack_args_zeroext
+; CHECK: fixedStack:
+; CHECK-DAG: id: [[P4:[0-9]]]{{.*}}offset: 0{{.*}}size: 1
+; CHECK-DAG: id: [[P5:[0-9]]]{{.*}}offset: 4{{.*}}size: 2
+; CHECK: liveins: %r0, %r1, %r2, %r3
+; CHECK: [[VREGP2:%[0-9]+]]{{.*}} = COPY %r2
+; CHECK: [[FIP4:%[0-9]+]]{{.*}} = G_FRAME_INDEX %fixed-stack.[[P4]]
+; CHECK: [[VREGP4:%[0-9]+]]{{.*}} = G_LOAD [[FIP4]](p0)
+; CHECK: [[SUM:%[0-9]+]]{{.*}} = G_ADD [[VREGP2]], [[VREGP4]]
+; CHECK: %r0 = COPY [[SUM]]
+; CHECK: BX_RET 14, _, implicit %r0
+entry:
+  %sum = add i8 %p2, %p4
+  ret i8 %sum
+}
index ba2a5469f85add912c0b10f3387083193f008fec..f5b706e7d21ae1674057a5f95d36ecceff34fd0b 100644 (file)
@@ -67,8 +67,8 @@ entry:
   ret i32 %sum
 }
 
-define i32 @test_many_args(i32 %p0, i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5) {
-; CHECK-LABEL: test_many_args:
+define i32 @test_stack_args_i32(i32 %p0, i32 %p1, i32 %p2, i32 %p3, i32 %p4, i32 %p5) {
+; CHECK-LABEL: test_stack_args_i32:
 ; CHECK: add [[P5ADDR:r[0-9]+]], sp, #4
 ; CHECK: ldr [[P5:r[0-9]+]], {{.*}}[[P5ADDR]]
 ; CHECK: add r0, r2, [[P5]]
@@ -77,3 +77,36 @@ entry:
   %sum = add i32 %p2, %p5
   ret i32 %sum
 }
+
+define i16 @test_stack_args_mixed(i32 %p0, i16 %p1, i8 %p2, i1 %p3, i8 %p4, i16 %p5) {
+; CHECK-LABEL: test_stack_args_mixed:
+; CHECK: add [[P5ADDR:r[0-9]+]], sp, #4
+; CHECK: ldrh [[P5:r[0-9]+]], {{.*}}[[P5ADDR]]
+; CHECK: add r0, r1, [[P5]]
+; CHECK: bx lr
+entry:
+  %sum = add i16 %p1, %p5
+  ret i16 %sum
+}
+
+define i16 @test_stack_args_zeroext(i32 %p0, i16 %p1, i8 %p2, i1 %p3, i16 zeroext %p4) {
+; CHECK-LABEL: test_stack_args_zeroext:
+; CHECK: mov [[P4ADDR:r[0-9]+]], sp
+; CHECK: ldr [[P4:r[0-9]+]], {{.*}}[[P4ADDR]]
+; CHECK: add r0, r1, [[P4]]
+; CHECK: bx lr
+entry:
+  %sum = add i16 %p1, %p4
+  ret i16 %sum
+}
+
+define i8 @test_stack_args_signext(i32 %p0, i16 %p1, i8 %p2, i1 %p3, i8 signext %p4) {
+; CHECK-LABEL: test_stack_args_signext:
+; CHECK: mov [[P4ADDR:r[0-9]+]], sp
+; CHECK: ldr [[P4:r[0-9]+]], {{.*}}[[P4ADDR]]
+; CHECK: add r0, r2, [[P4]]
+; CHECK: bx lr
+entry:
+  %sum = add i8 %p2, %p4
+  ret i8 %sum
+}