Commit a78e4baa by John Porto

Subzero. Allocate global initializers from a dedicated arena.

This allows Subzero to release the global initializers once they've been lowered. This CL also modifies the global initializer types to ensure they are trivially destructible -- therefore not requiring destructors to run. BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4360 R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1776473007 .
parent 76719b4a
...@@ -122,46 +122,43 @@ bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); } ...@@ -122,46 +122,43 @@ bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); }
namespace { namespace {
constexpr char BlockNameGlobalPrefix[] = ".L$profiler$block_name$"; constexpr char BlockNameGlobalPrefix[] = ".L$profiler$block_name$";
constexpr char BlockStatsGlobalPrefix[] = ".L$profiler$block_info$"; constexpr char BlockStatsGlobalPrefix[] = ".L$profiler$block_info$";
} // end of anonymous namespace
VariableDeclaration *nodeNameDeclaration(GlobalContext *Ctx, void Cfg::createNodeNameDeclaration(const IceString &NodeAsmName) {
const IceString &NodeAsmName) { auto *Var = VariableDeclaration::create(GlobalInits.get());
auto *Var = VariableDeclaration::create(Ctx);
Var->setName(BlockNameGlobalPrefix + NodeAsmName); Var->setName(BlockNameGlobalPrefix + NodeAsmName);
Var->setIsConstant(true); Var->setIsConstant(true);
Var->addInitializer(VariableDeclaration::DataInitializer::create( Var->addInitializer(VariableDeclaration::DataInitializer::create(
NodeAsmName.data(), NodeAsmName.size() + 1)); GlobalInits.get(), NodeAsmName.data(), NodeAsmName.size() + 1));
const SizeT Int64ByteSize = typeWidthInBytes(IceType_i64); const SizeT Int64ByteSize = typeWidthInBytes(IceType_i64);
Var->setAlignment(Int64ByteSize); // Wasteful, 32-bit could use 4 bytes. Var->setAlignment(Int64ByteSize); // Wasteful, 32-bit could use 4 bytes.
return Var; GlobalInits->push_back(Var);
} }
VariableDeclaration * void Cfg::createBlockProfilingInfoDeclaration(
blockProfilingInfoDeclaration(GlobalContext *Ctx, const IceString &NodeAsmName, const IceString &NodeAsmName, VariableDeclaration *NodeNameDeclaration) {
VariableDeclaration *NodeNameDeclaration) { auto *Var = VariableDeclaration::create(GlobalInits.get());
auto *Var = VariableDeclaration::create(Ctx);
Var->setName(BlockStatsGlobalPrefix + NodeAsmName); Var->setName(BlockStatsGlobalPrefix + NodeAsmName);
const SizeT Int64ByteSize = typeWidthInBytes(IceType_i64); const SizeT Int64ByteSize = typeWidthInBytes(IceType_i64);
Var->addInitializer( Var->addInitializer(VariableDeclaration::ZeroInitializer::create(
VariableDeclaration::ZeroInitializer::create(Int64ByteSize)); GlobalInits.get(), Int64ByteSize));
const RelocOffsetT NodeNameDeclarationOffset = 0; const RelocOffsetT NodeNameDeclarationOffset = 0;
Var->addInitializer(VariableDeclaration::RelocInitializer::create( Var->addInitializer(VariableDeclaration::RelocInitializer::create(
NodeNameDeclaration, GlobalInits.get(), NodeNameDeclaration,
{RelocOffset::create(Ctx, NodeNameDeclarationOffset)})); {RelocOffset::create(Ctx, NodeNameDeclarationOffset)}));
Var->setAlignment(Int64ByteSize); Var->setAlignment(Int64ByteSize);
return Var; GlobalInits->push_back(Var);
} }
} // end of anonymous namespace
void Cfg::profileBlocks() { void Cfg::profileBlocks() {
if (GlobalInits == nullptr) if (GlobalInits == nullptr)
GlobalInits.reset(new VariableDeclarationList()); GlobalInits.reset(new VariableDeclarationList());
for (CfgNode *Node : Nodes) { for (CfgNode *Node : Nodes) {
IceString NodeAsmName = Node->getAsmName(); const IceString NodeAsmName = Node->getAsmName();
GlobalInits->push_back(nodeNameDeclaration(Ctx, NodeAsmName)); createNodeNameDeclaration(NodeAsmName);
GlobalInits->push_back( createBlockProfilingInfoDeclaration(NodeAsmName, GlobalInits->back());
blockProfilingInfoDeclaration(Ctx, NodeAsmName, GlobalInits->back()));
Node->profileExecutionCount(GlobalInits->back()); Node->profileExecutionCount(GlobalInits->back());
} }
} }
......
...@@ -158,6 +158,12 @@ public: ...@@ -158,6 +158,12 @@ public:
} }
GlobalInits->push_back(Global); GlobalInits->push_back(Global);
} }
VariableDeclarationList *getGlobalPool() {
if (GlobalInits == nullptr) {
GlobalInits.reset(new VariableDeclarationList);
}
return GlobalInits.get();
}
/// @} /// @}
/// \name Miscellaneous accessors. /// \name Miscellaneous accessors.
...@@ -269,6 +275,11 @@ private: ...@@ -269,6 +275,11 @@ private:
/// code needs to be defined. /// code needs to be defined.
void profileBlocks(); void profileBlocks();
void createNodeNameDeclaration(const IceString &NodeAsmName);
void
createBlockProfilingInfoDeclaration(const IceString &NodeAsmName,
VariableDeclaration *NodeNameDeclaration);
/// Delete registered jump table placeholder instructions. This should only be /// Delete registered jump table placeholder instructions. This should only be
/// called once all repointing has taken place. /// called once all repointing has taken place.
void deleteJumpTableInsts(); void deleteJumpTableInsts();
......
...@@ -93,6 +93,9 @@ void Compiler::run(const Ice::ClFlagsExtra &ExtraFlags, GlobalContext &Ctx, ...@@ -93,6 +93,9 @@ void Compiler::run(const Ice::ClFlagsExtra &ExtraFlags, GlobalContext &Ctx,
Ctx.getErrorStatus()->assign(EC_Args); Ctx.getErrorStatus()->assign(EC_Args);
return; return;
} }
// Globals must be kept alive after lowering when converting from LLVM to
// Ice.
Ctx.setDisposeGlobalVariablesAfterLowering(false);
// Parse the input LLVM IR file into a module. // Parse the input LLVM IR file into a module.
llvm::SMDiagnostic Err; llvm::SMDiagnostic Err;
TimerMarker T1(Ice::TimerStack::TT_parse, &Ctx); TimerMarker T1(Ice::TimerStack::TT_parse, &Ctx);
......
...@@ -659,13 +659,13 @@ class LLVM2ICEGlobalsConverter : public LLVM2ICEConverter { ...@@ -659,13 +659,13 @@ class LLVM2ICEGlobalsConverter : public LLVM2ICEConverter {
operator=(const LLVM2ICEGlobalsConverter &) = delete; operator=(const LLVM2ICEGlobalsConverter &) = delete;
public: public:
explicit LLVM2ICEGlobalsConverter(Ice::Converter &Converter) explicit LLVM2ICEGlobalsConverter(Ice::Converter &Converter,
: LLVM2ICEConverter(Converter) {} Ice::VariableDeclarationList *G)
: LLVM2ICEConverter(Converter), GlobalPool(G) {}
/// Converts global variables, and their initializers into ICE global variable /// Converts global variables, and their initializers into ICE global variable
/// declarations, for module Mod. Returns the set of converted declarations. /// declarations, for module Mod. Returns the set of converted declarations.
std::unique_ptr<Ice::VariableDeclarationList> void convertGlobalsToIce(Module *Mod);
convertGlobalsToIce(Module *Mod);
private: private:
// Adds the Initializer to the list of initializers for the Global variable // Adds the Initializer to the list of initializers for the Global variable
...@@ -697,12 +697,11 @@ private: ...@@ -697,12 +697,11 @@ private:
report_fatal_error(StrBuf.str()); report_fatal_error(StrBuf.str());
return 0; return 0;
} }
Ice::VariableDeclarationList *GlobalPool;
}; };
std::unique_ptr<Ice::VariableDeclarationList> void LLVM2ICEGlobalsConverter::convertGlobalsToIce(Module *Mod) {
LLVM2ICEGlobalsConverter::convertGlobalsToIce(Module *Mod) {
std::unique_ptr<Ice::VariableDeclarationList> VariableDeclarations(
new Ice::VariableDeclarationList);
for (Module::const_global_iterator I = Mod->global_begin(), for (Module::const_global_iterator I = Mod->global_begin(),
E = Mod->global_end(); E = Mod->global_end();
I != E; ++I) { I != E; ++I) {
...@@ -711,7 +710,7 @@ LLVM2ICEGlobalsConverter::convertGlobalsToIce(Module *Mod) { ...@@ -711,7 +710,7 @@ LLVM2ICEGlobalsConverter::convertGlobalsToIce(Module *Mod) {
Ice::GlobalDeclaration *Var = getConverter().getGlobalDeclaration(GV); Ice::GlobalDeclaration *Var = getConverter().getGlobalDeclaration(GV);
auto *VarDecl = cast<Ice::VariableDeclaration>(Var); auto *VarDecl = cast<Ice::VariableDeclaration>(Var);
VariableDeclarations->push_back(VarDecl); GlobalPool->push_back(VarDecl);
if (!GV->hasInternalLinkage() && GV->hasInitializer()) { if (!GV->hasInternalLinkage() && GV->hasInitializer()) {
std::string Buffer; std::string Buffer;
...@@ -744,7 +743,6 @@ LLVM2ICEGlobalsConverter::convertGlobalsToIce(Module *Mod) { ...@@ -744,7 +743,6 @@ LLVM2ICEGlobalsConverter::convertGlobalsToIce(Module *Mod) {
addGlobalInitializer(*VarDecl, Initializer); addGlobalInitializer(*VarDecl, Initializer);
} }
} }
return VariableDeclarations;
} }
void LLVM2ICEGlobalsConverter::addGlobalInitializer( void LLVM2ICEGlobalsConverter::addGlobalInitializer(
...@@ -757,7 +755,7 @@ void LLVM2ICEGlobalsConverter::addGlobalInitializer( ...@@ -757,7 +755,7 @@ void LLVM2ICEGlobalsConverter::addGlobalInitializer(
assert(!HasOffset && isa<IntegerType>(CDA->getElementType()) && assert(!HasOffset && isa<IntegerType>(CDA->getElementType()) &&
(cast<IntegerType>(CDA->getElementType())->getBitWidth() == 8)); (cast<IntegerType>(CDA->getElementType())->getBitWidth() == 8));
Global.addInitializer(Ice::VariableDeclaration::DataInitializer::create( Global.addInitializer(Ice::VariableDeclaration::DataInitializer::create(
CDA->getRawDataValues().data(), CDA->getNumElements())); GlobalPool, CDA->getRawDataValues().data(), CDA->getNumElements()));
return; return;
} }
...@@ -766,7 +764,7 @@ void LLVM2ICEGlobalsConverter::addGlobalInitializer( ...@@ -766,7 +764,7 @@ void LLVM2ICEGlobalsConverter::addGlobalInitializer(
assert(!HasOffset && isa<IntegerType>(AT->getElementType()) && assert(!HasOffset && isa<IntegerType>(AT->getElementType()) &&
(cast<IntegerType>(AT->getElementType())->getBitWidth() == 8)); (cast<IntegerType>(AT->getElementType())->getBitWidth() == 8));
Global.addInitializer(Ice::VariableDeclaration::ZeroInitializer::create( Global.addInitializer(Ice::VariableDeclaration::ZeroInitializer::create(
AT->getNumElements())); GlobalPool, AT->getNumElements()));
} else { } else {
llvm_unreachable("Unhandled constant aggregate zero type"); llvm_unreachable("Unhandled constant aggregate zero type");
} }
...@@ -788,7 +786,7 @@ void LLVM2ICEGlobalsConverter::addGlobalInitializer( ...@@ -788,7 +786,7 @@ void LLVM2ICEGlobalsConverter::addGlobalInitializer(
const Ice::GlobalDeclaration *Addr = const Ice::GlobalDeclaration *Addr =
getConverter().getGlobalDeclaration(GV); getConverter().getGlobalDeclaration(GV);
Global.addInitializer(Ice::VariableDeclaration::RelocInitializer::create( Global.addInitializer(Ice::VariableDeclaration::RelocInitializer::create(
Addr, {Ice::RelocOffset::create(Ctx, Offset)})); GlobalPool, Addr, {Ice::RelocOffset::create(Ctx, Offset)}));
return; return;
} }
default: default:
...@@ -890,8 +888,8 @@ void Converter::installGlobalDeclarations(Module *Mod) { ...@@ -890,8 +888,8 @@ void Converter::installGlobalDeclarations(Module *Mod) {
I != E; ++I) { I != E; ++I) {
const GlobalVariable *GV = I; const GlobalVariable *GV = I;
constexpr bool NoSuppressMangling = false; constexpr bool NoSuppressMangling = false;
auto *Var = auto *Var = VariableDeclaration::create(
VariableDeclaration::create(Ctx, NoSuppressMangling, GV->getLinkage()); GlobalDeclarationsPool.get(), NoSuppressMangling, GV->getLinkage());
Var->setAlignment(GV->getAlignment()); Var->setAlignment(GV->getAlignment());
Var->setIsConstant(GV->isConstant()); Var->setIsConstant(GV->isConstant());
Var->setName(GV->getName()); Var->setName(GV->getName());
...@@ -909,7 +907,9 @@ void Converter::installGlobalDeclarations(Module *Mod) { ...@@ -909,7 +907,9 @@ void Converter::installGlobalDeclarations(Module *Mod) {
} }
void Converter::convertGlobals(Module *Mod) { void Converter::convertGlobals(Module *Mod) {
lowerGlobals(LLVM2ICEGlobalsConverter(*this).convertGlobalsToIce(Mod)); LLVM2ICEGlobalsConverter(*this, GlobalDeclarationsPool.get())
.convertGlobalsToIce(Mod);
lowerGlobals(std::move(GlobalDeclarationsPool));
} }
void Converter::convertFunctions() { void Converter::convertFunctions() {
......
...@@ -32,7 +32,8 @@ class Converter : public Translator { ...@@ -32,7 +32,8 @@ class Converter : public Translator {
public: public:
Converter(llvm::Module *Mod, GlobalContext *Ctx) Converter(llvm::Module *Mod, GlobalContext *Ctx)
: Translator(Ctx), Mod(Mod) {} : Translator(Ctx), Mod(Mod),
GlobalDeclarationsPool(new VariableDeclarationList()) {}
~Converter() override = default; ~Converter() override = default;
...@@ -52,6 +53,8 @@ private: ...@@ -52,6 +53,8 @@ private:
std::map<const llvm::GlobalValue *, GlobalDeclaration *>; std::map<const llvm::GlobalValue *, GlobalDeclaration *>;
GlobalDeclarationMapType GlobalDeclarationMap; GlobalDeclarationMapType GlobalDeclarationMap;
std::unique_ptr<VariableDeclarationList> GlobalDeclarationsPool;
/// Walks module and generates names for unnamed globals using prefix /// Walks module and generates names for unnamed globals using prefix
/// getFlags().DefaultGlobalPrefix, if the prefix is non-empty. /// getFlags().DefaultGlobalPrefix, if the prefix is non-empty.
void nameUnnamedGlobalVariables(llvm::Module *Mod); void nameUnnamedGlobalVariables(llvm::Module *Mod);
......
...@@ -73,6 +73,11 @@ class Variable; ...@@ -73,6 +73,11 @@ class Variable;
class VariableDeclaration; class VariableDeclaration;
class VariablesMetadata; class VariablesMetadata;
/// SizeT is for holding small-ish limits like number of source operands in an
/// instruction. It is used instead of size_t (which may be 64-bits wide) when
/// we want to save space.
using SizeT = uint32_t;
constexpr char GlobalOffsetTable[] = "_GLOBAL_OFFSET_TABLE_"; constexpr char GlobalOffsetTable[] = "_GLOBAL_OFFSET_TABLE_";
// makeUnique should be used when memory is expected to be allocated from the // makeUnique should be used when memory is expected to be allocated from the
// heap (as opposed to allocated from some Allocator.) It is intended to be // heap (as opposed to allocated from some Allocator.) It is intended to be
...@@ -139,12 +144,127 @@ using NodeList = CfgVector<CfgNode *>; ...@@ -139,12 +144,127 @@ using NodeList = CfgVector<CfgNode *>;
// Containers that use the default (global) allocator. // Containers that use the default (global) allocator.
using ConstantList = std::vector<Constant *>; using ConstantList = std::vector<Constant *>;
using FunctionDeclarationList = std::vector<FunctionDeclaration *>; using FunctionDeclarationList = std::vector<FunctionDeclaration *>;
using VariableDeclarationList = std::vector<VariableDeclaration *>;
/// SizeT is for holding small-ish limits like number of source operands in an /// VariableDeclarationList is a container for holding VariableDeclarations --
/// instruction. It is used instead of size_t (which may be 64-bits wide) when /// i.e., Global Variables. It is also used to create said variables, and their
/// we want to save space. /// initializers in an arena.
using SizeT = uint32_t; class VariableDeclarationList {
VariableDeclarationList(const VariableDeclarationList &) = delete;
VariableDeclarationList &operator=(const VariableDeclarationList &) = delete;
VariableDeclarationList(VariableDeclarationList &&) = delete;
VariableDeclarationList &operator=(VariableDeclarationList &&) = delete;
public:
using VariableDeclarationArray = std::vector<VariableDeclaration *>;
VariableDeclarationList() : Arena(new ArenaAllocator()) {}
~VariableDeclarationList() { clearAndPurge(); }
template <typename T> T *allocate_initializer(SizeT Count = 1) {
static_assert(
std::is_trivially_destructible<T>::value,
"allocate_initializer can only allocate trivially destructible types.");
return Arena->Allocate<T>(Count);
}
template <typename T> T *allocate_variable_declaration() {
static_assert(!std::is_trivially_destructible<T>::value,
"allocate_variable_declaration expects non-trivially "
"destructible types.");
T *Ret = Arena->Allocate<T>();
Dtors.emplace_back([Ret]() { Ret->~T(); });
return Ret;
}
// This do nothing method is invoked when a global variable is created, but it
// will not be emitted. If we ever need to track the created variabled, having
// this hook is handy.
void willNotBeEmitted(VariableDeclaration *) {}
/// Merges Other with this, effectively resetting Other to an empty state.
void merge(VariableDeclarationList *Other) {
assert(Other != nullptr);
addArena(std::move(Other->Arena));
for (std::size_t i = 0; i < Other->MergedArenas.size(); ++i) {
addArena(std::move(Other->MergedArenas[i]));
}
Other->MergedArenas.clear();
Dtors.insert(Dtors.end(), Other->Dtors.begin(), Other->Dtors.end());
Other->Dtors.clear();
Globals.insert(Globals.end(), Other->Globals.begin(), Other->Globals.end());
Other->Globals.clear();
}
/// Destroys all GlobalVariables and initializers that this knows about
/// (including those merged with it), and releases memory.
void clearAndPurge() {
if (Arena == nullptr) {
// Arena is only null if this was merged, so we ensure there's no state
// being held by this.
assert(Dtors.empty());
assert(Globals.empty());
assert(MergedArenas.empty());
return;
}
// Invokes destructors in reverse creation order.
for (auto Dtor = Dtors.rbegin(); Dtor != Dtors.rend(); ++Dtor) {
(*Dtor)();
}
Dtors.clear();
Globals.clear();
MergedArenas.clear();
Arena->Reset();
}
/// Adapt the relevant parts of the std::vector<VariableDeclaration *>
/// interface.
/// @{
VariableDeclarationArray::iterator begin() { return Globals.begin(); }
VariableDeclarationArray::iterator end() { return Globals.end(); }
VariableDeclarationArray::const_iterator begin() const {
return Globals.begin();
}
VariableDeclarationArray::const_iterator end() const { return Globals.end(); }
bool empty() const { return Globals.empty(); }
VariableDeclarationArray::size_type size() const { return Globals.size(); }
VariableDeclarationArray::reference
at(VariableDeclarationArray::size_type Pos) {
return Globals.at(Pos);
}
void push_back(VariableDeclaration *Global) { Globals.push_back(Global); }
void reserve(VariableDeclarationArray::size_type Capacity) {
Globals.reserve(Capacity);
}
void clear() { Globals.clear(); }
VariableDeclarationArray::reference back() { return Globals.back(); }
/// @}
private:
using ArenaPtr = std::unique_ptr<ArenaAllocator>;
using DestructorsArray = std::vector<std::function<void()>>;
void addArena(ArenaPtr NewArena) {
MergedArenas.emplace_back(std::move(NewArena));
}
ArenaPtr Arena;
VariableDeclarationArray Globals;
DestructorsArray Dtors;
std::vector<ArenaPtr> MergedArenas;
};
/// InstNumberT is for holding an instruction number. Instruction numbers are /// InstNumberT is for holding an instruction number. Instruction numbers are
/// used for representing Variable live ranges. /// used for representing Variable live ranges.
......
...@@ -288,7 +288,7 @@ classifyGlobalSection(const VariableDeclaration *Var) { ...@@ -288,7 +288,7 @@ classifyGlobalSection(const VariableDeclaration *Var) {
// Partition the Vars list by SectionType into VarsBySection. If TranslateOnly // Partition the Vars list by SectionType into VarsBySection. If TranslateOnly
// is non-empty, then only the TranslateOnly variable is kept for emission. // is non-empty, then only the TranslateOnly variable is kept for emission.
void partitionGlobalsBySection(const VariableDeclarationList &Vars, void partitionGlobalsBySection(const VariableDeclarationList &Vars,
VariableDeclarationList VarsBySection[], VariableDeclarationPartition VarsBySection[],
const IceString &TranslateOnly) { const IceString &TranslateOnly) {
for (VariableDeclaration *Var : Vars) { for (VariableDeclaration *Var : Vars) {
if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) { if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
...@@ -307,7 +307,7 @@ void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars, ...@@ -307,7 +307,7 @@ void ELFObjectWriter::writeDataSection(const VariableDeclarationList &Vars,
bool IsPIC) { bool IsPIC) {
TimerMarker Timer(TimerStack::TT_writeELF, &Ctx); TimerMarker Timer(TimerStack::TT_writeELF, &Ctx);
assert(!SectionNumbersAssigned); assert(!SectionNumbersAssigned);
VariableDeclarationList VarsBySection[ELFObjectWriter::NumSectionTypes]; VariableDeclarationPartition VarsBySection[ELFObjectWriter::NumSectionTypes];
for (auto &SectionList : VarsBySection) for (auto &SectionList : VarsBySection)
SectionList.reserve(Vars.size()); SectionList.reserve(Vars.size());
partitionGlobalsBySection(Vars, VarsBySection, partitionGlobalsBySection(Vars, VarsBySection,
...@@ -329,7 +329,7 @@ IceString MangleSectionName(const char Base[], const IceString &Suffix) { ...@@ -329,7 +329,7 @@ IceString MangleSectionName(const char Base[], const IceString &Suffix) {
// TODO(jvoung): Handle fdata-sections. // TODO(jvoung): Handle fdata-sections.
void ELFObjectWriter::writeDataOfType(SectionType ST, void ELFObjectWriter::writeDataOfType(SectionType ST,
const VariableDeclarationList &Vars, const VariableDeclarationPartition &Vars,
FixupKind RelocationKind, FixupKind RelocationKind,
const IceString &SectionSuffix, const IceString &SectionSuffix,
bool IsPIC) { bool IsPIC) {
...@@ -407,12 +407,11 @@ void ELFObjectWriter::writeDataOfType(SectionType ST, ...@@ -407,12 +407,11 @@ void ELFObjectWriter::writeDataOfType(SectionType ST,
Section->setSize(Section->getCurrentSize() + SymbolSize); Section->setSize(Section->getCurrentSize() + SymbolSize);
} else { } else {
assert(ST != BSS); assert(ST != BSS);
for (const std::unique_ptr<VariableDeclaration::Initializer> &Init : for (const auto *Init : Var->getInitializers()) {
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>(Init.get()) llvm::cast<VariableDeclaration::DataInitializer>(Init)
->getContents(); ->getContents();
Section->appendData(Str, llvm::StringRef(Data.data(), Data.size())); Section->appendData(Str, llvm::StringRef(Data.data(), Data.size()));
break; break;
...@@ -422,7 +421,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST, ...@@ -422,7 +421,7 @@ void ELFObjectWriter::writeDataOfType(SectionType ST,
break; break;
case VariableDeclaration::Initializer::RelocInitializerKind: { case VariableDeclaration::Initializer::RelocInitializerKind: {
const auto *Reloc = const auto *Reloc =
llvm::cast<VariableDeclaration::RelocInitializer>(Init.get()); llvm::cast<VariableDeclaration::RelocInitializer>(Init);
AssemblerFixup NewFixup; AssemblerFixup NewFixup;
NewFixup.set_position(Section->getCurrentSize()); NewFixup.set_position(Section->getCurrentSize());
NewFixup.set_kind(Reloc->hasFixup() ? Reloc->getFixup() NewFixup.set_kind(Reloc->hasFixup() ? Reloc->getFixup()
......
...@@ -24,6 +24,8 @@ using namespace llvm::ELF; ...@@ -24,6 +24,8 @@ using namespace llvm::ELF;
namespace Ice { namespace Ice {
using VariableDeclarationPartition = std::vector<VariableDeclaration *>;
/// Higher level ELF object writer. Manages section information and writes the /// Higher level ELF object writer. Manages section information and writes the
/// final ELF object. The object writer will write to file the code and data as /// final ELF object. The object writer will write to file the code and data as
/// it is being defined (rather than keep a copy). After all definitions are /// it is being defined (rather than keep a copy). After all definitions are
...@@ -153,7 +155,7 @@ private: ...@@ -153,7 +155,7 @@ private:
/// SectionType, given the global variables Vars belonging to that /// SectionType, given the global variables Vars belonging to that
/// SectionType. /// SectionType.
void writeDataOfType(SectionType SectionType, void writeDataOfType(SectionType SectionType,
const VariableDeclarationList &Vars, const VariableDeclarationPartition &Vars,
FixupKind RelocationKind, const IceString &SectionSuffix, FixupKind RelocationKind, const IceString &SectionSuffix,
bool IsPIC); bool IsPIC);
......
...@@ -292,17 +292,6 @@ GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError, ...@@ -292,17 +292,6 @@ GlobalContext::GlobalContext(Ostream *OsDump, Ostream *OsEmit, Ostream *OsError,
break; break;
} }
// ProfileBlockInfoVarDecl is initialized here because it takes this as a
// parameter -- we want to
// ensure that at least this' member variables are initialized.
ProfileBlockInfoVarDecl = VariableDeclaration::createExternal(this);
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");
TargetLowering::staticInit(this); TargetLowering::staticInit(this);
} }
...@@ -397,14 +386,10 @@ void GlobalContext::lowerConstants() { DataLowering->lowerConstants(); } ...@@ -397,14 +386,10 @@ void GlobalContext::lowerConstants() { DataLowering->lowerConstants(); }
void GlobalContext::lowerJumpTables() { DataLowering->lowerJumpTables(); } void GlobalContext::lowerJumpTables() { DataLowering->lowerJumpTables(); }
void GlobalContext::addBlockInfoPtrs(VariableDeclaration *ProfileBlockInfo) { void GlobalContext::saveBlockInfoPtrs() {
for (const VariableDeclaration *Global : Globals) { for (VariableDeclaration *Global : Globals) {
if (Cfg::isProfileGlobal(*Global)) { if (Cfg::isProfileGlobal(*Global)) {
constexpr RelocOffsetT BlockExecutionCounterOffset = 0; ProfileBlockInfos.push_back(Global);
ProfileBlockInfo->addInitializer(
VariableDeclaration::RelocInitializer::create(
Global,
{RelocOffset::create(this, BlockExecutionCounterOffset)}));
} }
} }
} }
...@@ -424,7 +409,7 @@ void GlobalContext::lowerGlobals(const IceString &SectionSuffix) { ...@@ -424,7 +409,7 @@ void GlobalContext::lowerGlobals(const IceString &SectionSuffix) {
if (Flags.getDisableTranslation()) if (Flags.getDisableTranslation())
return; return;
addBlockInfoPtrs(ProfileBlockInfoVarDecl); saveBlockInfoPtrs();
// If we need to shuffle the layout of global variables, shuffle them now. // If we need to shuffle the layout of global variables, shuffle them now.
if (getFlags().shouldReorderGlobalVariables()) { if (getFlags().shouldReorderGlobalVariables()) {
// Create a random number generator for global variable reordering. // Create a random number generator for global variable reordering.
...@@ -434,26 +419,48 @@ void GlobalContext::lowerGlobals(const IceString &SectionSuffix) { ...@@ -434,26 +419,48 @@ void GlobalContext::lowerGlobals(const IceString &SectionSuffix) {
[&RNG](int N) { return (uint32_t)RNG.next(N); }); [&RNG](int N) { return (uint32_t)RNG.next(N); });
} }
DataLowering->lowerGlobals(Globals, SectionSuffix); DataLowering->lowerGlobals(Globals, SectionSuffix);
for (VariableDeclaration *Var : Globals) { if (ProfileBlockInfos.empty() && DisposeGlobalVariablesAfterLowering) {
Var->discardInitializers(); Globals.clearAndPurge();
} } else {
Globals.clear(); Globals.clear();
}
} }
void GlobalContext::lowerProfileData() { void GlobalContext::lowerProfileData() {
// ProfileBlockInfoVarDecl is initialized in the constructor, and will only // ProfileBlockInfoVarDecl is initialized in the constructor, and will only
// ever be nullptr after this method completes. This assertion is a convoluted // ever be nullptr after this method completes. This assertion is a convoluted
// way of ensuring lowerProfileData is invoked a single time. // way of ensuring lowerProfileData is invoked a single time.
assert(ProfileBlockInfoVarDecl != nullptr); assert(ProfileBlockInfoVarDecl == nullptr);
auto GlobalVariablePool = getInitializerAllocator();
ProfileBlockInfoVarDecl =
VariableDeclaration::createExternal(GlobalVariablePool.get());
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");
for (const VariableDeclaration *PBI : ProfileBlockInfos) {
if (Cfg::isProfileGlobal(*PBI)) {
constexpr RelocOffsetT BlockExecutionCounterOffset = 0;
ProfileBlockInfoVarDecl->addInitializer(
VariableDeclaration::RelocInitializer::create(
GlobalVariablePool.get(), PBI,
{RelocOffset::create(this, BlockExecutionCounterOffset)}));
}
}
// This adds a 64-bit sentinel entry to the end of our array. For 32-bit // This adds a 64-bit sentinel entry to the end of our array. For 32-bit
// architectures this will waste 4 bytes. // architectures this will waste 4 bytes.
const SizeT Sizeof64BitNullPtr = typeWidthInBytes(IceType_i64); const SizeT Sizeof64BitNullPtr = typeWidthInBytes(IceType_i64);
ProfileBlockInfoVarDecl->addInitializer( ProfileBlockInfoVarDecl->addInitializer(
VariableDeclaration::ZeroInitializer::create(Sizeof64BitNullPtr)); VariableDeclaration::ZeroInitializer::create(GlobalVariablePool.get(),
Sizeof64BitNullPtr));
Globals.push_back(ProfileBlockInfoVarDecl); Globals.push_back(ProfileBlockInfoVarDecl);
constexpr char ProfileDataSection[] = "$sz_profiler$"; constexpr char ProfileDataSection[] = "$sz_profiler$";
lowerGlobals(ProfileDataSection); lowerGlobals(ProfileDataSection);
ProfileBlockInfoVarDecl = nullptr;
} }
void GlobalContext::emitItems() { void GlobalContext::emitItems() {
......
...@@ -57,6 +57,7 @@ public: ...@@ -57,6 +57,7 @@ public:
~LockedPtr() { Lock->unlock(); } ~LockedPtr() { Lock->unlock(); }
T *operator->() const { return Value; } T *operator->() const { return Value; }
T &operator*() const { return *Value; } T &operator*() const { return *Value; }
T *get() { return Value; }
private: private:
T *Value; T *Value;
...@@ -435,6 +436,18 @@ public: ...@@ -435,6 +436,18 @@ public:
static ClFlags Flags; static ClFlags Flags;
static ClFlagsExtra ExtraFlags; static ClFlagsExtra ExtraFlags;
/// DisposeGlobalVariablesAfterLowering controls whether the memory used by
/// GlobaleVariables can be reclaimed right after they have been lowered.
/// @{
bool getDisposeGlobalVariablesAfterLowering() const {
return DisposeGlobalVariablesAfterLowering;
}
void setDisposeGlobalVariablesAfterLowering(bool Value) {
DisposeGlobalVariablesAfterLowering = Value;
}
/// @}
private: private:
// Try to ensure mutexes are allocated on separate cache lines. // Try to ensure mutexes are allocated on separate cache lines.
...@@ -445,6 +458,11 @@ private: ...@@ -445,6 +458,11 @@ private:
ArenaAllocator Allocator; ArenaAllocator Allocator;
ICE_CACHELINE_BOUNDARY; ICE_CACHELINE_BOUNDARY;
// Managed by getInitializerAllocator()
GlobalLockType InitAllocLock;
VariableDeclarationList Globals;
ICE_CACHELINE_BOUNDARY;
// Managed by getDestructors() // Managed by getDestructors()
using DestructorArray = std::vector<std::function<void()>>; using DestructorArray = std::vector<std::function<void()>>;
GlobalLockType DestructorsLock; GlobalLockType DestructorsLock;
...@@ -499,13 +517,18 @@ private: ...@@ -499,13 +517,18 @@ private:
// TODO(jpp): move to EmitterContext. // TODO(jpp): move to EmitterContext.
bool HasSeenCode = false; bool HasSeenCode = false;
// TODO(jpp): move to EmitterContext. // TODO(jpp): move to EmitterContext.
VariableDeclarationList Globals; VariableDeclaration *ProfileBlockInfoVarDecl = nullptr;
// TODO(jpp): move to EmitterContext. std::vector<VariableDeclaration *> ProfileBlockInfos;
VariableDeclaration *ProfileBlockInfoVarDecl; /// Indicates if global variable declarations can be disposed of right after
/// lowering.
bool DisposeGlobalVariablesAfterLowering = true;
LockedPtr<ArenaAllocator> getAllocator() { LockedPtr<ArenaAllocator> getAllocator() {
return LockedPtr<ArenaAllocator>(&Allocator, &AllocLock); return LockedPtr<ArenaAllocator>(&Allocator, &AllocLock);
} }
LockedPtr<VariableDeclarationList> getInitializerAllocator() {
return LockedPtr<VariableDeclarationList>(&Globals, &InitAllocLock);
}
LockedPtr<ConstantPool> getConstPool() { LockedPtr<ConstantPool> getConstPool() {
return LockedPtr<ConstantPool>(ConstPool.get(), &ConstPoolLock); return LockedPtr<ConstantPool>(ConstPool.get(), &ConstPoolLock);
} }
...@@ -523,8 +546,10 @@ private: ...@@ -523,8 +546,10 @@ private:
} }
void accumulateGlobals(std::unique_ptr<VariableDeclarationList> Globls) { void accumulateGlobals(std::unique_ptr<VariableDeclarationList> Globls) {
if (Globls != nullptr) LockedPtr<VariableDeclarationList> _(&Globals, &InitAllocLock);
Globals.insert(Globals.end(), Globls->begin(), Globls->end()); if (Globls != nullptr) {
Globals.merge(Globls.get());
}
} }
void lowerGlobalsIfNoCodeHasBeenSeen() { void lowerGlobalsIfNoCodeHasBeenSeen() {
...@@ -535,7 +560,7 @@ private: ...@@ -535,7 +560,7 @@ private:
HasSeenCode = true; HasSeenCode = true;
} }
void addBlockInfoPtrs(VariableDeclaration *ProfileBlockInfo); void saveBlockInfoPtrs();
llvm::SmallVector<ThreadContext *, 128> AllThreadContexts; llvm::SmallVector<ThreadContext *, 128> AllThreadContexts;
llvm::SmallVector<std::thread, 128> TranslationThreads; llvm::SmallVector<std::thread, 128> TranslationThreads;
......
...@@ -138,12 +138,12 @@ void FunctionDeclaration::dump(Ostream &Stream) const { ...@@ -138,12 +138,12 @@ void FunctionDeclaration::dump(Ostream &Stream) const {
void VariableDeclaration::dumpType(Ostream &Stream) const { void VariableDeclaration::dumpType(Ostream &Stream) const {
if (!Ice::BuildDefs::dump()) if (!Ice::BuildDefs::dump())
return; return;
if (Initializers->size() == 1) { if (Initializers.size() == 1) {
Initializers->front()->dumpType(Stream); Initializers.front()->dumpType(Stream);
} else { } else {
Stream << "<{ "; Stream << "<{ ";
bool IsFirst = true; bool IsFirst = true;
for (const std::unique_ptr<Initializer> &Init : *Initializers) { for (const auto *Init : Initializers) {
if (IsFirst) { if (IsFirst) {
IsFirst = false; IsFirst = false;
} else { } else {
...@@ -163,13 +163,13 @@ void VariableDeclaration::dump(Ostream &Stream) const { ...@@ -163,13 +163,13 @@ void VariableDeclaration::dump(Ostream &Stream) const {
Stream << " " << (IsConstant ? "constant" : "global") << " "; Stream << " " << (IsConstant ? "constant" : "global") << " ";
// Add initializer. // Add initializer.
if (Initializers->size() == 1) { if (Initializers.size() == 1) {
Initializers->front()->dump(Stream); Initializers.front()->dump(Stream);
} else { } else {
dumpType(Stream); dumpType(Stream);
Stream << " <{ "; Stream << " <{ ";
bool IsFirst = true; bool IsFirst = true;
for (const std::unique_ptr<Initializer> &Init : *Initializers) { for (const auto *Init : Initializers) {
if (IsFirst) { if (IsFirst) {
IsFirst = false; IsFirst = false;
} else { } else {
...@@ -199,7 +199,8 @@ void VariableDeclaration::DataInitializer::dump(Ostream &Stream) const { ...@@ -199,7 +199,8 @@ void VariableDeclaration::DataInitializer::dump(Ostream &Stream) const {
Stream << " c\""; Stream << " c\"";
// Code taken from PrintEscapedString() in AsmWriter.cpp. Keep the strings in // Code taken from PrintEscapedString() in AsmWriter.cpp. Keep the strings in
// the same format as the .ll file for practical diffing. // the same format as the .ll file for practical diffing.
for (uint8_t C : Contents) { for (SizeT i = 0; i < ContentsSize; ++i) {
uint8_t C = Contents[i];
if (isprint(C) && C != '\\' && C != '"') if (isprint(C) && C != '\\' && C != '"')
Stream << C; Stream << C;
else else
......
...@@ -826,12 +826,11 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var, ...@@ -826,12 +826,11 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var,
Str << Name << ":\n"; Str << Name << ":\n";
if (HasNonzeroInitializer) { if (HasNonzeroInitializer) {
for (const std::unique_ptr<VariableDeclaration::Initializer> &Init : for (const auto *Init : Var.getInitializers()) {
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>(Init.get()) llvm::cast<VariableDeclaration::DataInitializer>(Init)
->getContents(); ->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";
...@@ -843,7 +842,7 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var, ...@@ -843,7 +842,7 @@ void TargetDataLowering::emitGlobal(const VariableDeclaration &Var,
break; break;
case VariableDeclaration::Initializer::RelocInitializerKind: { case VariableDeclaration::Initializer::RelocInitializerKind: {
const auto *Reloc = const auto *Reloc =
llvm::cast<VariableDeclaration::RelocInitializer>(Init.get()); llvm::cast<VariableDeclaration::RelocInitializer>(Init);
Str << "\t" << getEmit32Directive() << "\t"; Str << "\t" << getEmit32Directive() << "\t";
Str << Reloc->getDeclaration()->getName(); Str << Reloc->getDeclaration()->getName();
if (Reloc->hasFixup()) { if (Reloc->hasFixup()) {
......
...@@ -908,15 +908,19 @@ IceString TargetARM32::createGotoffRelocation(const ConstantRelocatable *CR) { ...@@ -908,15 +908,19 @@ IceString TargetARM32::createGotoffRelocation(const ConstantRelocatable *CR) {
"GOTOFF$" + Func->getFunctionName() + "$" + CRName; "GOTOFF$" + Func->getFunctionName() + "$" + CRName;
if (KnownGotoffs.count(CRGotoffName) == 0) { if (KnownGotoffs.count(CRGotoffName) == 0) {
constexpr bool SuppressMangling = true; constexpr bool SuppressMangling = true;
auto *Global = VariableDeclaration::create(Ctx, SuppressMangling); auto *Global =
VariableDeclaration::create(Func->getGlobalPool(), SuppressMangling);
Global->setIsConstant(true); Global->setIsConstant(true);
Global->setName(CRName); Global->setName(CRName);
Func->getGlobalPool()->willNotBeEmitted(Global);
auto *Gotoff = VariableDeclaration::create(Ctx, SuppressMangling); auto *Gotoff =
VariableDeclaration::create(Func->getGlobalPool(), SuppressMangling);
constexpr auto GotFixup = R_ARM_GOTOFF32; constexpr auto GotFixup = R_ARM_GOTOFF32;
Gotoff->setIsConstant(true); Gotoff->setIsConstant(true);
Gotoff->addInitializer(VariableDeclaration::RelocInitializer::create( Gotoff->addInitializer(VariableDeclaration::RelocInitializer::create(
Global, {RelocOffset::create(Ctx, 0)}, GotFixup)); Func->getGlobalPool(), Global, {RelocOffset::create(Ctx, 0)},
GotFixup));
Gotoff->setName(CRGotoffName); Gotoff->setName(CRGotoffName);
Func->addGlobal(Gotoff); Func->addGlobal(Gotoff);
KnownGotoffs.emplace(CRGotoffName); KnownGotoffs.emplace(CRGotoffName);
......
...@@ -257,6 +257,11 @@ public: ...@@ -257,6 +257,11 @@ public:
size_t getNumTypeIDValues() const { return TypeIDValues.size(); } size_t getNumTypeIDValues() const { return TypeIDValues.size(); }
/// Returns a pointer to the pool where globals are allocated.
Ice::VariableDeclarationList *getGlobalVariablesPool() {
return VariableDeclarations.get();
}
/// Returns the undefined type associated with type ID. Note: Returns extended /// Returns the undefined type associated with type ID. Note: Returns extended
/// type ready to be defined. /// type ready to be defined.
ExtendedType *getTypeByIDForDefining(NaClBcIndexSize_t ID) { ExtendedType *getTypeByIDForDefining(NaClBcIndexSize_t ID) {
...@@ -1021,9 +1026,11 @@ public: ...@@ -1021,9 +1026,11 @@ public:
: BlockParserBaseClass(BlockID, EnclosingParser), : BlockParserBaseClass(BlockID, EnclosingParser),
Timer(Ice::TimerStack::TT_parseGlobals, getTranslator().getContext()), Timer(Ice::TimerStack::TT_parseGlobals, getTranslator().getContext()),
NumFunctionIDs(Context->getNumFunctionIDs()), NumFunctionIDs(Context->getNumFunctionIDs()),
DummyGlobalVar( DummyGlobalVar(Ice::VariableDeclaration::create(
Ice::VariableDeclaration::create(getTranslator().getContext())), Context->getGlobalVariablesPool())),
CurGlobalVar(DummyGlobalVar) {} CurGlobalVar(DummyGlobalVar) {
Context->getGlobalVariablesPool()->willNotBeEmitted(DummyGlobalVar);
}
~GlobalsParser() final = default; ~GlobalsParser() final = default;
...@@ -1063,7 +1070,8 @@ private: ...@@ -1063,7 +1070,8 @@ private:
Ice::VariableDeclaration *getGlobalVarByID(NaClBcIndexSize_t Index) { Ice::VariableDeclaration *getGlobalVarByID(NaClBcIndexSize_t Index) {
Ice::VariableDeclaration *&Decl = GlobalVarsMap[Index]; Ice::VariableDeclaration *&Decl = GlobalVarsMap[Index];
if (Decl == nullptr) if (Decl == nullptr)
Decl = Ice::VariableDeclaration::create(getTranslator().getContext()); Decl =
Ice::VariableDeclaration::create(Context->getGlobalVariablesPool());
return Decl; return Decl;
} }
...@@ -1173,16 +1181,18 @@ void GlobalsParser::ProcessRecord() { ...@@ -1173,16 +1181,18 @@ void GlobalsParser::ProcessRecord() {
// ZEROFILL: [size] // ZEROFILL: [size]
if (!isValidRecordSize(1, "zerofill")) if (!isValidRecordSize(1, "zerofill"))
return; return;
auto *Pool = Context->getGlobalVariablesPool();
CurGlobalVar->addInitializer( CurGlobalVar->addInitializer(
Ice::VariableDeclaration::ZeroInitializer::create(Values[0])); Ice::VariableDeclaration::ZeroInitializer::create(Pool, Values[0]));
return; return;
} }
case naclbitc::GLOBALVAR_DATA: { case naclbitc::GLOBALVAR_DATA: {
// DATA: [b0, b1, ...] // DATA: [b0, b1, ...]
if (!isValidRecordSizeAtLeast(1, "data")) if (!isValidRecordSizeAtLeast(1, "data"))
return; return;
auto *Pool = Context->getGlobalVariablesPool();
CurGlobalVar->addInitializer( CurGlobalVar->addInitializer(
Ice::VariableDeclaration::DataInitializer::create(Values)); Ice::VariableDeclaration::DataInitializer::create(Pool, Values));
return; return;
} }
case naclbitc::GLOBALVAR_RELOC: { case naclbitc::GLOBALVAR_RELOC: {
...@@ -1208,10 +1218,12 @@ void GlobalsParser::ProcessRecord() { ...@@ -1208,10 +1218,12 @@ void GlobalsParser::ProcessRecord() {
Error(StrBuf.str()); Error(StrBuf.str());
} }
} }
auto *Pool = Context->getGlobalVariablesPool();
Ice::GlobalContext *Ctx = getTranslator().getContext(); Ice::GlobalContext *Ctx = getTranslator().getContext();
CurGlobalVar->addInitializer( CurGlobalVar->addInitializer(
Ice::VariableDeclaration::RelocInitializer::create( Ice::VariableDeclaration::RelocInitializer::create(
getGlobalDeclByID(Index), {Ice::RelocOffset::create(Ctx, Offset)})); Pool, getGlobalDeclByID(Index),
{Ice::RelocOffset::create(Ctx, Offset)}));
return; return;
} }
default: default:
......
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