[ARM] Add support for embedded position-independent code

This patch adds support for some new relocation models to the ARM
backend:

* Read-only position independence (ROPI): Code and read-only data is accessed
  PC-relative. The offsets between all code and RO data sections are known at
  static link time. This does not affect read-write data.
* Read-write position independence (RWPI): Read-write data is accessed relative
  to the static base register (r9). The offsets between all writeable data
  sections are known at static link time. This does not affect read-only data.

These two modes are independent (they specify how different objects
should be addressed), so they can be used individually or together. They
are otherwise the same as the "static" relocation model, and are not
compatible with SysV-style PIC using a global offset table.

These modes are normally used by bare-metal systems or systems with
small real-time operating systems. They are designed to avoid the need
for a dynamic linker, the only initialisation required is setting r9 to
an appropriate value for RWPI code.

I have only added support to SelectionDAG, not FastISel, because
FastISel is currently disabled for bare-metal targets where these modes
would be used.

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

llvm-svn: 278015
This commit is contained in:
Oliver Stannard 2016-08-08 15:28:31 +00:00
parent 219feac456
commit 8331aaee8f
16 changed files with 551 additions and 21 deletions

View File

@ -54,6 +54,12 @@ cl::opt<Reloc::Model> RelocModel(
"Fully relocatable, position independent code"),
clEnumValN(Reloc::DynamicNoPIC, "dynamic-no-pic",
"Relocatable external references, non-relocatable code"),
clEnumValN(Reloc::ROPI, "ropi",
"Code and read-only data relocatable, accessed PC-relative"),
clEnumValN(Reloc::RWPI, "rwpi",
"Read-write data relocatable, accessed relative to static base"),
clEnumValN(Reloc::ROPI_RWPI, "ropi-rwpi",
"Combination of ropi and rwpi"),
clEnumValEnd));
static inline Optional<Reloc::Model> getRelocModel() {

View File

@ -19,7 +19,7 @@ namespace llvm {
// Relocation model types.
namespace Reloc {
enum Model { Static, PIC_, DynamicNoPIC };
enum Model { Static, PIC_, DynamicNoPIC, ROPI, RWPI, ROPI_RWPI };
}
// Code model types.

View File

@ -725,16 +725,27 @@ void ARMAsmPrinter::emitAttributes() {
ATS.emitFPU(ARM::FK_VFPV2);
}
// RW data addressing.
if (isPositionIndependent()) {
// PIC specific attributes.
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RW_data,
ARMBuildAttrs::AddressRWPCRel);
} else if (STI.isRWPI()) {
// RWPI specific attributes.
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RW_data,
ARMBuildAttrs::AddressRWSBRel);
}
// RO data addressing.
if (isPositionIndependent() || STI.isROPI()) {
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_RO_data,
ARMBuildAttrs::AddressROPCRel);
}
// GOT use.
if (isPositionIndependent()) {
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_GOT_use,
ARMBuildAttrs::AddressGOT);
} else {
// Allow direct addressing of imported data for all other relocation models.
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_GOT_use,
ARMBuildAttrs::AddressDirect);
}
@ -858,14 +869,16 @@ void ARMAsmPrinter::emitAttributes() {
}
}
// TODO: We currently only support either reserving the register, or treating
// it as another callee-saved register, but not as SB or a TLS pointer; It
// would instead be nicer to push this from the frontend as metadata, as we do
// for the wchar and enum size tags
if (STI.isR9Reserved())
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use, ARMBuildAttrs::R9Reserved);
// We currently do not support using R9 as the TLS pointer.
if (STI.isRWPI())
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use,
ARMBuildAttrs::R9IsSB);
else if (STI.isR9Reserved())
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use,
ARMBuildAttrs::R9Reserved);
else
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use, ARMBuildAttrs::R9IsGPR);
ATS.emitAttribute(ARMBuildAttrs::ABI_PCS_R9_use,
ARMBuildAttrs::R9IsGPR);
if (STI.hasTrustZone() && STI.hasVirtualization())
ATS.emitAttribute(ARMBuildAttrs::Virtualization_use,
@ -899,6 +912,8 @@ getModifierVariantKind(ARMCP::ARMCPModifier Modifier) {
return MCSymbolRefExpr::VK_TPOFF;
case ARMCP::GOTTPOFF:
return MCSymbolRefExpr::VK_GOTTPOFF;
case ARMCP::SBREL:
return MCSymbolRefExpr::VK_ARM_SBREL;
case ARMCP::GOT_PREL:
return MCSymbolRefExpr::VK_ARM_GOT_PREL;
case ARMCP::SECREL:
@ -1037,7 +1052,7 @@ void ARMAsmPrinter::EmitJumpTableAddrs(const MachineInstr *MI) {
// .word (LBB1 - LJTI_0_0)
const MCExpr *Expr = MCSymbolRefExpr::create(MBB->getSymbol(), OutContext);
if (isPositionIndependent())
if (isPositionIndependent() || Subtarget->isROPI())
Expr = MCBinaryExpr::createSub(Expr, MCSymbolRefExpr::create(JTISymbol,
OutContext),
OutContext);

View File

@ -4119,6 +4119,9 @@ bool ARMBaseInstrInfo::verifyInstruction(const MachineInstr &MI,
void ARMBaseInstrInfo::expandLoadStackGuardBase(MachineBasicBlock::iterator MI,
unsigned LoadImmOpc,
unsigned LoadOpc) const {
assert(!Subtarget.isROPI() && !Subtarget.isRWPI() &&
"ROPI/RWPI not currently supported with stack guard");
MachineBasicBlock &MBB = *MI->getParent();
DebugLoc DL = MI->getDebugLoc();
unsigned Reg = MI->getOperand(0).getReg();

View File

@ -60,6 +60,8 @@ const char *ARMConstantPoolValue::getModifierText() const {
return "gottpoff";
case ARMCP::TPOFF:
return "tpoff";
case ARMCP::SBREL:
return "SBREL";
case ARMCP::SECREL:
return "secrel32";
}

View File

@ -43,6 +43,7 @@ namespace ARMCP {
GOTTPOFF, /// Global Offset Table, Thread Pointer Offset
TPOFF, /// Thread Pointer Offset
SECREL, /// Section Relative (Windows TLS)
SBREL, /// Static Base Relative (RWPI)
};
}

View File

@ -546,6 +546,10 @@ unsigned ARMFastISel::ARMMaterializeGV(const GlobalValue *GV, MVT VT) {
// For now 32-bit only.
if (VT != MVT::i32 || GV->isThreadLocal()) return 0;
// ROPI/RWPI not currently supported.
if (Subtarget->isROPI() || Subtarget->isRWPI())
return 0;
bool IsIndirect = Subtarget->isGVIndirectSymbol(GV);
const TargetRegisterClass *RC = isThumb2 ? &ARM::rGPRRegClass
: &ARM::GPRRegClass;

View File

@ -2530,7 +2530,7 @@ SDValue ARMTargetLowering::LowerBlockAddress(SDValue Op,
EVT PtrVT = getPointerTy(DAG.getDataLayout());
const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
SDValue CPAddr;
bool IsPositionIndependent = isPositionIndependent();
bool IsPositionIndependent = isPositionIndependent() || Subtarget->isROPI();
if (!IsPositionIndependent) {
CPAddr = DAG.getTargetConstantPool(BA, PtrVT, 4);
} else {
@ -2800,6 +2800,11 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
SDLoc dl(Op);
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
const TargetMachine &TM = getTargetMachine();
if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(GV))
GV = GA->getBaseObject();
bool IsRO =
(isa<GlobalVariable>(GV) && cast<GlobalVariable>(GV)->isConstant()) ||
isa<Function>(GV);
if (isPositionIndependent()) {
bool UseGOT_PREL = !TM.shouldAssumeDSOLocal(*GV->getParent(), GV);
@ -2826,6 +2831,23 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
DAG.getLoad(PtrVT, dl, Chain, Result,
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
return Result;
} else if (Subtarget->isROPI() && IsRO) {
// PC-relative.
SDValue G = DAG.getTargetGlobalAddress(GV, dl, PtrVT);
SDValue Result = DAG.getNode(ARMISD::WrapperPIC, dl, PtrVT, G);
return Result;
} else if (Subtarget->isRWPI() && !IsRO) {
// SB-relative.
ARMConstantPoolValue *CPV =
ARMConstantPoolConstant::Create(GV, ARMCP::SBREL);
SDValue CPAddr = DAG.getTargetConstantPool(CPV, PtrVT, 4);
CPAddr = DAG.getNode(ARMISD::Wrapper, dl, MVT::i32, CPAddr);
SDValue G = DAG.getLoad(
PtrVT, dl, DAG.getEntryNode(), CPAddr,
MachinePointerInfo::getConstantPool(DAG.getMachineFunction()));
SDValue SB = DAG.getCopyFromReg(DAG.getEntryNode(), dl, ARM::R9, PtrVT);
SDValue Result = DAG.getNode(ISD::ADD, dl, PtrVT, SB, G);
return Result;
}
// If we have T2 ops, we can materialize the address directly via movt/movw
@ -2847,6 +2869,8 @@ SDValue ARMTargetLowering::LowerGlobalAddressELF(SDValue Op,
SDValue ARMTargetLowering::LowerGlobalAddressDarwin(SDValue Op,
SelectionDAG &DAG) const {
assert(!Subtarget->isROPI() && !Subtarget->isRWPI() &&
"ROPI/RWPI not currently supported for Darwin");
EVT PtrVT = getPointerTy(DAG.getDataLayout());
SDLoc dl(Op);
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
@ -2873,6 +2897,8 @@ SDValue ARMTargetLowering::LowerGlobalAddressWindows(SDValue Op,
assert(Subtarget->isTargetWindows() && "non-Windows COFF is not supported");
assert(Subtarget->useMovt(DAG.getMachineFunction()) &&
"Windows on ARM expects to use movw/movt");
assert(!Subtarget->isROPI() && !Subtarget->isRWPI() &&
"ROPI/RWPI not currently supported for Windows");
const GlobalValue *GV = cast<GlobalAddressSDNode>(Op)->getGlobal();
const ARMII::TOF TargetFlags =
@ -4123,7 +4149,7 @@ SDValue ARMTargetLowering::LowerBR_JT(SDValue Op, SelectionDAG &DAG) const {
return DAG.getNode(ARMISD::BR2_JT, dl, MVT::Other, Chain,
Addr, Op.getOperand(2), JTI);
}
if (isPositionIndependent()) {
if (isPositionIndependent() || Subtarget->isROPI()) {
Addr =
DAG.getLoad((EVT)MVT::i32, dl, Chain, Addr,
MachinePointerInfo::getJumpTable(DAG.getMachineFunction()));
@ -7271,6 +7297,8 @@ void ARMTargetLowering::SetupEntryBlockForSjLj(MachineInstr &MI,
MachineBasicBlock *MBB,
MachineBasicBlock *DispatchBB,
int FI) const {
assert(!Subtarget->isROPI() && !Subtarget->isRWPI() &&
"ROPI/RWPI not currently supported with SjLj");
const TargetInstrInfo *TII = Subtarget->getInstrInfo();
DebugLoc dl = MI.getDebugLoc();
MachineFunction *MF = MBB->getParent();

View File

@ -199,6 +199,9 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
(Options.UnsafeFPMath || isTargetDarwin()))
UseNEONForSinglePrecisionFP = true;
if (isRWPI())
ReserveR9 = true;
// FIXME: Teach TableGen to deal with these instead of doing it manually here.
switch (ARMProcFamily) {
case Others:
@ -261,6 +264,15 @@ bool ARMSubtarget::isAAPCS16_ABI() const {
return TM.TargetABI == ARMBaseTargetMachine::ARM_ABI_AAPCS16;
}
bool ARMSubtarget::isROPI() const {
return TM.getRelocationModel() == Reloc::ROPI ||
TM.getRelocationModel() == Reloc::ROPI_RWPI;
}
bool ARMSubtarget::isRWPI() const {
return TM.getRelocationModel() == Reloc::RWPI ||
TM.getRelocationModel() == Reloc::ROPI_RWPI;
}
bool ARMSubtarget::isGVIndirectSymbol(const GlobalValue *GV) const {
if (!TM.shouldAssumeDSOLocal(*GV->getParent(), GV))
return true;

View File

@ -544,6 +544,9 @@ public:
bool isAAPCS_ABI() const;
bool isAAPCS16_ABI() const;
bool isROPI() const;
bool isRWPI() const;
bool useSoftFloat() const { return UseSoftFloat; }
bool isThumb() const { return InThumbMode; }
bool isThumb1Only() const { return InThumbMode && !HasThumb2; }

View File

@ -184,6 +184,10 @@ static Reloc::Model getEffectiveRelocModel(const Triple &TT,
// Default relocation model on Darwin is PIC.
return TT.isOSBinFormatMachO() ? Reloc::PIC_ : Reloc::Static;
if (*RM == Reloc::ROPI || *RM == Reloc::RWPI || *RM == Reloc::ROPI_RWPI)
assert(TT.isOSBinFormatELF() &&
"ROPI/RWPI currently only supported for ELF");
// DynamicNoPIC is only used on darwin.
if (*RM == Reloc::DynamicNoPIC && !TT.isOSDarwin())
return Reloc::Static;

View File

@ -242,10 +242,26 @@ unsigned ARMELFObjectWriter::GetRelocTypeInner(const MCValue &Target,
Type = ELF::R_ARM_JUMP24;
break;
case ARM::fixup_arm_movt_hi16:
Type = ELF::R_ARM_MOVT_ABS;
switch (Modifier) {
default: llvm_unreachable("Unsupported Modifier");
case MCSymbolRefExpr::VK_None:
Type = ELF::R_ARM_MOVT_ABS;
break;
case MCSymbolRefExpr::VK_ARM_SBREL:
Type = ELF:: R_ARM_MOVT_BREL;
break;
}
break;
case ARM::fixup_arm_movw_lo16:
Type = ELF::R_ARM_MOVW_ABS_NC;
switch (Modifier) {
default: llvm_unreachable("Unsupported Modifier");
case MCSymbolRefExpr::VK_None:
Type = ELF::R_ARM_MOVW_ABS_NC;
break;
case MCSymbolRefExpr::VK_ARM_SBREL:
Type = ELF:: R_ARM_MOVW_BREL_NC;
break;
}
break;
case ARM::fixup_t2_movt_hi16:
Type = ELF::R_ARM_THM_MOVT_ABS;

View File

@ -208,12 +208,13 @@ SectionKind TargetLoweringObjectFile::getKindForGlobal(const GlobalValue *GV,
}
} else {
// In static relocation model, the linker will resolve all addresses, so
// the relocation entries will actually be constants by the time the app
// starts up. However, we can't put this into a mergable section, because
// the linker doesn't take relocations into consideration when it tries to
// merge entries in the section.
if (ReloModel == Reloc::Static)
// In static, ROPI and RWPI relocation models, the linker will resolve
// all addresses, so the relocation entries will actually be constants by
// the time the app starts up. However, we can't put this into a
// mergable section, because the linker doesn't take relocations into
// consideration when it tries to merge entries in the section.
if (ReloModel == Reloc::Static || ReloModel == Reloc::ROPI ||
ReloModel == Reloc::RWPI || ReloModel == Reloc::ROPI_RWPI)
return SectionKind::getReadOnly();
// Otherwise, the dynamic linker needs to fix it up, put it in the

View File

@ -0,0 +1,114 @@
; Test for generation of jump table for ropi/rwpi
; RUN: llc -relocation-model=static -mtriple=armv7a--none-eabi -disable-block-placement < %s | FileCheck %s --check-prefix=CHECK --check-prefix=ARM --check-prefix=ARM_ABS
; RUN: llc -relocation-model=ropi -mtriple=armv7a--none-eabi -disable-block-placement < %s | FileCheck %s --check-prefix=CHECK --check-prefix=ARM --check-prefix=ARM_PC
; RUN: llc -relocation-model=ropi-rwpi -mtriple=armv7a--none-eabi -disable-block-placement < %s | FileCheck %s --check-prefix=CHECK --check-prefix=ARM --check-prefix=ARM_PC
; RUN: llc -relocation-model=static -mtriple=thumbv7m--none-eabi -disable-block-placement < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB2
; RUN: llc -relocation-model=ropi -mtriple=thumbv7m--none-eabi -disable-block-placement < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB2
; RUN: llc -relocation-model=ropi-rwpi -mtriple=thumbv7m--none-eabi -disable-block-placement < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB2
; RUN: llc -relocation-model=static -mtriple=thumbv6m--none-eabi -disable-block-placement < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB1 --check-prefix=THUMB1_ABS
; RUN: llc -relocation-model=ropi -mtriple=thumbv6m--none-eabi -disable-block-placement < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB1 --check-prefix=THUMB1_PC
; RUN: llc -relocation-model=ropi-rwpi -mtriple=thumbv6m--none-eabi -disable-block-placement < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB1 --check-prefix=THUMB1_PC
declare void @exit0()
declare void @exit1()
declare void @exit2()
declare void @exit3()
declare void @exit4()
define void @jump_table(i32 %val) {
entry:
switch i32 %val, label %default [ i32 1, label %lab1
i32 2, label %lab2
i32 3, label %lab3
i32 4, label %lab4 ]
default:
tail call void @exit0()
ret void
lab1:
tail call void @exit1()
ret void
lab2:
tail call void @exit2()
ret void
lab3:
tail call void @exit3()
ret void
lab4:
tail call void @exit4()
ret void
; CHECK-LABEL: jump_table:
; ARM: lsl r[[R_TAB_IDX:[0-9]+]], r{{[0-9]+}}, #2
; ARM: adr r[[R_TAB_BASE:[0-9]+]], [[LJTI:\.LJTI[0-9]+_[0-9]+]]
; ARM_ABS: ldr pc, [r[[R_TAB_IDX]], r[[R_TAB_BASE]]]
; ARM_PC: ldr r[[R_OFFSET:[0-9]+]], [r[[R_TAB_IDX]], r[[R_TAB_BASE]]]
; ARM_PC: add pc, r[[R_OFFSET]], r[[R_TAB_BASE]]
; ARM: [[LJTI]]
; ARM_ABS: .long [[LBB1:\.LBB[0-9]+_[0-9]+]]
; ARM_ABS: .long [[LBB2:\.LBB[0-9]+_[0-9]+]]
; ARM_ABS: .long [[LBB3:\.LBB[0-9]+_[0-9]+]]
; ARM_ABS: .long [[LBB4:\.LBB[0-9]+_[0-9]+]]
; ARM_PC: .long [[LBB1:\.LBB[0-9]+_[0-9]+]]-[[LJTI]]
; ARM_PC: .long [[LBB2:\.LBB[0-9]+_[0-9]+]]-[[LJTI]]
; ARM_PC: .long [[LBB3:\.LBB[0-9]+_[0-9]+]]-[[LJTI]]
; ARM_PC: .long [[LBB4:\.LBB[0-9]+_[0-9]+]]-[[LJTI]]
; ARM: [[LBB1]]
; ARM-NEXT: b exit1
; ARM: [[LBB2]]
; ARM-NEXT: b exit2
; ARM: [[LBB3]]
; ARM-NEXT: b exit3
; ARM: [[LBB4]]
; ARM-NEXT: b exit4
; THUMB2: [[LCPI:\.LCPI[0-9]+_[0-9]+]]:
; THUMB2: tbb [pc, r{{[0-9]+}}]
; THUMB2: .byte ([[LBB1:\.LBB[0-9]+_[0-9]+]]-([[LCPI]]+4))/2
; THUMB2: .byte ([[LBB2:\.LBB[0-9]+_[0-9]+]]-([[LCPI]]+4))/2
; THUMB2: .byte ([[LBB3:\.LBB[0-9]+_[0-9]+]]-([[LCPI]]+4))/2
; THUMB2: .byte ([[LBB4:\.LBB[0-9]+_[0-9]+]]-([[LCPI]]+4))/2
; THUMB2: [[LBB1]]
; THUMB2-NEXT: b exit1
; THUMB2: [[LBB2]]
; THUMB2-NEXT: b exit2
; THUMB2: [[LBB3]]
; THUMB2-NEXT: b exit3
; THUMB2: [[LBB4]]
; THUMB2-NEXT: b exit4
; THUMB1: lsls r[[R_TAB_INDEX:[0-9]+]], r{{[0-9]+}}, #2
; THUMB1: adr r[[R_TAB_BASE:[0-9]+]], [[LJTI:\.LJTI[0-9]+_[0-9]+]]
; THUMB1: ldr r[[R_BB_ADDR:[0-9]+]], [r[[R_TAB_INDEX]], r[[R_TAB_BASE]]]
; THUMB1_PC: adds r[[R_BB_ADDR]], r[[R_BB_ADDR]], r[[R_TAB_BASE]]
; THUMB1: mov pc, r[[R_BB_ADDR]]
; THUMB1: [[LJTI]]
; THUMB1_ABS: .long [[LBB1:\.LBB[0-9]+_[0-9]+]]+1
; THUMB1_ABS: .long [[LBB2:\.LBB[0-9]+_[0-9]+]]+1
; THUMB1_ABS: .long [[LBB3:\.LBB[0-9]+_[0-9]+]]+1
; THUMB1_ABS: .long [[LBB4:\.LBB[0-9]+_[0-9]+]]+1
; THUMB1_PC: .long [[LBB1:\.LBB[0-9]+_[0-9]+]]-[[LJTI]]
; THUMB1_PC: .long [[LBB2:\.LBB[0-9]+_[0-9]+]]-[[LJTI]]
; THUMB1_PC: .long [[LBB3:\.LBB[0-9]+_[0-9]+]]-[[LJTI]]
; THUMB1_PC: .long [[LBB4:\.LBB[0-9]+_[0-9]+]]-[[LJTI]]
; THUMB1: [[LBB1]]
; THUMB1-NEXT: bl exit1
; THUMB1-NEXT: pop
; THUMB1: [[LBB2]]
; THUMB1-NEXT: bl exit2
; THUMB1-NEXT: pop
; THUMB1: [[LBB3]]
; THUMB1-NEXT: bl exit3
; THUMB1-NEXT: pop
; THUMB1: [[LBB4]]
; THUMB1-NEXT: bl exit4
; THUMB1-NEXT: pop
}

View File

@ -0,0 +1,309 @@
; RUN: llc -relocation-model=static -mtriple=armv7a--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=ARM_RO_ABS --check-prefix=ARM_RW_ABS
; RUN: llc -relocation-model=ropi -mtriple=armv7a--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=ARM_RO_PC --check-prefix=ARM_RW_ABS
; RUN: llc -relocation-model=rwpi -mtriple=armv7a--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=ARM_RO_ABS --check-prefix=ARM_RW_SB
; RUN: llc -relocation-model=ropi-rwpi -mtriple=armv7a--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=ARM_RO_PC --check-prefix=ARM_RW_SB
; RUN: llc -relocation-model=static -mtriple=thumbv7m--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB2_RO_ABS --check-prefix=THUMB2_RW_ABS
; RUN: llc -relocation-model=ropi -mtriple=thumbv7m--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB2_RO_PC --check-prefix=THUMB2_RW_ABS
; RUN: llc -relocation-model=rwpi -mtriple=thumbv7m--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB2_RO_ABS --check-prefix=THUMB2_RW_SB
; RUN: llc -relocation-model=ropi-rwpi -mtriple=thumbv7m--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB2_RO_PC --check-prefix=THUMB2_RW_SB
; RUN: llc -relocation-model=static -mtriple=thumbv6m--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB1_RO_ABS --check-prefix=THUMB1_RW_ABS
; RUN: llc -relocation-model=ropi -mtriple=thumbv6m--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB1_RO_PC --check-prefix=THUMB1_RW_ABS
; RUN: llc -relocation-model=rwpi -mtriple=thumbv6m--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB1_RO_ABS --check-prefix=THUMB1_RW_SB
; RUN: llc -relocation-model=ropi-rwpi -mtriple=thumbv6m--none-eabi < %s | FileCheck %s --check-prefix=CHECK --check-prefix=THUMB1_RO_PC --check-prefix=THUMB1_RW_SB
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
@a = external global i32, align 4
@b = external constant i32, align 4
define i32 @read() {
entry:
%0 = load i32, i32* @a, align 4
ret i32 %0
; CHECK-LABEL: read:
; ARM_RW_ABS: movw r[[REG:[0-9]]], :lower16:a
; ARM_RW_ABS: movt r[[REG]], :upper16:a
; ARM_RW_ABS: ldr r0, [r[[REG]]]
; ARM_RW_SB: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; ARM_RW_SB: ldr r0, [r9, r[[REG]]]
; THUMB2_RW_ABS: movw r[[REG:[0-9]]], :lower16:a
; THUMB2_RW_ABS: movt r[[REG]], :upper16:a
; THUMB2_RW_ABS: ldr r0, [r[[REG]]]
; THUMB2_RW_SB: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB2_RW_SB: ldr.w r0, [r9, r[[REG]]]
; THUMB1_RW_ABS: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RW_ABS: ldr r0, [r[[REG]]]
; THUMB1_RW_SB: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RW_SB: mov r[[REG_SB:[0-9]+]], r9
; THUMB1_RW_SB: ldr r0, [r[[REG_SB]], r[[REG]]]
; CHECK: {{(bx lr|pop)}}
; ARM_RW_SB: [[LCPI]]
; ARM_RW_SB: .long a(sbrel)
; THUMB2_RW_SB: [[LCPI]]
; THUMB2_RW_SB: .long a(sbrel)
; THUMB1_RW_ABS: [[LCPI]]
; THUMB1_RW_ABS-NEXT: .long a
; THUMB1_RW_SB: [[LCPI]]
; THUMB1_RW_SB: .long a(sbrel)
}
define void @write(i32 %v) {
entry:
store i32 %v, i32* @a, align 4
ret void
; CHECK-LABEL: write:
; ARM_RW_ABS: movw r[[REG:[0-9]]], :lower16:a
; ARM_RW_ABS: movt r[[REG]], :upper16:a
; ARM_RW_ABS: str r0, [r[[REG:[0-9]]]]
; ARM_RW_SB: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; ARM_RW_SB: str r0, [r9, r[[REG]]]
; THUMB2_RW_ABS: movw r[[REG:[0-9]]], :lower16:a
; THUMB2_RW_ABS: movt r[[REG]], :upper16:a
; THUMB2_RW_ABS: str r0, [r[[REG]]]
; THUMB2_RW_SB: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB2_RW_SB: str.w r0, [r9, r[[REG]]]
; THUMB1_RW_ABS: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RW_ABS: str r0, [r[[REG]]]
; THUMB1_RW_SB: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RW_SB: mov r[[REG_SB:[0-9]+]], r9
; THUMB1_RW_SB: str r0, [r[[REG_SB]], r[[REG]]]
; CHECK: {{(bx lr|pop)}}
; ARM_RW_SB: [[LCPI]]
; ARM_RW_SB: .long a(sbrel)
; THUMB2_RW_SB: [[LCPI]]
; THUMB2_RW_SB: .long a(sbrel)
; THUMB1_RW_ABS: [[LCPI]]
; THUMB1_RW_ABS-NEXT: .long a
; THUMB1_RW_SB: [[LCPI]]
; THUMB1_RW_SB: .long a(sbrel)
}
define i32 @read_const() {
entry:
%0 = load i32, i32* @b, align 4
ret i32 %0
; CHECK-LABEL: read_const:
; ARM_RO_ABS: movw r[[reg:[0-9]]], :lower16:b
; ARM_RO_ABS: movt r[[reg]], :upper16:b
; ARM_RO_ABS: ldr r0, [r[[reg]]]
; ARM_RO_PC: movw r[[REG:[0-9]]], :lower16:(b-([[LPC:.LPC[0-9]+_[0-9]+]]+8))
; ARM_RO_PC: movt r[[REG]], :upper16:(b-([[LPC]]+8))
; ARM_RO_PC: [[LPC]]:
; ARM_RO_PC-NEXT: ldr r0, [pc, r[[REG]]]
; THUMB2_RO_ABS: movw r[[REG:[0-9]]], :lower16:b
; THUMB2_RO_ABS: movt r[[REG]], :upper16:b
; THUMB2_RO_ABS: ldr r0, [r[[REG]]]
; THUMB2_RO_PC: movw r[[REG:[0-9]]], :lower16:(b-([[LPC:.LPC[0-9]+_[0-9]+]]+4))
; THUMB2_RO_PC: movt r[[REG]], :upper16:(b-([[LPC]]+4))
; THUMB2_RO_PC: [[LPC]]:
; THUMB2_RO_PC-NEXT: add r[[REG]], pc
; THUMB2_RO_PC: ldr r0, [r[[REG]]]
; THUMB1_RO_ABS: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RO_ABS: ldr r0, [r[[REG]]]
; THUMB1_RO_PC: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RO_PC: [[LPC:.LPC[0-9]+_[0-9]+]]:
; THUMB1_RO_PC-NEXT: add r[[REG]], pc
; THUMB1_RO_PC: ldr r0, [r[[REG]]]
; CHECK: {{(bx lr|pop)}}
; THUMB1_RO_ABS: [[LCPI]]
; THUMB1_RO_ABS-NEXT: .long b
; THUMB1_RO_PC: [[LCPI]]
; THUMB1_RO_PC-NEXT: .long b-([[LPC]]+4)
}
define i32* @take_addr() {
entry:
ret i32* @a
; CHECK-LABEL: take_addr:
; ARM_RW_ABS: movw r[[REG:[0-9]]], :lower16:a
; ARM_RW_ABS: movt r[[REG]], :upper16:a
; ARM_RW_SB: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; ARM_RW_SB: add r0, r9, r[[REG]]
; THUMB2_RW_ABS: movw r[[REG:[0-9]]], :lower16:a
; THUMB2_RW_ABS: movt r[[REG]], :upper16:a
; THUMB2_RW_SB: ldr r0, [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB2_RW_SB: add r0, r9
; THUMB1_RW_ABS: ldr r0, [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RW_SB: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RW_SB: mov r[[REG_SB:[0-9]+]], r9
; THUMB1_RW_SB: adds r[[REG]], r[[REG_SB]], r[[REG]]
; CHECK: {{(bx lr|pop)}}
; ARM_RW_SB: [[LCPI]]
; ARM_RW_SB: .long a(sbrel)
; THUMB2_RW_SB: [[LCPI]]
; THUMB2_RW_SB: .long a(sbrel)
; THUMB1_RW_ABS: [[LCPI]]
; THUMB1_RW_ABS-NEXT: .long a
; THUMB1_RW_SB: [[LCPI]]
; THUMB1_RW_SB: .long a(sbrel)
}
define i32* @take_addr_const() {
entry:
ret i32* @b
; CHECK-LABEL: take_addr_const:
; ARM_RO_ABS: movw r[[REG:[0-9]]], :lower16:b
; ARM_RO_ABS: movt r[[REG]], :upper16:b
; ARM_RO_PC: movw r[[REG:[0-9]]], :lower16:(b-([[LPC:.LPC[0-9]+_[0-9]+]]+8))
; ARM_RO_PC: movt r[[REG]], :upper16:(b-([[LPC]]+8))
; ARM_RO_PC: [[LPC]]:
; ARM_RO_PC-NEXT: add r0, pc, r[[REG:[0-9]]]
; THUMB2_RO_ABS: movw r[[REG:[0-9]]], :lower16:b
; THUMB2_RO_ABS: movt r[[REG]], :upper16:b
; THUMB2_RO_PC: movw r0, :lower16:(b-([[LPC:.LPC[0-9]+_[0-9]+]]+4))
; THUMB2_RO_PC: movt r0, :upper16:(b-([[LPC]]+4))
; THUMB2_RO_PC: [[LPC]]:
; THUMB2_RO_PC-NEXT: add r0, pc
; THUMB1_RO_ABS: ldr r0, [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RO_PC: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RO_PC: [[LPC:.LPC[0-9]+_[0-9]+]]:
; THUMB1_RO_PC-NEXT: add r[[REG]], pc
; CHECK: {{(bx lr|pop)}}
; THUMB1_RO_ABS: [[LCPI]]
; THUMB1_RO_ABS-NEXT: .long b
; THUMB1_RO_PC: [[LCPI]]
; THUMB1_RO_PC-NEXT: .long b-([[LPC]]+4)
}
define i8* @take_addr_func() {
entry:
ret i8* bitcast (i8* ()* @take_addr_func to i8*)
; CHECK-LABEL: take_addr_func:
; ARM_RO_ABS: movw r[[REG:[0-9]]], :lower16:take_addr_func
; ARM_RO_ABS: movt r[[REG]], :upper16:take_addr_func
; ARM_RO_PC: movw r[[REG:[0-9]]], :lower16:(take_addr_func-([[LPC:.LPC[0-9]+_[0-9]+]]+8))
; ARM_RO_PC: movt r[[REG]], :upper16:(take_addr_func-([[LPC]]+8))
; ARM_RO_PC: [[LPC]]:
; ARM_RO_PC-NEXT: add r0, pc, r[[REG:[0-9]]]
; THUMB2_RO_ABS: movw r[[REG:[0-9]]], :lower16:take_addr_func
; THUMB2_RO_ABS: movt r[[REG]], :upper16:take_addr_func
; THUMB2_RO_PC: movw r0, :lower16:(take_addr_func-([[LPC:.LPC[0-9]+_[0-9]+]]+4))
; THUMB2_RO_PC: movt r0, :upper16:(take_addr_func-([[LPC]]+4))
; THUMB2_RO_PC: [[LPC]]:
; THUMB2_RO_PC-NEXT: add r0, pc
; THUMB1_RO_ABS: ldr r0, [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RO_PC: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RO_PC: [[LPC:.LPC[0-9]+_[0-9]+]]:
; THUMB1_RO_PC-NEXT: add r[[REG]], pc
; CHECK: {{(bx lr|pop)}}
; THUMB1_RO_ABS: [[LCPI]]
; THUMB1_RO_ABS-NEXT: .long take_addr_func
; THUMB1_RO_PC: [[LCPI]]
; THUMB1_RO_PC-NEXT: .long take_addr_func-([[LPC]]+4)
}
define i8* @block_addr() {
entry:
br label %lab1
lab1:
ret i8* blockaddress(@block_addr, %lab1)
; CHECK-LABEL: block_addr:
; ARM_RO_ABS: [[LTMP:.Ltmp[0-9]+]]:
; ARM_RO_ABS: ldr r0, [[LCPI:.LCPI[0-9]+_[0-9]+]]
; ARM_RO_PC: [[LTMP:.Ltmp[0-9]+]]:
; ARM_RO_PC: ldr r[[REG:[0-9]]], [[LCPI:.LCPI[0-9]+_[0-9]+]]
; ARM_RO_PC: [[LPC:.LPC[0-9]+_[0-9]+]]:
; ARM_RO_PC: add r0, pc, r[[REG]]
; THUMB2_RO_ABS: [[LTMP:.Ltmp[0-9]+]]:
; THUMB2_RO_ABS: ldr r0, [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB2_RO_PC: [[LTMP:.Ltmp[0-9]+]]:
; THUMB2_RO_PC: ldr r0, [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB2_RO_PC: [[LPC:.LPC[0-9]+_[0-9]+]]:
; THUMB2_RO_PC: add r0, pc
; THUMB1_RO_ABS: [[LTMP:.Ltmp[0-9]+]]:
; THUMB1_RO_ABS: ldr r0, [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RO_PC: [[LTMP:.Ltmp[0-9]+]]:
; THUMB1_RO_PC: ldr r0, [[LCPI:.LCPI[0-9]+_[0-9]+]]
; THUMB1_RO_PC: [[LPC:.LPC[0-9]+_[0-9]+]]:
; THUMB1_RO_PC: add r0, pc
; CHECK: bx lr
; ARM_RO_ABS: [[LCPI]]
; ARM_RO_ABS-NEXT: .long [[LTMP]]
; ARM_RO_PC: [[LCPI]]
; ARM_RO_PC-NEXT: .long [[LTMP]]-([[LPC]]+8)
; THUMB2_RO_ABS: [[LCPI]]
; THUMB2_RO_ABS-NEXT: .long [[LTMP]]
; THUMB2_RO_PC: [[LCPI]]
; THUMB2_RO_PC-NEXT: .long [[LTMP]]-([[LPC]]+4)
; THUMB1_RO_ABS: [[LCPI]]
; THUMB1_RO_ABS-NEXT: .long [[LTMP]]
; THUMB1_RO_PC: [[LCPI]]
; THUMB1_RO_PC-NEXT: .long [[LTMP]]-([[LPC]]+4)
}

View File

@ -147,6 +147,9 @@
; RUN: llc < %s -mtriple=arm-none-linux-gnueabi -mattr=+strict-align | FileCheck %s --check-prefix=RELOC-OTHER
; RUN: llc < %s -mtriple=arm-none-linux-gnueabi -mattr=+strict-align | FileCheck %s --check-prefix=PCS-R9-USE
; RUN: llc < %s -mtriple=arm-none-linux-gnueabi -mattr=+reserve-r9,+strict-align | FileCheck %s --check-prefix=PCS-R9-RESERVE
; RUN: llc < %s -mtriple=arm-none-linux-gnueabi -mattr=+strict-align -relocation-model=ropi | FileCheck %s --check-prefix=RELOC-ROPI
; RUN: llc < %s -mtriple=arm-none-linux-gnueabi -mattr=+strict-align -relocation-model=rwpi | FileCheck %s --check-prefix=RELOC-RWPI
; RUN: llc < %s -mtriple=arm-none-linux-gnueabi -mattr=+strict-align -relocation-model=ropi-rwpi | FileCheck %s --check-prefix=RELOC-ROPI-RWPI
; ARMv8.1a (AArch32)
; RUN: llc < %s -mtriple=armv8.1a-none-linux-gnueabi | FileCheck %s --check-prefix=NO-STRICT-ALIGN
@ -1522,6 +1525,15 @@
; RELOC-PIC: .eabi_attribute 16, 1
; RELOC-PIC: .eabi_attribute 17, 2
; RELOC-OTHER: .eabi_attribute 17, 1
; RELOC-ROPI-NOT: .eabi_attribute 15,
; RELOC-ROPI: .eabi_attribute 16, 1
; RELOC-ROPI: .eabi_attribute 17, 1
; RELOC-RWPI: .eabi_attribute 15, 2
; RELOC-RWPI-NOT: .eabi_attribute 16,
; RELOC-RWPI: .eabi_attribute 17, 1
; RELOC-ROPI-RWPI: .eabi_attribute 15, 2
; RELOC-ROPI-RWPI: .eabi_attribute 16, 1
; RELOC-ROPI-RWPI: .eabi_attribute 17, 1
; PCS-R9-USE: .eabi_attribute 14, 0
; PCS-R9-RESERVE: .eabi_attribute 14, 3