From: Oliver Stannard Date: Mon, 8 Aug 2016 15:28:31 +0000 (+0000) Subject: [ARM] Add support for embedded position-independent code X-Git-Tag: llvmorg-4.0.0-rc1~13054 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8331aaee8fb9172ddf0cb45c4b04cb76fe224da4;p=platform%2Fupstream%2Fllvm.git [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 --- diff --git a/llvm/include/llvm/CodeGen/CommandFlags.h b/llvm/include/llvm/CodeGen/CommandFlags.h index 7c1dc6f..4c05e7f 100644 --- a/llvm/include/llvm/CodeGen/CommandFlags.h +++ b/llvm/include/llvm/CodeGen/CommandFlags.h @@ -54,6 +54,12 @@ cl::opt 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 getRelocModel() { diff --git a/llvm/include/llvm/Support/CodeGen.h b/llvm/include/llvm/Support/CodeGen.h index e19abf8..941c112 100644 --- a/llvm/include/llvm/Support/CodeGen.h +++ b/llvm/include/llvm/Support/CodeGen.h @@ -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. diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp index 04863a7..e2d3821 100644 --- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp @@ -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); diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp index 043a3d4..9e0a499 100644 --- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -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(); diff --git a/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp b/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp index c0db001..f13ae48 100644 --- a/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp +++ b/llvm/lib/Target/ARM/ARMConstantPoolValue.cpp @@ -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"; } diff --git a/llvm/lib/Target/ARM/ARMConstantPoolValue.h b/llvm/lib/Target/ARM/ARMConstantPoolValue.h index c07331d..fae64dc 100644 --- a/llvm/lib/Target/ARM/ARMConstantPoolValue.h +++ b/llvm/lib/Target/ARM/ARMConstantPoolValue.h @@ -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) }; } diff --git a/llvm/lib/Target/ARM/ARMFastISel.cpp b/llvm/lib/Target/ARM/ARMFastISel.cpp index 165a8be..816d7b7b 100644 --- a/llvm/lib/Target/ARM/ARMFastISel.cpp +++ b/llvm/lib/Target/ARM/ARMFastISel.cpp @@ -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; diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index 0987eb2..e505a75 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -2530,7 +2530,7 @@ SDValue ARMTargetLowering::LowerBlockAddress(SDValue Op, EVT PtrVT = getPointerTy(DAG.getDataLayout()); const BlockAddress *BA = cast(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(Op)->getGlobal(); const TargetMachine &TM = getTargetMachine(); + if (const GlobalAlias *GA = dyn_cast(GV)) + GV = GA->getBaseObject(); + bool IsRO = + (isa(GV) && cast(GV)->isConstant()) || + isa(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(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(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(); diff --git a/llvm/lib/Target/ARM/ARMSubtarget.cpp b/llvm/lib/Target/ARM/ARMSubtarget.cpp index 1d7eef9..561f80a 100644 --- a/llvm/lib/Target/ARM/ARMSubtarget.cpp +++ b/llvm/lib/Target/ARM/ARMSubtarget.cpp @@ -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; diff --git a/llvm/lib/Target/ARM/ARMSubtarget.h b/llvm/lib/Target/ARM/ARMSubtarget.h index 910de0e..97bce6f 100644 --- a/llvm/lib/Target/ARM/ARMSubtarget.h +++ b/llvm/lib/Target/ARM/ARMSubtarget.h @@ -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; } diff --git a/llvm/lib/Target/ARM/ARMTargetMachine.cpp b/llvm/lib/Target/ARM/ARMTargetMachine.cpp index dc730a6..066587a 100644 --- a/llvm/lib/Target/ARM/ARMTargetMachine.cpp +++ b/llvm/lib/Target/ARM/ARMTargetMachine.cpp @@ -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; diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp index bb562df..fa468ea 100644 --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp @@ -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; diff --git a/llvm/lib/Target/TargetLoweringObjectFile.cpp b/llvm/lib/Target/TargetLoweringObjectFile.cpp index f863f42..3be4c1d 100644 --- a/llvm/lib/Target/TargetLoweringObjectFile.cpp +++ b/llvm/lib/Target/TargetLoweringObjectFile.cpp @@ -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 diff --git a/llvm/test/CodeGen/ARM/arm-position-independence-jump-table.ll b/llvm/test/CodeGen/ARM/arm-position-independence-jump-table.ll new file mode 100644 index 0000000..507f399 --- /dev/null +++ b/llvm/test/CodeGen/ARM/arm-position-independence-jump-table.ll @@ -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 +} diff --git a/llvm/test/CodeGen/ARM/arm-position-independence.ll b/llvm/test/CodeGen/ARM/arm-position-independence.ll new file mode 100644 index 0000000..02a6398 --- /dev/null +++ b/llvm/test/CodeGen/ARM/arm-position-independence.ll @@ -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) +} diff --git a/llvm/test/CodeGen/ARM/build-attributes.ll b/llvm/test/CodeGen/ARM/build-attributes.ll index 990db8a..53b8fc3 100644 --- a/llvm/test/CodeGen/ARM/build-attributes.ll +++ b/llvm/test/CodeGen/ARM/build-attributes.ll @@ -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