Initial TOC support for PowerPC64 object creation

This patch adds initial PPC64 TOC MC object creation using the small mcmodel
(a single 64K TOC) adding the some TOC relocations (R_PPC64_TOC,
R_PPC64_TOC16, and R_PPC64_TOC16DS).

The addition of 'undefinedExplicitRelSym' hook on 'MCELFObjectTargetWriter'
is meant to avoid the creation of an unreferenced ".TOC." symbol (used in
the .odp creation) as well to set the R_PPC64_TOC relocation target as the
temporary ".TOC." symbol. On PPC64 ABI, the R_PPC64_TOC relocation should
not point to any symbol.

llvm-svn: 166677
This commit is contained in:
Adhemerval Zanella 2012-10-25 12:27:42 +00:00
parent d93b6e7cd4
commit b08709a59f
11 changed files with 223 additions and 23 deletions

View File

@ -85,6 +85,9 @@ public:
const MCFragment &F,
const MCFixup &Fixup,
bool IsPCRel) const;
virtual const MCSymbol *undefinedExplicitRelSym(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const;
virtual void adjustFixupOffset(const MCFixup &Fixup,
uint64_t &RelocOffset);

View File

@ -133,6 +133,11 @@ class ELFObjectWriter : public MCObjectWriter {
bool IsPCRel) const {
return TargetObjectWriter->ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel);
}
const MCSymbol *undefinedExplicitRelSym(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const {
return TargetObjectWriter->undefinedExplicitRelSym(Target, Fixup, IsPCRel);
}
bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
bool hasRelocationAddend() const {
@ -639,7 +644,7 @@ const MCSymbol *ELFObjectWriter::SymbolToReloc(const MCAssembler &Asm,
if (ASymbol.isUndefined()) {
if (Renamed)
return Renamed;
return &ASymbol;
return undefinedExplicitRelSym(Target, Fixup, IsPCRel);
}
if (SD.isExternal()) {
@ -721,10 +726,13 @@ void ELFObjectWriter::RecordRelocation(const MCAssembler &Asm,
MCSymbolData &SD = Asm.getSymbolData(ASymbol);
MCFragment *F = SD.getFragment();
Index = F->getParent()->getOrdinal() + 1;
// Offset of the symbol in the section
Value += Layout.getSymbolOffset(&SD);
if (F) {
Index = F->getParent()->getOrdinal() + 1;
// Offset of the symbol in the section
Value += Layout.getSymbolOffset(&SD);
} else {
Index = 0;
}
} else {
if (Asm.getSymbolData(Symbol).getFlags() & ELF_Other_Weakref)
WeakrefUsedInReloc.insert(RelocSymbol);

View File

@ -9,6 +9,8 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCValue.h"
using namespace llvm;
@ -35,6 +37,12 @@ const MCSymbol *MCELFObjectTargetWriter::ExplicitRelSym(const MCAssembler &Asm,
return NULL;
}
const MCSymbol *MCELFObjectTargetWriter::undefinedExplicitRelSym(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const {
const MCSymbol &Symbol = Target.getSymA()->getSymbol();
return &Symbol.AliasedSymbol();
}
void MCELFObjectTargetWriter::adjustFixupOffset(const MCFixup &Fixup,
uint64_t &RelocOffset) {

View File

@ -29,9 +29,14 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
case FK_Data_1:
case FK_Data_2:
case FK_Data_4:
case FK_Data_8:
case PPC::fixup_ppc_toc:
return Value;
case PPC::fixup_ppc_lo14:
case PPC::fixup_ppc_toc16_ds:
return (Value & 0xffff) << 2;
case PPC::fixup_ppc_brcond14:
return Value & 0x3ffc;
return Value & 0xfffc;
case PPC::fixup_ppc_br24:
return Value & 0x3fffffc;
#if 0
@ -41,6 +46,7 @@ static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
case PPC::fixup_ppc_ha16:
return ((Value >> 16) + ((Value & 0x8000) ? 1 : 0)) & 0xffff;
case PPC::fixup_ppc_lo16:
case PPC::fixup_ppc_toc16:
return Value & 0xffff;
}
}
@ -72,7 +78,10 @@ public:
{ "fixup_ppc_brcond14", 16, 14, MCFixupKindInfo::FKF_IsPCRel },
{ "fixup_ppc_lo16", 16, 16, 0 },
{ "fixup_ppc_ha16", 16, 16, 0 },
{ "fixup_ppc_lo14", 16, 14, 0 }
{ "fixup_ppc_lo14", 16, 14, 0 },
{ "fixup_ppc_toc", 0, 64, 0 },
{ "fixup_ppc_toc16", 16, 16, 0 },
{ "fixup_ppc_toc16_ds", 16, 14, 0 }
};
if (Kind < FirstTargetFixupKind)

View File

@ -11,6 +11,8 @@
#include "MCTargetDesc/PPCMCTargetDesc.h"
#include "llvm/MC/MCELFObjectWriter.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCValue.h"
using namespace llvm;
@ -21,9 +23,15 @@ namespace {
virtual ~PPCELFObjectWriter();
protected:
virtual unsigned getRelocTypeInner(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const;
virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
bool IsPCRel, bool IsRelocWithSymbol,
int64_t Addend) const;
virtual const MCSymbol *undefinedExplicitRelSym(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const;
virtual void adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset);
};
}
@ -36,11 +44,13 @@ PPCELFObjectWriter::PPCELFObjectWriter(bool Is64Bit, uint8_t OSABI)
PPCELFObjectWriter::~PPCELFObjectWriter() {
}
unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel,
bool IsRelocWithSymbol,
int64_t Addend) const {
unsigned PPCELFObjectWriter::getRelocTypeInner(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const
{
MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ?
MCSymbolRefExpr::VK_None : Target.getSymA()->getKind();
// determine the type of the relocation
unsigned Type;
if (IsPCRel) {
@ -61,7 +71,7 @@ unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target,
Type = ELF::R_PPC_ADDR24;
break;
case PPC::fixup_ppc_brcond14:
Type = ELF::R_PPC_ADDR14_BRTAKEN; // XXX: or BRNTAKEN?_
Type = ELF::R_PPC_ADDR14; // XXX: or BRNTAKEN?_
break;
case PPC::fixup_ppc_ha16:
Type = ELF::R_PPC_ADDR16_HA;
@ -72,6 +82,26 @@ unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target,
case PPC::fixup_ppc_lo14:
Type = ELF::R_PPC_ADDR14;
break;
case PPC::fixup_ppc_toc:
Type = ELF::R_PPC64_TOC;
break;
case PPC::fixup_ppc_toc16:
Type = ELF::R_PPC64_TOC16;
break;
case PPC::fixup_ppc_toc16_ds:
Type = ELF::R_PPC64_TOC16_DS;
break;
case FK_Data_8:
switch (Modifier) {
default: llvm_unreachable("Unsupported Modifier");
case MCSymbolRefExpr::VK_PPC_TOC:
Type = ELF::R_PPC64_TOC;
break;
case MCSymbolRefExpr::VK_None:
Type = ELF::R_PPC64_ADDR64;
break;
}
break;
case FK_Data_4:
Type = ELF::R_PPC_ADDR32;
break;
@ -83,6 +113,34 @@ unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target,
return Type;
}
unsigned PPCELFObjectWriter::GetRelocType(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel,
bool IsRelocWithSymbol,
int64_t Addend) const {
return getRelocTypeInner(Target, Fixup, IsPCRel);
}
const MCSymbol *PPCELFObjectWriter::undefinedExplicitRelSym(const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const {
assert(Target.getSymA() && "SymA cannot be 0");
const MCSymbol &Symbol = Target.getSymA()->getSymbol().AliasedSymbol();
unsigned RelocType = getRelocTypeInner(Target, Fixup, IsPCRel);
// The .odp creation emits a relocation against the symbol ".TOC." which
// create a R_PPC64_TOC relocation. However the relocation symbol name
// in final object creation should be NULL, since the symbol does not
// really exist, it is just the reference to TOC base for the current
// object file.
bool EmitThisSym = RelocType != ELF::R_PPC64_TOC;
if (EmitThisSym && !Symbol.isTemporary())
return &Symbol;
return NULL;
}
void PPCELFObjectWriter::
adjustFixupOffset(const MCFixup &Fixup, uint64_t &RelocOffset) {
switch ((unsigned)Fixup.getKind()) {

View File

@ -34,6 +34,16 @@ enum Fixups {
/// fixup_ppc_lo14 - A 14-bit fixup corresponding to lo16(_foo) for instrs
/// like 'std'.
fixup_ppc_lo14,
/// fixup_ppc_toc - Insert value of TOC base (.TOC.).
fixup_ppc_toc,
/// fixup_ppc_toc16 - A 16-bit signed fixup relative to the TOC base.
fixup_ppc_toc16,
/// fixup_ppc_toc16_ds - A 14-bit signed fixup relative to the TOC base with
/// implied 2 zero bits
fixup_ppc_toc16_ds,
// Marker
LastTargetFixupKind,

View File

@ -15,7 +15,9 @@
#include "MCTargetDesc/PPCBaseInfo.h"
#include "MCTargetDesc/PPCFixupKinds.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
@ -28,13 +30,25 @@ class PPCMCCodeEmitter : public MCCodeEmitter {
PPCMCCodeEmitter(const PPCMCCodeEmitter &) LLVM_DELETED_FUNCTION;
void operator=(const PPCMCCodeEmitter &) LLVM_DELETED_FUNCTION;
const MCSubtargetInfo &STI;
Triple TT;
public:
PPCMCCodeEmitter(const MCInstrInfo &mcii, const MCSubtargetInfo &sti,
MCContext &ctx) {
MCContext &ctx)
: STI(sti), TT(STI.getTargetTriple()) {
}
~PPCMCCodeEmitter() {}
bool is64BitMode() const {
return (STI.getFeatureBits() & PPC::Feature64Bit) != 0;
}
bool isSVR4ABI() const {
return TT.isMacOSX() == 0;
}
unsigned getDirectBrEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups) const;
unsigned getCondBrEncoding(const MCInst &MI, unsigned OpNo,
@ -140,8 +154,12 @@ unsigned PPCMCCodeEmitter::getMemRIEncoding(const MCInst &MI, unsigned OpNo,
return (getMachineOpValue(MI, MO, Fixups) & 0xFFFF) | RegBits;
// Add a fixup for the displacement field.
Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_lo16));
if (isSVR4ABI() && is64BitMode())
Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_toc16));
else
Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_lo16));
return RegBits;
}
@ -158,8 +176,12 @@ unsigned PPCMCCodeEmitter::getMemRIXEncoding(const MCInst &MI, unsigned OpNo,
return (getMachineOpValue(MI, MO, Fixups) & 0x3FFF) | RegBits;
// Add a fixup for the branch target.
Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_lo14));
if (isSVR4ABI() && is64BitMode())
Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_toc16_ds));
else
Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
(MCFixupKind)PPC::fixup_ppc_lo14));
return RegBits;
}

View File

@ -420,10 +420,14 @@ void PPCLinuxAsmPrinter::EmitFunctionEntryLabel() {
OutStreamer.EmitValueToAlignment(8);
MCSymbol *Symbol1 =
OutContext.GetOrCreateSymbol(".L." + Twine(CurrentFnSym->getName()));
MCSymbol *Symbol2 = OutContext.GetOrCreateSymbol(StringRef(".TOC.@tocbase"));
// Generates a R_PPC64_ADDR64 (from FK_DATA_8) relocation for the function
// entry point.
OutStreamer.EmitValue(MCSymbolRefExpr::Create(Symbol1, OutContext),
8/*size*/, 0/*addrspace*/);
OutStreamer.EmitValue(MCSymbolRefExpr::Create(Symbol2, OutContext),
MCSymbol *Symbol2 = OutContext.GetOrCreateSymbol(StringRef(".TOC."));
// Generates a R_PPC64_TOC relocation for TOC base insertion.
OutStreamer.EmitValue(MCSymbolRefExpr::Create(Symbol2,
MCSymbolRefExpr::VK_PPC_TOC, OutContext),
8/*size*/, 0/*addrspace*/);
// Emit a null environment pointer.
OutStreamer.EmitIntValue(0, 8 /* size */, 0 /* addrspace */);

View File

@ -54,19 +54,26 @@ PPCSubtarget::PPCSubtarget(const std::string &TT, const std::string &CPU,
CPUName = sys::getHostCPUName();
#endif
// Parse features string.
ParseSubtargetFeatures(CPUName, FS);
// Initialize scheduling itinerary for the specified CPU.
InstrItins = getInstrItineraryForCPU(CPUName);
// Make sure 64-bit features are available when CPUname is generic
std::string FullFS = FS;
// If we are generating code for ppc64, verify that options make sense.
if (is64Bit) {
Has64BitSupport = true;
// Silently force 64-bit register use on ppc64.
Use64BitRegs = true;
if (!FullFS.empty())
FullFS = "+64bit," + FullFS;
else
FullFS = "+64bit";
}
// Parse features string.
ParseSubtargetFeatures(CPUName, FullFS);
// If the user requested use of 64-bit regs, but the cpu selected doesn't
// support it, ignore.
if (use64BitRegs() && !has64BitSupport())

View File

@ -0,0 +1,5 @@
config.suffixes = ['.ll', '.c', '.cpp', '.s']
targets = set(config.root.targets_to_build.split())
if not 'PowerPC' in targets:
config.unsupported = True

View File

@ -0,0 +1,66 @@
;; RUN: llc -mtriple=powerpc64-unknown-linux-gnu -O3 \
;; RUN: -filetype=obj %s -o - | \
;; RUN: elf-dump --dump-section-data | FileCheck %s
;; FIXME: this file need to be in .s form, change when asm parse is done.
@number64 = global i64 10, align 8
define i64 @access_int64(i64 %a) nounwind readonly {
entry:
%0 = load i64* @number64, align 8
%cmp = icmp eq i64 %0, %a
%conv1 = zext i1 %cmp to i64
ret i64 %conv1
}
declare double @sin(double) nounwind
define double @test_branch24 (double %x) nounwind readonly {
entry:
%add = call double @sin(double %x) nounwind
ret double %add
}
;; The relocations in .rela.text are the 'number64' load using a
;; R_PPC64_TOC16_DS against the .toc and the 'sin' external function
;; address using a R_PPC64_REL24
;; CHECK: '.rela.text'
;; CHECK: Relocation 0
;; CHECK-NEXT: 'r_offset',
;; CHECK-NEXT: 'r_sym', 0x00000006
;; CHECK-NEXT: 'r_type', 0x0000003f
;; CHECK: Relocation 1
;; CHECK-NEXT: 'r_offset',
;; CHECK-NEXT: 'r_sym', 0x0000000a
;; CHECK-NEXT: 'r_type', 0x0000000a
;; The .opd entry for the 'access_int64' function creates 2 relocations:
;; 1. A R_PPC64_ADDR64 against the .text segment plus addend (the function
; address itself);
;; 2. And a R_PPC64_TOC against no symbol (the linker will replace for the
;; module's TOC base).
;; CHECK: '.rela.opd'
;; CHECK: Relocation 0
;; CHECK-NEXT: 'r_offset',
;; CHECK-NEXT: 'r_sym', 0x00000002
;; CHECK-NEXT: 'r_type', 0x00000026
;; CHECK: Relocation 1
;; CHECK-NEXT: 'r_offset',
;; CHECK-NEXT: 'r_sym', 0x00000000
;; CHECK-NEXT: 'r_type', 0x00000033
;; Finally the TOC creates the relocation for the 'number64'.
;; CHECK: '.rela.toc'
;; CHECK: Relocation 0
;; CHECK-NEXT: 'r_offset',
;; CHECK-NEXT: 'r_sym', 0x00000008
;; CHECK-NEXT: 'r_type', 0x00000026
;; Check if the relocation references are for correct symbols.
;; CHECK: Symbol 7
;; CHECK-NEXT: 'access_int64'
;; CHECK: Symbol 8
;; CHECK-NEXT: 'number64'
;; CHECK: Symbol 10
;; CHECK-NEXT: 'sin'