Skip to content

Commit

Permalink
[PowerPC] 32-bit ELF PIC support
Browse files Browse the repository at this point in the history
This adds initial support for PPC32 ELF PIC (Position Independent Code; the
-fPIC variety), thus rectifying a long-standing deficiency in the PowerPC
backend.

Patch by Justin Hibbits!

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@213427 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Hal Finkel committed Jul 18, 2014
1 parent 286fbd1 commit d644d17
Show file tree
Hide file tree
Showing 20 changed files with 396 additions and 41 deletions.
1 change: 1 addition & 0 deletions include/llvm/Support/ELF.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ enum {
R_PPC_GOT16_LO = 15,
R_PPC_GOT16_HI = 16,
R_PPC_GOT16_HA = 17,
R_PPC_PLTREL24 = 18,
R_PPC_REL32 = 26,
R_PPC_TLS = 67,
R_PPC_DTPMOD32 = 68,
Expand Down
1 change: 1 addition & 0 deletions lib/Object/ELF.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type) {
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_GOT16_LO);
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_GOT16_HI);
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_GOT16_HA);
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_PLTREL24);
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_REL32);
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_TLS);
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_PPC_DTPMOD32);
Expand Down
10 changes: 9 additions & 1 deletion lib/Target/PowerPC/MCTargetDesc/PPCELFObjectWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,15 @@ unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target,
llvm_unreachable("Unimplemented");
case PPC::fixup_ppc_br24:
case PPC::fixup_ppc_br24abs:
Type = ELF::R_PPC_REL24;
switch (Modifier) {
default: llvm_unreachable("Unsupported Modifier");
case MCSymbolRefExpr::VK_None:
Type = ELF::R_PPC_REL24;
break;
case MCSymbolRefExpr::VK_PLT:
Type = ELF::R_PPC_PLTREL24;
break;
}
break;
case PPC::fixup_ppc_brcond14:
case PPC::fixup_ppc_brcond14abs:
Expand Down
9 changes: 5 additions & 4 deletions lib/Target/PowerPC/PPC.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ namespace llvm {
// PPC Specific MachineOperand flags.
MO_NO_FLAG,

/// MO_DARWIN_STUB - On a symbol operand "FOO", this indicates that the
/// reference is actually to the "FOO$stub" symbol. This is used for calls
/// and jumps to external functions on Tiger and earlier.
MO_DARWIN_STUB = 1,
/// MO_PLT_OR_STUB - On a symbol operand "FOO", this indicates that the
/// reference is actually to the "FOO$stub" or "FOO@plt" symbol. This is
/// used for calls and jumps to external functions on Tiger and earlier, and
/// for PIC calls on Linux and ELF systems.
MO_PLT_OR_STUB = 1,

/// MO_PIC_FLAG - If this bit is set, the symbol reference is relative to
/// the function's picbase, e.g. lo16(symbol-picbase).
Expand Down
132 changes: 128 additions & 4 deletions lib/Target/PowerPC/PPCAsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "PPC.h"
#include "InstPrinter/PPCInstPrinter.h"
#include "PPCMachineFunctionInfo.h"
#include "MCTargetDesc/PPCMCExpr.h"
#include "MCTargetDesc/PPCPredicates.h"
#include "PPCSubtarget.h"
Expand All @@ -27,6 +28,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
Expand Down Expand Up @@ -100,6 +102,7 @@ namespace {
}

bool doFinalization(Module &M) override;
void EmitStartOfAsmFile(Module &M) override;

void EmitFunctionEntryLabel() override;

Expand Down Expand Up @@ -330,6 +333,66 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
OutStreamer.EmitLabel(PICBase);
return;
}
case PPC::GetGBRO: {
// Get the offset from the GOT Base Register to the GOT
LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin());
MCSymbol *PICOffset = MF->getInfo<PPCFunctionInfo>()->getPICOffsetSymbol();
TmpInst.setOpcode(PPC::LWZ);
const MCExpr *Exp =
MCSymbolRefExpr::Create(PICOffset, MCSymbolRefExpr::VK_None, OutContext);
const MCExpr *PB =
MCSymbolRefExpr::Create(MF->getPICBaseSymbol(),
MCSymbolRefExpr::VK_None,
OutContext);
const MCOperand MO = TmpInst.getOperand(1);
TmpInst.getOperand(1) = MCOperand::CreateExpr(MCBinaryExpr::CreateSub(Exp,
PB,
OutContext));
TmpInst.addOperand(MO);
EmitToStreamer(OutStreamer, TmpInst);
return;
}
case PPC::UpdateGBR: {
// Update the GOT Base Register to point to the GOT. It may be possible to
// merge this with the PPC::GetGBRO, doing it all in one step.
LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin());
TmpInst.setOpcode(PPC::ADD4);
TmpInst.addOperand(TmpInst.getOperand(0));
EmitToStreamer(OutStreamer, TmpInst);
return;
}
case PPC::LWZtoc: {
// Transform %X3 = LWZtoc <ga:@min1>, %X2
LowerPPCMachineInstrToMCInst(MI, TmpInst, *this, Subtarget.isDarwin());

// Change the opcode to LWZ, and the global address operand to be a
// reference to the GOT entry we will synthesize later.
TmpInst.setOpcode(PPC::LWZ);
const MachineOperand &MO = MI->getOperand(1);

// Map symbol -> label of TOC entry
assert(MO.isGlobal() || MO.isCPI() || MO.isJTI());
MCSymbol *MOSymbol = nullptr;
if (MO.isGlobal())
MOSymbol = getSymbol(MO.getGlobal());
else if (MO.isCPI())
MOSymbol = GetCPISymbol(MO.getIndex());
else if (MO.isJTI())
MOSymbol = GetJTISymbol(MO.getIndex());

MCSymbol *TOCEntry = lookUpOrCreateTOCEntry(MOSymbol);

const MCExpr *Exp =
MCSymbolRefExpr::Create(TOCEntry, MCSymbolRefExpr::VK_None,
OutContext);
const MCExpr *PB =
MCSymbolRefExpr::Create(OutContext.GetOrCreateSymbol(Twine(".L.TOC.")),
OutContext);
Exp = MCBinaryExpr::CreateSub(Exp, PB, OutContext);
TmpInst.getOperand(1) = MCOperand::CreateExpr(Exp);
EmitToStreamer(OutStreamer, TmpInst);
return;
}
case PPC::LDtocJTI:
case PPC::LDtocCPT:
case PPC::LDtoc: {
Expand Down Expand Up @@ -717,9 +780,60 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
EmitToStreamer(OutStreamer, TmpInst);
}

void PPCLinuxAsmPrinter::EmitStartOfAsmFile(Module &M) {
if (Subtarget.isPPC64() || TM.getRelocationModel() != Reloc::PIC_)
return AsmPrinter::EmitStartOfAsmFile(M);

// FIXME: The use of .got2 assumes large GOT model (-fPIC), which is not
// optimal for some cases. We should consider supporting small model (-fpic)
// as well in the future.
assert(TM.getCodeModel() != CodeModel::Small &&
"Small code model PIC is currently unsupported.");
OutStreamer.SwitchSection(OutContext.getELFSection(".got2",
ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC,
SectionKind::getReadOnly()));

MCSymbol *TOCSym = OutContext.GetOrCreateSymbol(Twine(".L.TOC."));
MCSymbol *CurrentPos = OutContext.CreateTempSymbol();

OutStreamer.EmitLabel(CurrentPos);

// The GOT pointer points to the middle of the GOT, in order to reference the
// entire 64kB range. 0x8000 is the midpoint.
const MCExpr *tocExpr =
MCBinaryExpr::CreateAdd(MCSymbolRefExpr::Create(CurrentPos, OutContext),
MCConstantExpr::Create(0x8000, OutContext),
OutContext);

OutStreamer.EmitAssignment(TOCSym, tocExpr);

OutStreamer.SwitchSection(getObjFileLowering().getTextSection());
}

void PPCLinuxAsmPrinter::EmitFunctionEntryLabel() {
if (!Subtarget.isPPC64()) // linux/ppc32 - Normal entry label.
// linux/ppc32 - Normal entry label.
if (!Subtarget.isPPC64() && TM.getRelocationModel() != Reloc::PIC_)
return AsmPrinter::EmitFunctionEntryLabel();

if (!Subtarget.isPPC64()) {
const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>();
if (PPCFI->usesPICBase()) {
MCSymbol *RelocSymbol = PPCFI->getPICOffsetSymbol();
MCSymbol *PICBase = MF->getPICBaseSymbol();
OutStreamer.EmitLabel(RelocSymbol);

const MCExpr *OffsExpr =
MCBinaryExpr::CreateSub(
MCSymbolRefExpr::Create(OutContext.GetOrCreateSymbol(Twine(".L.TOC.")),
OutContext),
MCSymbolRefExpr::Create(PICBase, OutContext),
OutContext);
OutStreamer.EmitValue(OffsExpr, 4);
OutStreamer.EmitLabel(CurrentFnSym);
return;
} else
return AsmPrinter::EmitFunctionEntryLabel();
}

// Emit an official procedure descriptor.
MCSectionSubPair Current = OutStreamer.getCurrentSection();
Expand Down Expand Up @@ -759,8 +873,15 @@ bool PPCLinuxAsmPrinter::doFinalization(Module &M) {
PPCTargetStreamer &TS =
static_cast<PPCTargetStreamer &>(*OutStreamer.getTargetStreamer());

if (isPPC64 && !TOC.empty()) {
const MCSectionELF *Section = OutStreamer.getContext().getELFSection(".toc",
if (!TOC.empty()) {
const MCSectionELF *Section;

if (isPPC64)
Section = OutStreamer.getContext().getELFSection(".toc",
ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC,
SectionKind::getReadOnly());
else
Section = OutStreamer.getContext().getELFSection(".got2",
ELF::SHT_PROGBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC,
SectionKind::getReadOnly());
OutStreamer.SwitchSection(Section);
Expand All @@ -769,7 +890,10 @@ bool PPCLinuxAsmPrinter::doFinalization(Module &M) {
E = TOC.end(); I != E; ++I) {
OutStreamer.EmitLabel(I->second);
MCSymbol *S = OutContext.GetOrCreateSymbol(I->first->getName());
TS.emitTCEntry(*S);
if (isPPC64)
TS.emitTCEntry(*S);
else
OutStreamer.EmitSymbolValue(S, 4);
}
}

Expand Down
19 changes: 13 additions & 6 deletions lib/Target/PowerPC/PPCFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ void PPCFrameLowering::replaceFPWithRealFP(MachineFunction &MF) const {
const PPCRegisterInfo *RegInfo =
static_cast<const PPCRegisterInfo*>(MF.getTarget().getRegisterInfo());
bool HasBP = RegInfo->hasBasePointer(MF);
unsigned BPReg = HasBP ? (unsigned) PPC::R30 : FPReg;
unsigned BPReg = HasBP ? (unsigned) RegInfo->getBaseRegister(MF) : FPReg;
unsigned BP8Reg = HasBP ? (unsigned) PPC::X30 : FPReg;

for (MachineFunction::iterator BI = MF.begin(), BE = MF.end();
Expand Down Expand Up @@ -506,6 +506,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF) const {
DebugLoc dl;
bool needsFrameMoves = MMI.hasDebugInfo() ||
MF.getFunction()->needsUnwindTableEntry();
bool isPIC = MF.getTarget().getRelocationModel() == Reloc::PIC_;

// Get processor type.
bool isPPC64 = Subtarget.isPPC64();
Expand Down Expand Up @@ -546,7 +547,7 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF) const {
bool HasBP = RegInfo->hasBasePointer(MF);

unsigned SPReg = isPPC64 ? PPC::X1 : PPC::R1;
unsigned BPReg = isPPC64 ? PPC::X30 : PPC::R30;
unsigned BPReg = RegInfo->getBaseRegister(MF);
unsigned FPReg = isPPC64 ? PPC::X31 : PPC::R31;
unsigned LRReg = isPPC64 ? PPC::LR8 : PPC::LR;
unsigned ScratchReg = isPPC64 ? PPC::X0 : PPC::R0;
Expand Down Expand Up @@ -602,7 +603,9 @@ void PPCFrameLowering::emitPrologue(MachineFunction &MF) const {
BPOffset = FFI->getObjectOffset(BPIndex);
} else {
BPOffset =
PPCFrameLowering::getBasePointerSaveOffset(isPPC64, isDarwinABI);
PPCFrameLowering::getBasePointerSaveOffset(isPPC64,
isDarwinABI,
isPIC);
}
}

Expand Down Expand Up @@ -839,6 +842,7 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
// Get the ABI.
bool isDarwinABI = Subtarget.isDarwinABI();
bool isSVR4ABI = Subtarget.isSVR4ABI();
bool isPIC = MF.getTarget().getRelocationModel() == Reloc::PIC_;

// Check if the link register (LR) has been saved.
PPCFunctionInfo *FI = MF.getInfo<PPCFunctionInfo>();
Expand All @@ -849,7 +853,7 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
bool HasBP = RegInfo->hasBasePointer(MF);

unsigned SPReg = isPPC64 ? PPC::X1 : PPC::R1;
unsigned BPReg = isPPC64 ? PPC::X30 : PPC::R30;
unsigned BPReg = RegInfo->getBaseRegister(MF);
unsigned FPReg = isPPC64 ? PPC::X31 : PPC::R31;
unsigned ScratchReg = isPPC64 ? PPC::X0 : PPC::R0;
unsigned TempReg = isPPC64 ? PPC::X12 : PPC::R12; // another scratch reg
Expand Down Expand Up @@ -890,7 +894,9 @@ void PPCFrameLowering::emitEpilogue(MachineFunction &MF,
BPOffset = FFI->getObjectOffset(BPIndex);
} else {
BPOffset =
PPCFrameLowering::getBasePointerSaveOffset(isPPC64, isDarwinABI);
PPCFrameLowering::getBasePointerSaveOffset(isPPC64,
isDarwinABI,
isPIC);
}
}

Expand Down Expand Up @@ -1067,6 +1073,7 @@ PPCFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
int FPSI = FI->getFramePointerSaveIndex();
bool isPPC64 = Subtarget.isPPC64();
bool isDarwinABI = Subtarget.isDarwinABI();
bool isPIC = MF.getTarget().getRelocationModel() == Reloc::PIC_;
MachineFrameInfo *MFI = MF.getFrameInfo();

// If the frame pointer save index hasn't been defined yet.
Expand All @@ -1081,7 +1088,7 @@ PPCFrameLowering::processFunctionBeforeCalleeSavedScan(MachineFunction &MF,

int BPSI = FI->getBasePointerSaveIndex();
if (!BPSI && RegInfo->hasBasePointer(MF)) {
int BPOffset = getBasePointerSaveOffset(isPPC64, isDarwinABI);
int BPOffset = getBasePointerSaveOffset(isPPC64, isDarwinABI, isPIC);
// Allocate the frame index for the base pointer save area.
BPSI = MFI->CreateFixedObject(isPPC64? 8 : 4, BPOffset, true);
// Save the result.
Expand Down
6 changes: 4 additions & 2 deletions lib/Target/PowerPC/PPCFrameLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,14 @@ class PPCFrameLowering: public TargetFrameLowering {

/// getBasePointerSaveOffset - Return the previous frame offset to save the
/// base pointer.
static unsigned getBasePointerSaveOffset(bool isPPC64, bool isDarwinABI) {
static unsigned getBasePointerSaveOffset(bool isPPC64,
bool isDarwinABI,
bool isPIC) {
if (isDarwinABI)
return isPPC64 ? -16U : -8U;

// SVR4 ABI: First slot in the general register save area.
return isPPC64 ? -16U : -8U;
return isPPC64 ? -16U : isPIC ? -12U : -8U;
}

/// getLinkageSize - Return the size of the PowerPC ABI linkage area.
Expand Down
23 changes: 21 additions & 2 deletions lib/Target/PowerPC/PPCISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "PPC.h"
#include "MCTargetDesc/PPCPredicates.h"
#include "PPCMachineFunctionInfo.h"
#include "PPCTargetMachine.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
Expand Down Expand Up @@ -275,9 +276,21 @@ SDNode *PPCDAGToDAGISel::getGlobalBaseReg() {
DebugLoc dl;

if (PPCLowering->getPointerTy() == MVT::i32) {
GlobalBaseReg = RegInfo->createVirtualRegister(&PPC::GPRC_NOR0RegClass);
if (PPCSubTarget->isTargetELF())
GlobalBaseReg = PPC::R30;
else
GlobalBaseReg =
RegInfo->createVirtualRegister(&PPC::GPRC_NOR0RegClass);
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MovePCtoLR));
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MFLR), GlobalBaseReg);
if (PPCSubTarget->isTargetELF()) {
unsigned TempReg = RegInfo->createVirtualRegister(&PPC::GPRCRegClass);
BuildMI(FirstMBB, MBBI, dl,
TII.get(PPC::GetGBRO), TempReg).addReg(GlobalBaseReg);
BuildMI(FirstMBB, MBBI, dl,
TII.get(PPC::UpdateGBR)).addReg(GlobalBaseReg).addReg(TempReg);
MF->getInfo<PPCFunctionInfo>()->setUsesPICBase(true);
}
} else {
GlobalBaseReg = RegInfo->createVirtualRegister(&PPC::G8RC_NOX0RegClass);
BuildMI(FirstMBB, MBBI, dl, TII.get(PPC::MovePCtoLR8));
Expand Down Expand Up @@ -1445,7 +1458,13 @@ SDNode *PPCDAGToDAGISel::Select(SDNode *N) {
return CurDAG->SelectNodeTo(N, Reg, MVT::Other, Chain);
}
case PPCISD::TOC_ENTRY: {
assert (PPCSubTarget->isPPC64() && "Only supported for 64-bit ABI");
if (PPCSubTarget->isSVR4ABI() && !PPCSubTarget->isPPC64()) {
SDValue GA = N->getOperand(0);
return CurDAG->getMachineNode(PPC::LWZtoc, dl, MVT::i32, GA,
N->getOperand(1));
}
assert (PPCSubTarget->isPPC64() &&
"Only supported for 64-bit ABI and 32-bit SVR4");

// For medium and large code model, we generate two instructions as
// described below. Otherwise we allow SelectCodeCommon to handle this,
Expand Down
Loading

0 comments on commit d644d17

Please sign in to comment.