From 59720b422abfc090aadf246eb3c7fc583aeb2693 Mon Sep 17 00:00:00 2001 From: Diana Picus Date: Wed, 12 Dec 2018 10:32:15 +0000 Subject: [PATCH] [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 --- .../lib/Target/ARM/ARMInstructionSelector.cpp | 18 +++- llvm/lib/Target/ARM/ARMLegalizerInfo.cpp | 22 ++++- .../GlobalISel/arm-legalize-load-store.mir | 49 +++++++++++ .../CodeGen/ARM/GlobalISel/arm-legalizer.mir | 28 +------ .../GlobalISel/thumb-select-load-store.mir | 84 +++++++++++++++++++ 5 files changed, 171 insertions(+), 30 deletions(-) create mode 100644 llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-load-store.mir create mode 100644 llvm/test/CodeGen/ARM/GlobalISel/thumb-select-load-store.mir diff --git a/llvm/lib/Target/ARM/ARMInstructionSelector.cpp b/llvm/lib/Target/ARM/ARMInstructionSelector.cpp index 6692a4d41420..2d5c990ab0e7 100644 --- a/llvm/lib/Target/ARM/ARMInstructionSelector.cpp +++ b/llvm/lib/Target/ARM/ARMInstructionSelector.cpp @@ -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; diff --git a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp index 0455f6689cb4..2edeeacb6c62 100644 --- a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp +++ b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp @@ -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); diff --git a/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-load-store.mir b/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-load-store.mir new file mode 100644 index 000000000000..a955af9a97ff --- /dev/null +++ b/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-load-store.mir @@ -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 +... diff --git a/llvm/test/CodeGen/ARM/GlobalISel/arm-legalizer.mir b/llvm/test/CodeGen/ARM/GlobalISel/arm-legalizer.mir index 4d61593b47a1..a95e8d414606 100644 --- a/llvm/test/CodeGen/ARM/GlobalISel/arm-legalizer.mir +++ b/llvm/test/CodeGen/ARM/GlobalISel/arm-legalizer.mir @@ -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 ... --- diff --git a/llvm/test/CodeGen/ARM/GlobalISel/thumb-select-load-store.mir b/llvm/test/CodeGen/ARM/GlobalISel/thumb-select-load-store.mir new file mode 100644 index 000000000000..170c26e996cb --- /dev/null +++ b/llvm/test/CodeGen/ARM/GlobalISel/thumb-select-load-store.mir @@ -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 +...