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) { ...@@ -1256,7 +1256,10 @@ void CfgNode::profileExecutionCount(VariableDeclaration *Var) {
assert(Info != nullptr); assert(Info != nullptr);
Operand *RMWI64Name = Context->getConstantExternSym(RMW_I64); 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 *AtomicRMWOp = Context->getConstantInt32(Intrinsics::AtomicAdd);
Constant *One = Context->getConstantInt64(1); Constant *One = Context->getConstantInt64(1);
Constant *OrderAcquireRelease = Constant *OrderAcquireRelease =
......
...@@ -141,21 +141,28 @@ void Compiler::run(const Ice::ClFlagsExtra &ExtraFlags, GlobalContext &Ctx, ...@@ -141,21 +141,28 @@ void Compiler::run(const Ice::ClFlagsExtra &ExtraFlags, GlobalContext &Ctx,
} }
Ctx.waitForWorkerThreads(); Ctx.waitForWorkerThreads();
Translator->transferErrorCode(); if (Translator->getErrorStatus()) {
Translator->emitConstants(); Ctx.getErrorStatus()->assign(Translator->getErrorStatus().value());
} else {
if (Ctx.getFlags().getOutFileType() == FT_Elf) { Ctx.lowerGlobals("last");
TimerMarker T1(Ice::TimerStack::TT_emit, &Ctx); Ctx.lowerProfileData();
Ctx.getObjectWriter()->setUndefinedSyms(Ctx.getConstantExternSyms()); Ctx.lowerConstants();
Ctx.getObjectWriter()->writeNonUserSections();
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()) if (Ctx.getFlags().getSubzeroTimingEnabled())
Ctx.dumpTimers(); Ctx.dumpTimers();
if (Ctx.getFlags().getTimeEachFunction()) { if (Ctx.getFlags().getTimeEachFunction()) {
const bool DumpCumulative = false; const bool DumpCumulative = false;
Ctx.dumpTimers(GlobalContext::TSK_Funcs, DumpCumulative); Ctx.dumpTimers(GlobalContext::TSK_Funcs, DumpCumulative);
} }
const bool FinalStats = true; constexpr bool FinalStats = true;
Ctx.dumpStats("_FINAL_", FinalStats); Ctx.dumpStats("_FINAL_", FinalStats);
} }
......
...@@ -285,7 +285,8 @@ void partitionGlobalsBySection(const VariableDeclarationList &Vars, ...@@ -285,7 +285,8 @@ void partitionGlobalsBySection(const VariableDeclarationList &Vars,
} // end of anonymous namespace } // end of anonymous namespace
void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars, void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars,
FixupKind RelocationKind) { FixupKind RelocationKind,
const IceString &SectionSuffix) {
assert(!SectionNumbersAssigned); assert(!SectionNumbersAssigned);
VariableDeclarationList VarsBySection[ELFObjectWriter::NumSectionTypes]; VariableDeclarationList VarsBySection[ELFObjectWriter::NumSectionTypes];
for (auto &SectionList : VarsBySection) for (auto &SectionList : VarsBySection)
...@@ -294,18 +295,28 @@ void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars, ...@@ -294,18 +295,28 @@ void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars,
Ctx.getFlags().getTranslateOnly()); Ctx.getFlags().getTranslateOnly());
size_t I = 0; size_t I = 0;
for (auto &SectionList : VarsBySection) { 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, void ELFObjectWriter::writeDataOfType(SectionType ST,
const VariableDeclarationList &Vars, const VariableDeclarationList &Vars,
FixupKind RelocationKind) { FixupKind RelocationKind,
const IceString &SectionSuffix) {
if (Vars.empty()) if (Vars.empty())
return; return;
ELFDataSection *Section; ELFDataSection *Section;
ELFRelocationSection *RelSection; ELFRelocationSection *RelSection;
// TODO(jvoung): Handle fdata-sections.
IceString SectionName; IceString SectionName;
Elf64_Xword ShAddralign = 1; Elf64_Xword ShAddralign = 1;
for (VariableDeclaration *Var : Vars) { for (VariableDeclaration *Var : Vars) {
...@@ -316,9 +327,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST, ...@@ -316,9 +327,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST,
// Lift this out, so it can be re-used if we do fdata-sections? // Lift this out, so it can be re-used if we do fdata-sections?
switch (ST) { switch (ST) {
case ROData: { case ROData: {
SectionName = ".rodata"; const IceString SectionName = MangleSectionName(".rodata", SectionSuffix);
// Only expecting to write the data sections all in one shot for now.
assert(RODataSections.empty());
const Elf64_Xword ShFlags = SHF_ALLOC; const Elf64_Xword ShFlags = SHF_ALLOC;
Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags, Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
ShAddralign, ShEntsize); ShAddralign, ShEntsize);
...@@ -329,8 +338,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST, ...@@ -329,8 +338,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST,
break; break;
} }
case Data: { case Data: {
SectionName = ".data"; const IceString SectionName = MangleSectionName(".data", SectionSuffix);
assert(DataSections.empty());
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE; const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags, Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, ShFlags,
ShAddralign, ShEntsize); ShAddralign, ShEntsize);
...@@ -341,8 +349,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST, ...@@ -341,8 +349,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST,
break; break;
} }
case BSS: { case BSS: {
SectionName = ".bss"; const IceString SectionName = MangleSectionName(".bss", SectionSuffix);
assert(BSSSections.empty());
const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE; const Elf64_Xword ShFlags = SHF_ALLOC | SHF_WRITE;
Section = createSection<ELFDataSection>(SectionName, SHT_NOBITS, ShFlags, Section = createSection<ELFDataSection>(SectionName, SHT_NOBITS, ShFlags,
ShAddralign, ShEntsize); ShAddralign, ShEntsize);
...@@ -383,9 +390,8 @@ void ELFObjectWriter::writeDataOfType(SectionType ST, ...@@ -383,9 +390,8 @@ void ELFObjectWriter::writeDataOfType(SectionType ST,
for (VariableDeclaration::Initializer *Init : Var->getInitializers()) { for (VariableDeclaration::Initializer *Init : Var->getInitializers()) {
switch (Init->getKind()) { switch (Init->getKind()) {
case VariableDeclaration::Initializer::DataInitializerKind: { case VariableDeclaration::Initializer::DataInitializerKind: {
const auto Data = const auto Data = llvm::cast<VariableDeclaration::DataInitializer>(
llvm::cast<VariableDeclaration::DataInitializer>(Init) Init)->getContents();
->getContents();
Section->appendData(Str, llvm::StringRef(Data.data(), Data.size())); Section->appendData(Str, llvm::StringRef(Data.data(), Data.size()));
break; break;
} }
......
...@@ -30,11 +30,12 @@ namespace Ice { ...@@ -30,11 +30,12 @@ namespace Ice {
// sections and write them out. Expected usage: // sections and write them out. Expected usage:
// //
// (1) writeInitialELFHeader (invoke once) // (1) writeInitialELFHeader (invoke once)
// (2) writeDataSection (invoke once) // (2) writeDataSection (may be invoked multiple times, as long as
// (3) writeFunctionCode (must invoke once per function) // SectionSuffix is unique)
// (4) writeConstantPool (must invoke once per pooled primitive type) // (3) writeFunctionCode (must invoke once per function)
// (5) setUndefinedSyms (invoke once) // (4) writeConstantPool (must invoke once per pooled primitive type)
// (6) writeNonUserSections (invoke once) // (5) setUndefinedSyms (invoke once)
// (6) writeNonUserSections (invoke once)
// //
// The requirement for writeDataSection to be invoked only once can // The requirement for writeDataSection to be invoked only once can
// be relaxed if using -fdata-sections. The requirement to invoke only once // be relaxed if using -fdata-sections. The requirement to invoke only once
...@@ -42,11 +43,6 @@ namespace Ice { ...@@ -42,11 +43,6 @@ namespace Ice {
// SectionType are contiguous in the file. With -fdata-sections, each global // SectionType are contiguous in the file. With -fdata-sections, each global
// variable is in a separate section and therefore the sections will be // variable is in a separate section and therefore the sections will be
// trivially contiguous. // 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 { class ELFObjectWriter {
ELFObjectWriter() = delete; ELFObjectWriter() = delete;
ELFObjectWriter(const ELFObjectWriter &) = delete; ELFObjectWriter(const ELFObjectWriter &) = delete;
...@@ -64,7 +60,8 @@ public: ...@@ -64,7 +60,8 @@ public:
// of each global's definition in the symbol table. // of each global's definition in the symbol table.
// Use the given target's RelocationKind for any relocations. // Use the given target's RelocationKind for any relocations.
void writeDataSection(const VariableDeclarationList &Vars, 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 // Copy data of a function's text section to file and note the offset of the
// symbol's definition in the symbol table. // symbol's definition in the symbol table.
...@@ -151,7 +148,8 @@ private: ...@@ -151,7 +148,8 @@ private:
// SectionType, given the global variables Vars belonging to that SectionType. // SectionType, given the global variables Vars belonging to that SectionType.
void writeDataOfType(SectionType SectionType, void writeDataOfType(SectionType SectionType,
const VariableDeclarationList &Vars, const VariableDeclarationList &Vars,
FixupKind RelocationKind); FixupKind RelocationKind,
const IceString &SectionSuffix);
// Write the final relocation sections given the final symbol table. // Write the final relocation sections given the final symbol table.
// May also be able to seek around the file and resolve function calls // 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, ...@@ -222,7 +222,10 @@ GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError,
OptQ(/*Sequential=*/Flags.isSequential(), OptQ(/*Sequential=*/Flags.isSequential(),
/*MaxSize=*/Flags.getNumTranslationThreads()), /*MaxSize=*/Flags.getNumTranslationThreads()),
// EmitQ is allowed unlimited size. // 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(OsDump && "OsDump is not defined for GlobalContext");
assert(OsEmit && "OsEmit is not defined for GlobalContext"); assert(OsEmit && "OsEmit is not defined for GlobalContext");
assert(OsError && "OsError 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, ...@@ -254,6 +257,14 @@ GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError,
case FT_Iasm: case FT_Iasm:
break; 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() { void GlobalContext::translateFunctions() {
...@@ -322,67 +333,16 @@ void GlobalContext::translateFunctions() { ...@@ -322,67 +333,16 @@ void GlobalContext::translateFunctions() {
namespace { namespace {
// Adds an array of pointers to all the profiler-generated globals. The void addBlockInfoPtrs(const VariableDeclarationList &Globals,
// __Sz_profile_summary function iterates over this array for printing the VariableDeclaration *ProfileBlockInfo) {
// 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);
for (const VariableDeclaration *Global : Globals) { for (const VariableDeclaration *Global : Globals) {
if (Cfg::isProfileGlobal(*Global)) { if (Cfg::isProfileGlobal(*Global)) {
constexpr RelocOffsetT BlockExecutionCounterOffset = 0; constexpr RelocOffsetT BlockExecutionCounterOffset = 0;
Var->addInitializer(new VariableDeclaration::RelocInitializer( ProfileBlockInfo->addInitializer(
Global, BlockExecutionCounterOffset)); 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. // Ensure Pending is large enough that Pending[Index] is valid.
...@@ -391,13 +351,6 @@ void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) { ...@@ -391,13 +351,6 @@ void resizePending(std::vector<EmitterWorkItem *> &Pending, uint32_t Index) {
Pending.resize(Index + 1); 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 } // end of anonymous namespace
void GlobalContext::emitFileHeader() { void GlobalContext::emitFileHeader() {
...@@ -411,6 +364,40 @@ 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() { void GlobalContext::emitItems() {
const bool Threaded = !getFlags().isSequential(); const bool Threaded = !getFlags().isSequential();
// Pending is a vector containing the reassembled, ordered list of // Pending is a vector containing the reassembled, ordered list of
...@@ -419,8 +406,6 @@ void GlobalContext::emitItems() { ...@@ -419,8 +406,6 @@ void GlobalContext::emitItems() {
// the work queue, and if it's not the item we're waiting for, we // 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 // insert it into Pending and repeat. The work item is deleted
// after it is processed. // after it is processed.
std::unique_ptr<VariableDeclarationList> GlobalInits(
new VariableDeclarationList());
std::vector<EmitterWorkItem *> Pending; std::vector<EmitterWorkItem *> Pending;
uint32_t DesiredSequenceNumber = getFirstSequenceNumber(); uint32_t DesiredSequenceNumber = getFirstSequenceNumber();
while (true) { while (true) {
...@@ -444,10 +429,12 @@ void GlobalContext::emitItems() { ...@@ -444,10 +429,12 @@ void GlobalContext::emitItems() {
case EmitterWorkItem::WI_Nop: case EmitterWorkItem::WI_Nop:
break; break;
case EmitterWorkItem::WI_GlobalInits: { case EmitterWorkItem::WI_GlobalInits: {
addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get()); accumulateGlobals(Item->getGlobalInits());
} break; } break;
case EmitterWorkItem::WI_Asm: { case EmitterWorkItem::WI_Asm: {
addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get()); lowerGlobalsIfNoCodeHasBeenSeen();
accumulateGlobals(Item->getGlobalInits());
std::unique_ptr<Assembler> Asm = Item->getAsm(); std::unique_ptr<Assembler> Asm = Item->getAsm();
Asm->alignFunction(); Asm->alignFunction();
IceString MangledName = mangleName(Asm->getFunctionName()); IceString MangledName = mangleName(Asm->getFunctionName());
...@@ -469,8 +456,8 @@ void GlobalContext::emitItems() { ...@@ -469,8 +456,8 @@ void GlobalContext::emitItems() {
case EmitterWorkItem::WI_Cfg: { case EmitterWorkItem::WI_Cfg: {
if (!ALLOW_DUMP) if (!ALLOW_DUMP)
llvm::report_fatal_error("WI_Cfg work item created inappropriately"); llvm::report_fatal_error("WI_Cfg work item created inappropriately");
lowerGlobalsIfNoCodeHasBeenSeen();
addAllIfNotNull(Item->getGlobalInits(), GlobalInits.get()); accumulateGlobals(Item->getGlobalInits());
assert(getFlags().getOutFileType() == FT_Asm); assert(getFlags().getOutFileType() == FT_Asm);
std::unique_ptr<Cfg> Func = Item->getCfg(); std::unique_ptr<Cfg> Func = Item->getCfg();
...@@ -485,8 +472,9 @@ void GlobalContext::emitItems() { ...@@ -485,8 +472,9 @@ void GlobalContext::emitItems() {
} }
} }
lowerGlobals(this, std::move(GlobalInits), // In case there are no code to be generated, we invoke the conditional
TargetDataLowering::createLowering(this).get()); // 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 // Scan a string for S[0-9A-Z]*_ patterns and replace them with
......
...@@ -303,6 +303,8 @@ public: ...@@ -303,6 +303,8 @@ public:
// Emit file header for output file. // Emit file header for output file.
void emitFileHeader(); void emitFileHeader();
void lowerConstants();
void emitQueueBlockingPush(EmitterWorkItem *Item); void emitQueueBlockingPush(EmitterWorkItem *Item);
EmitterWorkItem *emitQueueBlockingPop(); EmitterWorkItem *emitQueueBlockingPop();
void emitQueueNotifyEnd() { EmitQ.notifyEnd(); } void emitQueueNotifyEnd() { EmitQ.notifyEnd(); }
...@@ -380,6 +382,13 @@ public: ...@@ -380,6 +382,13 @@ public:
// until the queue is empty. // until the queue is empty.
void emitItems(); 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. // 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 // 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, // a particular function or symbol based on a command-line argument,
...@@ -432,9 +441,22 @@ private: ...@@ -432,9 +441,22 @@ private:
Intrinsics IntrinsicsInfo; Intrinsics IntrinsicsInfo;
const ClFlags &Flags; const ClFlags &Flags;
RandomNumberGenerator RNG; // TODO(stichnot): Move into Cfg. RandomNumberGenerator RNG; // TODO(stichnot): Move into Cfg.
// TODO(jpp): move to EmitterContext.
std::unique_ptr<ELFObjectWriter> ObjectWriter; std::unique_ptr<ELFObjectWriter> ObjectWriter;
BoundedProducerConsumerQueue<Cfg> OptQ; BoundedProducerConsumerQueue<Cfg> OptQ;
BoundedProducerConsumerQueue<EmitterWorkItem> EmitQ; 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() { LockedPtr<ArenaAllocator<>> getAllocator() {
return LockedPtr<ArenaAllocator<>>(&Allocator, &AllocLock); return LockedPtr<ArenaAllocator<>>(&Allocator, &AllocLock);
...@@ -449,6 +471,19 @@ private: ...@@ -449,6 +471,19 @@ private:
return LockedPtr<TimerList>(&Timers, &TimerLock); 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<ThreadContext *, 128> AllThreadContexts;
llvm::SmallVector<std::thread, 128> TranslationThreads; llvm::SmallVector<std::thread, 128> TranslationThreads;
llvm::SmallVector<std::thread, 128> EmitterThreads; llvm::SmallVector<std::thread, 128> EmitterThreads;
......
...@@ -446,40 +446,63 @@ TargetDataLowering::createLowering(GlobalContext *Ctx) { ...@@ -446,40 +446,63 @@ TargetDataLowering::createLowering(GlobalContext *Ctx) {
TargetDataLowering::~TargetDataLowering() {} 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) if (!ALLOW_DUMP)
return; return;
// If external and not initialized, this must be a cross test. // If external and not initialized, this must be a cross test.
// Don't generate a declaration for such cases. // 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()) if (IsExternal && !Var.hasInitializer())
return; return;
Ostream &Str = Ctx->getStrEmit(); Ostream &Str = Ctx->getStrEmit();
const VariableDeclaration::InitializerListType &Initializers = const bool HasNonzeroInitializer = Var.hasNonzeroInitializer();
Var.getInitializers(); const bool IsConstant = Var.getIsConstant();
bool HasNonzeroInitializer = Var.hasNonzeroInitializer(); const SizeT Size = Var.getNumBytes();
bool IsConstant = Var.getIsConstant(); const IceString MangledName = Var.mangleName(Ctx);
uint32_t Align = Var.getAlignment();
SizeT Size = Var.getNumBytes();
IceString MangledName = Var.mangleName(Ctx);
IceString SectionSuffix = "";
if (Ctx->getFlags().getDataSections())
SectionSuffix = "." + MangledName;
Str << "\t.type\t" << MangledName << ",%object\n"; Str << "\t.type\t" << MangledName << ",%object\n";
const bool UseDataSections = Ctx->getFlags().getDataSections();
const IceString Suffix =
dataSectionSuffix(SectionSuffix, MangledName, UseDataSections);
if (IsConstant) if (IsConstant)
Str << "\t.section\t.rodata" << SectionSuffix << ",\"a\",%progbits\n"; Str << "\t.section\t.rodata" << Suffix << ",\"a\",%progbits\n";
else if (HasNonzeroInitializer) else if (HasNonzeroInitializer)
Str << "\t.section\t.data" << SectionSuffix << ",\"aw\",%progbits\n"; Str << "\t.section\t.data" << Suffix << ",\"aw\",%progbits\n";
else else
Str << "\t.section\t.bss" << SectionSuffix << ",\"aw\",%nobits\n"; Str << "\t.section\t.bss" << Suffix << ",\"aw\",%nobits\n";
if (IsExternal) if (IsExternal)
Str << "\t.globl\t" << MangledName << "\n"; Str << "\t.globl\t" << MangledName << "\n";
const uint32_t Align = Var.getAlignment();
if (Align > 1) { if (Align > 1) {
assert(llvm::isPowerOf2_32(Align)); assert(llvm::isPowerOf2_32(Align));
// Use the .p2align directive, since the .align N directive can either // Use the .p2align directive, since the .align N directive can either
...@@ -490,11 +513,11 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var) { ...@@ -490,11 +513,11 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var) {
Str << MangledName << ":\n"; Str << MangledName << ":\n";
if (HasNonzeroInitializer) { if (HasNonzeroInitializer) {
for (VariableDeclaration::Initializer *Init : Initializers) { for (VariableDeclaration::Initializer *Init : Var.getInitializers()) {
switch (Init->getKind()) { switch (Init->getKind()) {
case VariableDeclaration::Initializer::DataInitializerKind: { case VariableDeclaration::Initializer::DataInitializerKind: {
const auto Data = llvm::cast<VariableDeclaration::DataInitializer>(Init) const auto &Data = llvm::cast<VariableDeclaration::DataInitializer>(
->getContents(); Init)->getContents();
for (SizeT i = 0; i < Init->getNumBytes(); ++i) { for (SizeT i = 0; i < Init->getNumBytes(); ++i) {
Str << "\t.byte\t" << (((unsigned)Data[i]) & 0xff) << "\n"; Str << "\t.byte\t" << (((unsigned)Data[i]) & 0xff) << "\n";
} }
...@@ -504,7 +527,7 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var) { ...@@ -504,7 +527,7 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var) {
Str << "\t.zero\t" << Init->getNumBytes() << "\n"; Str << "\t.zero\t" << Init->getNumBytes() << "\n";
break; break;
case VariableDeclaration::Initializer::RelocInitializerKind: { case VariableDeclaration::Initializer::RelocInitializerKind: {
const auto Reloc = const auto *Reloc =
llvm::cast<VariableDeclaration::RelocInitializer>(Init); llvm::cast<VariableDeclaration::RelocInitializer>(Init);
Str << "\t" << getEmit32Directive() << "\t"; Str << "\t" << getEmit32Directive() << "\t";
Str << Reloc->getDeclaration()->mangleName(Ctx); Str << Reloc->getDeclaration()->mangleName(Ctx);
...@@ -519,12 +542,13 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var) { ...@@ -519,12 +542,13 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var) {
} }
} }
} }
} else } else {
// NOTE: for non-constant zero initializers, this is BSS (no bits), // NOTE: for non-constant zero initializers, this is BSS (no bits),
// so an ELF writer would not write to the file, and only track // so an ELF writer would not write to the file, and only track
// virtual offsets, but the .s writer still needs this .zero and // virtual offsets, but the .s writer still needs this .zero and
// cannot simply use the .size to advance offsets. // cannot simply use the .size to advance offsets.
Str << "\t.zero\t" << Size << "\n"; Str << "\t.zero\t" << Size << "\n";
}
Str << "\t.size\t" << MangledName << ", " << Size << "\n"; Str << "\t.size\t" << MangledName << ", " << Size << "\n";
} }
......
...@@ -380,16 +380,18 @@ public: ...@@ -380,16 +380,18 @@ public:
static std::unique_ptr<TargetDataLowering> createLowering(GlobalContext *Ctx); static std::unique_ptr<TargetDataLowering> createLowering(GlobalContext *Ctx);
virtual ~TargetDataLowering(); 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; virtual void lowerConstants() = 0;
protected: 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 // For now, we assume .long is the right directive for emitting 4 byte
// emit global relocations. However, LLVM MIPS usually uses .4byte instead. // emit global relocations. However, LLVM MIPS usually uses .4byte instead.
// Perhaps there is some difference when the location is unaligned. // 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) {} explicit TargetDataLowering(GlobalContext *Ctx) : Ctx(Ctx) {}
GlobalContext *Ctx; GlobalContext *Ctx;
......
...@@ -2207,20 +2207,20 @@ void TargetARM32::emit(const ConstantUndef *) const { ...@@ -2207,20 +2207,20 @@ void TargetARM32::emit(const ConstantUndef *) const {
TargetDataARM32::TargetDataARM32(GlobalContext *Ctx) TargetDataARM32::TargetDataARM32(GlobalContext *Ctx)
: TargetDataLowering(Ctx) {} : TargetDataLowering(Ctx) {}
void TargetDataARM32::lowerGlobals( void TargetDataARM32::lowerGlobals(const VariableDeclarationList &Vars,
std::unique_ptr<VariableDeclarationList> Vars) { const IceString &SectionSuffix) {
switch (Ctx->getFlags().getOutFileType()) { switch (Ctx->getFlags().getOutFileType()) {
case FT_Elf: { case FT_Elf: {
ELFObjectWriter *Writer = Ctx->getObjectWriter(); ELFObjectWriter *Writer = Ctx->getObjectWriter();
Writer->writeDataSection(*Vars, llvm::ELF::R_ARM_ABS32); Writer->writeDataSection(Vars, llvm::ELF::R_ARM_ABS32, SectionSuffix);
} break; } break;
case FT_Asm: case FT_Asm:
case FT_Iasm: { case FT_Iasm: {
const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly(); const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly();
OstreamLocker L(Ctx); OstreamLocker L(Ctx);
for (const VariableDeclaration *Var : *Vars) { for (const VariableDeclaration *Var : Vars) {
if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) { if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
emitGlobal(*Var); emitGlobal(*Var, SectionSuffix);
} }
} }
} break; } break;
......
...@@ -323,7 +323,8 @@ public: ...@@ -323,7 +323,8 @@ public:
return std::unique_ptr<TargetDataLowering>(new TargetDataARM32(Ctx)); 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; void lowerConstants() override;
protected: protected:
......
...@@ -671,20 +671,20 @@ void ConstantUndef::emit(GlobalContext *) const { ...@@ -671,20 +671,20 @@ void ConstantUndef::emit(GlobalContext *) const {
TargetDataMIPS32::TargetDataMIPS32(GlobalContext *Ctx) TargetDataMIPS32::TargetDataMIPS32(GlobalContext *Ctx)
: TargetDataLowering(Ctx) {} : TargetDataLowering(Ctx) {}
void TargetDataMIPS32::lowerGlobals( void TargetDataMIPS32::lowerGlobals(const VariableDeclarationList &Vars,
std::unique_ptr<VariableDeclarationList> Vars) { const IceString &SectionSuffix) {
switch (Ctx->getFlags().getOutFileType()) { switch (Ctx->getFlags().getOutFileType()) {
case FT_Elf: { case FT_Elf: {
ELFObjectWriter *Writer = Ctx->getObjectWriter(); ELFObjectWriter *Writer = Ctx->getObjectWriter();
Writer->writeDataSection(*Vars, llvm::ELF::R_MIPS_GLOB_DAT); Writer->writeDataSection(Vars, llvm::ELF::R_MIPS_GLOB_DAT, SectionSuffix);
} break; } break;
case FT_Asm: case FT_Asm:
case FT_Iasm: { case FT_Iasm: {
const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly(); const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly();
OstreamLocker L(Ctx); OstreamLocker L(Ctx);
for (const VariableDeclaration *Var : *Vars) { for (const VariableDeclaration *Var : Vars) {
if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) { if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
emitGlobal(*Var); emitGlobal(*Var, SectionSuffix);
} }
} }
} break; } break;
......
...@@ -137,7 +137,8 @@ public: ...@@ -137,7 +137,8 @@ public:
return std::unique_ptr<TargetDataLowering>(new TargetDataMIPS32(Ctx)); 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; void lowerConstants() override;
protected: protected:
......
...@@ -3296,11 +3296,10 @@ void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { ...@@ -3296,11 +3296,10 @@ void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
Func->setError("Unexpected memory ordering for AtomicRMW"); Func->setError("Unexpected memory ordering for AtomicRMW");
return; return;
} }
lowerAtomicRMW( lowerAtomicRMW(Instr->getDest(),
Instr->getDest(), static_cast<uint32_t>(llvm::cast<ConstantInteger32>(
static_cast<uint32_t>( Instr->getArg(0))->getValue()),
llvm::cast<ConstantInteger32>(Instr->getArg(0))->getValue()), Instr->getArg(1), Instr->getArg(2));
Instr->getArg(1), Instr->getArg(2));
return; return;
case Intrinsics::AtomicStore: { case Intrinsics::AtomicStore: {
if (!Intrinsics::isMemoryOrderValid( if (!Intrinsics::isMemoryOrderValid(
...@@ -5021,20 +5020,20 @@ void TargetX8632::emit(const ConstantUndef *) const { ...@@ -5021,20 +5020,20 @@ void TargetX8632::emit(const ConstantUndef *) const {
TargetDataX8632::TargetDataX8632(GlobalContext *Ctx) TargetDataX8632::TargetDataX8632(GlobalContext *Ctx)
: TargetDataLowering(Ctx) {} : TargetDataLowering(Ctx) {}
void TargetDataX8632::lowerGlobals( void TargetDataX8632::lowerGlobals(const VariableDeclarationList &Vars,
std::unique_ptr<VariableDeclarationList> Vars) { const IceString &SectionSuffix) {
switch (Ctx->getFlags().getOutFileType()) { switch (Ctx->getFlags().getOutFileType()) {
case FT_Elf: { case FT_Elf: {
ELFObjectWriter *Writer = Ctx->getObjectWriter(); ELFObjectWriter *Writer = Ctx->getObjectWriter();
Writer->writeDataSection(*Vars, llvm::ELF::R_386_32); Writer->writeDataSection(Vars, llvm::ELF::R_386_32, SectionSuffix);
} break; } break;
case FT_Asm: case FT_Asm:
case FT_Iasm: { case FT_Iasm: {
const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly(); const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly();
OstreamLocker L(Ctx); OstreamLocker L(Ctx);
for (const VariableDeclaration *Var : *Vars) { for (const VariableDeclaration *Var : Vars) {
if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) { if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
emitGlobal(*Var); emitGlobal(*Var, SectionSuffix);
} }
} }
} break; } break;
......
...@@ -587,7 +587,8 @@ public: ...@@ -587,7 +587,8 @@ public:
return std::unique_ptr<TargetDataLowering>(new TargetDataX8632(Ctx)); 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; void lowerConstants() override;
protected: protected:
......
...@@ -57,16 +57,6 @@ void Translator::translateFcn(std::unique_ptr<Cfg> Func) { ...@@ -57,16 +57,6 @@ void Translator::translateFcn(std::unique_ptr<Cfg> Func) {
Ctx->optQueueBlockingPush(std::move(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( void Translator::lowerGlobals(
std::unique_ptr<VariableDeclarationList> VariableDeclarations) { std::unique_ptr<VariableDeclarationList> VariableDeclarations) {
EmitterWorkItem *Item = new EmitterWorkItem(getNextSequenceNumber(), EmitterWorkItem *Item = new EmitterWorkItem(getNextSequenceNumber(),
......
...@@ -48,13 +48,6 @@ public: ...@@ -48,13 +48,6 @@ public:
/// Takes ownership of Func. /// Takes ownership of Func.
void translateFcn(std::unique_ptr<Cfg> 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 /// Lowers the given list of global addresses to target. Generates
/// list of corresponding variable declarations. /// list of corresponding variable declarations.
void void
......
...@@ -270,8 +270,7 @@ define void @_start(i32) { ...@@ -270,8 +270,7 @@ define void @_start(i32) {
; CHECK: ] ; CHECK: ]
; CHECK: Address: 0x0 ; CHECK: Address: 0x0
; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}} ; CHECK: Offset: 0x{{[1-9A-F][0-9A-F]*}}
; Size is 56 instead of 48 due to __Sz_block_profile_info . ; CHECK: Size: 48
; CHECK: Size: 56
; CHECK: Link: 0 ; CHECK: Link: 0
; CHECK: Info: 0 ; CHECK: Info: 0
; CHECK: AddressAlignment: 32 ; 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