Commit 877b04e4 by Jim Stichnoth

Subzero: Speed up VariablesMetadata initialization.

Currently, O2 calls VariablesMetadata::init() 4 times: - Twice for liveness analysis, where only multi-block use information is needed for dealing with sparse bit vectors. - Once for address mode inference, where single-definition information is needed. - Once for register allocation, where all information is needed, including the set of all definitions which is needed for determining AllowOverlap. So we limit the amount of data we gather based on the actual need. BUG= none R=jvoung@chromium.org Review URL: https://codereview.chromium.org/650613003
parent 7b451a92
......@@ -164,7 +164,7 @@ void Cfg::genFrame() {
// doesn't need to iterate until convergence.
void Cfg::livenessLightweight() {
TimerMarker T(TimerStack::TT_livenessLightweight, this);
getVMetadata()->init();
getVMetadata()->init(VMK_Uses);
for (CfgNode *Node : Nodes)
Node->livenessLightweight();
}
......@@ -172,7 +172,7 @@ void Cfg::livenessLightweight() {
void Cfg::liveness(LivenessMode Mode) {
TimerMarker T(TimerStack::TT_liveness, this);
Live.reset(new Liveness(this, Mode));
getVMetadata()->init();
getVMetadata()->init(VMK_Uses);
Live->init();
// Initialize with all nodes needing to be processed.
llvm::BitVector NeedToProcess(Nodes.size(), true);
......
......@@ -185,8 +185,10 @@ Variable Variable::asType(Type Ty) {
return V;
}
void VariableTracking::markUse(const Inst *Instr, const CfgNode *Node,
bool IsFromDef, bool IsImplicit) {
void VariableTracking::markUse(MetadataKind TrackingKind, const Inst *Instr,
const CfgNode *Node, bool IsFromDef,
bool IsImplicit) {
(void)TrackingKind;
if (MultiBlock == MBS_MultiBlock)
return;
// TODO(stichnot): If the use occurs as a source operand in the
......@@ -227,19 +229,31 @@ void VariableTracking::markUse(const Inst *Instr, const CfgNode *Node,
}
}
void VariableTracking::markDef(const Inst *Instr, const CfgNode *Node) {
void VariableTracking::markDef(MetadataKind TrackingKind, const Inst *Instr,
const CfgNode *Node) {
// TODO(stichnot): If the definition occurs in the last instruction
// of the block, consider not marking this as a separate use. But
// be careful not to omit all uses of the variable if markDef() and
// markUse() both use this optimization.
assert(Node);
// Verify that instructions are added in increasing order.
assert(Definitions.empty() ||
Instr->getNumber() >= Definitions.back()->getNumber());
Definitions.push_back(Instr);
#ifndef NDEBUG
if (TrackingKind == VMK_All) {
const Inst *LastInstruction =
Definitions.empty() ? FirstOrSingleDefinition : Definitions.back();
assert(LastInstruction == NULL ||
Instr->getNumber() >= LastInstruction->getNumber());
}
#endif
const bool IsFromDef = true;
const bool IsImplicit = false;
markUse(Instr, Node, IsFromDef, IsImplicit);
markUse(TrackingKind, Instr, Node, IsFromDef, IsImplicit);
if (TrackingKind == VMK_Uses)
return;
if (FirstOrSingleDefinition == NULL)
FirstOrSingleDefinition = Instr;
else if (TrackingKind == VMK_All)
Definitions.push_back(Instr);
switch (MultiDef) {
case MDS_Unknown:
assert(SingleDefNode == NULL);
......@@ -275,8 +289,8 @@ const Inst *VariableTracking::getFirstDefinition() const {
return NULL;
case MDS_SingleDef:
case MDS_MultiDefSingleBlock:
assert(!Definitions.empty());
return Definitions[0];
assert(FirstOrSingleDefinition);
return FirstOrSingleDefinition;
}
}
......@@ -287,13 +301,14 @@ const Inst *VariableTracking::getSingleDefinition() const {
case MDS_MultiDefSingleBlock:
return NULL;
case MDS_SingleDef:
assert(!Definitions.empty());
return Definitions[0];
assert(FirstOrSingleDefinition);
return FirstOrSingleDefinition;
}
}
void VariablesMetadata::init() {
void VariablesMetadata::init(MetadataKind TrackingKind) {
TimerMarker T(TimerStack::TT_vmetadata, Func);
Kind = TrackingKind;
Metadata.clear();
Metadata.resize(Func->getNumVariables());
......@@ -303,7 +318,8 @@ void VariablesMetadata::init() {
const CfgNode *EntryNode = Func->getEntryNode();
const bool IsFromDef = false;
const bool IsImplicit = true;
Metadata[Var->getIndex()].markUse(NoInst, EntryNode, IsFromDef, IsImplicit);
Metadata[Var->getIndex()]
.markUse(Kind, NoInst, EntryNode, IsFromDef, IsImplicit);
}
for (CfgNode *Node : Func->getNodes()) {
......@@ -318,14 +334,14 @@ void VariablesMetadata::init() {
Variable *Var = llvm::cast<Variable>(I->getSrc(SrcNum));
SizeT VarNum = Var->getIndex();
assert(VarNum < Metadata.size());
Metadata[VarNum].markDef(Kill, Node);
Metadata[VarNum].markDef(Kind, Kill, Node);
}
continue; // no point in executing the rest
}
if (Variable *Dest = I->getDest()) {
SizeT DestNum = Dest->getIndex();
assert(DestNum < Metadata.size());
Metadata[DestNum].markDef(I, Node);
Metadata[DestNum].markDef(Kind, I, Node);
}
for (SizeT SrcNum = 0; SrcNum < I->getSrcSize(); ++SrcNum) {
Operand *Src = I->getSrc(SrcNum);
......@@ -336,7 +352,7 @@ void VariablesMetadata::init() {
assert(VarNum < Metadata.size());
const bool IsFromDef = false;
const bool IsImplicit = false;
Metadata[VarNum].markUse(I, Node, IsFromDef, IsImplicit);
Metadata[VarNum].markUse(Kind, I, Node, IsFromDef, IsImplicit);
}
}
}
......@@ -344,6 +360,7 @@ void VariablesMetadata::init() {
}
bool VariablesMetadata::isMultiDef(const Variable *Var) const {
assert(Kind != VMK_Uses);
if (Var->getIsArg())
return false;
if (!isTracked(Var))
......@@ -364,6 +381,7 @@ bool VariablesMetadata::isMultiBlock(const Variable *Var) const {
}
const Inst *VariablesMetadata::getFirstDefinition(const Variable *Var) const {
assert(Kind != VMK_Uses);
if (!isTracked(Var))
return NULL; // conservative answer
SizeT VarNum = Var->getIndex();
......@@ -371,6 +389,7 @@ const Inst *VariablesMetadata::getFirstDefinition(const Variable *Var) const {
}
const Inst *VariablesMetadata::getSingleDefinition(const Variable *Var) const {
assert(Kind != VMK_Uses);
if (!isTracked(Var))
return NULL; // conservative answer
SizeT VarNum = Var->getIndex();
......@@ -378,11 +397,12 @@ const Inst *VariablesMetadata::getSingleDefinition(const Variable *Var) const {
}
const InstDefList &
VariablesMetadata::getDefinitions(const Variable *Var) const {
VariablesMetadata::getLatterDefinitions(const Variable *Var) const {
assert(Kind == VMK_All);
if (!isTracked(Var))
return NoDefinitions;
SizeT VarNum = Var->getIndex();
return Metadata[VarNum].getDefinitions();
return Metadata[VarNum].getLatterDefinitions();
}
const CfgNode *VariablesMetadata::getLocalUseNode(const Variable *Var) const {
......
......@@ -516,6 +516,11 @@ protected:
Variable *VarsReal[1];
};
enum MetadataKind {
VMK_Uses, // Track only uses, not defs
VMK_SingleDefs, // Track uses+defs, but only record single def
VMK_All // Track uses+defs, including full def list
};
typedef std::vector<const Inst *> InstDefList;
// VariableTracking tracks the metadata for a single variable. It is
......@@ -539,16 +544,17 @@ public:
};
VariableTracking()
: MultiDef(MDS_Unknown), MultiBlock(MBS_Unknown), SingleUseNode(NULL),
SingleDefNode(NULL) {}
SingleDefNode(NULL), FirstOrSingleDefinition(NULL) {}
MultiDefState getMultiDef() const { return MultiDef; }
MultiBlockState getMultiBlock() const { return MultiBlock; }
const Inst *getFirstDefinition() const;
const Inst *getSingleDefinition() const;
const InstDefList &getDefinitions() const { return Definitions; }
const InstDefList &getLatterDefinitions() const { return Definitions; }
const CfgNode *getNode() const { return SingleUseNode; }
void markUse(const Inst *Instr, const CfgNode *Node, bool IsFromDef,
bool IsImplicit);
void markDef(const Inst *Instr, const CfgNode *Node);
void markUse(MetadataKind TrackingKind, const Inst *Instr,
const CfgNode *Node, bool IsFromDef, bool IsImplicit);
void markDef(MetadataKind TrackingKind, const Inst *Instr,
const CfgNode *Node);
private:
MultiDefState MultiDef;
......@@ -557,7 +563,8 @@ private:
const CfgNode *SingleDefNode;
// All definitions of the variable are collected here, in increasing
// order of instruction number.
InstDefList Definitions;
InstDefList Definitions; // Only used if Kind==VMK_All
const Inst *FirstOrSingleDefinition; // == Definitions[0] if Kind==VMK_All
};
// VariablesMetadata analyzes and summarizes the metadata for the
......@@ -570,7 +577,7 @@ public:
VariablesMetadata(const Cfg *Func) : Func(Func) {}
// Initialize the state by traversing all instructions/variables in
// the CFG.
void init();
void init(MetadataKind TrackingKind);
// Returns whether the given Variable is tracked in this object. It
// should only return false if changes were made to the CFG after
// running init(), in which case the state is stale and the results
......@@ -594,7 +601,7 @@ public:
const Inst *getSingleDefinition(const Variable *Var) const;
// Returns the list of all definition instructions of the given
// Variable.
const InstDefList &getDefinitions(const Variable *Var) const;
const InstDefList &getLatterDefinitions(const Variable *Var) const;
// Returns whether the given Variable is live across multiple
// blocks. Mainly, this is used to partition Variables into
......@@ -610,6 +617,7 @@ public:
private:
const Cfg *Func;
MetadataKind Kind;
std::vector<VariableTracking> Metadata;
const static InstDefList NoDefinitions;
};
......
......@@ -32,7 +32,10 @@ namespace {
bool overlapsDefs(const Cfg *Func, const Variable *Item, const Variable *Var) {
const bool UseTrimmed = true;
VariablesMetadata *VMetadata = Func->getVMetadata();
const InstDefList &Defs = VMetadata->getDefinitions(Var);
if (const Inst *FirstDef = VMetadata->getFirstDefinition(Var))
if (Item->getLiveRange().overlapsInst(FirstDef->getNumber(), UseTrimmed))
return true;
const InstDefList &Defs = VMetadata->getLatterDefinitions(Var);
for (size_t i = 0; i < Defs.size(); ++i) {
if (Item->getLiveRange().overlapsInst(Defs[i]->getNumber(), UseTrimmed))
return true;
......@@ -47,11 +50,11 @@ void dumpDisableOverlap(const Cfg *Func, const Variable *Var,
Ostream &Str = Func->getContext()->getStrDump();
Str << "Disabling Overlap due to " << Reason << " " << *Var
<< " LIVE=" << Var->getLiveRange() << " Defs=";
const InstDefList &Defs = VMetadata->getDefinitions(Var);
if (const Inst *FirstDef = VMetadata->getFirstDefinition(Var))
Str << FirstDef->getNumber();
const InstDefList &Defs = VMetadata->getLatterDefinitions(Var);
for (size_t i = 0; i < Defs.size(); ++i) {
if (i > 0)
Str << ",";
Str << Defs[i]->getNumber();
Str << "," << Defs[i]->getNumber();
}
Str << "\n";
}
......
......@@ -329,7 +329,7 @@ void TargetX8632::translateO2() {
Func->dump("After Phi lowering");
// Address mode optimization.
Func->getVMetadata()->init();
Func->getVMetadata()->init(VMK_SingleDefs);
Func->doAddressOpt();
// Argument lowering
......@@ -372,7 +372,7 @@ void TargetX8632::translateO2() {
// The post-codegen dump is done here, after liveness analysis and
// associated cleanup, to make the dump cleaner and more useful.
Func->dump("After initial x8632 codegen");
Func->getVMetadata()->init();
Func->getVMetadata()->init(VMK_All);
regAlloc();
if (Func->hasError())
return;
......
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