Subzero. Refactors Switch Lowering.
BUG=
R=stichnot@chromium.org
Review URL: https://codereview.chromium.org/1860473002 .
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index e2bee72..33a5992 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -1025,11 +1025,6 @@
Str << Name << ":\n";
}
-void Cfg::deleteJumpTableInsts() {
- for (InstJumpTable *JumpTable : JumpTables)
- JumpTable->setDeleted();
-}
-
void Cfg::emitJumpTables() {
switch (getFlags().getOutFileType()) {
case FT_Elf:
@@ -1037,14 +1032,7 @@
// The emission needs to be delayed until the after the text section so
// save the offsets in the global context.
for (const InstJumpTable *JumpTable : JumpTables) {
- SizeT NumTargets = JumpTable->getNumTargets();
- 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);
+ Ctx->addJumpTableData(JumpTable->toJumpTableData(getAssembler()));
}
} break;
case FT_Asm: {
@@ -1071,7 +1059,6 @@
const bool NeedSandboxing = getFlags().getUseSandboxing();
emitTextHeader(FunctionName, Ctx, Asm);
- deleteJumpTableInsts();
if (getFlags().getDecorateAsm()) {
for (Variable *Var : getVariables()) {
if (Var->getStackOffset() && !Var->isRematerializable()) {
@@ -1095,7 +1082,6 @@
TimerMarker T(TimerStack::TT_emitAsm, this);
// The emitIAS() routines emit into the internal assembler buffer, so there's
// no need to lock the streams.
- deleteJumpTableInsts();
const bool NeedSandboxing = getFlags().getUseSandboxing();
for (CfgNode *Node : Nodes) {
if (NeedSandboxing && Node->needsAlignment())
diff --git a/src/IceCfg.h b/src/IceCfg.h
index abb6722..a34a9ee 100644
--- a/src/IceCfg.h
+++ b/src/IceCfg.h
@@ -282,9 +282,6 @@
createBlockProfilingInfoDeclaration(const std::string &NodeAsmName,
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.
void emitJumpTables();
diff --git a/src/IceELFObjectWriter.cpp b/src/IceELFObjectWriter.cpp
index e960d9c..38919cc 100644
--- a/src/IceELFObjectWriter.cpp
+++ b/src/IceELFObjectWriter.cpp
@@ -581,12 +581,8 @@
const Elf64_Xword PointerSize = typeWidthInBytes(getPointerType());
const Elf64_Xword ShAddralign = PointerSize;
const Elf64_Xword ShEntsize = PointerSize;
- const GlobalString JTName = JT.getFunctionName();
const std::string SectionName = MangleSectionName(
- IsPIC ? ".data.rel.ro" : ".rodata",
- (JTName.hasStdString() ? JTName.toString()
- : std::to_string(JTName.getID())) +
- "$jumptable");
+ IsPIC ? ".data.rel.ro" : ".rodata", JT.getSectionName());
Section = createSection<ELFDataSection>(SectionName, SHT_PROGBITS, SHF_ALLOC,
ShAddralign, ShEntsize);
Section->setFileOffset(alignFileOffset(ShAddralign));
@@ -598,8 +594,7 @@
Section->padToAlignment(Str, PointerSize);
const bool IsExternal = getFlags().getDisableInternal();
const uint8_t SymbolBinding = IsExternal ? STB_GLOBAL : STB_LOCAL;
- GlobalString JumpTableName = Ctx.getGlobalString(
- InstJumpTable::makeName(JT.getFunctionName(), JT.getId()));
+ const auto JumpTableName = JT.getName();
SymTab->createDefinedSym(JumpTableName, SymbolType, SymbolBinding, Section,
Section->getCurrentSize(), PointerSize);
StrTab->add(JumpTableName);
diff --git a/src/IceGlobalContext.cpp b/src/IceGlobalContext.cpp
index e7faa50..25e1cc6 100644
--- a/src/IceGlobalContext.cpp
+++ b/src/IceGlobalContext.cpp
@@ -872,12 +872,8 @@
return JumpTables;
}
-JumpTableData &
-GlobalContext::addJumpTable(GlobalString FuncName, SizeT Id,
- const JumpTableData::TargetList &TargetList) {
- auto JumpTableList = getJumpTableList();
- JumpTableList->emplace_back(FuncName, Id, TargetList);
- return JumpTableList->back();
+void GlobalContext::addJumpTableData(JumpTableData JumpTable) {
+ getJumpTableList()->emplace_back(std::move(JumpTable));
}
TimerStackIdT GlobalContext::newTimerStackID(const std::string &Name) {
diff --git a/src/IceGlobalContext.h b/src/IceGlobalContext.h
index 2ce1083..7aaf513 100644
--- a/src/IceGlobalContext.h
+++ b/src/IceGlobalContext.h
@@ -268,9 +268,8 @@
/// Return a locked pointer to the registered jump tables.
JumpTableDataList getJumpTables();
- /// Create a new jump table entry and return a reference to it.
- JumpTableData &addJumpTable(GlobalString FuncName, SizeT Id,
- const JumpTableData::TargetList &TargetList);
+ /// Adds JumpTable to the list of know jump tables, for a posteriori emission.
+ void addJumpTableData(JumpTableData JumpTable);
/// Allocate data of type T using the global allocator. We allow entities
/// allocated from this global allocator to be either trivially or
diff --git a/src/IceInst.cpp b/src/IceInst.cpp
index 719791a..6cd2a04 100644
--- a/src/IceInst.cpp
+++ b/src/IceInst.cpp
@@ -569,12 +569,26 @@
InstFakeKill::InstFakeKill(Cfg *Func, const Inst *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)
: 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);
- for (SizeT I = 0; I < NumTargets; ++I)
+ for (SizeT I = 0; I < NumTargets; ++I) {
Targets[I] = Default;
+ }
}
bool InstJumpTable::repointEdges(CfgNode *OldNode, CfgNode *NewNode) {
@@ -588,6 +602,15 @@
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 {
if (Dest == nullptr)
return IceType_void;
diff --git a/src/IceInst.h b/src/IceInst.h
index dfb873c..1b49419 100644
--- a/src/IceInst.h
+++ b/src/IceInst.h
@@ -22,6 +22,7 @@
#include "IceDefs.h"
#include "IceInst.def"
#include "IceIntrinsics.h"
+#include "IceSwitchLowering.h"
#include "IceTypes.h"
// TODO: The Cfg structure, and instructions in particular, need to be
@@ -943,12 +944,22 @@
static bool classof(const Inst *Instr) {
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?
- static std::string makeName(GlobalString FuncName, SizeT Id) {
- if (FuncName.hasStdString())
- return ".L" + FuncName + "$jumptable$__" + std::to_string(Id);
- return ".L" + std::to_string(FuncName.getID()) + "_" + std::to_string(Id);
+ // InstJumpTable is just a placeholder for the switch targets, and it does not
+ // need to emit any code, so we redefine emit and emitIAS to do nothing.
+ void emit(const Cfg *) const override {}
+ void emitIAS(const Cfg * /* Func */) const override {}
+
+ const std::string getName() const {
+ assert(Name.hasStdString());
+ return Name.toString();
+ }
+
+ std::string getSectionName() const {
+ return JumpTableData::createSectionName(FuncName);
}
private:
@@ -961,6 +972,8 @@
const SizeT Id;
const SizeT NumTargets;
CfgNode **Targets;
+ GlobalString Name; // This JumpTable's name in the output.
+ GlobalString FuncName;
};
/// The Target instruction is the base class for all target-specific
diff --git a/src/IceSwitchLowering.cpp b/src/IceSwitchLowering.cpp
index 35749bf..ede1a94 100644
--- a/src/IceSwitchLowering.cpp
+++ b/src/IceSwitchLowering.cpp
@@ -23,10 +23,11 @@
CaseClusterArray CaseCluster::clusterizeSwitch(Cfg *Func,
const InstSwitch *Instr) {
+ const SizeT NumCases = Instr->getNumCases();
CaseClusterArray CaseClusters;
+ CaseClusters.reserve(NumCases);
// Load the cases
- SizeT NumCases = Instr->getNumCases();
CaseClusters.reserve(NumCases);
for (SizeT I = 0; I < NumCases; ++I)
CaseClusters.emplace_back(Instr->getValue(I), Instr->getLabel(I));
@@ -60,21 +61,21 @@
// 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
// the jump table quickly without figuring out how to unbalance the tree.
- uint64_t MaxValue = CaseClusters.back().High;
- uint64_t MinValue = CaseClusters.front().Low;
+ const uint64_t MaxValue = CaseClusters.back().High;
+ const uint64_t MinValue = CaseClusters.front().Low;
// 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
- if (NumCases * 2 <= TotalRange)
+ if (NumCases * 2 <= Range)
return CaseClusters;
// Unlikely. Would mean can't store size of jump table.
- if (TotalRange == UINT64_MAX)
+ if (Range == UINT64_MAX)
return CaseClusters;
- ++TotalRange;
+ const uint64_t TotalRange = Range + 1;
// Replace everything with a jump table
- InstJumpTable *JumpTable =
+ auto *JumpTable =
InstJumpTable::create(Func, TotalRange, Instr->getLabelDefault());
for (const CaseCluster &Case : CaseClusters) {
// Case.High could be UINT64_MAX which makes the loop awkward. Unwrap the
@@ -94,7 +95,8 @@
bool CaseCluster::tryAppend(const CaseCluster &New) {
// 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)
this->High = New.High;
return CanAppend;
diff --git a/src/IceSwitchLowering.h b/src/IceSwitchLowering.h
index d4f5291..57dd828 100644
--- a/src/IceSwitchLowering.h
+++ b/src/IceSwitchLowering.h
@@ -18,6 +18,8 @@
#include "IceDefs.h"
#include "IceStringPool.h"
+#include <string>
+
namespace Ice {
class CaseCluster;
@@ -85,18 +87,27 @@
public:
using TargetList = std::vector<intptr_t>;
- JumpTableData(GlobalString FuncName, SizeT Id,
+ JumpTableData(GlobalString Name, GlobalString FuncName, SizeT Id,
const TargetList &TargetOffsets)
- : FuncName(FuncName), Id(Id), TargetOffsets(TargetOffsets) {}
+ : Name(Name), FuncName(FuncName), Id(Id), TargetOffsets(TargetOffsets) {}
JumpTableData(const JumpTableData &) = default;
JumpTableData(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; }
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:
+ GlobalString Name;
GlobalString FuncName;
SizeT Id;
TargetList TargetOffsets;
diff --git a/src/IceTargetLoweringX86BaseImpl.h b/src/IceTargetLoweringX86BaseImpl.h
index a344d57..c1a5f74 100644
--- a/src/IceTargetLoweringX86BaseImpl.h
+++ b/src/IceTargetLoweringX86BaseImpl.h
@@ -5881,10 +5881,8 @@
}
constexpr RelocOffsetT RelocOffset = 0;
- GlobalString FunctionName = Func->getFunctionName();
constexpr Variable *NoBase = nullptr;
- auto JTName = GlobalString::createWithString(
- Ctx, InstJumpTable::makeName(FunctionName, JumpTable->getId()));
+ auto JTName = GlobalString::createWithString(Ctx, JumpTable->getName());
Constant *Offset = Ctx->getConstantSym(RelocOffset, JTName);
uint16_t Shift = typeWidthInBytesLog2(PointerType);
constexpr auto Segment = X86OperandMem::SegmentRegisters::DefaultSegment;
@@ -7277,17 +7275,16 @@
template <typename TraitsType>
void TargetX86Base<TraitsType>::emitJumpTable(
- const Cfg *Func, const InstJumpTable *JumpTable) const {
+ const Cfg *, const InstJumpTable *JumpTable) const {
if (!BuildDefs::dump())
return;
Ostream &Str = Ctx->getStrEmit();
const bool UseNonsfi = getFlags().getUseNonsfi();
- GlobalString FunctionName = Func->getFunctionName();
const char *Prefix = UseNonsfi ? ".data.rel.ro." : ".rodata.";
- Str << "\t.section\t" << Prefix << FunctionName
- << "$jumptable,\"a\",@progbits\n";
- Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n";
- Str << InstJumpTable::makeName(FunctionName, JumpTable->getId()) << ":";
+ Str << "\t.section\t" << Prefix << JumpTable->getSectionName()
+ << ",\"a\",@progbits\n"
+ "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n"
+ << JumpTable->getName() << ":";
// On X86 ILP32 pointers are 32-bit hence the use of .long
for (SizeT I = 0; I < JumpTable->getNumTargets(); ++I)
@@ -7389,10 +7386,10 @@
Ostream &Str = Ctx->getStrEmit();
const char *Prefix = IsPIC ? ".data.rel.ro." : ".rodata.";
for (const JumpTableData &JT : Ctx->getJumpTables()) {
- Str << "\t.section\t" << Prefix << JT.getFunctionName()
- << "$jumptable,\"a\",@progbits\n";
- Str << "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n";
- Str << InstJumpTable::makeName(JT.getFunctionName(), JT.getId()) << ":";
+ Str << "\t.section\t" << Prefix << JT.getSectionName()
+ << ",\"a\",@progbits\n"
+ "\t.align\t" << typeWidthInBytes(getPointerType()) << "\n"
+ << JT.getName().toString() << ":";
// On X8664 ILP32 pointers are 32-bit hence the use of .long
for (intptr_t TargetOffset : JT.getTargetOffsets())