#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/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
using namespace llvm;
void TargetLoweringObjectFile::Initialize(MCContext &ctx,
const TargetMachine &TM) {
Ctx = &ctx;
delete Mang;
Mang = new Mangler();
InitMCObjectFileInfo(TM.getTargetTriple(), TM.isPositionIndependent(), *Ctx,
TM.getCodeModel() == CodeModel::Large);
}
TargetLoweringObjectFile::~TargetLoweringObjectFile() {
delete Mang;
}
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 Ctx->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 {
}
SectionKind TargetLoweringObjectFile::getKindForGlobal(const GlobalObject *GO,
const TargetMachine &TM){
assert(!GO->isDeclaration() && !GO->hasAvailableExternallyLinkage() &&
"Can only be used for global definitions");
if (isa<Function>(GO))
return SectionKind::getText();
const auto *GVar = cast<GlobalVariable>(GO);
if (GVar->isThreadLocal()) {
if (isSuitableForBSS(GVar) && !TM.Options.NoZerosInBSS)
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->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)
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("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::getSectionForJumpTable(
const Function &F, const TargetMachine &TM) const {
unsigned Align = 0;
return getSectionForConstant(F.getParent()->getDataLayout(),
SectionKind::getReadOnly(), nullptr,
Align);
}
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,
unsigned &Align) const {
if (Kind.isReadOnly() && ReadOnlySection != nullptr)
return ReadOnlySection;
return DataSection;
}
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, *Ctx);
}
void TargetLoweringObjectFile::getNameWithPrefix(
SmallVectorImpl<char> &OutName, const GlobalValue *GV,
const TargetMachine &TM) const {
Mang->getNameWithPrefix(OutName, GV, false);
}