"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() {
// Relocation model types.
namespace Reloc {
- enum Model { Static, PIC_, DynamicNoPIC };
+ enum Model { Static, PIC_, DynamicNoPIC, ROPI, RWPI, ROPI_RWPI };
}
// Code model types.
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);
}
}
}
- // 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,
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:
// .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);
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();
return "gottpoff";
case ARMCP::TPOFF:
return "tpoff";
+ case ARMCP::SBREL:
+ return "SBREL";
case ARMCP::SECREL:
return "secrel32";
}
GOTTPOFF, /// Global Offset Table, Thread Pointer Offset
TPOFF, /// Thread Pointer Offset
SECREL, /// Section Relative (Windows TLS)
+ SBREL, /// Static Base Relative (RWPI)
};
}
// 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;
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 {
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);
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
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();
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 =
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()));
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();
(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:
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;
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; }
// 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;
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;
}
} 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
--- /dev/null
+; 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
+}
--- /dev/null
+; 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)
+}
; 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
; 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