forked from OSchip/llvm-project
[AIX] Emit TOC entries for ASM printing
Summary: Emit the correct .toc psuedo op when we change to the TOC and emit TC entries. Make sure TOC psuedos get the right symbols via overriding getMCSymbolForTOCPseudoMO on AIX. Add a test for TOC assembly writing and update tests to include TOC entries. Also make sure external globals have a csect set and handle external function descriptor (originally authored by Jason Liu) so we can emit TOC entries for them. Reviewers: DiggerLin, sfertile, Xiangling_L, jasonliu, hubert.reinterpretcast Reviewed By: jasonliu Subscribers: arphaman, wuzish, nemanjai, hiraditya, kbarton, jsji, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D70461
This commit is contained in:
parent
40963b2bf0
commit
98740643f7
|
@ -333,6 +333,10 @@ protected:
|
||||||
/// protected visibility. Defaults to MCSA_Protected
|
/// protected visibility. Defaults to MCSA_Protected
|
||||||
MCSymbolAttr ProtectedVisibilityAttr = MCSA_Protected;
|
MCSymbolAttr ProtectedVisibilityAttr = MCSA_Protected;
|
||||||
|
|
||||||
|
// This attribute is used to indicate symbols such as commons on AIX may have
|
||||||
|
// a storage mapping class embedded in the name.
|
||||||
|
bool SymbolsHaveSMC = false;
|
||||||
|
|
||||||
//===--- Dwarf Emission Directives -----------------------------------===//
|
//===--- Dwarf Emission Directives -----------------------------------===//
|
||||||
|
|
||||||
/// True if target supports emission of debugging information. Defaults to
|
/// True if target supports emission of debugging information. Defaults to
|
||||||
|
@ -587,6 +591,8 @@ public:
|
||||||
return ProtectedVisibilityAttr;
|
return ProtectedVisibilityAttr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool getSymbolsHaveSMC() const { return SymbolsHaveSMC; }
|
||||||
|
|
||||||
bool doesSupportDebugInformation() const { return SupportsDebugInformation; }
|
bool doesSupportDebugInformation() const { return SupportsDebugInformation; }
|
||||||
|
|
||||||
bool doesSupportExceptionHandling() const {
|
bool doesSupportExceptionHandling() const {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#define LLVM_MC_MCSYMBOLXCOFF_H
|
#define LLVM_MC_MCSYMBOLXCOFF_H
|
||||||
|
|
||||||
#include "llvm/ADT/Optional.h"
|
#include "llvm/ADT/Optional.h"
|
||||||
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/BinaryFormat/XCOFF.h"
|
#include "llvm/BinaryFormat/XCOFF.h"
|
||||||
#include "llvm/MC/MCSymbol.h"
|
#include "llvm/MC/MCSymbol.h"
|
||||||
|
|
||||||
|
@ -50,6 +51,17 @@ public:
|
||||||
|
|
||||||
bool hasContainingCsect() const { return ContainingCsect != nullptr; }
|
bool hasContainingCsect() const { return ContainingCsect != nullptr; }
|
||||||
|
|
||||||
|
StringRef getUnqualifiedName() const {
|
||||||
|
const StringRef name = getName();
|
||||||
|
if (name.back() == ']') {
|
||||||
|
StringRef lhs, rhs;
|
||||||
|
std::tie(lhs, rhs) = name.rsplit('[');
|
||||||
|
assert(!rhs.empty() && "Invalid SMC format in XCOFF symbol.");
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Optional<XCOFF::StorageClass> StorageClass;
|
Optional<XCOFF::StorageClass> StorageClass;
|
||||||
MCSectionXCOFF *ContainingCsect = nullptr;
|
MCSectionXCOFF *ContainingCsect = nullptr;
|
||||||
|
|
|
@ -24,6 +24,10 @@ StringRef XCOFF::getMappingClassString(XCOFF::StorageMappingClass SMC) {
|
||||||
return "BS";
|
return "BS";
|
||||||
case XCOFF::XMC_RO:
|
case XCOFF::XMC_RO:
|
||||||
return "RO";
|
return "RO";
|
||||||
|
case XCOFF::XMC_UA:
|
||||||
|
return "UA";
|
||||||
|
case XCOFF::XMC_TC:
|
||||||
|
return "TC";
|
||||||
default:
|
default:
|
||||||
report_fatal_error("Unhandled storage-mapping class.");
|
report_fatal_error("Unhandled storage-mapping class.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,8 @@ void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
|
||||||
case XCOFF::XMC_DS:
|
case XCOFF::XMC_DS:
|
||||||
OS << "\t.csect " << QualName->getName() << '\n';
|
OS << "\t.csect " << QualName->getName() << '\n';
|
||||||
break;
|
break;
|
||||||
|
case XCOFF::XMC_TC:
|
||||||
|
break;
|
||||||
case XCOFF::XMC_TC0:
|
case XCOFF::XMC_TC0:
|
||||||
OS << "\t.toc\n";
|
OS << "\t.toc\n";
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -87,4 +87,5 @@ PPCXCOFFMCAsmInfo::PPCXCOFFMCAsmInfo(bool Is64Bit, const Triple &T) {
|
||||||
assert(!IsLittleEndian && "Little-endian XCOFF not supported.");
|
assert(!IsLittleEndian && "Little-endian XCOFF not supported.");
|
||||||
CodePointerSize = CalleeSaveStackSlotSize = Is64Bit ? 8 : 4;
|
CodePointerSize = CalleeSaveStackSlotSize = Is64Bit ? 8 : 4;
|
||||||
ZeroDirective = "\t.space\t";
|
ZeroDirective = "\t.space\t";
|
||||||
|
SymbolsHaveSMC = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "llvm/MC/MCSubtargetInfo.h"
|
#include "llvm/MC/MCSubtargetInfo.h"
|
||||||
#include "llvm/MC/MCSymbol.h"
|
#include "llvm/MC/MCSymbol.h"
|
||||||
#include "llvm/MC/MCSymbolELF.h"
|
#include "llvm/MC/MCSymbolELF.h"
|
||||||
|
#include "llvm/MC/MCSymbolXCOFF.h"
|
||||||
#include "llvm/Support/Casting.h"
|
#include "llvm/Support/Casting.h"
|
||||||
#include "llvm/Support/CodeGen.h"
|
#include "llvm/Support/CodeGen.h"
|
||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
|
@ -108,8 +109,11 @@ public:
|
||||||
: PPCTargetStreamer(S), OS(OS) {}
|
: PPCTargetStreamer(S), OS(OS) {}
|
||||||
|
|
||||||
void emitTCEntry(const MCSymbol &S) override {
|
void emitTCEntry(const MCSymbol &S) override {
|
||||||
|
const MCAsmInfo *MAI = Streamer.getContext().getAsmInfo();
|
||||||
OS << "\t.tc ";
|
OS << "\t.tc ";
|
||||||
OS << S.getName();
|
OS << (MAI->getSymbolsHaveSMC()
|
||||||
|
? cast<MCSymbolXCOFF>(S).getUnqualifiedName()
|
||||||
|
: S.getName());
|
||||||
OS << "[TC],";
|
OS << "[TC],";
|
||||||
OS << S.getName();
|
OS << S.getName();
|
||||||
OS << '\n';
|
OS << '\n';
|
||||||
|
@ -243,7 +247,7 @@ public:
|
||||||
PPCTargetXCOFFStreamer(MCStreamer &S) : PPCTargetStreamer(S) {}
|
PPCTargetXCOFFStreamer(MCStreamer &S) : PPCTargetStreamer(S) {}
|
||||||
|
|
||||||
void emitTCEntry(const MCSymbol &S) override {
|
void emitTCEntry(const MCSymbol &S) override {
|
||||||
report_fatal_error("TOC entries not supported yet.");
|
// Object writing TOC entries not supported yet.
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitMachine(StringRef CPU) override {
|
void emitMachine(StringRef CPU) override {
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
|
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
|
||||||
#include "llvm/IR/DataLayout.h"
|
#include "llvm/IR/DataLayout.h"
|
||||||
#include "llvm/IR/GlobalValue.h"
|
#include "llvm/IR/GlobalValue.h"
|
||||||
|
#include "llvm/IR/GlobalVariable.h"
|
||||||
#include "llvm/IR/Module.h"
|
#include "llvm/IR/Module.h"
|
||||||
#include "llvm/MC/MCAsmInfo.h"
|
#include "llvm/MC/MCAsmInfo.h"
|
||||||
#include "llvm/MC/MCContext.h"
|
#include "llvm/MC/MCContext.h"
|
||||||
|
@ -82,6 +83,8 @@ protected:
|
||||||
const PPCSubtarget *Subtarget = nullptr;
|
const PPCSubtarget *Subtarget = nullptr;
|
||||||
StackMaps SM;
|
StackMaps SM;
|
||||||
|
|
||||||
|
virtual MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PPCAsmPrinter(TargetMachine &TM,
|
explicit PPCAsmPrinter(TargetMachine &TM,
|
||||||
std::unique_ptr<MCStreamer> Streamer)
|
std::unique_ptr<MCStreamer> Streamer)
|
||||||
|
@ -161,6 +164,11 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class PPCAIXAsmPrinter : public PPCAsmPrinter {
|
class PPCAIXAsmPrinter : public PPCAsmPrinter {
|
||||||
|
private:
|
||||||
|
static void ValidateGV(const GlobalVariable *GV);
|
||||||
|
protected:
|
||||||
|
MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PPCAIXAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
|
PPCAIXAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
|
||||||
: PPCAsmPrinter(TM, std::move(Streamer)) {}
|
: PPCAsmPrinter(TM, std::move(Streamer)) {}
|
||||||
|
@ -514,17 +522,16 @@ void PPCAsmPrinter::EmitTlsCall(const MachineInstr *MI,
|
||||||
|
|
||||||
/// Map a machine operand for a TOC pseudo-machine instruction to its
|
/// Map a machine operand for a TOC pseudo-machine instruction to its
|
||||||
/// corresponding MCSymbol.
|
/// corresponding MCSymbol.
|
||||||
static MCSymbol *getMCSymbolForTOCPseudoMO(const MachineOperand &MO,
|
MCSymbol *PPCAsmPrinter::getMCSymbolForTOCPseudoMO(const MachineOperand &MO) {
|
||||||
AsmPrinter &AP) {
|
|
||||||
switch (MO.getType()) {
|
switch (MO.getType()) {
|
||||||
case MachineOperand::MO_GlobalAddress:
|
case MachineOperand::MO_GlobalAddress:
|
||||||
return AP.getSymbol(MO.getGlobal());
|
return getSymbol(MO.getGlobal());
|
||||||
case MachineOperand::MO_ConstantPoolIndex:
|
case MachineOperand::MO_ConstantPoolIndex:
|
||||||
return AP.GetCPISymbol(MO.getIndex());
|
return GetCPISymbol(MO.getIndex());
|
||||||
case MachineOperand::MO_JumpTableIndex:
|
case MachineOperand::MO_JumpTableIndex:
|
||||||
return AP.GetJTISymbol(MO.getIndex());
|
return GetJTISymbol(MO.getIndex());
|
||||||
case MachineOperand::MO_BlockAddress:
|
case MachineOperand::MO_BlockAddress:
|
||||||
return AP.GetBlockAddressSymbol(MO.getBlockAddress());
|
return GetBlockAddressSymbol(MO.getBlockAddress());
|
||||||
default:
|
default:
|
||||||
llvm_unreachable("Unexpected operand type to get symbol.");
|
llvm_unreachable("Unexpected operand type to get symbol.");
|
||||||
}
|
}
|
||||||
|
@ -688,7 +695,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||||
"Invalid operand for LWZtoc.");
|
"Invalid operand for LWZtoc.");
|
||||||
|
|
||||||
// Map the operand to its corresponding MCSymbol.
|
// Map the operand to its corresponding MCSymbol.
|
||||||
const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
|
const MCSymbol *const MOSymbol = getMCSymbolForTOCPseudoMO(MO);
|
||||||
|
|
||||||
// Create a reference to the GOT entry for the symbol. The GOT entry will be
|
// Create a reference to the GOT entry for the symbol. The GOT entry will be
|
||||||
// synthesized later.
|
// synthesized later.
|
||||||
|
@ -749,7 +756,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||||
// global address operand to be a reference to the TOC entry we will
|
// global address operand to be a reference to the TOC entry we will
|
||||||
// synthesize later.
|
// synthesize later.
|
||||||
MCSymbol *TOCEntry =
|
MCSymbol *TOCEntry =
|
||||||
lookUpOrCreateTOCEntry(getMCSymbolForTOCPseudoMO(MO, *this));
|
lookUpOrCreateTOCEntry(getMCSymbolForTOCPseudoMO(MO));
|
||||||
|
|
||||||
const MCSymbolRefExpr::VariantKind VK =
|
const MCSymbolRefExpr::VariantKind VK =
|
||||||
IsAIX ? MCSymbolRefExpr::VK_None : MCSymbolRefExpr::VK_PPC_TOC;
|
IsAIX ? MCSymbolRefExpr::VK_None : MCSymbolRefExpr::VK_PPC_TOC;
|
||||||
|
@ -775,7 +782,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||||
"Invalid operand for ADDIStocHA.");
|
"Invalid operand for ADDIStocHA.");
|
||||||
|
|
||||||
// Map the machine operand to its corresponding MCSymbol.
|
// Map the machine operand to its corresponding MCSymbol.
|
||||||
MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
|
MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO);
|
||||||
|
|
||||||
// Always use TOC on AIX. Map the global address operand to be a reference
|
// Always use TOC on AIX. Map the global address operand to be a reference
|
||||||
// to the TOC entry we will synthesize later. 'TOCEntry' is a label used to
|
// to the TOC entry we will synthesize later. 'TOCEntry' is a label used to
|
||||||
|
@ -805,7 +812,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||||
"Invalid operand for LWZtocL.");
|
"Invalid operand for LWZtocL.");
|
||||||
|
|
||||||
// Map the machine operand to its corresponding MCSymbol.
|
// Map the machine operand to its corresponding MCSymbol.
|
||||||
MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
|
MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO);
|
||||||
|
|
||||||
// Always use TOC on AIX. Map the global address operand to be a reference
|
// Always use TOC on AIX. Map the global address operand to be a reference
|
||||||
// to the TOC entry we will synthesize later. 'TOCEntry' is a label used to
|
// to the TOC entry we will synthesize later. 'TOCEntry' is a label used to
|
||||||
|
@ -835,7 +842,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||||
assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
|
assert((MO.isGlobal() || MO.isCPI() || MO.isJTI() || MO.isBlockAddress()) &&
|
||||||
"Invalid operand for ADDIStocHA8!");
|
"Invalid operand for ADDIStocHA8!");
|
||||||
|
|
||||||
const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
|
const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO);
|
||||||
|
|
||||||
const bool GlobalToc =
|
const bool GlobalToc =
|
||||||
MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal());
|
MO.isGlobal() && Subtarget->isGVIndirectSymbol(MO.getGlobal());
|
||||||
|
@ -881,7 +888,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||||
"LDtocL used on symbol that could be accessed directly is "
|
"LDtocL used on symbol that could be accessed directly is "
|
||||||
"invalid. Must match ADDIStocHA8."));
|
"invalid. Must match ADDIStocHA8."));
|
||||||
|
|
||||||
const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO, *this);
|
const MCSymbol *MOSymbol = getMCSymbolForTOCPseudoMO(MO);
|
||||||
|
|
||||||
if (!MO.isCPI() || TM.getCodeModel() == CodeModel::Large)
|
if (!MO.isCPI() || TM.getCodeModel() == CodeModel::Large)
|
||||||
MOSymbol = lookUpOrCreateTOCEntry(MOSymbol);
|
MOSymbol = lookUpOrCreateTOCEntry(MOSymbol);
|
||||||
|
@ -911,7 +918,7 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||||
"Interposable definitions must use indirect access."));
|
"Interposable definitions must use indirect access."));
|
||||||
|
|
||||||
const MCExpr *Exp =
|
const MCExpr *Exp =
|
||||||
MCSymbolRefExpr::create(getMCSymbolForTOCPseudoMO(MO, *this),
|
MCSymbolRefExpr::create(getMCSymbolForTOCPseudoMO(MO),
|
||||||
MCSymbolRefExpr::VK_PPC_TOC_LO, OutContext);
|
MCSymbolRefExpr::VK_PPC_TOC_LO, OutContext);
|
||||||
TmpInst.getOperand(2) = MCOperand::createExpr(Exp);
|
TmpInst.getOperand(2) = MCOperand::createExpr(Exp);
|
||||||
EmitToStreamer(*OutStreamer, TmpInst);
|
EmitToStreamer(*OutStreamer, TmpInst);
|
||||||
|
@ -1736,7 +1743,7 @@ void PPCAIXAsmPrinter::SetupMachineFunction(MachineFunction &MF) {
|
||||||
return AsmPrinter::SetupMachineFunction(MF);
|
return AsmPrinter::SetupMachineFunction(MF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
|
void PPCAIXAsmPrinter::ValidateGV(const GlobalVariable *GV) {
|
||||||
// Early error checking limiting what is supported.
|
// Early error checking limiting what is supported.
|
||||||
if (GV->isThreadLocal())
|
if (GV->isThreadLocal())
|
||||||
report_fatal_error("Thread local not yet supported on AIX.");
|
report_fatal_error("Thread local not yet supported on AIX.");
|
||||||
|
@ -1746,6 +1753,19 @@ void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
|
||||||
|
|
||||||
if (GV->hasComdat())
|
if (GV->hasComdat())
|
||||||
report_fatal_error("COMDAT not yet supported by AIX.");
|
report_fatal_error("COMDAT not yet supported by AIX.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
|
||||||
|
ValidateGV(GV);
|
||||||
|
|
||||||
|
// External global variables are already handled.
|
||||||
|
if (!GV->hasInitializer())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Create the symbol, set its storage class.
|
||||||
|
MCSymbolXCOFF *GVSym = cast<MCSymbolXCOFF>(getSymbol(GV));
|
||||||
|
GVSym->setStorageClass(
|
||||||
|
TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GV));
|
||||||
|
|
||||||
SectionKind GVKind = getObjFileLowering().getKindForGlobal(GV, TM);
|
SectionKind GVKind = getObjFileLowering().getKindForGlobal(GV, TM);
|
||||||
if ((!GVKind.isCommon() && !GVKind.isBSS() && !GVKind.isData() &&
|
if ((!GVKind.isCommon() && !GVKind.isBSS() && !GVKind.isData() &&
|
||||||
|
@ -1759,11 +1779,6 @@ void PPCAIXAsmPrinter::EmitGlobalVariable(const GlobalVariable *GV) {
|
||||||
MCSectionXCOFF *Csect = cast<MCSectionXCOFF>(
|
MCSectionXCOFF *Csect = cast<MCSectionXCOFF>(
|
||||||
getObjFileLowering().SectionForGlobal(GV, GVKind, TM));
|
getObjFileLowering().SectionForGlobal(GV, GVKind, TM));
|
||||||
OutStreamer->SwitchSection(Csect);
|
OutStreamer->SwitchSection(Csect);
|
||||||
|
|
||||||
// Create the symbol, set its storage class, and emit it.
|
|
||||||
MCSymbolXCOFF *GVSym = cast<MCSymbolXCOFF>(getSymbol(GV));
|
|
||||||
GVSym->setStorageClass(
|
|
||||||
TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GV));
|
|
||||||
GVSym->setContainingCsect(Csect);
|
GVSym->setContainingCsect(Csect);
|
||||||
|
|
||||||
const DataLayout &DL = GV->getParent()->getDataLayout();
|
const DataLayout &DL = GV->getParent()->getDataLayout();
|
||||||
|
@ -1802,7 +1817,10 @@ void PPCAIXAsmPrinter::EmitFunctionDescriptor() {
|
||||||
OutStreamer->EmitValue(MCSymbolRefExpr::create(CurrentFnSym, OutContext),
|
OutStreamer->EmitValue(MCSymbolRefExpr::create(CurrentFnSym, OutContext),
|
||||||
PointerSize);
|
PointerSize);
|
||||||
// Emit TOC base address.
|
// Emit TOC base address.
|
||||||
MCSymbol *TOCBaseSym = OutContext.getOrCreateSymbol(StringRef("TOC[TC0]"));
|
const MCSectionXCOFF *TOCBaseSec = OutStreamer->getContext().getXCOFFSection(
|
||||||
|
StringRef("TOC"), XCOFF::XMC_TC0, XCOFF::XTY_SD, XCOFF::C_HIDEXT,
|
||||||
|
SectionKind::getData());
|
||||||
|
const MCSymbol *TOCBaseSym = TOCBaseSec->getQualNameSymbol();
|
||||||
OutStreamer->EmitValue(MCSymbolRefExpr::create(TOCBaseSym, OutContext),
|
OutStreamer->EmitValue(MCSymbolRefExpr::create(TOCBaseSym, OutContext),
|
||||||
PointerSize);
|
PointerSize);
|
||||||
// Emit a null environment pointer.
|
// Emit a null environment pointer.
|
||||||
|
@ -1823,8 +1841,80 @@ void PPCAIXAsmPrinter::EmitEndOfAsmFile(Module &M) {
|
||||||
SectionKind::getData());
|
SectionKind::getData());
|
||||||
// Switch to section to emit TOC base.
|
// Switch to section to emit TOC base.
|
||||||
OutStreamer->SwitchSection(TOCBaseSection);
|
OutStreamer->SwitchSection(TOCBaseSection);
|
||||||
|
|
||||||
|
PPCTargetStreamer &TS =
|
||||||
|
static_cast<PPCTargetStreamer &>(*OutStreamer->getTargetStreamer());
|
||||||
|
|
||||||
|
for (auto &I : TOC) {
|
||||||
|
// Setup the csect for the current TC entry.
|
||||||
|
MCSectionXCOFF *TCEntry = OutStreamer->getContext().getXCOFFSection(
|
||||||
|
cast<MCSymbolXCOFF>(I.first)->getUnqualifiedName(), XCOFF::XMC_TC,
|
||||||
|
XCOFF::XTY_SD, XCOFF::C_HIDEXT, SectionKind::getData());
|
||||||
|
cast<MCSymbolXCOFF>(I.second)->setContainingCsect(TCEntry);
|
||||||
|
OutStreamer->SwitchSection(TCEntry);
|
||||||
|
|
||||||
|
OutStreamer->EmitLabel(I.second);
|
||||||
|
TS.emitTCEntry(*I.first);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MCSymbol *
|
||||||
|
PPCAIXAsmPrinter::getMCSymbolForTOCPseudoMO(const MachineOperand &MO) {
|
||||||
|
const GlobalObject *GO = nullptr;
|
||||||
|
|
||||||
|
// If the MO is a function or certain kind of globals, we want to make sure to
|
||||||
|
// refer to the csect symbol, otherwise we can just do the default handling.
|
||||||
|
if (MO.getType() != MachineOperand::MO_GlobalAddress ||
|
||||||
|
!(GO = dyn_cast<const GlobalObject>(MO.getGlobal())))
|
||||||
|
return PPCAsmPrinter::getMCSymbolForTOCPseudoMO(MO);
|
||||||
|
|
||||||
|
// Do an early error check for globals we don't support. This will go away
|
||||||
|
// eventually.
|
||||||
|
const auto *GV = dyn_cast<const GlobalVariable>(GO);
|
||||||
|
if (GV) {
|
||||||
|
ValidateGV(GV);
|
||||||
|
}
|
||||||
|
|
||||||
|
MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(getSymbol(GO));
|
||||||
|
|
||||||
|
// If the global object is a global variable without initializer or is a
|
||||||
|
// declaration of a function, then XSym is an external referenced symbol.
|
||||||
|
// Hence we may need to explictly create a MCSectionXCOFF for it so that we
|
||||||
|
// can return its symbol later.
|
||||||
|
if (GO->isDeclaration() && !XSym->hasContainingCsect()) {
|
||||||
|
// Make sure the storage class is set.
|
||||||
|
const XCOFF::StorageClass SC =
|
||||||
|
TargetLoweringObjectFileXCOFF::getStorageClassForGlobal(GO);
|
||||||
|
XSym->setStorageClass(SC);
|
||||||
|
|
||||||
|
MCSectionXCOFF *Csect = OutStreamer->getContext().getXCOFFSection(
|
||||||
|
XSym->getName(), isa<Function>(GO) ? XCOFF::XMC_DS : XCOFF::XMC_UA,
|
||||||
|
XCOFF::XTY_ER, SC, SectionKind::getMetadata());
|
||||||
|
XSym->setContainingCsect(Csect);
|
||||||
|
|
||||||
|
return Csect->getQualNameSymbol();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle initialized global variables.
|
||||||
|
if (GV) {
|
||||||
|
SectionKind GVKind = getObjFileLowering().getKindForGlobal(GV, TM);
|
||||||
|
|
||||||
|
// If the operand is a common then we should refer to the csect symbol.
|
||||||
|
if (GVKind.isCommon() || GVKind.isBSSLocal()) {
|
||||||
|
MCSectionXCOFF *Csect = cast<MCSectionXCOFF>(
|
||||||
|
getObjFileLowering().SectionForGlobal(GV, GVKind, TM));
|
||||||
|
return Csect->getQualNameSymbol();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other global variables are refered to by labels inside of a single csect,
|
||||||
|
// so refer to the label directly.
|
||||||
|
return getSymbol(GV);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the MO is a function, we want to make sure to refer to the function
|
||||||
|
// descriptor csect.
|
||||||
|
return XSym->getContainingCsect()->getQualNameSymbol();
|
||||||
|
}
|
||||||
|
|
||||||
/// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code
|
/// createPPCAsmPrinterPass - Returns a pass that prints the PPC assembly code
|
||||||
/// for a MachineFunction to the given output stream, in a format that the
|
/// for a MachineFunction to the given output stream, in a format that the
|
||||||
|
|
|
@ -69,4 +69,4 @@ __here:
|
||||||
; 64LARGE-ASM: ld [[REG2:[0-9]+]], LC0@l([[REG1]])
|
; 64LARGE-ASM: ld [[REG2:[0-9]+]], LC0@l([[REG1]])
|
||||||
|
|
||||||
; CHECK: .toc
|
; CHECK: .toc
|
||||||
; CHECK-NOT: .tc
|
; CHECK: .tc Ltmp0[TC],Ltmp0
|
||||||
|
|
|
@ -84,4 +84,4 @@ entry:
|
||||||
; 64LARGE-ASM: blr
|
; 64LARGE-ASM: blr
|
||||||
|
|
||||||
; CHECK: .toc
|
; CHECK: .toc
|
||||||
; CHECK-NOT: .tc
|
; CHECK: .tc .LCPI0_0[TC],.LCPI0_0
|
||||||
|
|
|
@ -185,4 +185,4 @@
|
||||||
; 64LARGE-ASM: .long LBB0_5-.LJTI0_0
|
; 64LARGE-ASM: .long LBB0_5-.LJTI0_0
|
||||||
|
|
||||||
; CHECK: .toc
|
; CHECK: .toc
|
||||||
; CHECK-NOT: .tc
|
; CHECK: .tc .LJTI0_0[TC],.LJTI0_0
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
; RUN: llc -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck %s
|
||||||
|
; RUN: llc -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
@a = external global i32, align 4
|
||||||
|
@b = external global i64, align 8
|
||||||
|
@c = external global i16, align 2
|
||||||
|
@globa = common global i32 0, align 4
|
||||||
|
|
||||||
|
@ptr = internal global void (...)* null, align 4
|
||||||
|
|
||||||
|
; CHECK-NOT: .toc
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
; RUN: llc -verify-machineinstrs -mcpu=pwr7 -mtriple powerpc-ibm-aix-xcoff < %s | FileCheck --check-prefixes CHECK,CHECK32 %s
|
||||||
|
; RUN: llc -verify-machineinstrs -mcpu=pwr7 -mtriple powerpc64-ibm-aix-xcoff < %s 2>&1 | FileCheck --check-prefixes CHECK,CHECK64 %s
|
||||||
|
|
||||||
|
@a = external global i32, align 4
|
||||||
|
@b = external global i64, align 8
|
||||||
|
@c = external global i16, align 2
|
||||||
|
@globa = common global i32 0, align 4
|
||||||
|
|
||||||
|
@ptr = internal global void (...)* null, align 4
|
||||||
|
|
||||||
|
declare void @foo()
|
||||||
|
|
||||||
|
define void @bar() {
|
||||||
|
%1 = alloca i8*, align 8
|
||||||
|
store i32 0, i32* @a, align 4
|
||||||
|
store i64 0, i64* @b, align 8
|
||||||
|
store i16 0, i16* @c, align 2
|
||||||
|
store i32 0, i32* @globa, align 4
|
||||||
|
store void (...)* bitcast (void ()* @bar to void (...)*), void (...)** @ptr, align 4
|
||||||
|
store i8* bitcast (void ()* @foo to i8*), i8** %1, align 8
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK-NOT: .comm a
|
||||||
|
; CHECK-NOT: .lcomm a
|
||||||
|
; CHECK-NOT: .comm b
|
||||||
|
; CHECK-NOT: .lcomm b
|
||||||
|
; CHECK-NOT: .comm c
|
||||||
|
; CHECK-NOT: .lcomm c
|
||||||
|
; CHECK: .comm globa[RW],4,2
|
||||||
|
; CHECK32: .lcomm ptr,4,ptr[BS],2
|
||||||
|
; CHECK64: .lcomm ptr,8,ptr[BS],2
|
||||||
|
; CHECK: .toc
|
||||||
|
; CHECK-NEXT: LC0:
|
||||||
|
; CHECK-NEXT: .tc a[TC],a[UA]
|
||||||
|
; CHECK-NEXT: LC1:
|
||||||
|
; CHECK-NEXT: .tc b[TC],b[UA]
|
||||||
|
; CHECK-NEXT: LC2:
|
||||||
|
; CHECK-NEXT: .tc c[TC],c[UA]
|
||||||
|
; CHECK-NEXT: LC3:
|
||||||
|
; CHECK-NEXT: .tc globa[TC],globa[RW]
|
||||||
|
; CHECK-NEXT: LC4:
|
||||||
|
; CHECK-NEXT: .tc ptr[TC],ptr[BS]
|
||||||
|
; CHECK-NEXT: LC5:
|
||||||
|
; CHECK-NEXT: .tc bar[TC],bar[DS]
|
||||||
|
; CHECK-NEXT: LC6:
|
||||||
|
; CHECK-NEXT: .tc foo[TC],foo[DS]
|
||||||
|
|
|
@ -41,5 +41,5 @@ define void @test_store(i32 %0) {
|
||||||
; LARGE: stw [[REG3:[0-9]+]], 0([[REG2]])
|
; LARGE: stw [[REG3:[0-9]+]], 0([[REG2]])
|
||||||
; LARGE: blr
|
; LARGE: blr
|
||||||
|
|
||||||
; TODO Update test when TOC-entry emission lands.
|
; CHECK: .tc a[TC],a
|
||||||
; CHECK-NOT: .tc
|
; CHECK: .tc b[TC],b
|
||||||
|
|
|
@ -41,5 +41,5 @@ define void @test_store(i32 zeroext %0) {
|
||||||
; LARGE: stw [[REG3:[0-9]+]], 0([[REG2]])
|
; LARGE: stw [[REG3:[0-9]+]], 0([[REG2]])
|
||||||
; LARGE: blr
|
; LARGE: blr
|
||||||
|
|
||||||
; TODO Update test when TOC-entry emission lands.
|
; CHECK: .tc a[TC],a
|
||||||
; CHECK-NOT: .tc
|
; CHECK: .tc b[TC],b
|
||||||
|
|
Loading…
Reference in New Issue