Commit cc89c959 by Jim Stichnoth

Subzero: Ignore variables with no actual uses.

Liveness analysis uses a pair of bit vectors in each CFG node. The early bits correspond to "global" variables that are referenced in more than one block, and the latter bits correspond to "local" variables that are referenced in only that particular single block. Due to an oversight, variables that have no uses are conservatively classified as global, and consume space in every liveness bit vector. This CL improves memory usage by reducing liveness bit vector size: 1. Identify variables with no actual uses and exclude them from the bit vectors. 2. Don't do liveness analysis on rematerializable variables, because they have no need to be involved in register allocation or dead code elimination. BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4366 R=jpp@chromium.org Review URL: https://codereview.chromium.org/1844713004 .
parent b5eee3d7
...@@ -206,7 +206,7 @@ bool Inst::liveness(InstNumberT InstNumber, LivenessBV &Live, ...@@ -206,7 +206,7 @@ bool Inst::liveness(InstNumberT InstNumber, LivenessBV &Live,
assert(!isDeleted()); assert(!isDeleted());
Dead = false; Dead = false;
if (Dest) { if (Dest && !Dest->isRematerializable()) {
SizeT VarNum = Liveness->getLiveIndex(Dest->getIndex()); SizeT VarNum = Liveness->getLiveIndex(Dest->getIndex());
if (Live[VarNum]) { if (Live[VarNum]) {
if (!isDestRedefined()) { if (!isDestRedefined()) {
...@@ -227,6 +227,8 @@ bool Inst::liveness(InstNumberT InstNumber, LivenessBV &Live, ...@@ -227,6 +227,8 @@ bool Inst::liveness(InstNumberT InstNumber, LivenessBV &Live,
bool IsPhi = llvm::isa<InstPhi>(this); bool IsPhi = llvm::isa<InstPhi>(this);
resetLastUses(); resetLastUses();
FOREACH_VAR_IN_INST(Var, *this) { FOREACH_VAR_IN_INST(Var, *this) {
if (Var->isRematerializable())
continue;
SizeT VarNum = Liveness->getLiveIndex(Var->getIndex()); SizeT VarNum = Liveness->getLiveIndex(Var->getIndex());
if (!Live[VarNum]) { if (!Live[VarNum]) {
setLastUse(IndexOfVarInInst(Var)); setLastUse(IndexOfVarInInst(Var));
...@@ -411,10 +413,12 @@ void InstPhi::livenessPhiOperand(LivenessBV &Live, CfgNode *Target, ...@@ -411,10 +413,12 @@ void InstPhi::livenessPhiOperand(LivenessBV &Live, CfgNode *Target,
for (SizeT I = 0; I < getSrcSize(); ++I) { for (SizeT I = 0; I < getSrcSize(); ++I) {
if (Labels[I] == Target) { if (Labels[I] == Target) {
if (auto *Var = llvm::dyn_cast<Variable>(getSrc(I))) { if (auto *Var = llvm::dyn_cast<Variable>(getSrc(I))) {
SizeT SrcIndex = Liveness->getLiveIndex(Var->getIndex()); if (!Var->isRematerializable()) {
if (!Live[SrcIndex]) { SizeT SrcIndex = Liveness->getLiveIndex(Var->getIndex());
setLastUse(I); if (!Live[SrcIndex]) {
Live[SrcIndex] = true; setLastUse(I);
Live[SrcIndex] = true;
}
} }
} }
return; return;
......
...@@ -50,7 +50,7 @@ void Liveness::initInternal(NodeList::const_iterator FirstNode, ...@@ -50,7 +50,7 @@ void Liveness::initInternal(NodeList::const_iterator FirstNode,
Variable *Var = *I; Variable *Var = *I;
if (VMetadata->isMultiBlock(Var)) { if (VMetadata->isMultiBlock(Var)) {
++TmpNumGlobals; ++TmpNumGlobals;
} else { } else if (VMetadata->isSingleBlock(Var)) {
SizeT Index = VMetadata->getLocalUseNode(Var)->getIndex(); SizeT Index = VMetadata->getLocalUseNode(Var)->getIndex();
++Nodes[Index].NumLocals; ++Nodes[Index].NumLocals;
} }
...@@ -81,18 +81,18 @@ void Liveness::initInternal(NodeList::const_iterator FirstNode, ...@@ -81,18 +81,18 @@ void Liveness::initInternal(NodeList::const_iterator FirstNode,
for (auto I = FirstVar, E = Func->getVariables().end(); I != E; ++I) { for (auto I = FirstVar, E = Func->getVariables().end(); I != E; ++I) {
Variable *Var = *I; Variable *Var = *I;
SizeT VarIndex = Var->getIndex(); SizeT VarIndex = Var->getIndex();
SizeT LiveIndex; SizeT LiveIndex = InvalidLiveIndex;
if (VMetadata->isMultiBlock(Var)) { if (VMetadata->isMultiBlock(Var)) {
LiveIndex = TmpNumGlobals++; LiveIndex = TmpNumGlobals++;
LiveToVarMap[LiveIndex] = Var; LiveToVarMap[LiveIndex] = Var;
} else { } else if (VMetadata->isSingleBlock(Var)) {
SizeT NodeIndex = VMetadata->getLocalUseNode(Var)->getIndex(); SizeT NodeIndex = VMetadata->getLocalUseNode(Var)->getIndex();
LiveIndex = Nodes[NodeIndex].NumLocals++; LiveIndex = Nodes[NodeIndex].NumLocals++;
Nodes[NodeIndex].LiveToVarMap[LiveIndex] = Var; Nodes[NodeIndex].LiveToVarMap[LiveIndex] = Var;
LiveIndex += NumGlobals; LiveIndex += NumGlobals;
} }
VarToLiveMap[VarIndex] = LiveIndex; VarToLiveMap[VarIndex] = LiveIndex;
if (Var->getIgnoreLiveness()) if (LiveIndex == InvalidLiveIndex || Var->getIgnoreLiveness())
RangeMask[VarIndex] = false; RangeMask[VarIndex] = false;
} }
assert(TmpNumGlobals == (IsFullInit ? NumGlobals : 0)); assert(TmpNumGlobals == (IsFullInit ? NumGlobals : 0));
......
...@@ -67,7 +67,11 @@ public: ...@@ -67,7 +67,11 @@ public:
Cfg *getFunc() const { return Func; } Cfg *getFunc() const { return Func; }
LivenessMode getMode() const { return Mode; } LivenessMode getMode() const { return Mode; }
Variable *getVariable(SizeT LiveIndex, const CfgNode *Node) const; Variable *getVariable(SizeT LiveIndex, const CfgNode *Node) const;
SizeT getLiveIndex(SizeT VarIndex) const { return VarToLiveMap[VarIndex]; } SizeT getLiveIndex(SizeT VarIndex) const {
const SizeT LiveIndex = VarToLiveMap[VarIndex];
assert(LiveIndex != InvalidLiveIndex);
return LiveIndex;
}
SizeT getNumGlobalVars() const { return NumGlobals; } SizeT getNumGlobalVars() const { return NumGlobals; }
SizeT getNumVarsInNode(const CfgNode *Node) const { SizeT getNumVarsInNode(const CfgNode *Node) const {
return NumGlobals + Nodes[Node->getIndex()].NumLocals; return NumGlobals + Nodes[Node->getIndex()].NumLocals;
...@@ -106,6 +110,7 @@ private: ...@@ -106,6 +110,7 @@ private:
if (Index >= Nodes.size()) if (Index >= Nodes.size())
Nodes.resize(Index + 1); Nodes.resize(Index + 1);
} }
static constexpr SizeT InvalidLiveIndex = -1;
Cfg *Func; Cfg *Func;
LivenessMode Mode; LivenessMode Mode;
SizeT NumGlobals = 0; SizeT NumGlobals = 0;
......
...@@ -256,6 +256,7 @@ void VariableTracking::markUse(MetadataKind TrackingKind, const Inst *Instr, ...@@ -256,6 +256,7 @@ void VariableTracking::markUse(MetadataKind TrackingKind, const Inst *Instr,
if (!MakeMulti) { if (!MakeMulti) {
switch (MultiBlock) { switch (MultiBlock) {
case MBS_Unknown: case MBS_Unknown:
case MBS_NoUses:
MultiBlock = MBS_SingleBlock; MultiBlock = MBS_SingleBlock;
SingleUseNode = Node; SingleUseNode = Node;
break; break;
...@@ -370,7 +371,7 @@ void VariablesMetadata::init(MetadataKind TrackingKind) { ...@@ -370,7 +371,7 @@ void VariablesMetadata::init(MetadataKind TrackingKind) {
TimerMarker T(TimerStack::TT_vmetadata, Func); TimerMarker T(TimerStack::TT_vmetadata, Func);
Kind = TrackingKind; Kind = TrackingKind;
Metadata.clear(); Metadata.clear();
Metadata.resize(Func->getNumVariables()); Metadata.resize(Func->getNumVariables(), VariableTracking::MBS_NoUses);
// Mark implicit args as being used in the entry node. // Mark implicit args as being used in the entry node.
for (Variable *Var : Func->getImplicitArgs()) { for (Variable *Var : Func->getImplicitArgs()) {
...@@ -439,11 +440,42 @@ bool VariablesMetadata::isMultiDef(const Variable *Var) const { ...@@ -439,11 +440,42 @@ bool VariablesMetadata::isMultiDef(const Variable *Var) const {
bool VariablesMetadata::isMultiBlock(const Variable *Var) const { bool VariablesMetadata::isMultiBlock(const Variable *Var) const {
if (Var->getIsArg()) if (Var->getIsArg())
return true; return true;
if (Var->isRematerializable())
return false;
if (!isTracked(Var)) if (!isTracked(Var))
return true; // conservative answer return true; // conservative answer
SizeT VarNum = Var->getIndex(); SizeT VarNum = Var->getIndex();
switch (Metadata[VarNum].getMultiBlock()) {
case VariableTracking::MBS_NoUses:
case VariableTracking::MBS_SingleBlock:
return false;
// Conservatively return true if the state is unknown. // Conservatively return true if the state is unknown.
return Metadata[VarNum].getMultiBlock() != VariableTracking::MBS_SingleBlock; case VariableTracking::MBS_Unknown:
case VariableTracking::MBS_MultiBlock:
return true;
}
assert(0);
return true;
}
bool VariablesMetadata::isSingleBlock(const Variable *Var) const {
if (Var->getIsArg())
return false;
if (Var->isRematerializable())
return false;
if (!isTracked(Var))
return false; // conservative answer
SizeT VarNum = Var->getIndex();
switch (Metadata[VarNum].getMultiBlock()) {
case VariableTracking::MBS_SingleBlock:
return true;
case VariableTracking::MBS_Unknown:
case VariableTracking::MBS_NoUses:
case VariableTracking::MBS_MultiBlock:
return false;
}
assert(0);
return false;
} }
const Inst * const Inst *
......
...@@ -661,7 +661,9 @@ public: ...@@ -661,7 +661,9 @@ public:
void setIsImplicitArg(bool Val = true) { IsImplicitArgument = Val; } void setIsImplicitArg(bool Val = true) { IsImplicitArgument = Val; }
void setIgnoreLiveness() { IgnoreLiveness = true; } void setIgnoreLiveness() { IgnoreLiveness = true; }
bool getIgnoreLiveness() const { return IgnoreLiveness; } bool getIgnoreLiveness() const {
return IgnoreLiveness || IsRematerializable;
}
int32_t getStackOffset() const { return StackOffset; } int32_t getStackOffset() const { return StackOffset; }
void setStackOffset(int32_t Offset) { StackOffset = Offset; } void setStackOffset(int32_t Offset) { StackOffset = Offset; }
...@@ -863,8 +865,6 @@ using InstDefList = CfgVector<const Inst *>; ...@@ -863,8 +865,6 @@ using InstDefList = CfgVector<const Inst *>;
/// VariableTracking tracks the metadata for a single variable. It is /// VariableTracking tracks the metadata for a single variable. It is
/// only meant to be used internally by VariablesMetadata. /// only meant to be used internally by VariablesMetadata.
class VariableTracking { class VariableTracking {
VariableTracking &operator=(const VariableTracking &) = delete;
public: public:
enum MultiDefState { enum MultiDefState {
// TODO(stichnot): Consider using just a simple counter. // TODO(stichnot): Consider using just a simple counter.
...@@ -873,9 +873,16 @@ public: ...@@ -873,9 +873,16 @@ public:
MDS_MultiDefSingleBlock, MDS_MultiDefSingleBlock,
MDS_MultiDefMultiBlock MDS_MultiDefMultiBlock
}; };
enum MultiBlockState { MBS_Unknown, MBS_SingleBlock, MBS_MultiBlock }; enum MultiBlockState {
MBS_Unknown, // Not yet initialized, so be conservative
MBS_NoUses, // Known to have no uses
MBS_SingleBlock, // All uses in are in a single block
MBS_MultiBlock // Several uses across several blocks
};
VariableTracking() = default; VariableTracking() = default;
VariableTracking(const VariableTracking &) = default; VariableTracking(const VariableTracking &) = default;
VariableTracking &operator=(const VariableTracking &) = default;
VariableTracking(MultiBlockState MultiBlock) : MultiBlock(MultiBlock) {}
MultiDefState getMultiDef() const { return MultiDef; } MultiDefState getMultiDef() const { return MultiDef; }
MultiBlockState getMultiBlock() const { return MultiBlock; } MultiBlockState getMultiBlock() const { return MultiBlock; }
const Inst *getFirstDefinitionSingleBlock() const; const Inst *getFirstDefinitionSingleBlock() const;
...@@ -948,6 +955,7 @@ public: ...@@ -948,6 +955,7 @@ public:
/// always considered multi-block because they are live coming into the entry /// always considered multi-block because they are live coming into the entry
/// block. /// block.
bool isMultiBlock(const Variable *Var) const; bool isMultiBlock(const Variable *Var) const;
bool isSingleBlock(const Variable *Var) const;
/// Returns the node that the given Variable is used in, assuming /// Returns the node that the given Variable is used in, assuming
/// isMultiBlock() returns false. Otherwise, nullptr is returned. /// isMultiBlock() returns false. Otherwise, nullptr is returned.
CfgNode *getLocalUseNode(const Variable *Var) const; CfgNode *getLocalUseNode(const Variable *Var) const;
......
...@@ -219,8 +219,6 @@ void LinearScan::initForInfOnly() { ...@@ -219,8 +219,6 @@ void LinearScan::initForInfOnly() {
if (Instr.isDeleted()) if (Instr.isDeleted())
continue; continue;
FOREACH_VAR_IN_INST(Var, Instr) { FOREACH_VAR_IN_INST(Var, Instr) {
if (Var->isRematerializable())
continue;
if (Var->getIgnoreLiveness()) if (Var->getIgnoreLiveness())
continue; continue;
if (Var->hasReg() || Var->mustHaveReg()) { if (Var->hasReg() || Var->mustHaveReg()) {
...@@ -231,7 +229,7 @@ void LinearScan::initForInfOnly() { ...@@ -231,7 +229,7 @@ void LinearScan::initForInfOnly() {
} }
} }
if (const Variable *Var = Instr.getDest()) { if (const Variable *Var = Instr.getDest()) {
if (!Var->isRematerializable() && !Var->getIgnoreLiveness() && if (!Var->getIgnoreLiveness() &&
(Var->hasReg() || Var->mustHaveReg())) { (Var->hasReg() || Var->mustHaveReg())) {
if (LRBegin[Var->getIndex()] == Inst::NumberSentinel) { if (LRBegin[Var->getIndex()] == Inst::NumberSentinel) {
LRBegin[Var->getIndex()] = Instr.getNumber(); LRBegin[Var->getIndex()] = Instr.getNumber();
......
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