ARM: avoid clobbering register in v6 jump-table expansion.

If we got unlucky with register allocation and actual constpool placement, we
could end up producing a tTBB_JT with an index that's already been clobbered.

Technically, we might be able to fix this situation up with a MOV, but I think
the constant islands pass is complex enough without having to deal with more
weird edge-cases.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@297871 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Tim Northover 2017-03-15 18:38:13 +00:00
parent 1d95032b0c
commit f4523b0efd
6 changed files with 399 additions and 2 deletions

View File

@ -381,6 +381,7 @@ struct MachineFunction {
StringRef Name;
unsigned Alignment = 0;
bool ExposesReturnsTwice = false;
bool NoVRegs;
// GISel MachineFunctionProperties.
bool Legalized = false;
bool RegBankSelected = false;
@ -405,6 +406,7 @@ template <> struct MappingTraits<MachineFunction> {
YamlIO.mapRequired("name", MF.Name);
YamlIO.mapOptional("alignment", MF.Alignment);
YamlIO.mapOptional("exposesReturnsTwice", MF.ExposesReturnsTwice);
YamlIO.mapOptional("noVRegs", MF.NoVRegs);
YamlIO.mapOptional("legalized", MF.Legalized);
YamlIO.mapOptional("regBankSelected", MF.RegBankSelected);
YamlIO.mapOptional("selected", MF.Selected);

View File

@ -332,6 +332,8 @@ bool MIRParserImpl::initializeMachineFunction(MachineFunction &MF) {
MF.setAlignment(YamlMF.Alignment);
MF.setExposesReturnsTwice(YamlMF.ExposesReturnsTwice);
if (YamlMF.NoVRegs)
MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);
if (YamlMF.Legalized)
MF.getProperties().set(MachineFunctionProperties::Property::Legalized);
if (YamlMF.RegBankSelected)

View File

@ -175,6 +175,8 @@ void MIRPrinter::print(const MachineFunction &MF) {
YamlMF.Alignment = MF.getAlignment();
YamlMF.ExposesReturnsTwice = MF.exposesReturnsTwice();
YamlMF.NoVRegs = MF.getProperties().hasProperty(
MachineFunctionProperties::Property::NoVRegs);
YamlMF.Legalized = MF.getProperties().hasProperty(
MachineFunctionProperties::Property::Legalized);
YamlMF.RegBankSelected = MF.getProperties().hasProperty(

View File

@ -2104,6 +2104,12 @@ bool ARMConstantIslands::optimizeThumb2JumpTables() {
IdxReg = Shift->getOperand(2).getReg();
unsigned ShiftedIdxReg = Shift->getOperand(0).getReg();
// It's important that IdxReg is live until the actual TBB/TBH. Most of
// the range is checked later, but the LEA might still clobber it and not
// actually get removed.
if (BaseReg == IdxReg && !jumpTableFollowsTB(MI, User.CPEMI))
continue;
MachineInstr *Load = User.MI->getNextNode();
if (Load->getOpcode() != ARM::tLDRr)
continue;
@ -2135,14 +2141,14 @@ bool ARMConstantIslands::optimizeThumb2JumpTables() {
// IdxReg gets redefined in the middle of the sequence.
continue;
}
// Now safe to delete the load and lsl. The LEA will be removed later.
CanDeleteLEA = true;
Shift->eraseFromParent();
Load->eraseFromParent();
DeadSize += 4;
}
DEBUG(dbgs() << "Shrink JT: " << *MI);
MachineInstr *CPEMI = User.CPEMI;
unsigned Opc = ByteOk ? ARM::t2TBB_JT : ARM::t2TBH_JT;

View File

@ -0,0 +1,384 @@
# RUN: llc -run-pass=arm-cp-islands -o - %s | FileCheck %s
# Test created by tweaking the register allocation after stopping the IR below
# just before constant islands. We were forwarding the table index to the end of
# the block, even though the LEA clobbered it.
# CHECK-LABEL: name: foo
# CHECK: tBR_JT
# This order is important. If the jump-table comes first then the
# transformation is valid because the LEA can be removed, see second test.
# CHECK: CONSTPOOL_ENTRY
# CHECK: JUMPTABLE_ADDRS
# CHECK-LABEL: name: bar
# CHECK: tTBB_JT %pc, killed %r1
--- |
; ModuleID = 'simple.ll'
source_filename = "simple.ll"
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "thumbv6m-none--eabi"
define void @foo(i8 %in, i32* %addr) {
store i32 12345678, i32* %addr
%1 = call i32 @llvm.arm.space(i32 980, i32 undef)
%2 = zext i8 %in to i32
switch i32 %2, label %default [
i32 0, label %d1
i32 1, label %d2
i32 3, label %d3
i32 4, label %d4
i32 5, label %d5
i32 6, label %d6
i32 7, label %d7
i32 2, label %d8
i32 8, label %d9
i32 9, label %d10
i32 19, label %d11
i32 20, label %d12
i32 21, label %d13
i32 22, label %d14
i32 24, label %d15
i32 25, label %d16
i32 26, label %d17
]
default: ; preds = %0
unreachable
d1: ; preds = %0
unreachable
d2: ; preds = %0
unreachable
d3: ; preds = %0
unreachable
d4: ; preds = %0
unreachable
d5: ; preds = %0
unreachable
d6: ; preds = %0
unreachable
d7: ; preds = %0
unreachable
d8: ; preds = %0
unreachable
d9: ; preds = %0
unreachable
d10: ; preds = %0
unreachable
d11: ; preds = %0
unreachable
d12: ; preds = %0
unreachable
d13: ; preds = %0
unreachable
d14: ; preds = %0
unreachable
d15: ; preds = %0
unreachable
d16: ; preds = %0
unreachable
d17: ; preds = %0
unreachable
}
define void @bar(i8 %in, i32* %addr) {
store i32 12345678, i32* %addr
%1 = zext i8 %in to i32
switch i32 %1, label %default [
i32 0, label %d1
i32 1, label %d2
i32 3, label %d3
i32 4, label %d4
i32 5, label %d5
i32 6, label %d6
i32 7, label %d7
i32 2, label %d8
i32 8, label %d9
i32 9, label %d10
i32 19, label %d11
i32 20, label %d12
i32 21, label %d13
i32 22, label %d14
i32 24, label %d15
i32 25, label %d16
i32 26, label %d17
]
default: ; preds = %0
unreachable
d1: ; preds = %0
unreachable
d2: ; preds = %0
unreachable
d3: ; preds = %0
unreachable
d4: ; preds = %0
unreachable
d5: ; preds = %0
unreachable
d6: ; preds = %0
unreachable
d7: ; preds = %0
unreachable
d8: ; preds = %0
unreachable
d9: ; preds = %0
unreachable
d10: ; preds = %0
unreachable
d11: ; preds = %0
unreachable
d12: ; preds = %0
unreachable
d13: ; preds = %0
unreachable
d14: ; preds = %0
unreachable
d15: ; preds = %0
unreachable
d16: ; preds = %0
unreachable
d17: ; preds = %0
unreachable
}
; Function Attrs: nounwind
declare i32 @llvm.arm.space(i32, i32) #0
; Function Attrs: nounwind
declare void @llvm.stackprotector(i8*, i8**) #0
attributes #0 = { nounwind }
...
---
name: foo
alignment: 1
exposesReturnsTwice: false
noVRegs: true
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
liveins:
- { reg: '%r0' }
- { reg: '%r1' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 0
offsetAdjustment: 0
maxAlignment: 0
adjustsStack: false
hasCalls: false
maxCallFrameSize: 0
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
constants:
- id: 0
value: i32 12345678
alignment: 4
jumpTable:
kind: inline
entries:
- id: 0
blocks: [ '%bb.3.d2', '%bb.9.d8', '%bb.4.d3', '%bb.5.d4',
'%bb.6.d5', '%bb.7.d6', '%bb.8.d7', '%bb.10.d9',
'%bb.11.d10', '%bb.2.d1', '%bb.2.d1', '%bb.2.d1',
'%bb.2.d1', '%bb.2.d1', '%bb.2.d1', '%bb.2.d1',
'%bb.2.d1', '%bb.2.d1', '%bb.12.d11', '%bb.13.d12',
'%bb.14.d13', '%bb.15.d14', '%bb.2.d1', '%bb.16.d15',
'%bb.17.d16', '%bb.18.d17' ]
body: |
bb.0 (%ir-block.0):
successors: %bb.2.d1(0x03c3c3c4), %bb.1(0x7c3c3c3c)
liveins: %r0, %r1
%r2 = tLDRpci %const.0, 14, _
tSTRi killed %r2, killed %r1, 0, 14, _ :: (store 4 into %ir.addr)
dead %r1 = SPACE 980, undef %r0
%r0 = tUXTB killed %r0, 14, _
%r1, dead %cpsr = tSUBi3 killed %r0, 1, 14, _
tCMPi8 %r1, 25, 14, _, implicit-def %cpsr
tBcc %bb.2.d1, 8, killed %cpsr
bb.1 (%ir-block.0):
successors: %bb.3.d2(0x07c549d2), %bb.9.d8(0x07c549d2), %bb.4.d3(0x07c549d2), %bb.5.d4(0x07c549d2), %bb.6.d5(0x07c549d2), %bb.7.d6(0x07c549d2), %bb.8.d7(0x07c549d2), %bb.10.d9(0x07c549d2), %bb.11.d10(0x07c549d2), %bb.2.d1(0x03ab62db), %bb.12.d11(0x07c549d2), %bb.13.d12(0x07c549d2), %bb.14.d13(0x07c549d2), %bb.15.d14(0x07c549d2), %bb.16.d15(0x07c549d2), %bb.17.d16(0x07c549d2), %bb.18.d17(0x07c549d2)
liveins: %r1
%r0, dead %cpsr = tLSLri killed %r1, 2, 14, _
%r1 = tLEApcrelJT %jump-table.0, 14, _
%r0 = tLDRr killed %r0, killed %r1, 14, _ :: (load 4 from jump-table)
tBR_JTr killed %r0, %jump-table.0
bb.3.d2:
bb.9.d8:
bb.4.d3:
bb.5.d4:
bb.6.d5:
bb.7.d6:
bb.8.d7:
bb.10.d9:
bb.11.d10:
bb.2.d1:
bb.12.d11:
bb.13.d12:
bb.14.d13:
bb.15.d14:
bb.16.d15:
bb.17.d16:
bb.18.d17:
...
---
name: bar
alignment: 1
exposesReturnsTwice: false
noVRegs: true
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
liveins:
- { reg: '%r0' }
- { reg: '%r1' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 0
offsetAdjustment: 0
maxAlignment: 0
adjustsStack: false
hasCalls: false
maxCallFrameSize: 0
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
constants:
- id: 0
value: i32 12345678
alignment: 4
jumpTable:
kind: inline
entries:
- id: 0
blocks: [ '%bb.3.d2', '%bb.9.d8', '%bb.4.d3', '%bb.5.d4',
'%bb.6.d5', '%bb.7.d6', '%bb.8.d7', '%bb.10.d9',
'%bb.11.d10', '%bb.2.d1', '%bb.2.d1', '%bb.2.d1',
'%bb.2.d1', '%bb.2.d1', '%bb.2.d1', '%bb.2.d1',
'%bb.2.d1', '%bb.2.d1', '%bb.12.d11', '%bb.13.d12',
'%bb.14.d13', '%bb.15.d14', '%bb.2.d1', '%bb.16.d15',
'%bb.17.d16', '%bb.18.d17' ]
body: |
bb.0 (%ir-block.0):
successors: %bb.2.d1(0x03c3c3c4), %bb.1(0x7c3c3c3c)
liveins: %r0, %r1
%r2 = tLDRpci %const.0, 14, _
tSTRi killed %r2, killed %r1, 0, 14, _ :: (store 4 into %ir.addr)
%r0 = tUXTB killed %r0, 14, _
%r1, dead %cpsr = tSUBi3 killed %r0, 1, 14, _
tCMPi8 %r1, 25, 14, _, implicit-def %cpsr
tBcc %bb.2.d1, 8, killed %cpsr
bb.1 (%ir-block.0):
successors: %bb.3.d2(0x07c549d2), %bb.9.d8(0x07c549d2), %bb.4.d3(0x07c549d2), %bb.5.d4(0x07c549d2), %bb.6.d5(0x07c549d2), %bb.7.d6(0x07c549d2), %bb.8.d7(0x07c549d2), %bb.10.d9(0x07c549d2), %bb.11.d10(0x07c549d2), %bb.2.d1(0x03ab62db), %bb.12.d11(0x07c549d2), %bb.13.d12(0x07c549d2), %bb.14.d13(0x07c549d2), %bb.15.d14(0x07c549d2), %bb.16.d15(0x07c549d2), %bb.17.d16(0x07c549d2), %bb.18.d17(0x07c549d2)
liveins: %r1
%r0, dead %cpsr = tLSLri killed %r1, 2, 14, _
%r1 = tLEApcrelJT %jump-table.0, 14, _
%r0 = tLDRr killed %r0, killed %r1, 14, _ :: (load 4 from jump-table)
tBR_JTr killed %r0, %jump-table.0
bb.3.d2:
bb.9.d8:
bb.4.d3:
bb.5.d4:
bb.6.d5:
bb.7.d6:
bb.8.d7:
bb.10.d9:
bb.11.d10:
bb.2.d1:
bb.12.d11:
bb.13.d12:
bb.14.d13:
bb.15.d14:
bb.16.d15:
bb.17.d16:
bb.18.d17:
...

View File

@ -5,6 +5,7 @@ define void @test_void_return() {
; CHECK-LABEL: name: test_void_return
; CHECK: alignment: 4
; CHECK-NEXT: exposesReturnsTwice: false
; CHECK-NEXT: noVRegs: false
; CHECK-NEXT: legalized: false
; CHECK-NEXT: regBankSelected: false
; CHECK-NEXT: selected: false