Commit 8b1a7051 by John Porto

Fix a bug that would cause subzero to fail when --threads=0.

Creates a single TargetDataLowering. BUG= None R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1179313004.
parent 8e32fed5
......@@ -1256,7 +1256,10 @@ void CfgNode::profileExecutionCount(VariableDeclaration *Var) {
assert(Info != nullptr);
Operand *RMWI64Name = Context->getConstantExternSym(RMW_I64);
Constant *Counter = Context->getConstantExternSym(Var->getName());
constexpr RelocOffsetT Offset = 0;
constexpr bool SuppressMangling = true;
Constant *Counter =
Context->getConstantSym(Offset, Var->getName(), SuppressMangling);
Constant *AtomicRMWOp = Context->getConstantInt32(Intrinsics::AtomicAdd);
Constant *One = Context->getConstantInt64(1);
Constant *OrderAcquireRelease =
......
......@@ -141,21 +141,28 @@ void Compiler::run(const Ice::ClFlagsExtra &ExtraFlags, GlobalContext &Ctx,
}
Ctx.waitForWorkerThreads();
Translator->transferErrorCode();
Translator->emitConstants();
if (Ctx.getFlags().getOutFileType() == FT_Elf) {
TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx);
Ctx.getObjectWriter()->setUndefinedSyms(Ctx.getConstantExternSyms());
Ctx.getObjectWriter()->writeNonUserSections();
if (Translator->getErrorStatus()) {
Ctx.getErrorStatus()->assign(Translator->getErrorStatus().value());
} else {
Ctx.lowerGlobals("last");
Ctx.lowerProfileData();
Ctx.lowerConstants();
if (Ctx.getFlags().getOutFileType() == FT_Elf) {
TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx);
Ctx.getObjectWriter()->setUndefinedSyms(Ctx.getConstantExternSyms());
Ctx.getObjectWriter()->writeNonUserSections();
}
}
if (Ctx.getFlags().getSubzeroTimingEnabled())
Ctx.dumpTimers();
if (Ctx.getFlags().getTimeEachFunction()) {
const bool DumpCumulative = false;
Ctx.dumpTimers(GlobalContext::TSK_Funcs, DumpCumulative);
}
const bool FinalStats = true;
constexpr bool FinalStats = true;
Ctx.dumpStats("_FINAL_", FinalStats);
}
......
......@@ -285,7 +285,8 @@ void partitionGlobalsBySection(const VariableDeclarationList &Vars,
} // end of anonymous namespace
void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars,
FixupKind RelocationKind) {
FixupKind RelocationKind,
const IceString &SectionSuffix) {
assert(!SectionNumbersAssigned);
VariableDeclarationList VarsBySection[ELFObjectWriter::NumSectionTypes];
for (auto &SectionList : VarsBySection)
......@@ -294,18 +295,28 @@ void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars,
Ctx.getFlags().getTranslateOnly());
size_t I = 0;
for (auto &SectionList : VarsBySection) {
writeDataOfType(static_cast<SectionType>(I++), SectionList, RelocationKind);
writeDataOfType(static_cast<SectionType>(I++), SectionList, RelocationKind,
SectionSuffix);
}
}
namespace {
IceString MangleSectionName(const char Base[], const IceString &Suffix) {
if (Suffix.empty())
return Base;
return Base + ("." + Suffix);
}
} // end of anonymous namespace
// TODO(jvoung): Handle fdata-sections.
void ELFObjectWriter::writeDataOfType(SectionType ST,
const VariableDeclarationList &Vars,
FixupKind RelocationKind) {
FixupKind RelocationKind,
const IceString &SectionSuffix) {
if (Vars.empty())
return;
ELFDataSection *Section;
ELFRelocationSection *RelSection;
// TODO(jvoung): Handle fdata-sections.
IceString SectionName;
Elf64_Xword ShAddralign = 1;
for (VariableDeclaration *Var : Vars) {
......@@ -316,9 +327,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST,
// Lift this out, so it can be re-used if we do fdata-sections?
switch (ST) {
case ROData: {
SectionName = ".rodata";
// Only expecting to write the data sections all in one shot for now.
assert(RODataSections.empty());
const IceString SectionName = MangleSectionName(".rodata", SectionSuffix);
const Elf64_Xword ShFlags = SHF_ALLOC;
Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
ShAddralign, ShEntsize);
......@@ -329,8 +338,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST,
break;
}
case Data: {
SectionName = ".data";
assert(DataSections.empty());
const IceString SectionName = MangleSectionName(".data", SectionSuffix);
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
ShAddralign, ShEntsize);
......@@ -341,8 +349,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST,
break;
}
case BSS: {
SectionName = ".bss";
assert(BSSSections.empty());
const IceString SectionName = MangleSectionName(".bss", SectionSuffix);
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
Section = createSection<ELFDataSection>(SectionName, SHT_NOBITS, ShFlags,
ShAddralign, ShEntsize);
......@@ -383,9 +390,8 @@ void ELFObjectWriter::writeDataOfType(SectionType ST,
for (VariableDeclaration::Initializer *Init : Var->getInitializers()) {
switch (Init->getKind()) {
case VariableDeclaration::Initializer::DataInitializerKind: {
const auto Data =
llvm::cast<VariableDeclaration::DataInitializer>(Init)
->getContents();
const auto Data = llvm::cast<VariableDeclaration::DataInitializer>(
Init)->getContents();
Section->appendData(Str, llvm::StringRef(Data.data(), Data.size()));
break;
}
......
......@@ -30,11 +30,12 @@ namespace Ice {
// sections and write them out. Expected usage:
//
// (1) writeInitialELFHeader (invoke once)
// (2) writeDataSection (invoke once)
// (3) writeFunctionCode (must invoke once per function)
// (4) writeConstantPool (must invoke once per pooled primitive type)
// (5) setUndefinedSyms (invoke once)
// (6) writeNonUserSections (invoke once)
// (2) writeDataSection (may be invoked multiple times, as long as
// SectionSuffix is unique)
// (3) writeFunctionCode (must invoke once per function)
// (4) writeConstantPool (must invoke once per pooled primitive type)
// (5) setUndefinedSyms (invoke once)
// (6) writeNonUserSections (invoke once)
//
// The requirement for writeDataSection to be invoked only once can
// be relaxed if using -fdata-sections. The requirement to invoke only once
......@@ -42,11 +43,6 @@ namespace Ice {
// SectionType are contiguous in the file. With -fdata-sections, each global
// variable is in a separate section and therefore the sections will be
// trivially contiguous.
//
// The motivation for requiring that writeFunctionCode happen after
// writeDataSection: to keep the .text and .data sections contiguous in the
// file. Having both -fdata-sections and -ffunction-sections does allow
// relaxing this requirement.
class ELFObjectWriter {
ELFObjectWriter() = delete;
ELFObjectWriter(const ELFObjectWriter &) = delete;
......@@ -64,7 +60,8 @@ public:
// of each global's definition in the symbol table.
// Use the given target's RelocationKind for any relocations.
void writeDataSection(const VariableDeclarationList &Vars,
FixupKind RelocationKind);
FixupKind RelocationKind,
const IceString &SectionSuffix);
// Copy data of a function's text section to file and note the offset of the
// symbol's definition in the symbol table.
......@@ -151,7 +148,8 @@ private:
// SectionType, given the global variables Vars belonging to that SectionType.
void writeDataOfType(SectionType SectionType,
const VariableDeclarationList &Vars,
FixupKind RelocationKind);
FixupKind RelocationKind,
const IceString &SectionSuffix);
// Write the final relocation sections given the final symbol table.
// May also be able to seek around the file and resolve function calls
......
......@@ -222,7 +222,10 @@ GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError,
OptQ(/*Sequential=*/Flags.isSequential(),
/*MaxSize=*/Flags.getNumTranslationThreads()),
// EmitQ is allowed unlimited size.
EmitQ(/*Sequential=*/Flags.isSequential()) {
EmitQ(/*Sequential=*/Flags.isSequential()),
DataLowering(TargetDataLowering::createLowering(this)),
HasSeenCode(false),
ProfileBlockInfoVarDecl(VariableDeclaration::create()) {
assert(OsDump && "OsDump is not defined for GlobalContext");
assert(OsEmit && "OsEmit is not defined for GlobalContext");
assert(OsError && "OsError is not defined for GlobalContext");
......@@ -254,6 +257,14 @@ GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError,
case FT_Iasm:
break;
}
ProfileBlockInfoVarDecl->setAlignment(typeWidthInBytes(IceType_i64));
ProfileBlockInfoVarDecl->setIsConstant(true);
// Note: if you change this symbol, make sure to update
// runtime/szrt_profiler.c as well.
ProfileBlockInfoVarDecl->setName("__Sz_block_profile_info");
ProfileBlockInfoVarDecl->setSuppressMangling();
ProfileBlockInfoVarDecl->setLinkage(llvm::GlobalValue::ExternalLinkage);
}
void GlobalContext::translateFunctions() {
......@@ -322,67 +333,16 @@ void GlobalContext::translateFunctions() {
namespace {
// Adds an array of pointers to all the profiler-generated globals. The
// __Sz_profile_summary function iterates over this array for printing the
// profiling counters.
VariableDeclaration *blockProfileInfo(const VariableDeclarationList &Globals) {
auto *Var = VariableDeclaration::create();
Var->setAlignment(typeWidthInBytes(IceType_i64));
Var->setIsConstant(true);
// Note: if you change this symbol, make sure to update
// runtime/szrt_profiler.c as well.
Var->setName("__Sz_block_profile_info");
Var->setSuppressMangling();
Var->setLinkage(llvm::GlobalValue::ExternalLinkage);
void addBlockInfoPtrs(const VariableDeclarationList &Globals,
VariableDeclaration *ProfileBlockInfo) {
for (const VariableDeclaration *Global : Globals) {
if (Cfg::isProfileGlobal(*Global)) {
constexpr RelocOffsetT BlockExecutionCounterOffset = 0;
Var->addInitializer(new VariableDeclaration::RelocInitializer(
Global, BlockExecutionCounterOffset));
ProfileBlockInfo->addInitializer(
new VariableDeclaration::RelocInitializer(
Global, BlockExecutionCounterOffset));
}
}
// This adds a 64-bit sentinel entry to the end of our array. For 32-bit
// architectures this will waste 4 bytes.
const SizeT Sizeof64BitNullPtr = typeWidthInBytes(IceType_i64);
Var->addInitializer(
new VariableDeclaration::ZeroInitializer(Sizeof64BitNullPtr));
return Var;
}
void addBlockProfileInfoArrayToGlobals(VariableDeclarationList *Globals) {
// Purposefully create the Var temp to prevent bugs in case the compiler
// reorders instructions in a way that Globals is extended before the call
// to profileInfoArray.
VariableDeclaration *Var = blockProfileInfo(*Globals);
Globals->push_back(Var);
}
void lowerGlobals(GlobalContext *Ctx,
std::unique_ptr<VariableDeclarationList> VariableDeclarations,
TargetDataLowering *DataLowering) {
TimerMarker T(TimerStack::TT_emitGlobalInitializers, Ctx);
const bool DumpGlobalVariables = ALLOW_DUMP && Ctx->getFlags().getVerbose() &&
Ctx->getFlags().getVerboseFocusOn().empty();
if (DumpGlobalVariables) {
OstreamLocker L(Ctx);
Ostream &Stream = Ctx->getStrDump();
for (const Ice::VariableDeclaration *Global : *VariableDeclarations) {
Global->dump(Ctx, Stream);
}
}
if (Ctx->getFlags().getDisableTranslation())
return;
// There should be no need to emit the block_profile_info array if profiling
// is disabled. In practice, given that szrt_profiler.o will always be
// embedded in the application, we need to add it. In a non-profiled build
// this array will only contain the nullptr terminator.
addBlockProfileInfoArrayToGlobals(VariableDeclarations.get());
DataLowering->lowerGlobals(std::move(VariableDeclarations));
}
// Ensure Pending is large enough that Pending[Index] is valid.
......@@ -391,13 +351,6 @@ void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) {
Pending.resize(Index + 1);
}
void addAllIfNotNull(std::unique_ptr<VariableDeclarationList> src,
VariableDeclarationList *dst) {
if (src != nullptr) {
dst->insert(dst->end(), src->begin(), src->end());
}
}
} // end of anonymous namespace
void GlobalContext::emitFileHeader() {
......@@ -411,6 +364,40 @@ void GlobalContext::emitFileHeader() {
}
}
void GlobalContext::lowerConstants() {
DataLowering->lowerConstants();
}
void GlobalContext::lowerGlobals(const IceString &SectionSuffix) {
TimerMarker T(TimerStack::TT_emitGlobalInitializers, this);
const bool DumpGlobalVariables =
ALLOW_DUMP && Flags.getVerbose() && Flags.getVerboseFocusOn().empty();
if (DumpGlobalVariables) {
OstreamLocker L(this);
Ostream &Stream = getStrDump();
for (const Ice::VariableDeclaration *Global : Globals) {
Global->dump(this, Stream);
}
}
if (Flags.getDisableTranslation())
return;
addBlockInfoPtrs(Globals, ProfileBlockInfoVarDecl.get());
DataLowering->lowerGlobals(Globals, SectionSuffix);
Globals.clear();
}
void GlobalContext::lowerProfileData() {
// This adds a 64-bit sentinel entry to the end of our array. For 32-bit
// architectures this will waste 4 bytes.
const SizeT Sizeof64BitNullPtr = typeWidthInBytes(IceType_i64);
ProfileBlockInfoVarDecl->addInitializer(
new VariableDeclaration::ZeroInitializer(Sizeof64BitNullPtr));
Globals.push_back(ProfileBlockInfoVarDecl.get());
constexpr char ProfileDataSection[] = "$sz_profiler$";
lowerGlobals(ProfileDataSection);
}
void GlobalContext::emitItems() {
const bool Threaded = !getFlags().isSequential();
// Pending is a vector containing the reassembled, ordered list of
......@@ -419,8 +406,6 @@ void GlobalContext::emitItems() {
// the work queue, and if it's not the item we're waiting for, we
// insert it into Pending and repeat. The work item is deleted
// after it is processed.
std::unique_ptr<VariableDeclarationList> GlobalInits(
new VariableDeclarationList());
std::vector<EmitterWorkItem *> Pending;
uint32_t DesiredSequenceNumber = getFirstSequenceNumber();
while (true) {
......@@ -444,10 +429,12 @@ void GlobalContext::emitItems() {
case EmitterWorkItem::WI_Nop:
break;
case EmitterWorkItem::WI_GlobalInits: {
addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get());
accumulateGlobals(Item->getGlobalInits());
} break;
case EmitterWorkItem::WI_Asm: {
addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get());
lowerGlobalsIfNoCodeHasBeenSeen();
accumulateGlobals(Item->getGlobalInits());
std::unique_ptr<Assembler> Asm = Item->getAsm();
Asm->alignFunction();
IceString MangledName = mangleName(Asm->getFunctionName());
......@@ -469,8 +456,8 @@ void GlobalContext::emitItems() {
case EmitterWorkItem::WI_Cfg: {
if (!ALLOW_DUMP)
llvm::report_fatal_error("WI_Cfg work item created inappropriately");
addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get());
lowerGlobalsIfNoCodeHasBeenSeen();
accumulateGlobals(Item->getGlobalInits());
assert(getFlags().getOutFileType() == FT_Asm);
std::unique_ptr<Cfg> Func = Item->getCfg();
......@@ -485,8 +472,9 @@ void GlobalContext::emitItems() {
}
}
lowerGlobals(this, std::move(GlobalInits),
TargetDataLowering::createLowering(this).get());
// In case there are no code to be generated, we invoke the conditional
// lowerGlobals again -- this is a no-op if code has been emitted.
lowerGlobalsIfNoCodeHasBeenSeen();
}
// Scan a string for S[0-9A-Z]*_ patterns and replace them with
......
......@@ -303,6 +303,8 @@ public:
// Emit file header for output file.
void emitFileHeader();
void lowerConstants();
void emitQueueBlockingPush(EmitterWorkItem *Item);
EmitterWorkItem *emitQueueBlockingPop();
void emitQueueNotifyEnd() { EmitQ.notifyEnd(); }
......@@ -380,6 +382,13 @@ public:
// until the queue is empty.
void emitItems();
// Uses DataLowering to lower Globals. As a side effect, clears the Globals
// array.
void lowerGlobals(const IceString &SectionSuffix);
// Lowers the profile information.
void lowerProfileData();
// Utility function to match a symbol name against a match string.
// This is used in a few cases where we want to take some action on
// a particular function or symbol based on a command-line argument,
......@@ -432,9 +441,22 @@ private:
Intrinsics IntrinsicsInfo;
const ClFlags &Flags;
RandomNumberGenerator RNG; // TODO(stichnot): Move into Cfg.
// TODO(jpp): move to EmitterContext.
std::unique_ptr<ELFObjectWriter> ObjectWriter;
BoundedProducerConsumerQueue<Cfg> OptQ;
BoundedProducerConsumerQueue<EmitterWorkItem> EmitQ;
// DataLowering is only ever used by a single thread at a time (either in
// emitItems(), or in IceCompiler::run before the compilation is over.)
// TODO(jpp): move to EmitterContext.
std::unique_ptr<TargetDataLowering> DataLowering;
// If !HasEmittedCode, SubZero will accumulate all Globals (which are "true"
// program global variables) until the first code WorkItem is seen.
// TODO(jpp): move to EmitterContext.
bool HasSeenCode;
// TODO(jpp): move to EmitterContext.
VariableDeclarationList Globals;
// TODO(jpp): move to EmitterContext.
std::unique_ptr<VariableDeclaration> ProfileBlockInfoVarDecl;
LockedPtr<ArenaAllocator<>> getAllocator() {
return LockedPtr<ArenaAllocator<>>(&Allocator, &AllocLock);
......@@ -449,6 +471,19 @@ private:
return LockedPtr<TimerList>(&Timers, &TimerLock);
}
void accumulateGlobals(std::unique_ptr<VariableDeclarationList> Globls) {
if (Globls != nullptr)
Globals.insert(Globals.end(), Globls->begin(), Globls->end());
}
void lowerGlobalsIfNoCodeHasBeenSeen() {
if (HasSeenCode)
return;
constexpr char NoSuffix[] = "";
lowerGlobals(NoSuffix);
HasSeenCode = true;
}
llvm::SmallVector<ThreadContext *, 128> AllThreadContexts;
llvm::SmallVector<std::thread, 128> TranslationThreads;
llvm::SmallVector<std::thread, 128> EmitterThreads;
......
......@@ -446,40 +446,63 @@ TargetDataLowering::createLowering(GlobalContext *Ctx) {
TargetDataLowering::~TargetDataLowering() {}
void TargetDataLowering::emitGlobal(const VariableDeclaration &Var) {
namespace {
// dataSectionSuffix decides whether to use SectionSuffix or MangledVarName as
// data section suffix. Essentially, when using separate data sections for
// globals SectionSuffix is not necessary.
IceString dataSectionSuffix(const IceString &SectionSuffix,
const IceString &MangledVarName,
const bool DataSections) {
if (SectionSuffix.empty() && !DataSections) {
return "";
}
if (DataSections) {
// With data sections we don't need to use the SectionSuffix.
return "." + MangledVarName;
}
assert(!SectionSuffix.empty());
return "." + SectionSuffix;
}
} // end of anonymous namespace
void TargetDataLowering::emitGlobal(const VariableDeclaration &Var,
const IceString &SectionSuffix) {
if (!ALLOW_DUMP)
return;
// If external and not initialized, this must be a cross test.
// Don't generate a declaration for such cases.
bool IsExternal = Var.isExternal() || Ctx->getFlags().getDisableInternal();
const bool IsExternal =
Var.isExternal() || Ctx->getFlags().getDisableInternal();
if (IsExternal && !Var.hasInitializer())
return;
Ostream &Str = Ctx->getStrEmit();
const VariableDeclaration::InitializerListType &Initializers =
Var.getInitializers();
bool HasNonzeroInitializer = Var.hasNonzeroInitializer();
bool IsConstant = Var.getIsConstant();
uint32_t Align = Var.getAlignment();
SizeT Size = Var.getNumBytes();
IceString MangledName = Var.mangleName(Ctx);
IceString SectionSuffix = "";
if (Ctx->getFlags().getDataSections())
SectionSuffix = "." + MangledName;
const bool HasNonzeroInitializer = Var.hasNonzeroInitializer();
const bool IsConstant = Var.getIsConstant();
const SizeT Size = Var.getNumBytes();
const IceString MangledName = Var.mangleName(Ctx);
Str << "\t.type\t" << MangledName << ",%object\n";
const bool UseDataSections = Ctx->getFlags().getDataSections();
const IceString Suffix =
dataSectionSuffix(SectionSuffix, MangledName, UseDataSections);
if (IsConstant)
Str << "\t.section\t.rodata" << SectionSuffix << ",\"a\",%progbits\n";
Str << "\t.section\t.rodata" << Suffix << ",\"a\",%progbits\n";
else if (HasNonzeroInitializer)
Str << "\t.section\t.data" << SectionSuffix << ",\"aw\",%progbits\n";
Str << "\t.section\t.data" << Suffix << ",\"aw\",%progbits\n";
else
Str << "\t.section\t.bss" << SectionSuffix << ",\"aw\",%nobits\n";
Str << "\t.section\t.bss" << Suffix << ",\"aw\",%nobits\n";
if (IsExternal)
Str << "\t.globl\t" << MangledName << "\n";
const uint32_t Align = Var.getAlignment();
if (Align > 1) {
assert(llvm::isPowerOf2_32(Align));
// Use the .p2align directive, since the .align N directive can either
......@@ -490,11 +513,11 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var) {
Str << MangledName << ":\n";
if (HasNonzeroInitializer) {
for (VariableDeclaration::Initializer *Init : Initializers) {
for (VariableDeclaration::Initializer *Init : Var.getInitializers()) {
switch (Init->getKind()) {
case VariableDeclaration::Initializer::DataInitializerKind: {
const auto Data = llvm::cast<VariableDeclaration::DataInitializer>(Init)
->getContents();
const auto &Data = llvm::cast<VariableDeclaration::DataInitializer>(
Init)->getContents();
for (SizeT i = 0; i < Init->getNumBytes(); ++i) {
Str << "\t.byte\t" << (((unsigned)Data[i]) & 0xff) << "\n";
}
......@@ -504,7 +527,7 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var) {
Str << "\t.zero\t" << Init->getNumBytes() << "\n";
break;
case VariableDeclaration::Initializer::RelocInitializerKind: {
const auto Reloc =
const auto *Reloc =
llvm::cast<VariableDeclaration::RelocInitializer>(Init);
Str << "\t" << getEmit32Directive() << "\t";
Str << Reloc->getDeclaration()->mangleName(Ctx);
......@@ -519,12 +542,13 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var) {
}
}
}
} else
} else {
// NOTE: for non-constant zero initializers, this is BSS (no bits),
// so an ELF writer would not write to the file, and only track
// virtual offsets, but the .s writer still needs this .zero and
// cannot simply use the .size to advance offsets.
Str << "\t.zero\t" << Size << "\n";
}
Str << "\t.size\t" << MangledName << ", " << Size << "\n";
}
......
......@@ -380,16 +380,18 @@ public:
static std::unique_ptr<TargetDataLowering> createLowering(GlobalContext *Ctx);
virtual ~TargetDataLowering();
virtual void lowerGlobals(std::unique_ptr<VariableDeclarationList> Vars) = 0;
virtual void lowerGlobals(const VariableDeclarationList &Vars,
const IceString &SectionSuffix) = 0;
virtual void lowerConstants() = 0;
protected:
void emitGlobal(const VariableDeclaration &Var);
void emitGlobal(const VariableDeclaration &Var,
const IceString &SectionSuffix);
// For now, we assume .long is the right directive for emitting 4 byte
// emit global relocations. However, LLVM MIPS usually uses .4byte instead.
// Perhaps there is some difference when the location is unaligned.
const char *getEmit32Directive() { return ".long"; }
static const char *getEmit32Directive() { return ".long"; }
explicit TargetDataLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
GlobalContext *Ctx;
......
......@@ -2207,20 +2207,20 @@ void TargetARM32::emit(const ConstantUndef *) const {
TargetDataARM32::TargetDataARM32(GlobalContext *Ctx)
: TargetDataLowering(Ctx) {}
void TargetDataARM32::lowerGlobals(
std::unique_ptr<VariableDeclarationList> Vars) {
void TargetDataARM32::lowerGlobals(const VariableDeclarationList &Vars,
const IceString &SectionSuffix) {
switch (Ctx->getFlags().getOutFileType()) {
case FT_Elf: {
ELFObjectWriter *Writer = Ctx->getObjectWriter();
Writer->writeDataSection(*Vars, llvm::ELF::R_ARM_ABS32);
Writer->writeDataSection(Vars, llvm::ELF::R_ARM_ABS32, SectionSuffix);
} break;
case FT_Asm:
case FT_Iasm: {
const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly();
OstreamLocker L(Ctx);
for (const VariableDeclaration *Var : *Vars) {
for (const VariableDeclaration *Var : Vars) {
if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
emitGlobal(*Var);
emitGlobal(*Var, SectionSuffix);
}
}
} break;
......
......@@ -323,7 +323,8 @@ public:
return std::unique_ptr<TargetDataLowering>(new TargetDataARM32(Ctx));
}
void lowerGlobals(std::unique_ptr<VariableDeclarationList> Vars) override;
void lowerGlobals(const VariableDeclarationList &Vars,
const IceString &SectionSuffix) override;
void lowerConstants() override;
protected:
......
......@@ -671,20 +671,20 @@ void ConstantUndef::emit(GlobalContext *) const {
TargetDataMIPS32::TargetDataMIPS32(GlobalContext *Ctx)
: TargetDataLowering(Ctx) {}
void TargetDataMIPS32::lowerGlobals(
std::unique_ptr<VariableDeclarationList> Vars) {
void TargetDataMIPS32::lowerGlobals(const VariableDeclarationList &Vars,
const IceString &SectionSuffix) {
switch (Ctx->getFlags().getOutFileType()) {
case FT_Elf: {
ELFObjectWriter *Writer = Ctx->getObjectWriter();
Writer->writeDataSection(*Vars, llvm::ELF::R_MIPS_GLOB_DAT);
Writer->writeDataSection(Vars, llvm::ELF::R_MIPS_GLOB_DAT, SectionSuffix);
} break;
case FT_Asm:
case FT_Iasm: {
const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly();
OstreamLocker L(Ctx);
for (const VariableDeclaration *Var : *Vars) {
for (const VariableDeclaration *Var : Vars) {
if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
emitGlobal(*Var);
emitGlobal(*Var, SectionSuffix);
}
}
} break;
......
......@@ -137,7 +137,8 @@ public:
return std::unique_ptr<TargetDataLowering>(new TargetDataMIPS32(Ctx));
}
void lowerGlobals(std::unique_ptr<VariableDeclarationList> Vars) override;
void lowerGlobals(const VariableDeclarationList &Vars,
const IceString &SectionSuffix) override;
void lowerConstants() override;
protected:
......
......@@ -3296,11 +3296,10 @@ void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
Func->setError("Unexpected memory ordering for AtomicRMW");
return;
}
lowerAtomicRMW(
Instr->getDest(),
static_cast<uint32_t>(
llvm::cast<ConstantInteger32>(Instr->getArg(0))->getValue()),
Instr->getArg(1), Instr->getArg(2));
lowerAtomicRMW(Instr->getDest(),
static_cast<uint32_t>(llvm::cast<ConstantInteger32>(
Instr->getArg(0))->getValue()),
Instr->getArg(1), Instr->getArg(2));
return;
case Intrinsics::AtomicStore: {
if (!Intrinsics::isMemoryOrderValid(
......@@ -5021,20 +5020,20 @@ void TargetX8632::emit(const ConstantUndef *) const {
TargetDataX8632::TargetDataX8632(GlobalContext *Ctx)
: TargetDataLowering(Ctx) {}
void TargetDataX8632::lowerGlobals(
std::unique_ptr<VariableDeclarationList> Vars) {
void TargetDataX8632::lowerGlobals(const VariableDeclarationList &Vars,
const IceString &SectionSuffix) {
switch (Ctx->getFlags().getOutFileType()) {
case FT_Elf: {
ELFObjectWriter *Writer = Ctx->getObjectWriter();
Writer->writeDataSection(*Vars, llvm::ELF::R_386_32);
Writer->writeDataSection(Vars, llvm::ELF::R_386_32, SectionSuffix);
} break;
case FT_Asm:
case FT_Iasm: {
const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly();
OstreamLocker L(Ctx);
for (const VariableDeclaration *Var : *Vars) {
for (const VariableDeclaration *Var : Vars) {
if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
emitGlobal(*Var);
emitGlobal(*Var, SectionSuffix);
}
}
} break;
......
......@@ -587,7 +587,8 @@ public:
return std::unique_ptr<TargetDataLowering>(new TargetDataX8632(Ctx));
}
void lowerGlobals(std::unique_ptr<VariableDeclarationList> Vars) override;
void lowerGlobals(const VariableDeclarationList &Vars,
const IceString &SectionSuffix) override;
void lowerConstants() override;
protected:
......
......@@ -57,16 +57,6 @@ void Translator::translateFcn(std::unique_ptr<Cfg> Func) {
Ctx->optQueueBlockingPush(std::move(Func));
}
void Translator::emitConstants() {
if (!getErrorStatus())
TargetDataLowering::createLowering(Ctx)->lowerConstants();
}
void Translator::transferErrorCode() const {
if (getErrorStatus())
Ctx->getErrorStatus()->assign(getErrorStatus().value());
}
void Translator::lowerGlobals(
std::unique_ptr<VariableDeclarationList> VariableDeclarations) {
EmitterWorkItem *Item = new EmitterWorkItem(getNextSequenceNumber(),
......
......@@ -48,13 +48,6 @@ public:
/// Takes ownership of Func.
void translateFcn(std::unique_ptr<Cfg> Func);
/// Emits the constant pool.
void emitConstants();
/// If there was an error during bitcode reading/parsing, copy the
/// error code into the GlobalContext.
void transferErrorCode() const;
/// Lowers the given list of global addresses to target. Generates
/// list of corresponding variable declarations.
void
......
......@@ -270,8 +270,7 @@ define void @_start(i32) {
; CHECK: ]
; CHECK: Address: 0x0
; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}}
; Size is 56 instead of 48 due to __Sz_block_profile_info .
; CHECK: Size: 56
; CHECK: Size: 48
; CHECK: Link: 0
; CHECK: Info: 0
; CHECK: AddressAlignment: 32
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment