#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/SectionKind.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
using namespace llvm;
void TargetLoweringObjectFile::Initialize(MCContext &ctx,
const TargetMachine &TM) {
delete Mang;
Mang = new Mangler();
initMCObjectFileInfo(ctx, TM.isPositionIndependent(),
TM.getCodeModel() == CodeModel::Large);
PersonalityEncoding = LSDAEncoding = TTypeEncoding = dwarf::DW_EH_PE_absptr;
CallSiteEncoding = dwarf::DW_EH_PE_uleb128;
this->TM = &TM;
}
TargetLoweringObjectFile::~TargetLoweringObjectFile() {
delete Mang;
}
unsigned TargetLoweringObjectFile::getCallSiteEncoding() const {
if (!getContext().getAsmInfo()->hasLEB128Directives())
return dwarf::DW_EH_PE_udata4;
return CallSiteEncoding;
}
static bool isNullOrUndef(const Constant *C) {
if (C->isNullValue() || isa<UndefValue>(C))
return true;
if (!isa<ConstantAggregate>(C))
return false;
for (auto Operand : C->operand_values()) {
if (!isNullOrUndef(cast<Constant>(Operand)))
return false;
}
return true;
}
static bool isSuitableForBSS(const GlobalVariable *GV) {
const Constant *C = GV->getInitializer();
if (!isNullOrUndef(C))
return false;
if (GV->isConstant())
return false;
if (GV->hasSection())
return false;
return true;
}
static bool IsNullTerminatedString(const Constant *C) {
if (const ConstantDataSequential *CDS = dyn_cast<ConstantDataSequential>(C)) {
unsigned NumElts = CDS->getNumElements();
assert(NumElts != 0 && "Can't have an empty CDS");
if (CDS->getElementAsInteger(NumElts-1) != 0)
return false;
for (unsigned i = 0; i != NumElts-1; ++i)
if (CDS->getElementAsInteger(i) == 0)
return false;
return true;
}
if (isa<ConstantAggregateZero>(C))
return cast<ArrayType>(C->getType())->getNumElements() == 1;
return false;
}
MCSymbol *TargetLoweringObjectFile::getSymbolWithGlobalValueBase(
const GlobalValue *GV, StringRef Suffix, const TargetMachine &TM) const {
assert(!Suffix.empty());
SmallString<60> NameStr;
NameStr += GV->getParent()->getDataLayout().getPrivateGlobalPrefix();
TM.getNameWithPrefix(NameStr, GV, *Mang);
NameStr.append(Suffix.begin(), Suffix.end());
return getContext().getOrCreateSymbol(NameStr);
}
MCSymbol *TargetLoweringObjectFile::getCFIPersonalitySymbol(
const GlobalValue *GV, const TargetMachine &TM,
MachineModuleInfo *MMI) const {
return TM.getSymbol(GV);
}
void TargetLoweringObjectFile::emitPersonalityValue(MCStreamer &Streamer,
const DataLayout &,
const MCSymbol *Sym) const {
}
void TargetLoweringObjectFile::emitCGProfileMetadata(MCStreamer &Streamer,
Module &M) const {
MCContext &C = getContext();
SmallVector<Module::ModuleFlagEntry, 8> ModuleFlags;
M.getModuleFlagsMetadata(ModuleFlags);
MDNode *CFGProfile = nullptr;
for (const auto &MFE : ModuleFlags) {
StringRef Key = MFE.Key->getString();
if (Key == "CG Profile") {
CFGProfile = cast<MDNode>(MFE.Val);
break;
}
}
if (!CFGProfile)
return;
auto GetSym = [this](const MDOperand &MDO) -> MCSymbol * {
if (!MDO)
return nullptr;
auto *V = cast<ValueAsMetadata>(MDO);
const Function *F = cast<Function>(V->getValue()->stripPointerCasts());
if (F->hasDLLImportStorageClass())
return nullptr;
return TM->getSymbol(F);
};
for (const auto &Edge : CFGProfile->operands()) {
MDNode *E = cast<MDNode>(Edge);
const MCSymbol *From = GetSym(E->getOperand(0));
const MCSymbol *To = GetSym(E->getOperand(1));
if (!From || !To)
continue;
uint64_t Count = cast<ConstantAsMetadata>(E->getOperand(2))
->getValue()
->getUniqueInteger()
.getZExtValue();
Streamer.emitCGProfileEntry(
MCSymbolRefExpr::create(From, MCSymbolRefExpr::VK_None, C),
MCSymbolRefExpr::create(To, MCSymbolRefExpr::VK_None, C), Count);
}
}
SectionKind TargetLoweringObjectFile::getKindForGlobal(const GlobalObject *GO,
const TargetMachine &TM){
assert(!GO->isDeclarationForLinker() &&
"Can only be used for global definitions");
if (isa<Function>(GO))
return SectionKind::getText();
if (isa<BasicBlock>(GO))
return SectionKind::getText();
const auto *GVar = cast<GlobalVariable>(GO);
if (GVar->isThreadLocal()) {
if (isSuitableForBSS(GVar) && !TM.Options.NoZerosInBSS) {
if (GVar->hasLocalLinkage()) {
return SectionKind::getThreadBSSLocal();
}
return SectionKind::getThreadBSS();
}
return SectionKind::getThreadData();
}
if (GVar->hasCommonLinkage())
return SectionKind::getCommon();
if (isSuitableForBSS(GVar) && !TM.Options.NoZerosInBSS) {
if (GVar->hasLocalLinkage())
return SectionKind::getBSSLocal();
else if (GVar->hasExternalLinkage())
return SectionKind::getBSSExtern();
return SectionKind::getBSS();
}
if (GVar->hasSection())
if (MDNode *MD = GVar->getMetadata(LLVMContext::MD_exclude))
if (!MD->getNumOperands())
return SectionKind::getExclude();
if (GVar->isConstant()) {
const Constant *C = GVar->getInitializer();
if (!C->needsRelocation()) {
if (!GVar->hasGlobalUnnamedAddr())
return SectionKind::getReadOnly();
if (ArrayType *ATy = dyn_cast<ArrayType>(C->getType())) {
if (IntegerType *ITy =
dyn_cast<IntegerType>(ATy->getElementType())) {
if ((ITy->getBitWidth() == 8 || ITy->getBitWidth() == 16 ||
ITy->getBitWidth() == 32) &&
IsNullTerminatedString(C)) {
if (ITy->getBitWidth() == 8)
return SectionKind::getMergeable1ByteCString();
if (ITy->getBitWidth() == 16)
return SectionKind::getMergeable2ByteCString();
assert(ITy->getBitWidth() == 32 && "Unknown width");
return SectionKind::getMergeable4ByteCString();
}
}
}
switch (
GVar->getParent()->getDataLayout().getTypeAllocSize(C->getType())) {
case 4: return SectionKind::getMergeableConst4();
case 8: return SectionKind::getMergeableConst8();
case 16: return SectionKind::getMergeableConst16();
case 32: return SectionKind::getMergeableConst32();
default:
return SectionKind::getReadOnly();
}
} else {
Reloc::Model ReloModel = TM.getRelocationModel();
if (ReloModel == Reloc::Static || ReloModel == Reloc::ROPI ||
ReloModel == Reloc::RWPI || ReloModel == Reloc::ROPI_RWPI ||
!C->needsDynamicRelocation())
return SectionKind::getReadOnly();
return SectionKind::getReadOnlyWithRel();
}
}
return SectionKind::getData();
}
MCSection *TargetLoweringObjectFile::SectionForGlobal(
const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
if (GO->hasSection())
return getExplicitSectionGlobal(GO, Kind, TM);
if (auto *GVar = dyn_cast<GlobalVariable>(GO)) {
auto Attrs = GVar->getAttributes();
if ((Attrs.hasAttribute("bss-section") && Kind.isBSS()) ||
(Attrs.hasAttribute("data-section") && Kind.isData()) ||
(Attrs.hasAttribute("relro-section") && Kind.isReadOnlyWithRel()) ||
(Attrs.hasAttribute("rodata-section") && Kind.isReadOnly())) {
return getExplicitSectionGlobal(GO, Kind, TM);
}
}
if (auto *F = dyn_cast<Function>(GO)) {
if (F->hasFnAttribute("implicit-section-name"))
return getExplicitSectionGlobal(GO, Kind, TM);
}
return SelectSectionForGlobal(GO, Kind, TM);
}
MCSection *
TargetLoweringObjectFile::SectionForGlobal(const GlobalObject *GO,
const TargetMachine &TM) const {
return SectionForGlobal(GO, getKindForGlobal(GO, TM), TM);
}
MCSection *TargetLoweringObjectFile::getSectionForJumpTable(
const Function &F, const TargetMachine &TM) const {
Align Alignment(1);
return getSectionForConstant(F.getParent()->getDataLayout(),
SectionKind::getReadOnly(), nullptr,
Alignment);
}
bool TargetLoweringObjectFile::shouldPutJumpTableInFunctionSection(
bool UsesLabelDifference, const Function &F) const {
if (UsesLabelDifference)
return true;
return F.isWeakForLinker();
}
MCSection *TargetLoweringObjectFile::getSectionForConstant(
const DataLayout &DL, SectionKind Kind, const Constant *C,
Align &Alignment) const {
if (Kind.isReadOnly() && ReadOnlySection != nullptr)
return ReadOnlySection;
return DataSection;
}
MCSection *TargetLoweringObjectFile::getSectionForMachineBasicBlock(
const Function &F, const MachineBasicBlock &MBB,
const TargetMachine &TM) const {
return nullptr;
}
MCSection *TargetLoweringObjectFile::getUniqueSectionForFunction(
const Function &F, const TargetMachine &TM) const {
return nullptr;
}
const MCExpr *TargetLoweringObjectFile::getTTypeGlobalReference(
const GlobalValue *GV, unsigned Encoding, const TargetMachine &TM,
MachineModuleInfo *MMI, MCStreamer &Streamer) const {
const MCSymbolRefExpr *Ref =
MCSymbolRefExpr::create(TM.getSymbol(GV), getContext());
return getTTypeReference(Ref, Encoding, Streamer);
}
const MCExpr *TargetLoweringObjectFile::
getTTypeReference(const MCSymbolRefExpr *Sym, unsigned Encoding,
MCStreamer &Streamer) const {
switch (Encoding & 0x70) {
default:
report_fatal_error("We do not support this DWARF encoding yet!");
case dwarf::DW_EH_PE_absptr:
return Sym;
case dwarf::DW_EH_PE_pcrel: {
MCSymbol *PCSym = getContext().createTempSymbol();
Streamer.emitLabel(PCSym);
const MCExpr *PC = MCSymbolRefExpr::create(PCSym, getContext());
return MCBinaryExpr::createSub(Sym, PC, getContext());
}
}
}
const MCExpr *TargetLoweringObjectFile::getDebugThreadLocalSymbol(const MCSymbol *Sym) const {
return MCSymbolRefExpr::create(Sym, getContext());
}
void TargetLoweringObjectFile::getNameWithPrefix(
SmallVectorImpl<char> &OutName, const GlobalValue *GV,
const TargetMachine &TM) const {
Mang->getNameWithPrefix(OutName, GV, false);
}