Index: include/llvm/CodeGen/CommandFlags.h =================================================================== --- include/llvm/CodeGen/CommandFlags.h +++ include/llvm/CodeGen/CommandFlags.h @@ -54,6 +54,12 @@ "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() { Index: include/llvm/Support/CodeGen.h =================================================================== --- include/llvm/Support/CodeGen.h +++ include/llvm/Support/CodeGen.h @@ -19,7 +19,7 @@ // Relocation model types. namespace Reloc { - enum Model { Static, PIC_, DynamicNoPIC }; + enum Model { Static, PIC_, DynamicNoPIC, ROPI, RWPI, ROPI_RWPI }; } // Code model types. Index: lib/Target/ARM/ARMAsmPrinter.cpp =================================================================== --- lib/Target/ARM/ARMAsmPrinter.cpp +++ lib/Target/ARM/ARMAsmPrinter.cpp @@ -725,16 +725,27 @@ 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 @@ } } - // 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 @@ 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 @@ // .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); Index: lib/Target/ARM/ARMBaseInstrInfo.cpp =================================================================== --- lib/Target/ARM/ARMBaseInstrInfo.cpp +++ lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -4119,6 +4119,9 @@ 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(); Index: lib/Target/ARM/ARMConstantPoolValue.h =================================================================== --- lib/Target/ARM/ARMConstantPoolValue.h +++ lib/Target/ARM/ARMConstantPoolValue.h @@ -43,6 +43,7 @@ GOTTPOFF, /// Global Offset Table, Thread Pointer Offset TPOFF, /// Thread Pointer Offset SECREL, /// Section Relative (Windows TLS) + SBREL, /// Static Base Relative (RWPI) }; } Index: lib/Target/ARM/ARMConstantPoolValue.cpp =================================================================== --- lib/Target/ARM/ARMConstantPoolValue.cpp +++ lib/Target/ARM/ARMConstantPoolValue.cpp @@ -60,6 +60,8 @@ return "gottpoff"; case ARMCP::TPOFF: return "tpoff"; + case ARMCP::SBREL: + return "SBREL"; case ARMCP::SECREL: return "secrel32"; } Index: lib/Target/ARM/ARMFastISel.cpp =================================================================== --- lib/Target/ARM/ARMFastISel.cpp +++ lib/Target/ARM/ARMFastISel.cpp @@ -546,6 +546,10 @@ // 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; Index: lib/Target/ARM/ARMISelLowering.cpp =================================================================== --- lib/Target/ARM/ARMISelLowering.cpp +++ lib/Target/ARM/ARMISelLowering.cpp @@ -2530,7 +2530,7 @@ 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 @@ 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 @@ 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::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 @@ 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 @@ 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 @@ 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(); Index: lib/Target/ARM/ARMSubtarget.h =================================================================== --- lib/Target/ARM/ARMSubtarget.h +++ lib/Target/ARM/ARMSubtarget.h @@ -544,6 +544,9 @@ 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; } Index: lib/Target/ARM/ARMSubtarget.cpp =================================================================== --- lib/Target/ARM/ARMSubtarget.cpp +++ lib/Target/ARM/ARMSubtarget.cpp @@ -199,6 +199,9 @@ (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 @@ 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; Index: lib/Target/ARM/ARMTargetMachine.cpp =================================================================== --- lib/Target/ARM/ARMTargetMachine.cpp +++ lib/Target/ARM/ARMTargetMachine.cpp @@ -184,6 +184,10 @@ // 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; Index: lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp +++ lib/Target/ARM/MCTargetDesc/ARMELFObjectWriter.cpp @@ -242,10 +242,26 @@ 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; Index: lib/Target/TargetLoweringObjectFile.cpp =================================================================== --- lib/Target/TargetLoweringObjectFile.cpp +++ lib/Target/TargetLoweringObjectFile.cpp @@ -208,12 +208,13 @@ } } 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 Index: test/CodeGen/ARM/arm-position-independence-jump-table.ll =================================================================== --- /dev/null +++ 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 +} Index: test/CodeGen/ARM/arm-position-independence.ll =================================================================== --- /dev/null +++ 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) +} Index: test/CodeGen/ARM/build-attributes.ll =================================================================== --- test/CodeGen/ARM/build-attributes.ll +++ 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