mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[PowerPC] Fix large code model with the ELFv2 ABI
The global entry point prologue currently assumes that the TOC associated with a function is less than 2GB away from the function entry point. This is always true when using the medium or small code model, but may not be the case when using the large code model. This patch adds a new variant of the ELFv2 global entry point prologue that lifts the 2GB restriction when building with -mcmodel=large. This works by emitting a quadword containing the distance from the function entry point to its associated TOC immediately before the entry point, and then using a prologue like: ld r2,-8(r12) add r2,r2,r12 Since creation of the entry point prologue is now split across two separate routines (PPCLinuxAsmPrinter::EmitFunctionEntryLabel emits the data word, PPCLinuxAsmPrinter::EmitFunctionBodyStart the prolog code), I've switched to using named labels instead of just temporaries to indicate the locations of the global and local entry points and the new TOC offset data word. These names are provided by new routines in PPCFunctionInfo modeled after the existing PPCFunctionInfo::getPICOffsetSymbol. Note that a corresponding change was committed to GCC here: https://gcc.gnu.org/ml/gcc-patches/2015-12/msg00355.html Reviewers: hfinkel Differential Revision: http://reviews.llvm.org/D15500 llvm-svn: 257597
This commit is contained in:
parent
3e4a1e477a
commit
257810adf2
@ -1092,8 +1092,28 @@ void PPCLinuxAsmPrinter::EmitFunctionEntryLabel() {
|
||||
}
|
||||
|
||||
// ELFv2 ABI - Normal entry label.
|
||||
if (Subtarget->isELFv2ABI())
|
||||
if (Subtarget->isELFv2ABI()) {
|
||||
// In the Large code model, we allow arbitrary displacements between
|
||||
// the text section and its associated TOC section. We place the
|
||||
// full 8-byte offset to the TOC in memory immediatedly preceding
|
||||
// the function global entry point.
|
||||
if (TM.getCodeModel() == CodeModel::Large
|
||||
&& !MF->getRegInfo().use_empty(PPC::X2)) {
|
||||
const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>();
|
||||
|
||||
MCSymbol *TOCSymbol = OutContext.getOrCreateSymbol(StringRef(".TOC."));
|
||||
MCSymbol *GlobalEPSymbol = PPCFI->getGlobalEPSymbol();
|
||||
const MCExpr *TOCDeltaExpr =
|
||||
MCBinaryExpr::createSub(MCSymbolRefExpr::create(TOCSymbol, OutContext),
|
||||
MCSymbolRefExpr::create(GlobalEPSymbol,
|
||||
OutContext),
|
||||
OutContext);
|
||||
|
||||
OutStreamer->EmitLabel(PPCFI->getTOCOffsetSymbol());
|
||||
OutStreamer->EmitValue(TOCDeltaExpr, 8);
|
||||
}
|
||||
return AsmPrinter::EmitFunctionEntryLabel();
|
||||
}
|
||||
|
||||
// Emit an official procedure descriptor.
|
||||
MCSectionSubPair Current = OutStreamer->getCurrentSection();
|
||||
@ -1160,10 +1180,25 @@ void PPCLinuxAsmPrinter::EmitFunctionBodyStart() {
|
||||
// thus emit a prefix sequence along the following lines:
|
||||
//
|
||||
// func:
|
||||
// .Lfunc_gepNN:
|
||||
// # global entry point
|
||||
// addis r2,r12,(.TOC.-func)@ha
|
||||
// addi r2,r2,(.TOC.-func)@l
|
||||
// .localentry func, .-func
|
||||
// addis r2,r12,(.TOC.-.Lfunc_gepNN)@ha
|
||||
// addi r2,r2,(.TOC.-.Lfunc_gepNN)@l
|
||||
// .Lfunc_lepNN:
|
||||
// .localentry func, .Lfunc_lepNN-.Lfunc_gepNN
|
||||
// # local entry point, followed by function body
|
||||
//
|
||||
// For the Large code model, we create
|
||||
//
|
||||
// .Lfunc_tocNN:
|
||||
// .quad .TOC.-.Lfunc_gepNN # done by EmitFunctionEntryLabel
|
||||
// func:
|
||||
// .Lfunc_gepNN:
|
||||
// # global entry point
|
||||
// ld r2,.Lfunc_tocNN-.Lfunc_gepNN(r12)
|
||||
// add r2,r2,r12
|
||||
// .Lfunc_lepNN:
|
||||
// .localentry func, .Lfunc_lepNN-.Lfunc_gepNN
|
||||
// # local entry point, followed by function body
|
||||
//
|
||||
// This ensures we have r2 set up correctly while executing the function
|
||||
@ -1171,32 +1206,49 @@ void PPCLinuxAsmPrinter::EmitFunctionBodyStart() {
|
||||
if (Subtarget->isELFv2ABI()
|
||||
// Only do all that if the function uses r2 in the first place.
|
||||
&& !MF->getRegInfo().use_empty(PPC::X2)) {
|
||||
const PPCFunctionInfo *PPCFI = MF->getInfo<PPCFunctionInfo>();
|
||||
|
||||
MCSymbol *GlobalEntryLabel = OutContext.createTempSymbol();
|
||||
MCSymbol *GlobalEntryLabel = PPCFI->getGlobalEPSymbol();
|
||||
OutStreamer->EmitLabel(GlobalEntryLabel);
|
||||
const MCSymbolRefExpr *GlobalEntryLabelExp =
|
||||
MCSymbolRefExpr::create(GlobalEntryLabel, OutContext);
|
||||
|
||||
MCSymbol *TOCSymbol = OutContext.getOrCreateSymbol(StringRef(".TOC."));
|
||||
const MCExpr *TOCDeltaExpr =
|
||||
MCBinaryExpr::createSub(MCSymbolRefExpr::create(TOCSymbol, OutContext),
|
||||
GlobalEntryLabelExp, OutContext);
|
||||
if (TM.getCodeModel() != CodeModel::Large) {
|
||||
MCSymbol *TOCSymbol = OutContext.getOrCreateSymbol(StringRef(".TOC."));
|
||||
const MCExpr *TOCDeltaExpr =
|
||||
MCBinaryExpr::createSub(MCSymbolRefExpr::create(TOCSymbol, OutContext),
|
||||
GlobalEntryLabelExp, OutContext);
|
||||
|
||||
const MCExpr *TOCDeltaHi =
|
||||
PPCMCExpr::createHa(TOCDeltaExpr, false, OutContext);
|
||||
EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS)
|
||||
.addReg(PPC::X2)
|
||||
.addReg(PPC::X12)
|
||||
.addExpr(TOCDeltaHi));
|
||||
const MCExpr *TOCDeltaHi =
|
||||
PPCMCExpr::createHa(TOCDeltaExpr, false, OutContext);
|
||||
EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDIS)
|
||||
.addReg(PPC::X2)
|
||||
.addReg(PPC::X12)
|
||||
.addExpr(TOCDeltaHi));
|
||||
|
||||
const MCExpr *TOCDeltaLo =
|
||||
PPCMCExpr::createLo(TOCDeltaExpr, false, OutContext);
|
||||
EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDI)
|
||||
.addReg(PPC::X2)
|
||||
.addReg(PPC::X2)
|
||||
.addExpr(TOCDeltaLo));
|
||||
const MCExpr *TOCDeltaLo =
|
||||
PPCMCExpr::createLo(TOCDeltaExpr, false, OutContext);
|
||||
EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADDI)
|
||||
.addReg(PPC::X2)
|
||||
.addReg(PPC::X2)
|
||||
.addExpr(TOCDeltaLo));
|
||||
} else {
|
||||
MCSymbol *TOCOffset = PPCFI->getTOCOffsetSymbol();
|
||||
const MCExpr *TOCOffsetDeltaExpr =
|
||||
MCBinaryExpr::createSub(MCSymbolRefExpr::create(TOCOffset, OutContext),
|
||||
GlobalEntryLabelExp, OutContext);
|
||||
|
||||
MCSymbol *LocalEntryLabel = OutContext.createTempSymbol();
|
||||
EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::LD)
|
||||
.addReg(PPC::X2)
|
||||
.addExpr(TOCOffsetDeltaExpr)
|
||||
.addReg(PPC::X12));
|
||||
EmitToStreamer(*OutStreamer, MCInstBuilder(PPC::ADD8)
|
||||
.addReg(PPC::X2)
|
||||
.addReg(PPC::X2)
|
||||
.addReg(PPC::X12));
|
||||
}
|
||||
|
||||
MCSymbol *LocalEntryLabel = PPCFI->getLocalEPSymbol();
|
||||
OutStreamer->EmitLabel(LocalEntryLabel);
|
||||
const MCSymbolRefExpr *LocalEntryLabelExp =
|
||||
MCSymbolRefExpr::create(LocalEntryLabel, OutContext);
|
||||
|
@ -23,3 +23,24 @@ MCSymbol *PPCFunctionInfo::getPICOffsetSymbol() const {
|
||||
Twine(MF.getFunctionNumber()) +
|
||||
"$poff");
|
||||
}
|
||||
|
||||
MCSymbol *PPCFunctionInfo::getGlobalEPSymbol() const {
|
||||
const DataLayout &DL = MF.getDataLayout();
|
||||
return MF.getContext().getOrCreateSymbol(Twine(DL.getPrivateGlobalPrefix()) +
|
||||
"func_gep" +
|
||||
Twine(MF.getFunctionNumber()));
|
||||
}
|
||||
|
||||
MCSymbol *PPCFunctionInfo::getLocalEPSymbol() const {
|
||||
const DataLayout &DL = MF.getDataLayout();
|
||||
return MF.getContext().getOrCreateSymbol(Twine(DL.getPrivateGlobalPrefix()) +
|
||||
"func_lep" +
|
||||
Twine(MF.getFunctionNumber()));
|
||||
}
|
||||
|
||||
MCSymbol *PPCFunctionInfo::getTOCOffsetSymbol() const {
|
||||
const DataLayout &DL = MF.getDataLayout();
|
||||
return MF.getContext().getOrCreateSymbol(Twine(DL.getPrivateGlobalPrefix()) +
|
||||
"func_toc" +
|
||||
Twine(MF.getFunctionNumber()));
|
||||
}
|
||||
|
@ -197,6 +197,10 @@ public:
|
||||
bool usesPICBase() const { return UsesPICBase; }
|
||||
|
||||
MCSymbol *getPICOffsetSymbol() const;
|
||||
|
||||
MCSymbol *getGlobalEPSymbol() const;
|
||||
MCSymbol *getLocalEPSymbol() const;
|
||||
MCSymbol *getTOCOffsetSymbol() const;
|
||||
};
|
||||
|
||||
} // end of namespace llvm
|
||||
|
27
test/CodeGen/PowerPC/ppc64le-localentry-large.ll
Normal file
27
test/CodeGen/PowerPC/ppc64le-localentry-large.ll
Normal file
@ -0,0 +1,27 @@
|
||||
; RUN: llc -march=ppc64le -code-model=large < %s | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-n32:64"
|
||||
target triple = "powerpc64le-unknown-linux-gnu"
|
||||
|
||||
@number64 = global i64 10, align 8
|
||||
|
||||
; CHECK: .abiversion 2
|
||||
|
||||
define i64 @use_toc(i64 %a) nounwind {
|
||||
entry:
|
||||
; CHECK: .Lfunc_toc[[FN:[0-9]+]]:
|
||||
; CHECK-NEXT: .quad .TOC.-.Lfunc_gep[[FN]]
|
||||
; CHECK: use_toc:
|
||||
; CHECK-NEXT: .L{{.*}}:
|
||||
; CHECK-NEXT: .Lfunc_gep[[FN]]:
|
||||
; CHECK-NEXT: ld 2, .Lfunc_toc[[FN]]-.Lfunc_gep[[FN]](12)
|
||||
; CHECK-NEXT: add 2, 2, 12
|
||||
; CHECK-NEXT: .Lfunc_lep[[FN]]:
|
||||
; CHECK-NEXT: .localentry use_toc, .Lfunc_lep[[FN]]-.Lfunc_gep[[FN]]
|
||||
; CHECK-NEXT: %entry
|
||||
%0 = load i64, i64* @number64, align 8
|
||||
%cmp = icmp eq i64 %0, %a
|
||||
%conv1 = zext i1 %cmp to i64
|
||||
ret i64 %conv1
|
||||
}
|
||||
|
@ -17,11 +17,11 @@ define i64 @use_toc(i64 %a) nounwind {
|
||||
entry:
|
||||
; CHECK-LABEL: @use_toc
|
||||
; CHECK-NEXT: .L{{.*}}:
|
||||
; CHECK-NEXT: .Ltmp[[TMP1:[0-9]+]]:
|
||||
; CHECK-NEXT: addis 2, 12, .TOC.-.Ltmp[[TMP1]]@ha
|
||||
; CHECK-NEXT: addi 2, 2, .TOC.-.Ltmp[[TMP1]]@l
|
||||
; CHECK-NEXT: .Ltmp[[TMP2:[0-9]+]]:
|
||||
; CHECK-NEXT: .localentry use_toc, .Ltmp[[TMP2]]-.Ltmp[[TMP1]]
|
||||
; CHECK-NEXT: .Lfunc_gep[[FN:[0-9]+]]:
|
||||
; CHECK-NEXT: addis 2, 12, .TOC.-.Lfunc_gep[[FN]]@ha
|
||||
; CHECK-NEXT: addi 2, 2, .TOC.-.Lfunc_gep[[FN]]@l
|
||||
; CHECK-NEXT: .Lfunc_lep[[FN]]:
|
||||
; CHECK-NEXT: .localentry use_toc, .Lfunc_lep[[FN]]-.Lfunc_gep[[FN]]
|
||||
; CHECK-NEXT: %entry
|
||||
%0 = load i64, i64* @number64, align 8
|
||||
%cmp = icmp eq i64 %0, %a
|
||||
@ -34,11 +34,11 @@ define void @use_toc_implicit() nounwind {
|
||||
entry:
|
||||
; CHECK-LABEL: @use_toc_implicit
|
||||
; CHECK-NEXT: .L{{.*}}:
|
||||
; CHECK-NEXT: .Ltmp[[TMP1:[0-9]+]]:
|
||||
; CHECK-NEXT: addis 2, 12, .TOC.-.Ltmp[[TMP1]]@ha
|
||||
; CHECK-NEXT: addi 2, 2, .TOC.-.Ltmp[[TMP1]]@l
|
||||
; CHECK-NEXT: .Ltmp[[TMP2:[0-9]+]]:
|
||||
; CHECK-NEXT: .localentry use_toc_implicit, .Ltmp[[TMP2]]-.Ltmp[[TMP1]]
|
||||
; CHECK-NEXT: .Lfunc_gep[[FN:[0-9]+]]:
|
||||
; CHECK-NEXT: addis 2, 12, .TOC.-.Lfunc_gep[[FN]]@ha
|
||||
; CHECK-NEXT: addi 2, 2, .TOC.-.Lfunc_gep[[FN]]@l
|
||||
; CHECK-NEXT: .Lfunc_lep[[FN]]:
|
||||
; CHECK-NEXT: .localentry use_toc_implicit, .Lfunc_lep[[FN]]-.Lfunc_gep[[FN]]
|
||||
; CHECK-NEXT: %entry
|
||||
call void @callee()
|
||||
ret void
|
||||
|
Loading…
Reference in New Issue
Block a user