mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-09 21:32:49 +00:00
[AIX]Emit function descriptor csect in assembly
This patch emits the function descriptor csect for functions with definitions under both 32-bit/64-bit mode on AIX. Differential Revision: https://reviews.llvm.org/D66724 llvm-svn: 373009
This commit is contained in:
parent
1e425c53e9
commit
be30366603
@ -111,6 +111,10 @@ public:
|
||||
/// of each call to runOnMachineFunction().
|
||||
MCSymbol *CurrentFnSym = nullptr;
|
||||
|
||||
/// The symbol for the current function descriptor on AIX. This is created
|
||||
/// at the beginning of each call to SetupMachineFunction().
|
||||
MCSymbol *CurrentFnDescSym = nullptr;
|
||||
|
||||
/// The symbol used to represent the start of the current function for the
|
||||
/// purpose of calculating its size (e.g. using the .size directive). By
|
||||
/// default, this is equal to CurrentFnSym.
|
||||
@ -304,7 +308,7 @@ public:
|
||||
|
||||
/// This should be called when a new MachineFunction is being processed from
|
||||
/// runOnMachineFunction.
|
||||
void SetupMachineFunction(MachineFunction &MF);
|
||||
virtual void SetupMachineFunction(MachineFunction &MF);
|
||||
|
||||
/// This method emits the body and trailer for a function.
|
||||
void EmitFunctionBody();
|
||||
@ -414,6 +418,10 @@ public:
|
||||
|
||||
virtual void EmitFunctionEntryLabel();
|
||||
|
||||
virtual void EmitFunctionDescriptor() {
|
||||
llvm_unreachable("Function descriptor is target-specific.");
|
||||
}
|
||||
|
||||
virtual void EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV);
|
||||
|
||||
/// Targets can override this to change how global constants that are part of
|
||||
|
@ -317,6 +317,10 @@ protected:
|
||||
/// Defaults to false.
|
||||
bool HasLinkOnceDirective = false;
|
||||
|
||||
/// True if we have a .lglobl directive, which is used to emit the information
|
||||
/// of a static symbol into the symbol table. Defaults to false.
|
||||
bool HasDotLGloblDirective = false;
|
||||
|
||||
/// This attribute, if not MCSA_Invalid, is used to declare a symbol as having
|
||||
/// hidden visibility. Defaults to MCSA_Hidden.
|
||||
MCSymbolAttr HiddenVisibilityAttr = MCSA_Hidden;
|
||||
@ -392,6 +396,9 @@ protected:
|
||||
// %hi(), and similar unary operators.
|
||||
bool HasMipsExpressions = false;
|
||||
|
||||
// If true, emit function descriptor symbol on AIX.
|
||||
bool NeedsFunctionDescriptors = false;
|
||||
|
||||
public:
|
||||
explicit MCAsmInfo();
|
||||
virtual ~MCAsmInfo();
|
||||
@ -565,6 +572,8 @@ public:
|
||||
|
||||
bool hasLinkOnceDirective() const { return HasLinkOnceDirective; }
|
||||
|
||||
bool hasDotLGloblDirective() const { return HasDotLGloblDirective; }
|
||||
|
||||
MCSymbolAttr getHiddenVisibilityAttr() const { return HiddenVisibilityAttr; }
|
||||
|
||||
MCSymbolAttr getHiddenDeclarationVisibilityAttr() const {
|
||||
@ -647,6 +656,7 @@ public:
|
||||
bool canRelaxRelocations() const { return RelaxELFRelocations; }
|
||||
void setRelaxELFRelocations(bool V) { RelaxELFRelocations = V; }
|
||||
bool hasMipsExpressions() const { return HasMipsExpressions; }
|
||||
bool needsFunctionDescriptors() const { return NeedsFunctionDescriptors; }
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -18,6 +18,11 @@ class MCAsmInfoXCOFF : public MCAsmInfo {
|
||||
|
||||
protected:
|
||||
MCAsmInfoXCOFF();
|
||||
|
||||
public:
|
||||
// Return true only when the identifier Name does not need quotes to be
|
||||
// syntactically correct for XCOFF.
|
||||
bool isValidUnquotedName(StringRef Name) const override;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -28,6 +28,7 @@ enum MCSymbolAttr {
|
||||
MCSA_ELF_TypeNoType, ///< .type _foo, STT_NOTYPE # aka @notype
|
||||
MCSA_ELF_TypeGnuUniqueObject, /// .type _foo, @gnu_unique_object
|
||||
MCSA_Global, ///< .globl
|
||||
MCSA_LGlobal, ///< .lglobl (XCOFF)
|
||||
MCSA_Hidden, ///< .hidden (ELF)
|
||||
MCSA_IndirectSymbol, ///< .indirect_symbol (MachO)
|
||||
MCSA_Internal, ///< .internal (ELF)
|
||||
|
@ -35,14 +35,14 @@ public:
|
||||
return StorageClass.getValue();
|
||||
}
|
||||
|
||||
void setContainingCsect(const MCSectionXCOFF *C) {
|
||||
void setContainingCsect(MCSectionXCOFF *C) {
|
||||
assert((!ContainingCsect || ContainingCsect == C) &&
|
||||
"Trying to set a containing csect that doesn't match the one that"
|
||||
"this symbol is already mapped to.");
|
||||
ContainingCsect = C;
|
||||
}
|
||||
|
||||
const MCSectionXCOFF *getContainingCsect() const {
|
||||
MCSectionXCOFF *getContainingCsect() const {
|
||||
assert(ContainingCsect &&
|
||||
"Trying to get containing csect but none was set.");
|
||||
return ContainingCsect;
|
||||
@ -50,7 +50,7 @@ public:
|
||||
|
||||
private:
|
||||
Optional<XCOFF::StorageClass> StorageClass;
|
||||
const MCSectionXCOFF *ContainingCsect = nullptr;
|
||||
MCSectionXCOFF *ContainingCsect = nullptr;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
@ -91,10 +91,12 @@
|
||||
#include "llvm/MC/MCSectionCOFF.h"
|
||||
#include "llvm/MC/MCSectionELF.h"
|
||||
#include "llvm/MC/MCSectionMachO.h"
|
||||
#include "llvm/MC/MCSectionXCOFF.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/MC/MCSymbolELF.h"
|
||||
#include "llvm/MC/MCSymbolXCOFF.h"
|
||||
#include "llvm/MC/MCTargetOptions.h"
|
||||
#include "llvm/MC/MCValue.h"
|
||||
#include "llvm/MC/SectionKind.h"
|
||||
@ -426,7 +428,10 @@ void AsmPrinter::EmitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const {
|
||||
OutStreamer->EmitSymbolAttribute(GVSym, MCSA_Global);
|
||||
return;
|
||||
case GlobalValue::PrivateLinkage:
|
||||
return;
|
||||
case GlobalValue::InternalLinkage:
|
||||
if (MAI->hasDotLGloblDirective())
|
||||
OutStreamer->EmitSymbolAttribute(GVSym, MCSA_LGlobal);
|
||||
return;
|
||||
case GlobalValue::AppendingLinkage:
|
||||
case GlobalValue::AvailableExternallyLinkage:
|
||||
@ -662,6 +667,10 @@ void AsmPrinter::EmitFunctionHeader() {
|
||||
OutStreamer->SwitchSection(getObjFileLowering().SectionForGlobal(&F, TM));
|
||||
EmitVisibility(CurrentFnSym, F.getVisibility());
|
||||
|
||||
if (MAI->needsFunctionDescriptors() &&
|
||||
F.getLinkage() != GlobalValue::InternalLinkage)
|
||||
EmitLinkage(&F, CurrentFnDescSym);
|
||||
|
||||
EmitLinkage(&F, CurrentFnSym);
|
||||
if (MAI->hasFunctionAlignment())
|
||||
EmitAlignment(MF->getAlignment(), &F);
|
||||
@ -697,8 +706,13 @@ void AsmPrinter::EmitFunctionHeader() {
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the CurrentFnSym. This is a virtual function to allow targets to
|
||||
// do their wild and crazy things as required.
|
||||
// Emit the function descriptor. This is a virtual function to allow targets
|
||||
// to emit their specific function descriptor.
|
||||
if (MAI->needsFunctionDescriptors())
|
||||
EmitFunctionDescriptor();
|
||||
|
||||
// Emit the CurrentFnSym. This is a virtual function to allow targets to do
|
||||
// their wild and crazy things as required.
|
||||
EmitFunctionEntryLabel();
|
||||
|
||||
// If the function had address-taken blocks that got deleted, then we have
|
||||
@ -1644,8 +1658,27 @@ MCSymbol *AsmPrinter::getCurExceptionSym() {
|
||||
|
||||
void AsmPrinter::SetupMachineFunction(MachineFunction &MF) {
|
||||
this->MF = &MF;
|
||||
|
||||
// Get the function symbol.
|
||||
CurrentFnSym = getSymbol(&MF.getFunction());
|
||||
if (MAI->needsFunctionDescriptors()) {
|
||||
assert(TM.getTargetTriple().isOSAIX() && "Function descriptor is only"
|
||||
" supported on AIX.");
|
||||
assert(CurrentFnDescSym && "The function descriptor symbol needs to be"
|
||||
" initalized first.");
|
||||
|
||||
// Get the function entry point symbol.
|
||||
CurrentFnSym =
|
||||
OutContext.getOrCreateSymbol("." + CurrentFnDescSym->getName());
|
||||
|
||||
const Function &F = MF.getFunction();
|
||||
MCSectionXCOFF *FnEntryPointSec =
|
||||
cast<MCSectionXCOFF>(getObjFileLowering().SectionForGlobal(&F, TM));
|
||||
// Set the containing csect.
|
||||
cast<MCSymbolXCOFF>(CurrentFnSym)->setContainingCsect(FnEntryPointSec);
|
||||
} else {
|
||||
CurrentFnSym = getSymbol(&MF.getFunction());
|
||||
}
|
||||
|
||||
CurrentFnSymForSize = CurrentFnSym;
|
||||
CurrentFnBegin = nullptr;
|
||||
CurExceptionSym = nullptr;
|
||||
|
@ -20,5 +20,16 @@ MCAsmInfoXCOFF::MCAsmInfoXCOFF() {
|
||||
UseDotAlignForAlignment = true;
|
||||
AsciiDirective = nullptr; // not supported
|
||||
AscizDirective = nullptr; // not supported
|
||||
NeedsFunctionDescriptors = true;
|
||||
HasDotLGloblDirective = true;
|
||||
Data64bitsDirective = "\t.llong\t";
|
||||
SupportsQuotedNames = false;
|
||||
}
|
||||
|
||||
bool MCAsmInfoXCOFF::isValidUnquotedName(StringRef Name) const {
|
||||
// FIXME: Remove this function when we stop using "TOC[TC0]" as a symbol name.
|
||||
if (Name.equals("TOC[TC0]"))
|
||||
return true;
|
||||
|
||||
return MCAsmInfo::isValidUnquotedName(Name);
|
||||
}
|
||||
|
@ -650,6 +650,7 @@ bool MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
|
||||
case MCSA_Global: // .globl/.global
|
||||
OS << MAI->getGlobalDirective();
|
||||
break;
|
||||
case MCSA_LGlobal: OS << "\t.lglobl\t"; break;
|
||||
case MCSA_Hidden: OS << "\t.hidden\t"; break;
|
||||
case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break;
|
||||
case MCSA_Internal: OS << "\t.internal\t"; break;
|
||||
|
@ -277,6 +277,9 @@ bool MCELFStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
|
||||
|
||||
case MCSA_AltEntry:
|
||||
llvm_unreachable("ELF doesn't support the .alt_entry attribute");
|
||||
|
||||
case MCSA_LGlobal:
|
||||
llvm_unreachable("ELF doesn't support the .lglobl attribute");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -330,6 +330,7 @@ bool MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Sym,
|
||||
case MCSA_Protected:
|
||||
case MCSA_Weak:
|
||||
case MCSA_Local:
|
||||
case MCSA_LGlobal:
|
||||
return false;
|
||||
|
||||
case MCSA_Global:
|
||||
|
@ -15,26 +15,46 @@ using namespace llvm;
|
||||
|
||||
MCSectionXCOFF::~MCSectionXCOFF() = default;
|
||||
|
||||
static StringRef getMappingClassString(XCOFF::StorageMappingClass SMC) {
|
||||
switch (SMC) {
|
||||
case XCOFF::XMC_DS:
|
||||
return "DS";
|
||||
case XCOFF::XMC_RW:
|
||||
return "RW";
|
||||
case XCOFF::XMC_PR:
|
||||
return "PR";
|
||||
default:
|
||||
report_fatal_error("Unhandled storage-mapping class.");
|
||||
}
|
||||
}
|
||||
|
||||
void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
|
||||
raw_ostream &OS,
|
||||
const MCExpr *Subsection) const {
|
||||
if (getKind().isText()) {
|
||||
if (getMappingClass() != XCOFF::XMC_PR)
|
||||
llvm_unreachable("Unsupported storage-mapping class for .text csect");
|
||||
report_fatal_error("Unhandled storage-mapping class for .text csect");
|
||||
|
||||
OS << "\t.csect " << getSectionName() << "["
|
||||
<< "PR"
|
||||
<< getMappingClassString(getMappingClass())
|
||||
<< "]" << '\n';
|
||||
return;
|
||||
}
|
||||
|
||||
if (getKind().isData()) {
|
||||
assert(getMappingClass() == XCOFF::XMC_RW &&
|
||||
"Unhandled storage-mapping class for data section.");
|
||||
|
||||
OS << "\t.csect " << getSectionName() << "["
|
||||
<< "RW"
|
||||
<< "]" << '\n';
|
||||
switch (getMappingClass()) {
|
||||
case XCOFF::XMC_RW:
|
||||
case XCOFF::XMC_DS:
|
||||
OS << "\t.csect " << getSectionName() << "["
|
||||
<< getMappingClassString(getMappingClass()) << "]" << '\n';
|
||||
break;
|
||||
case XCOFF::XMC_TC0:
|
||||
OS << "\t.toc\n";
|
||||
break;
|
||||
default:
|
||||
report_fatal_error(
|
||||
"Unhandled storage-mapping class for .data csect.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -235,6 +235,9 @@ void XCOFFObjectWriter::executePostLayoutBinding(
|
||||
break;
|
||||
}
|
||||
report_fatal_error("Unhandled mapping of read-write csect to section.");
|
||||
case XCOFF::XMC_TC0:
|
||||
// TODO FIXME Handle emiting the TOC base.
|
||||
break;
|
||||
case XCOFF::XMC_BS:
|
||||
assert(XCOFF::XTY_CM == MCSec->getCSectType() &&
|
||||
"Mapping invalid csect. CSECT with bss storage class must be "
|
||||
|
@ -167,7 +167,13 @@ public:
|
||||
|
||||
StringRef getPassName() const override { return "AIX PPC Assembly Printer"; }
|
||||
|
||||
void SetupMachineFunction(MachineFunction &MF) override;
|
||||
|
||||
void EmitGlobalVariable(const GlobalVariable *GV) override;
|
||||
|
||||
void EmitFunctionDescriptor() override;
|
||||
|
||||
void EmitEndOfAsmFile(Module &) override;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
@ -1669,6 +1675,18 @@ bool PPCDarwinAsmPrinter::doFinalization(Module &M) {
|
||||
return AsmPrinter::doFinalization(M);
|
||||
}
|
||||
|
||||
void PPCAIXAsmPrinter::SetupMachineFunction(MachineFunction &MF) {
|
||||
// Get the function descriptor symbol.
|
||||
CurrentFnDescSym = getSymbol(&MF.getFunction());
|
||||
// Set the containing csect.
|
||||
MCSectionXCOFF *FnDescSec = OutStreamer->getContext().getXCOFFSection(
|
||||
CurrentFnDescSym->getName(), XCOFF::XMC_DS, XCOFF::XTY_SD,
|
||||
XCOFF::C_HIDEXT, SectionKind::getData());
|
||||
cast<MCSymbolXCOFF>(CurrentFnDescSym)->setContainingCsect(FnDescSec);
|
||||
|
||||
return AsmPrinter::SetupMachineFunction(MF);
|
||||
}
|
||||
|
||||
void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
|
||||
// Early error checking limiting what is supported.
|
||||
if (GV->isThreadLocal())
|
||||
@ -1718,6 +1736,45 @@ void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
|
||||
EmitGlobalConstant(GV->getParent()->getDataLayout(), GV->getInitializer());
|
||||
}
|
||||
|
||||
void PPCAIXAsmPrinter::EmitFunctionDescriptor() {
|
||||
const DataLayout &DL = getDataLayout();
|
||||
const unsigned PointerSize = DL.getPointerSizeInBits() == 64 ? 8 : 4;
|
||||
|
||||
MCSectionSubPair Current = OutStreamer->getCurrentSection();
|
||||
// Emit function descriptor.
|
||||
OutStreamer->SwitchSection(
|
||||
cast<MCSymbolXCOFF>(CurrentFnDescSym)->getContainingCsect());
|
||||
OutStreamer->EmitLabel(CurrentFnDescSym);
|
||||
// Emit function entry point address.
|
||||
OutStreamer->EmitValue(MCSymbolRefExpr::create(CurrentFnSym, OutContext),
|
||||
PointerSize);
|
||||
// Emit TOC base address.
|
||||
MCSymbol *TOCBaseSym = OutContext.getOrCreateSymbol(StringRef("TOC[TC0]"));
|
||||
OutStreamer->EmitValue(MCSymbolRefExpr::create(TOCBaseSym, OutContext),
|
||||
PointerSize);
|
||||
// Emit a null environment pointer.
|
||||
OutStreamer->EmitIntValue(0, PointerSize);
|
||||
|
||||
OutStreamer->SwitchSection(Current.first, Current.second);
|
||||
}
|
||||
|
||||
void PPCAIXAsmPrinter::EmitEndOfAsmFile(Module &M) {
|
||||
// If there are no functions in this module, we will never need to reference
|
||||
// the TOC base.
|
||||
if (M.empty())
|
||||
return;
|
||||
|
||||
// Emit TOC base.
|
||||
MCSymbol *TOCBaseSym = OutContext.getOrCreateSymbol(StringRef("TOC[TC0]"));
|
||||
MCSectionXCOFF *TOCBaseSection = OutStreamer->getContext().getXCOFFSection(
|
||||
StringRef("TOC"), XCOFF::XMC_TC0, XCOFF::XTY_SD, XCOFF::C_HIDEXT,
|
||||
SectionKind::getData());
|
||||
cast<MCSymbolXCOFF>(TOCBaseSym)->setContainingCsect(TOCBaseSection);
|
||||
// Switch to section to emit TOC base.
|
||||
OutStreamer->SwitchSection(TOCBaseSection);
|
||||
}
|
||||
|
||||
|
||||
/// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code
|
||||
/// for a MachineFunction to the given output stream, in a format that the
|
||||
/// Darwin assembler can deal with.
|
||||
|
@ -21,6 +21,8 @@
|
||||
|
||||
@array = common local_unnamed_addr global [33 x i8] zeroinitializer, align 1
|
||||
|
||||
; CHECK-NOT: .toc
|
||||
|
||||
; CHECK: .csect .text[PR]
|
||||
; CHECK-NEXT: .file
|
||||
; CHECK-NEXT: .comm a,4,2
|
||||
|
74
test/CodeGen/PowerPC/test_func_desc.ll
Normal file
74
test/CodeGen/PowerPC/test_func_desc.ll
Normal file
@ -0,0 +1,74 @@
|
||||
; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | \
|
||||
; RUN: FileCheck --check-prefixes=CHECK,32BIT %s
|
||||
|
||||
; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s | \
|
||||
; RUN: FileCheck --check-prefixes=CHECK,64BIT %s
|
||||
|
||||
|
||||
define i32 @foo() {
|
||||
entry:
|
||||
ret i32 3
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
entry:
|
||||
%0 = call i32 @foo()
|
||||
%1 = call i32 bitcast (i32 (...)* @extern_foo to i32 ()*)()
|
||||
%2 = call i32 @static_foo()
|
||||
%3 = add nsw i32 %0, %1
|
||||
%4 = add nsw i32 %3, %2
|
||||
ret i32 %4
|
||||
}
|
||||
|
||||
declare i32 @extern_foo(...)
|
||||
|
||||
define internal i32 @static_foo() {
|
||||
entry:
|
||||
ret i32 3
|
||||
}
|
||||
|
||||
; CHECK: .globl foo
|
||||
; CHECK: .globl .foo
|
||||
; CHECK: .csect foo[DS]
|
||||
; CHECK-NEXT: foo:
|
||||
; 32BIT: .long .foo
|
||||
; 32BIT-NEXT: .long TOC[TC0]
|
||||
; 32BIT-NEXT: .long 0
|
||||
; 64BIT: .llong .foo
|
||||
; 64BIT-NEXT: .llong TOC[TC0]
|
||||
; 64BIT-NEXT: .llong 0
|
||||
; CHECK-NEXT: .csect .text[PR]
|
||||
; CHECK-LABEL: .foo:
|
||||
|
||||
; CHECK: .globl main
|
||||
; CHECK: .globl .main
|
||||
; CHECK: .csect main[DS]
|
||||
; CHECK-NEXT: main:
|
||||
; 32BIT: .long .main
|
||||
; 32BIT-NEXT: .long TOC[TC0]
|
||||
; 32BIT-NEXT: .long 0
|
||||
; 64BIT: .llong .main
|
||||
; 64BIT-NEXT: .llong TOC[TC0]
|
||||
; 64BIT-NEXT: .llong 0
|
||||
; CHECK-NEXT: .csect .text[PR]
|
||||
; CHECK-LABEL: .main:
|
||||
; CHECK: bl .foo
|
||||
; CHECK: bl .extern_foo
|
||||
; CHECK: bl .static_foo
|
||||
|
||||
; CHECK: .lglobl .static_foo
|
||||
; CHECK: .csect static_foo[DS]
|
||||
; CHECK-NEXT: static_foo:
|
||||
; 32BIT: .long .static_foo
|
||||
; 32BIT-NEXT: .long TOC[TC0]
|
||||
; 32BIT-NEXT: .long 0
|
||||
; 64BIT: .llong .static_foo
|
||||
; 64BIT-NEXT: .llong TOC[TC0]
|
||||
; 64BIT-NEXT: .llong 0
|
||||
; CHECK-NEXT: .csect .text[PR]
|
||||
; CHECK-LABEL: .static_foo:
|
||||
|
||||
; CHECK-NOT: .csect extern_foo
|
||||
|
||||
; CHECK: .toc
|
||||
; CHECK-NOT: .tc
|
Loading…
Reference in New Issue
Block a user