Commit 03077211 by John Porto

Subzero. Refactors Switch Lowering.

BUG= R=stichnot@chromium.org Review URL: https://codereview.chromium.org/1860473002 .
parent 681f90fe
...@@ -1025,11 +1025,6 @@ void Cfg::emitTextHeader(GlobalString Name, GlobalContext *Ctx, ...@@ -1025,11 +1025,6 @@ void Cfg::emitTextHeader(GlobalString Name, GlobalContext *Ctx,
Str << Name << ":\n"; Str << Name << ":\n";
} }
void Cfg::deleteJumpTableInsts() {
for (InstJumpTable *JumpTable : JumpTables)
JumpTable->setDeleted();
}
void Cfg::emitJumpTables() { void Cfg::emitJumpTables() {
switch (getFlags().getOutFileType()) { switch (getFlags().getOutFileType()) {
case FT_Elf: case FT_Elf:
...@@ -1037,14 +1032,7 @@ void Cfg::emitJumpTables() { ...@@ -1037,14 +1032,7 @@ void Cfg::emitJumpTables() {
// The emission needs to be delayed until the after the text section so // The emission needs to be delayed until the after the text section so
// save the offsets in the global context. // save the offsets in the global context.
for (const InstJumpTable *JumpTable : JumpTables) { for (const InstJumpTable *JumpTable : JumpTables) {
SizeT NumTargets = JumpTable->getNumTargets(); Ctx->addJumpTableData(JumpTable->toJumpTableData(getAssembler()));
JumpTableData::TargetList TargetList;
for (SizeT I = 0; I < NumTargets; ++I) {
SizeT Index = JumpTable->getTarget(I)->getIndex();
TargetList.emplace_back(
getAssembler()->getCfgNodeLabel(Index)->getPosition());
}
Ctx->addJumpTable(FunctionName, JumpTable->getId(), TargetList);
} }
} break; } break;
case FT_Asm: { case FT_Asm: {
...@@ -1071,7 +1059,6 @@ void Cfg::emit() { ...@@ -1071,7 +1059,6 @@ void Cfg::emit() {
const bool NeedSandboxing = getFlags().getUseSandboxing(); const bool NeedSandboxing = getFlags().getUseSandboxing();
emitTextHeader(FunctionName, Ctx, Asm); emitTextHeader(FunctionName, Ctx, Asm);
deleteJumpTableInsts();
if (getFlags().getDecorateAsm()) { if (getFlags().getDecorateAsm()) {
for (Variable *Var : getVariables()) { for (Variable *Var : getVariables()) {
if (Var->getStackOffset() && !Var->isRematerializable()) { if (Var->getStackOffset() && !Var->isRematerializable()) {
...@@ -1095,7 +1082,6 @@ void Cfg::emitIAS() { ...@@ -1095,7 +1082,6 @@ void Cfg::emitIAS() {
TimerMarker T(TimerStack::TT_emitAsm, this); TimerMarker T(TimerStack::TT_emitAsm, this);
// The emitIAS() routines emit into the internal assembler buffer, so there's // The emitIAS() routines emit into the internal assembler buffer, so there's
// no need to lock the streams. // no need to lock the streams.
deleteJumpTableInsts();
const bool NeedSandboxing = getFlags().getUseSandboxing(); const bool NeedSandboxing = getFlags().getUseSandboxing();
for (CfgNode *Node : Nodes) { for (CfgNode *Node : Nodes) {
if (NeedSandboxing && Node->needsAlignment()) if (NeedSandboxing && Node->needsAlignment())
......
...@@ -282,9 +282,6 @@ private: ...@@ -282,9 +282,6 @@ private:
createBlockProfilingInfoDeclaration(const std::string &NodeAsmName, createBlockProfilingInfoDeclaration(const std::string &NodeAsmName,
VariableDeclaration *NodeNameDeclaration); VariableDeclaration *NodeNameDeclaration);
/// Delete registered jump table placeholder instructions. This should only be
/// called once all repointing has taken place.
void deleteJumpTableInsts();
/// Iterate through the registered jump tables and emit them. /// Iterate through the registered jump tables and emit them.
void emitJumpTables(); void emitJumpTables();
......
...@@ -581,12 +581,8 @@ void ELFObjectWriter::writeJumpTable(const JumpTableData &JT, ...@@ -581,12 +581,8 @@ void ELFObjectWriter::writeJumpTable(const JumpTableData &JT,
const Elf64_Xword PointerSize = typeWidthInBytes(getPointerType()); const Elf64_Xword PointerSize = typeWidthInBytes(getPointerType());
const Elf64_Xword ShAddralign = PointerSize; const Elf64_Xword ShAddralign = PointerSize;
const Elf64_Xword ShEntsize = PointerSize; const Elf64_Xword ShEntsize = PointerSize;
const GlobalString JTName = JT.getFunctionName();
const std::string SectionName = MangleSectionName( const std::string SectionName = MangleSectionName(
IsPIC ? ".data.rel.ro" : ".rodata", IsPIC ? ".data.rel.ro" : ".rodata", JT.getSectionName());
(JTName.hasStdString() ? JTName.toString()
: std::to_string(JTName.getID())) +
"$jumptable");
Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, SHF_ALLOC, Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, SHF_ALLOC,
ShAddralign, ShEntsize); ShAddralign, ShEntsize);
Section->setFileOffset(alignFileOffset(ShAddralign)); Section->setFileOffset(alignFileOffset(ShAddralign));
...@@ -598,8 +594,7 @@ void ELFObjectWriter::writeJumpTable(const JumpTableData &JT, ...@@ -598,8 +594,7 @@ void ELFObjectWriter::writeJumpTable(const JumpTableData &JT,
Section->padToAlignment(Str, PointerSize); Section->padToAlignment(Str, PointerSize);
const bool IsExternal = getFlags().getDisableInternal(); const bool IsExternal = getFlags().getDisableInternal();
const uint8_t SymbolBinding = IsExternal ? STB_GLOBAL : STB_LOCAL; const uint8_t SymbolBinding = IsExternal ? STB_GLOBAL : STB_LOCAL;
GlobalString JumpTableName = Ctx.getGlobalString( const auto JumpTableName = JT.getName();
InstJumpTable::makeName(JT.getFunctionName(), JT.getId()));
SymTab->createDefinedSym(JumpTableName, SymbolType, SymbolBinding, Section, SymTab->createDefinedSym(JumpTableName, SymbolType, SymbolBinding, Section,
Section->getCurrentSize(), PointerSize); Section->getCurrentSize(), PointerSize);
StrTab->add(JumpTableName); StrTab->add(JumpTableName);
......
...@@ -872,12 +872,8 @@ JumpTableDataList GlobalContext::getJumpTables() { ...@@ -872,12 +872,8 @@ JumpTableDataList GlobalContext::getJumpTables() {
return JumpTables; return JumpTables;
} }
JumpTableData & void GlobalContext::addJumpTableData(JumpTableData JumpTable) {
GlobalContext::addJumpTable(GlobalString FuncName, SizeT Id, getJumpTableList()->emplace_back(std::move(JumpTable));
const JumpTableData::TargetList &TargetList) {
auto JumpTableList = getJumpTableList();
JumpTableList->emplace_back(FuncName, Id, TargetList);
return JumpTableList->back();
} }
TimerStackIdT GlobalContext::newTimerStackID(const std::string &Name) { TimerStackIdT GlobalContext::newTimerStackID(const std::string &Name) {
......
...@@ -268,9 +268,8 @@ public: ...@@ -268,9 +268,8 @@ public:
/// Return a locked pointer to the registered jump tables. /// Return a locked pointer to the registered jump tables.
JumpTableDataList getJumpTables(); JumpTableDataList getJumpTables();
/// Create a new jump table entry and return a reference to it. /// Adds JumpTable to the list of know jump tables, for a posteriori emission.
JumpTableData &addJumpTable(GlobalString FuncName, SizeT Id, void addJumpTableData(JumpTableData JumpTable);
const JumpTableData::TargetList &TargetList);
/// Allocate data of type T using the global allocator. We allow entities /// Allocate data of type T using the global allocator. We allow entities
/// allocated from this global allocator to be either trivially or /// allocated from this global allocator to be either trivially or
......
...@@ -569,12 +569,26 @@ InstFakeUse::InstFakeUse(Cfg *Func, Variable *Src, uint32_t Weight) ...@@ -569,12 +569,26 @@ InstFakeUse::InstFakeUse(Cfg *Func, Variable *Src, uint32_t Weight)
InstFakeKill::InstFakeKill(Cfg *Func, const Inst *Linked) InstFakeKill::InstFakeKill(Cfg *Func, const Inst *Linked)
: InstHighLevel(Func, Inst::FakeKill, 0, nullptr), Linked(Linked) {} : InstHighLevel(Func, Inst::FakeKill, 0, nullptr), Linked(Linked) {}
namespace {
GlobalString makeName(Cfg *Func, const SizeT Id) {
const auto FuncName = Func->getFunctionName();
auto *Ctx = Func->getContext();
if (FuncName.hasStdString())
return GlobalString::createWithString(
Ctx, ".L" + FuncName.toString() + "$jumptable$__" + std::to_string(Id));
return GlobalString::createWithString(
Ctx, ".L" + std::to_string(FuncName.getID()) + "_" + std::to_string(Id));
}
} // end of anonymous namespace
InstJumpTable::InstJumpTable(Cfg *Func, SizeT NumTargets, CfgNode *Default) InstJumpTable::InstJumpTable(Cfg *Func, SizeT NumTargets, CfgNode *Default)
: InstHighLevel(Func, Inst::JumpTable, 1, nullptr), : InstHighLevel(Func, Inst::JumpTable, 1, nullptr),
Id(Func->getTarget()->makeNextJumpTableNumber()), NumTargets(NumTargets) { Id(Func->getTarget()->makeNextJumpTableNumber()), NumTargets(NumTargets),
Name(makeName(Func, Id)), FuncName(Func->getFunctionName()) {
Targets = Func->allocateArrayOf<CfgNode *>(NumTargets); Targets = Func->allocateArrayOf<CfgNode *>(NumTargets);
for (SizeT I = 0; I < NumTargets; ++I) for (SizeT I = 0; I < NumTargets; ++I) {
Targets[I] = Default; Targets[I] = Default;
}
} }
bool InstJumpTable::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { bool InstJumpTable::repointEdges(CfgNode *OldNode, CfgNode *NewNode) {
...@@ -588,6 +602,15 @@ bool InstJumpTable::repointEdges(CfgNode *OldNode, CfgNode *NewNode) { ...@@ -588,6 +602,15 @@ bool InstJumpTable::repointEdges(CfgNode *OldNode, CfgNode *NewNode) {
return Found; return Found;
} }
JumpTableData InstJumpTable::toJumpTableData(Assembler *Asm) const {
JumpTableData::TargetList TargetList(NumTargets);
for (SizeT i = 0; i < NumTargets; ++i) {
const SizeT Index = Targets[i]->getIndex();
TargetList[i] = Asm->getCfgNodeLabel(Index)->getPosition();
}
return JumpTableData(Name, FuncName, Id, TargetList);
}
Type InstCall::getReturnType() const { Type InstCall::getReturnType() const {
if (Dest == nullptr) if (Dest == nullptr)
return IceType_void; return IceType_void;
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "IceDefs.h" #include "IceDefs.h"
#include "IceInst.def" #include "IceInst.def"
#include "IceIntrinsics.h" #include "IceIntrinsics.h"
#include "IceSwitchLowering.h"
#include "IceTypes.h" #include "IceTypes.h"
// TODO: The Cfg structure, and instructions in particular, need to be // TODO: The Cfg structure, and instructions in particular, need to be
...@@ -943,12 +944,22 @@ public: ...@@ -943,12 +944,22 @@ public:
static bool classof(const Inst *Instr) { static bool classof(const Inst *Instr) {
return Instr->getKind() == JumpTable; return Instr->getKind() == JumpTable;
} }
// Creates a JumpTableData struct (used for ELF emission) that represents this
// InstJumpTable.
JumpTableData toJumpTableData(Assembler *Asm) const;
// TODO(stichnot): Should this create&save GlobalString values? // InstJumpTable is just a placeholder for the switch targets, and it does not
static std::string makeName(GlobalString FuncName, SizeT Id) { // need to emit any code, so we redefine emit and emitIAS to do nothing.
if (FuncName.hasStdString()) void emit(const Cfg *) const override {}
return ".L" + FuncName + "$jumptable$__" + std::to_string(Id); void emitIAS(const Cfg * /* Func */) const override {}
return ".L" + std::to_string(FuncName.getID()) + "_" + std::to_string(Id);
const std::string getName() const {
assert(Name.hasStdString());
return Name.toString();
}
std::string getSectionName() const {
return JumpTableData::createSectionName(FuncName);
} }
private: private:
...@@ -961,6 +972,8 @@ private: ...@@ -961,6 +972,8 @@ private:
const SizeT Id; const SizeT Id;
const SizeT NumTargets; const SizeT NumTargets;
CfgNode **Targets; CfgNode **Targets;
GlobalString Name; // This JumpTable's name in the output.
GlobalString FuncName;
}; };
/// The Target instruction is the base class for all target-specific /// The Target instruction is the base class for all target-specific
......
...@@ -23,10 +23,11 @@ namespace Ice { ...@@ -23,10 +23,11 @@ namespace Ice {
CaseClusterArray CaseCluster::clusterizeSwitch(Cfg *Func, CaseClusterArray CaseCluster::clusterizeSwitch(Cfg *Func,
const InstSwitch *Instr) { const InstSwitch *Instr) {
const SizeT NumCases = Instr->getNumCases();
CaseClusterArray CaseClusters; CaseClusterArray CaseClusters;
CaseClusters.reserve(NumCases);
// Load the cases // Load the cases
SizeT NumCases = Instr->getNumCases();
CaseClusters.reserve(NumCases); CaseClusters.reserve(NumCases);
for (SizeT I = 0; I < NumCases; ++I) for (SizeT I = 0; I < NumCases; ++I)
CaseClusters.emplace_back(Instr->getValue(I), Instr->getLabel(I)); CaseClusters.emplace_back(Instr->getValue(I), Instr->getLabel(I));
...@@ -60,21 +61,21 @@ CaseClusterArray CaseCluster::clusterizeSwitch(Cfg *Func, ...@@ -60,21 +61,21 @@ CaseClusterArray CaseCluster::clusterizeSwitch(Cfg *Func,
// frequently executed code but we can't do this well without profiling data. // frequently executed code but we can't do this well without profiling data.
// So, this single jump table is a good starting point where you can get to // So, this single jump table is a good starting point where you can get to
// the jump table quickly without figuring out how to unbalance the tree. // the jump table quickly without figuring out how to unbalance the tree.
uint64_t MaxValue = CaseClusters.back().High; const uint64_t MaxValue = CaseClusters.back().High;
uint64_t MinValue = CaseClusters.front().Low; const uint64_t MinValue = CaseClusters.front().Low;
// Don't +1 yet to avoid (INT64_MAX-0)+1 overflow // Don't +1 yet to avoid (INT64_MAX-0)+1 overflow
uint64_t TotalRange = MaxValue - MinValue; const uint64_t Range = MaxValue - MinValue;
// Might be too sparse for the jump table // Might be too sparse for the jump table
if (NumCases * 2 <= TotalRange) if (NumCases * 2 <= Range)
return CaseClusters; return CaseClusters;
// Unlikely. Would mean can't store size of jump table. // Unlikely. Would mean can't store size of jump table.
if (TotalRange == UINT64_MAX) if (Range == UINT64_MAX)
return CaseClusters; return CaseClusters;
++TotalRange; const uint64_t TotalRange = Range + 1;
// Replace everything with a jump table // Replace everything with a jump table
InstJumpTable *JumpTable = auto *JumpTable =
InstJumpTable::create(Func, TotalRange, Instr->getLabelDefault()); InstJumpTable::create(Func, TotalRange, Instr->getLabelDefault());
for (const CaseCluster &Case : CaseClusters) { for (const CaseCluster &Case : CaseClusters) {
// Case.High could be UINT64_MAX which makes the loop awkward. Unwrap the // Case.High could be UINT64_MAX which makes the loop awkward. Unwrap the
...@@ -94,7 +95,8 @@ CaseClusterArray CaseCluster::clusterizeSwitch(Cfg *Func, ...@@ -94,7 +95,8 @@ CaseClusterArray CaseCluster::clusterizeSwitch(Cfg *Func,
bool CaseCluster::tryAppend(const CaseCluster &New) { bool CaseCluster::tryAppend(const CaseCluster &New) {
// Can only append ranges with the same target and are adjacent // Can only append ranges with the same target and are adjacent
bool CanAppend = this->Target == New.Target && this->High + 1 == New.Low; const bool CanAppend =
this->Target == New.Target && this->High + 1 == New.Low;
if (CanAppend) if (CanAppend)
this->High = New.High; this->High = New.High;
return CanAppend; return CanAppend;
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include "IceDefs.h" #include "IceDefs.h"
#include "IceStringPool.h" #include "IceStringPool.h"
#include <string>
namespace Ice { namespace Ice {
class CaseCluster; class CaseCluster;
...@@ -85,18 +87,27 @@ class JumpTableData { ...@@ -85,18 +87,27 @@ class JumpTableData {
public: public:
using TargetList = std::vector<intptr_t>; using TargetList = std::vector<intptr_t>;
JumpTableData(GlobalString FuncName, SizeT Id, JumpTableData(GlobalString Name, GlobalString FuncName, SizeT Id,
const TargetList &TargetOffsets) const TargetList &TargetOffsets)
: FuncName(FuncName), Id(Id), TargetOffsets(TargetOffsets) {} : Name(Name), FuncName(FuncName), Id(Id), TargetOffsets(TargetOffsets) {}
JumpTableData(const JumpTableData &) = default; JumpTableData(const JumpTableData &) = default;
JumpTableData(JumpTableData &&) = default; JumpTableData(JumpTableData &&) = default;
JumpTableData &operator=(JumpTableData &&) = default; JumpTableData &operator=(JumpTableData &&) = default;
const GlobalString getFunctionName() const { return FuncName; } GlobalString getName() const { return Name; }
GlobalString getFunctionName() const { return FuncName; }
SizeT getId() const { return Id; } SizeT getId() const { return Id; }
const TargetList &getTargetOffsets() const { return TargetOffsets; } const TargetList &getTargetOffsets() const { return TargetOffsets; }
static std::string createSectionName(const GlobalString Name) {
if (Name.hasStdString()) {
return Name.toString() + "$jumptable";
}
return std::to_string(Name.getID()) + "$jumptable";
}
std::string getSectionName() const { return createSectionName(FuncName); }
private: private:
GlobalString Name;
GlobalString FuncName; GlobalString FuncName;
SizeT Id; SizeT Id;
TargetList TargetOffsets; TargetList TargetOffsets;
......
...@@ -5881,10 +5881,8 @@ void TargetX86Base<TraitsType>::lowerCaseCluster(const CaseCluster &Case, ...@@ -5881,10 +5881,8 @@ void TargetX86Base<TraitsType>::lowerCaseCluster(const CaseCluster &Case,
} }
constexpr RelocOffsetT RelocOffset = 0; constexpr RelocOffsetT RelocOffset = 0;
GlobalString FunctionName = Func->getFunctionName();
constexpr Variable *NoBase = nullptr; constexpr Variable *NoBase = nullptr;
auto JTName = GlobalString::createWithString( auto JTName = GlobalString::createWithString(Ctx, JumpTable->getName());
Ctx, InstJumpTable::makeName(FunctionName, JumpTable->getId()));
Constant *Offset = Ctx->getConstantSym(RelocOffset, JTName); Constant *Offset = Ctx->getConstantSym(RelocOffset, JTName);
uint16_t Shift = typeWidthInBytesLog2(PointerType); uint16_t Shift = typeWidthInBytesLog2(PointerType);
constexpr auto Segment = X86OperandMem::SegmentRegisters::DefaultSegment; constexpr auto Segment = X86OperandMem::SegmentRegisters::DefaultSegment;
...@@ -7277,17 +7275,16 @@ TargetX86Base<TraitsType>::randomizeOrPoolImmediate(X86OperandMem *MemOperand, ...@@ -7277,17 +7275,16 @@ TargetX86Base<TraitsType>::randomizeOrPoolImmediate(X86OperandMem *MemOperand,
template <typename TraitsType> template <typename TraitsType>
void TargetX86Base<TraitsType>::emitJumpTable( void TargetX86Base<TraitsType>::emitJumpTable(
const Cfg *Func, const InstJumpTable *JumpTable) const { const Cfg *, const InstJumpTable *JumpTable) const {
if (!BuildDefs::dump()) if (!BuildDefs::dump())
return; return;
Ostream &Str = Ctx->getStrEmit(); Ostream &Str = Ctx->getStrEmit();
const bool UseNonsfi = getFlags().getUseNonsfi(); const bool UseNonsfi = getFlags().getUseNonsfi();
GlobalString FunctionName = Func->getFunctionName();
const char *Prefix = UseNonsfi ? ".data.rel.ro." : ".rodata."; const char *Prefix = UseNonsfi ? ".data.rel.ro." : ".rodata.";
Str << "\t.section\t" << Prefix << FunctionName Str << "\t.section\t" << Prefix << JumpTable->getSectionName()
<< "$jumptable,\"a\",@progbits\n"; << ",\"a\",@progbits\n"
Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n"; "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n"
Str << InstJumpTable::makeName(FunctionName, JumpTable->getId()) << ":"; << JumpTable->getName() << ":";
// On X86 ILP32 pointers are 32-bit hence the use of .long // On X86 ILP32 pointers are 32-bit hence the use of .long
for (SizeT I = 0; I < JumpTable->getNumTargets(); ++I) for (SizeT I = 0; I < JumpTable->getNumTargets(); ++I)
...@@ -7389,10 +7386,10 @@ void TargetDataX86<TraitsType>::lowerJumpTables() { ...@@ -7389,10 +7386,10 @@ void TargetDataX86<TraitsType>::lowerJumpTables() {
Ostream &Str = Ctx->getStrEmit(); Ostream &Str = Ctx->getStrEmit();
const char *Prefix = IsPIC ? ".data.rel.ro." : ".rodata."; const char *Prefix = IsPIC ? ".data.rel.ro." : ".rodata.";
for (const JumpTableData &JT : Ctx->getJumpTables()) { for (const JumpTableData &JT : Ctx->getJumpTables()) {
Str << "\t.section\t" << Prefix << JT.getFunctionName() Str << "\t.section\t" << Prefix << JT.getSectionName()
<< "$jumptable,\"a\",@progbits\n"; << ",\"a\",@progbits\n"
Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n"; "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n"
Str << InstJumpTable::makeName(JT.getFunctionName(), JT.getId()) << ":"; << JT.getName().toString() << ":";
// On X8664 ILP32 pointers are 32-bit hence the use of .long // On X8664 ILP32 pointers are 32-bit hence the use of .long
for (intptr_t TargetOffset : JT.getTargetOffsets()) for (intptr_t TargetOffset : JT.getTargetOffsets())
......
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