From f4523b0efd797e6f9f147129bc404fedecf18ebf Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Wed, 15 Mar 2017 18:38:13 +0000 Subject: [PATCH] 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 --- include/llvm/CodeGen/MIRYamlMapping.h | 2 + lib/CodeGen/MIRParser/MIRParser.cpp | 2 + lib/CodeGen/MIRPrinter.cpp | 2 + lib/Target/ARM/ARMConstantIslandPass.cpp | 10 +- test/CodeGen/ARM/v6-jumptable-clobber.mir | 384 ++++++++++++++++++ .../X86/GlobalISel/irtranslator-call.ll | 1 + 6 files changed, 399 insertions(+), 2 deletions(-) create mode 100644 test/CodeGen/ARM/v6-jumptable-clobber.mir diff --git a/include/llvm/CodeGen/MIRYamlMapping.h b/include/llvm/CodeGen/MIRYamlMapping.h index 05d0429ab63..38cf8aa165a 100644 --- a/include/llvm/CodeGen/MIRYamlMapping.h +++ b/include/llvm/CodeGen/MIRYamlMapping.h @@ -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 { 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); diff --git a/lib/CodeGen/MIRParser/MIRParser.cpp b/lib/CodeGen/MIRParser/MIRParser.cpp index 0c694c465b6..79189e30ccd 100644 --- a/lib/CodeGen/MIRParser/MIRParser.cpp +++ b/lib/CodeGen/MIRParser/MIRParser.cpp @@ -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) diff --git a/lib/CodeGen/MIRPrinter.cpp b/lib/CodeGen/MIRPrinter.cpp index 899973488bb..8693a9a269d 100644 --- a/lib/CodeGen/MIRPrinter.cpp +++ b/lib/CodeGen/MIRPrinter.cpp @@ -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( diff --git a/lib/Target/ARM/ARMConstantIslandPass.cpp b/lib/Target/ARM/ARMConstantIslandPass.cpp index 8b1204f257a..0de628b2c19 100644 --- a/lib/Target/ARM/ARMConstantIslandPass.cpp +++ b/lib/Target/ARM/ARMConstantIslandPass.cpp @@ -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; diff --git a/test/CodeGen/ARM/v6-jumptable-clobber.mir b/test/CodeGen/ARM/v6-jumptable-clobber.mir new file mode 100644 index 00000000000..0e9bc42565f --- /dev/null +++ b/test/CodeGen/ARM/v6-jumptable-clobber.mir @@ -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: + +... diff --git a/test/CodeGen/X86/GlobalISel/irtranslator-call.ll b/test/CodeGen/X86/GlobalISel/irtranslator-call.ll index 425d2609380..c1bf4441766 100644 --- a/test/CodeGen/X86/GlobalISel/irtranslator-call.ll +++ b/test/CodeGen/X86/GlobalISel/irtranslator-call.ll @@ -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 -- 2.50.1