forked from OSchip/llvm-project
[ARM GlobalISel] Select load/store for Thumb2
Unfortunately we can't use TableGen for this because it doesn't yet support predicates on the source pattern root. Therefore, add a bit of handwritten code to the instruction selector to handle the most basic cases. Also mark them as legal and extract their legalizer test cases to a new test file. llvm-svn: 348920
This commit is contained in:
parent
87a7e436c0
commit
59720b422a
|
@ -248,10 +248,23 @@ static unsigned selectSimpleExtOpc(unsigned Opc, unsigned Size) {
|
|||
/// bits, the value will be zero extended. Returns the original opcode if it
|
||||
/// doesn't know how to select a better one.
|
||||
static unsigned selectLoadStoreOpCode(unsigned Opc, unsigned RegBank,
|
||||
unsigned Size) {
|
||||
unsigned Size, bool isThumb) {
|
||||
bool isStore = Opc == TargetOpcode::G_STORE;
|
||||
|
||||
if (RegBank == ARM::GPRRegBankID) {
|
||||
if (isThumb)
|
||||
switch (Size) {
|
||||
case 1:
|
||||
case 8:
|
||||
return isStore ? ARM::t2STRBi12 : ARM::t2LDRBi12;
|
||||
case 16:
|
||||
return isStore ? ARM::t2STRHi12 : ARM::t2LDRHi12;
|
||||
case 32:
|
||||
return isStore ? ARM::t2STRi12 : ARM::t2LDRi12;
|
||||
default:
|
||||
return Opc;
|
||||
}
|
||||
|
||||
switch (Size) {
|
||||
case 1:
|
||||
case 8:
|
||||
|
@ -901,7 +914,8 @@ bool ARMInstructionSelector::select(MachineInstr &I,
|
|||
assert((ValSize != 64 || STI.hasVFP2()) &&
|
||||
"Don't know how to load/store 64-bit value without VFP");
|
||||
|
||||
const auto NewOpc = selectLoadStoreOpCode(I.getOpcode(), RegBank, ValSize);
|
||||
const auto NewOpc =
|
||||
selectLoadStoreOpCode(I.getOpcode(), RegBank, ValSize, STI.isThumb());
|
||||
if (NewOpc == G_LOAD || NewOpc == G_STORE)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -75,6 +75,24 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
|
|||
const LLT s32 = LLT::scalar(32);
|
||||
const LLT s64 = LLT::scalar(64);
|
||||
|
||||
if (ST.isThumb1Only()) {
|
||||
// Thumb1 is not supported yet.
|
||||
computeTables();
|
||||
verify(*ST.getInstrInfo());
|
||||
return;
|
||||
}
|
||||
|
||||
// We're keeping these builders around because we'll want to add support for
|
||||
// floating point to them.
|
||||
auto &LoadStoreBuilder =
|
||||
getActionDefinitionsBuilder({G_LOAD, G_STORE})
|
||||
.legalForTypesWithMemSize({
|
||||
{s1, p0, 8},
|
||||
{s8, p0, 8},
|
||||
{s16, p0, 16},
|
||||
{s32, p0, 32},
|
||||
{p0, p0, 32}});
|
||||
|
||||
if (ST.isThumb()) {
|
||||
// FIXME: merge with the code for non-Thumb.
|
||||
computeTables();
|
||||
|
@ -149,10 +167,6 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
|
|||
|
||||
// We're keeping these builders around because we'll want to add support for
|
||||
// floating point to them.
|
||||
auto &LoadStoreBuilder =
|
||||
getActionDefinitionsBuilder({G_LOAD, G_STORE})
|
||||
.legalForCartesianProduct({s1, s8, s16, s32, p0}, {p0});
|
||||
|
||||
auto &PhiBuilder =
|
||||
getActionDefinitionsBuilder(G_PHI).legalFor({s32, p0}).minScalar(0, s32);
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
# RUN: llc -mtriple arm-- -run-pass=legalizer %s -o - | FileCheck %s
|
||||
# RUN: llc -mtriple thumb-- -mattr=+v6t2 -run-pass=legalizer %s -o - | FileCheck %s
|
||||
--- |
|
||||
define void @test_legal_loads_stores() { ret void }
|
||||
...
|
||||
---
|
||||
name: test_legal_loads_stores
|
||||
# CHECK-LABEL: name: test_legal_loads_stores
|
||||
legalized: false
|
||||
# CHECK: legalized: true
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
tracksRegLiveness: true
|
||||
registers:
|
||||
- { id: 0, class: _ }
|
||||
- { id: 1, class: _ }
|
||||
- { id: 2, class: _ }
|
||||
- { id: 3, class: _ }
|
||||
- { id: 4, class: _ }
|
||||
- { id: 5, class: _ }
|
||||
- { id: 6, class: _ }
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $r0
|
||||
|
||||
; These are all legal, so we should find them unchanged in the output
|
||||
; CHECK-DAG: G_STORE {{%[0-9]+}}(s32), %0(p0)
|
||||
; CHECK-DAG: G_STORE {{%[0-9]+}}(s16), %0(p0)
|
||||
; CHECK-DAG: G_STORE {{%[0-9]+}}(s8), %0(p0)
|
||||
; CHECK-DAG: G_STORE {{%[0-9]+}}(s1), %0(p0)
|
||||
; CHECK-DAG: G_STORE {{%[0-9]+}}(p0), %0(p0)
|
||||
; CHECK-DAG: {{%[0-9]+}}:_(s32) = G_LOAD %0(p0)
|
||||
; CHECK-DAG: {{%[0-9]+}}:_(s16) = G_LOAD %0(p0)
|
||||
; CHECK-DAG: {{%[0-9]+}}:_(s8) = G_LOAD %0(p0)
|
||||
; CHECK-DAG: {{%[0-9]+}}:_(s1) = G_LOAD %0(p0)
|
||||
; CHECK-DAG: {{%[0-9]+}}:_(p0) = G_LOAD %0(p0)
|
||||
%0(p0) = COPY $r0
|
||||
%2(s32) = G_LOAD %0(p0) :: (load 4)
|
||||
G_STORE %2(s32), %0(p0) :: (store 4)
|
||||
%3(s16) = G_LOAD %0(p0) :: (load 2)
|
||||
G_STORE %3(s16), %0(p0) :: (store 2)
|
||||
%4(s8) = G_LOAD %0(p0) :: (load 1)
|
||||
G_STORE %4(s8), %0(p0) :: (store 1)
|
||||
%5(s1) = G_LOAD %0(p0) :: (load 1)
|
||||
G_STORE %5(s1), %0(p0) :: (store 1)
|
||||
%6(p0) = G_LOAD %0(p0) :: (load 4)
|
||||
G_STORE %6(p0), %0(p0) :: (store 4)
|
||||
BX_RET 14, $noreg
|
||||
...
|
|
@ -35,7 +35,7 @@
|
|||
define void @test_shl_s32() { ret void }
|
||||
|
||||
define void @test_load_from_stack() { ret void }
|
||||
define void @test_legal_loads_stores() #0 { ret void }
|
||||
define void @test_load_store_64() #0 { ret void }
|
||||
|
||||
define void @test_gep() { ret void }
|
||||
|
||||
|
@ -792,8 +792,8 @@ body: |
|
|||
BX_RET 14, $noreg, implicit $r0
|
||||
...
|
||||
---
|
||||
name: test_legal_loads_stores
|
||||
# CHECK-LABEL: name: test_legal_loads_stores
|
||||
name: test_load_store_64
|
||||
# CHECK-LABEL: name: test_load_store_64
|
||||
legalized: false
|
||||
# CHECK: legalized: true
|
||||
regBankSelected: false
|
||||
|
@ -811,32 +811,12 @@ body: |
|
|||
bb.0:
|
||||
liveins: $r0
|
||||
|
||||
; These are all legal, so we should find them unchanged in the output
|
||||
; These are legal, so we should find them unchanged in the output
|
||||
; CHECK-DAG: G_STORE {{%[0-9]+}}(s64), %0(p0)
|
||||
; CHECK-DAG: G_STORE {{%[0-9]+}}(s32), %0(p0)
|
||||
; CHECK-DAG: G_STORE {{%[0-9]+}}(s16), %0(p0)
|
||||
; CHECK-DAG: G_STORE {{%[0-9]+}}(s8), %0(p0)
|
||||
; CHECK-DAG: G_STORE {{%[0-9]+}}(s1), %0(p0)
|
||||
; CHECK-DAG: G_STORE {{%[0-9]+}}(p0), %0(p0)
|
||||
; CHECK-DAG: {{%[0-9]+}}:_(s64) = G_LOAD %0(p0)
|
||||
; CHECK-DAG: {{%[0-9]+}}:_(s32) = G_LOAD %0(p0)
|
||||
; CHECK-DAG: {{%[0-9]+}}:_(s16) = G_LOAD %0(p0)
|
||||
; CHECK-DAG: {{%[0-9]+}}:_(s8) = G_LOAD %0(p0)
|
||||
; CHECK-DAG: {{%[0-9]+}}:_(s1) = G_LOAD %0(p0)
|
||||
; CHECK-DAG: {{%[0-9]+}}:_(p0) = G_LOAD %0(p0)
|
||||
%0(p0) = COPY $r0
|
||||
%1(s64) = G_LOAD %0(p0) :: (load 8)
|
||||
G_STORE %1(s64), %0(p0) :: (store 8)
|
||||
%2(s32) = G_LOAD %0(p0) :: (load 4)
|
||||
G_STORE %2(s32), %0(p0) :: (store 4)
|
||||
%3(s16) = G_LOAD %0(p0) :: (load 2)
|
||||
G_STORE %3(s16), %0(p0) :: (store 2)
|
||||
%4(s8) = G_LOAD %0(p0) :: (load 1)
|
||||
G_STORE %4(s8), %0(p0) :: (store 1)
|
||||
%5(s1) = G_LOAD %0(p0) :: (load 1)
|
||||
G_STORE %5(s1), %0(p0) :: (store 1)
|
||||
%6(p0) = G_LOAD %0(p0) :: (load 4)
|
||||
G_STORE %6(p0), %0(p0) :: (store 4)
|
||||
BX_RET 14, $noreg
|
||||
...
|
||||
---
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
# RUN: llc -O0 -mtriple thumb-- -mattr=+v6t2 -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
|
||||
--- |
|
||||
define void @test_s8() { ret void }
|
||||
define void @test_s16() { ret void }
|
||||
define void @test_s32() { ret void }
|
||||
...
|
||||
---
|
||||
name: test_s8
|
||||
# CHECK-LABEL: name: test_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(p0) = COPY $r0
|
||||
; CHECK: %[[P:[0-9]+]]:gpr = COPY $r0
|
||||
|
||||
%1(s8) = G_LOAD %0(p0) :: (load 1)
|
||||
; CHECK: %[[V:[0-9]+]]:rgpr = t2LDRBi12 %[[P]], 0, 14, $noreg :: (load 1)
|
||||
|
||||
G_STORE %1(s8), %0(p0) :: (store 1)
|
||||
; CHECK: t2STRBi12 %[[V]], %[[P]], 0, 14, $noreg :: (store 1)
|
||||
|
||||
BX_RET 14, $noreg
|
||||
; CHECK: BX_RET 14, $noreg
|
||||
...
|
||||
---
|
||||
name: test_s16
|
||||
# CHECK-LABEL: name: test_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(p0) = COPY $r0
|
||||
; CHECK: %[[P:[0-9]+]]:gpr = COPY $r0
|
||||
|
||||
%1(s16) = G_LOAD %0(p0) :: (load 2)
|
||||
; CHECK: %[[V:[0-9]+]]:rgpr = t2LDRHi12 %[[P]], 0, 14, $noreg :: (load 2)
|
||||
|
||||
G_STORE %1(s16), %0(p0) :: (store 2)
|
||||
; CHECK: t2STRHi12 %[[V]], %[[P]], 0, 14, $noreg :: (store 2)
|
||||
|
||||
BX_RET 14, $noreg
|
||||
; CHECK: BX_RET 14, $noreg
|
||||
...
|
||||
---
|
||||
name: test_s32
|
||||
# CHECK-LABEL: name: test_s32
|
||||
legalized: true
|
||||
regBankSelected: true
|
||||
selected: false
|
||||
# CHECK: selected: true
|
||||
registers:
|
||||
- { id: 0, class: gprb }
|
||||
- { id: 1, class: gprb }
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $r0
|
||||
|
||||
%0(p0) = COPY $r0
|
||||
; CHECK: %[[P:[0-9]+]]:gpr = COPY $r0
|
||||
|
||||
%1(s32) = G_LOAD %0(p0) :: (load 4)
|
||||
; CHECK: %[[V:[0-9]+]]:gpr = t2LDRi12 %[[P]], 0, 14, $noreg :: (load 4)
|
||||
|
||||
G_STORE %1(s32), %0(p0) :: (store 4)
|
||||
; CHECK: t2STRi12 %[[V]], %[[P]], 0, 14, $noreg :: (store 4)
|
||||
|
||||
BX_RET 14, $noreg
|
||||
; CHECK: BX_RET 14, $noreg
|
||||
...
|
Loading…
Reference in New Issue