Commit 607e9f0e by Jim Stichnoth

Subzero: Implement InstList in terms of llvm::ilist<> .

Use LLVM's intrusive list ADT template to implement instruction lists. This embeds prev/next pointers into the instruction, and as such, iterators essentially double as instruction pointers. This means stripping off one level of indirection when dereferencing, and also the range-based for loop can't be used. The performance difference in translation time seems to be 1-2%. I tried to also do this for the much less used PhiList and AssignList, but ran into SFINAE problems. BUG= none R=jvoung@chromium.org Review URL: https://codereview.chromium.org/709533002
parent 6fcbdddb
......@@ -318,7 +318,8 @@ bool Cfg::validateLiveness() const {
Ostream &Str = Ctx->getStrDump();
for (CfgNode *Node : Nodes) {
Inst *FirstInst = NULL;
for (Inst *Inst : Node->getInsts()) {
for (auto Inst = Node->getInsts().begin(), E = Node->getInsts().end();
Inst != E; ++Inst) {
if (Inst->isDeleted())
continue;
if (FirstInst == NULL)
......@@ -337,7 +338,8 @@ bool Cfg::validateLiveness() const {
// temporary may be live at the end of the previous block,
// and if it is also assigned in the first instruction of
// this block, the adjacent live ranges get merged.
if (Inst != FirstInst && !Inst->isDestNonKillable() &&
if (static_cast<class Inst *>(Inst) != FirstInst &&
!Inst->isDestNonKillable() &&
Dest->getLiveRange().containsValue(InstNumber - 1, IsDest))
Invalid = true;
if (Invalid) {
......
......@@ -59,7 +59,7 @@ void CfgNode::renumberInstructions() {
InstNumberT FirstNumber = Func->getNextInstNumber();
for (InstPhi *I : Phis)
I->renumber(Func);
for (Inst *I : Insts)
for (auto I = Insts.begin(), E = Insts.end(); I != E; ++I)
I->renumber(Func);
InstCountEstimate = Func->getNextInstNumber() - FirstNumber;
}
......@@ -69,7 +69,7 @@ void CfgNode::renumberInstructions() {
// constructed, the computePredecessors() pass finalizes it by
// creating the InEdges list.
void CfgNode::computePredecessors() {
OutEdges = (*Insts.rbegin())->getTerminatorEdges();
OutEdges = Insts.rbegin()->getTerminatorEdges();
for (CfgNode *Succ : OutEdges)
Succ->InEdges.push_back(this);
}
......@@ -117,7 +117,7 @@ void CfgNode::placePhiStores() {
// Confirm that InsertionPoint is a terminator instruction. Calling
// getTerminatorEdges() on a non-terminator instruction will cause
// an llvm_unreachable().
(void)(*InsertionPoint)->getTerminatorEdges();
(void)InsertionPoint->getTerminatorEdges();
// SafeInsertionPoint is always immediately before the terminator
// instruction. If the block ends in a compare and conditional
// branch, it's better to place the Phi store before the compare so
......@@ -167,13 +167,13 @@ void CfgNode::placePhiStores() {
// instruction, and the previous instruction is a compare
// instruction, then we move the insertion point before the compare
// instruction so as not to interfere with compare/branch fusing.
if (InstBr *Branch = llvm::dyn_cast<InstBr>(*InsertionPoint)) {
if (InstBr *Branch = llvm::dyn_cast<InstBr>(InsertionPoint)) {
if (!Branch->isUnconditional()) {
if (InsertionPoint != Insts.begin()) {
--InsertionPoint;
if (llvm::isa<InstIcmp>(*InsertionPoint) ||
llvm::isa<InstFcmp>(*InsertionPoint)) {
CmpInstDest = (*InsertionPoint)->getDest();
if (llvm::isa<InstIcmp>(InsertionPoint) ||
llvm::isa<InstFcmp>(InsertionPoint)) {
CmpInstDest = InsertionPoint->getDest();
} else {
++InsertionPoint;
}
......@@ -250,8 +250,8 @@ CfgNode *CfgNode::splitIncomingEdge(CfgNode *Pred, SizeT EdgeIndex) {
Found = false;
for (auto I = Pred->getInsts().rbegin(), E = Pred->getInsts().rend();
!Found && I != E; ++I) {
if (!(*I)->isDeleted()) {
Found = (*I)->repointEdge(this, NewNode);
if (!I->isDeleted()) {
Found = I->repointEdge(this, NewNode);
}
}
assert(Found);
......@@ -530,9 +530,9 @@ void CfgNode::livenessLightweight() {
// Process regular instructions in reverse order.
// TODO(stichnot): Use llvm::make_range with LLVM 3.5.
for (auto I = Insts.rbegin(), E = Insts.rend(); I != E; ++I) {
if ((*I)->isDeleted())
if (I->isDeleted())
continue;
(*I)->livenessLightweight(Func, Live);
I->livenessLightweight(Func, Live);
}
for (InstPhi *I : Phis) {
if (I->isDeleted())
......@@ -573,9 +573,9 @@ bool CfgNode::liveness(Liveness *Liveness) {
// Process regular instructions in reverse order.
for (auto I = Insts.rbegin(), E = Insts.rend(); I != E; ++I) {
if ((*I)->isDeleted())
if (I->isDeleted())
continue;
(*I)->liveness((*I)->getNumber(), Live, Liveness, LiveBegin, LiveEnd);
I->liveness(I->getNumber(), Live, Liveness, LiveBegin, LiveEnd);
}
// Process phis in forward order so that we can override the
// instruction number to be that of the earliest phi instruction in
......@@ -654,7 +654,7 @@ void CfgNode::livenessPostprocess(LivenessMode Mode, Liveness *Liveness) {
LastInstNum = I->getNumber();
}
// Process instructions
for (Inst *I : Insts) {
for (auto I = Insts.begin(), E = Insts.end(); I != E; ++I) {
I->deleteIfDead();
if (I->isDeleted())
continue;
......@@ -753,7 +753,7 @@ void CfgNode::contractIfEmpty() {
if (InEdges.empty())
return;
Inst *Branch = NULL;
for (Inst *I : Insts) {
for (auto I = Insts.begin(), E = Insts.end(); I != E; ++I) {
if (I->isDeleted())
continue;
if (I->isUnconditionalBranch())
......@@ -776,7 +776,8 @@ void CfgNode::contractIfEmpty() {
OutEdges.front()->InEdges.push_back(Pred);
}
}
for (Inst *I : Pred->getInsts()) {
for (auto I = Pred->getInsts().begin(), E = Pred->getInsts().end();
I != E; ++I) {
if (!I->isDeleted())
I->repointEdge(this, OutEdges.front());
}
......@@ -795,7 +796,7 @@ void CfgNode::doBranchOpt(const CfgNode *NextNode) {
// first opportunity, unless there is some target lowering where we
// have the possibility of multiple such optimizations per block
// (currently not the case for x86 lowering).
for (Inst *I : Insts) {
for (auto I = Insts.begin(), E = Insts.end(); I != E; ++I) {
if (!I->isDeleted()) {
Target->doBranchOpt(I, NextNode);
}
......@@ -901,7 +902,7 @@ void CfgNode::emit(Cfg *Func) const {
Inst *Instr = Phi;
Instr->emit(Func);
}
for (Inst *I : Insts) {
for (auto I = Insts.begin(), E = Insts.end(); I != E; ++I) {
if (I->isDeleted())
continue;
if (I->isRedundantAssign()) {
......@@ -931,7 +932,7 @@ void CfgNode::emitIAS(Cfg *Func) const {
Inst *Instr = Phi;
Instr->emitIAS(Func);
}
for (Inst *I : Insts) {
for (auto I = Insts.begin(), E = Insts.end(); I != E; ++I) {
if (I->isDeleted())
continue;
if (I->isRedundantAssign())
......@@ -982,7 +983,7 @@ void CfgNode::dump(Cfg *Func) const {
if (Func->getContext()->isVerbose(IceV_Instructions)) {
for (InstPhi *I : Phis)
I->dumpDecorated(Func);
for (Inst *I : Insts)
for (auto I = Insts.begin(), E = Insts.end(); I != E; ++I)
I->dumpDecorated(Func);
}
// Dump the live-out variables.
......
......@@ -17,6 +17,7 @@
#define SUBZERO_SRC_ICECFGNODE_H
#include "IceDefs.h"
#include "IceInst.h" // InstList traits
namespace Ice {
......
......@@ -28,6 +28,8 @@
#include <vector>
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/ilist.h"
#include "llvm/ADT/ilist_node.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
......@@ -56,7 +58,7 @@ class VariablesMetadata;
// TODO: Switch over to LLVM's ADT container classes.
// http://llvm.org/docs/ProgrammersManual.html#picking-the-right-data-structure-for-a-task
typedef std::string IceString;
typedef std::list<Inst *> InstList;
typedef llvm::ilist<Inst> InstList;
typedef std::list<InstAssign *> AssignList;
typedef std::list<InstPhi *> PhiList;
typedef std::vector<Variable *> VarList;
......
......@@ -34,7 +34,7 @@ namespace Ice {
// InstHighLevel and InstTarget. High-level ICE instructions inherit
// from InstHighLevel, and low-level (target-specific) ICE
// instructions inherit from InstTarget.
class Inst {
class Inst : public llvm::ilist_node<Inst> {
Inst(const Inst &) = delete;
Inst &operator=(const Inst &) = delete;
......@@ -838,4 +838,22 @@ protected:
} // end of namespace Ice
// Override the default ilist traits so that Inst's private ctor and
// deleted dtor aren't invoked.
template <>
struct llvm::ilist_traits<Ice::Inst> : public llvm::ilist_default_traits<
Ice::Inst> {
Ice::Inst *createSentinel() const {
return static_cast<Ice::Inst *>(&Sentinel);
}
static void destroySentinel(Ice::Inst *) {}
Ice::Inst *provideInitialHead() const { return createSentinel(); }
Ice::Inst *ensureHead(Ice::Inst *) const { return createSentinel(); }
static void noteHead(Ice::Inst *, Ice::Inst *) {}
void deleteNode(Ice::Inst *) {}
private:
mutable ilist_half_node<Ice::Inst> Sentinel;
};
#endif // SUBZERO_SRC_ICEINST_H
......@@ -347,7 +347,8 @@ void VariablesMetadata::addNode(CfgNode *Node) {
}
}
for (Inst *I : Node->getInsts()) {
for (auto I = Node->getInsts().begin(), E = Node->getInsts().end(); I != E;
++I) {
if (I->isDeleted())
continue;
// Note: The implicit definitions (and uses) from InstFakeKill are
......
......@@ -62,7 +62,7 @@ void LoweringContext::insert(Inst *Inst) {
}
void LoweringContext::skipDeleted(InstList::iterator &I) const {
while (I != End && (*I)->isDeleted())
while (I != End && I->isDeleted())
++I;
}
......@@ -116,7 +116,7 @@ void TargetLowering::doAddressOpt() {
bool TargetLowering::shouldDoNopInsertion() const { return DoNopInsertion; }
void TargetLowering::doNopInsertion() {
Inst *I = *Context.getCur();
Inst *I = Context.getCur();
bool ShouldSkip = llvm::isa<InstFakeUse>(I) || llvm::isa<InstFakeDef>(I) ||
llvm::isa<InstFakeKill>(I) || I->isRedundantAssign() ||
I->isDeleted();
......@@ -141,7 +141,7 @@ void TargetLowering::doNopInsertion() {
// instructions it consumes.
void TargetLowering::lower() {
assert(!Context.atEnd());
Inst *Inst = *Context.getCur();
Inst *Inst = Context.getCur();
// Mark the current instruction as deleted before lowering,
// otherwise the Dest variable will likely get marked as non-SSA.
// See Variable::setDefinition().
......
......@@ -45,13 +45,13 @@ public:
Inst *getNextInst() const {
if (Next == End)
return NULL;
return *Next;
return Next;
}
Inst *getNextInst(InstList::iterator &Iter) const {
advanceForward(Iter);
if (Iter == End)
return NULL;
return *Iter;
return Iter;
}
CfgNode *getNode() const { return Node; }
bool atEnd() const { return Cur == End; }
......
......@@ -3826,7 +3826,7 @@ void TargetX8632::lowerLoad(const InstLoad *Inst) {
}
void TargetX8632::doAddressOptLoad() {
Inst *Inst = *Context.getCur();
Inst *Inst = Context.getCur();
Variable *Dest = Inst->getDest();
Operand *Addr = Inst->getSrc(0);
Variable *Index = NULL;
......@@ -4004,7 +4004,7 @@ void TargetX8632::lowerStore(const InstStore *Inst) {
}
void TargetX8632::doAddressOptStore() {
InstStore *Inst = llvm::cast<InstStore>(*Context.getCur());
InstStore *Inst = llvm::cast<InstStore>(Context.getCur());
Operand *Data = Inst->getData();
Operand *Addr = Inst->getAddr();
Variable *Index = NULL;
......@@ -4502,7 +4502,7 @@ void TargetX8632::postLower() {
if (Ctx->getOptLevel() != Opt_m1) {
// Find two-address non-SSA instructions where Dest==Src0, and set
// the DestNonKillable flag to keep liveness analysis consistent.
for (Inst *Inst : Context) {
for (auto Inst = Context.begin(), E = Context.end(); Inst != E; ++Inst) {
if (Inst->isDeleted())
continue;
if (Variable *Dest = Inst->getDest()) {
......@@ -4529,7 +4529,7 @@ void TargetX8632::postLower() {
// The first pass also keeps track of which instruction is the last
// use for each infinite-weight variable. After the last use, the
// variable is released to the free list.
for (Inst *Inst : Context) {
for (auto Inst = Context.begin(), E = Context.end(); Inst != E; ++Inst) {
if (Inst->isDeleted())
continue;
// Don't consider a FakeKill instruction, because (currently) it
......@@ -4560,7 +4560,7 @@ void TargetX8632::postLower() {
// The second pass colors infinite-weight variables.
llvm::SmallBitVector AvailableRegisters = WhiteList;
llvm::SmallBitVector FreedRegisters(WhiteList.size());
for (Inst *Inst : Context) {
for (auto Inst = Context.begin(), E = Context.end(); Inst != E; ++Inst) {
FreedRegisters.reset();
if (Inst->isDeleted())
continue;
......
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