Commit 144cdcea by Jim Stichnoth

Subzero: Refactor tracking of Defs and block-local Variables.

This affects tracking of two kinds of Variable metadata: whether a Variable is block-local (i.e., all uses are in a single block) and if so, which CfgNode that is; and whether a Variable has a single defining instruction, and if so, which Inst that is. Originally, this metadata was constructed incrementally, which was quite fragile and most likely inaccurate under many circumstances. In the new approach, this metadata is reconstructed in a separate pass as needed. As a side benefit, the metadata fields are removed from each Variable and pulled into a separate structure, shrinking the size of Variable. There should be no functional changes, except that simple stack slot coalescing is turned off under Om1, since it takes a separate pass to calculate block-local variables, and passes are minimized under Om1. As a result, a couple of the lit tests needed to be changed. There are a few non-mechanical changes, generally to tighten up Variable tracking for liveness analysis. This is being done mainly to get precise Variable definition information so that register allocation can infer the best register preferences as well as when overlapping live ranges are allowable. BUG=none R=jvoung@chromium.org Review URL: https://codereview.chromium.org/589003002
parent cff9dae7
......@@ -28,7 +28,7 @@ Cfg::Cfg(GlobalContext *Ctx)
IsInternalLinkage(false), HasError(false), ErrorMessage(""), Entry(NULL),
NextInstNumber(1), Live(NULL),
Target(TargetLowering::createLowering(Ctx->getTargetArch(), this)),
CurrentNode(NULL) {}
VMetadata(new VariablesMetadata(this)), CurrentNode(NULL) {}
Cfg::~Cfg() {}
......@@ -45,16 +45,20 @@ CfgNode *Cfg::makeNode(const IceString &Name) {
return Node;
}
Variable *Cfg::makeVariable(Type Ty, const CfgNode *Node,
const IceString &Name) {
return makeVariable<Variable>(Ty, Node, Name);
Variable *Cfg::makeVariable(Type Ty, const IceString &Name) {
return makeVariable<Variable>(Ty, Name);
}
void Cfg::addArg(Variable *Arg) {
Arg->setIsArg(this);
Arg->setIsArg();
Args.push_back(Arg);
}
void Cfg::addImplicitArg(Variable *Arg) {
Arg->setIsImplicitArg();
ImplicitArgs.push_back(Arg);
}
// Returns whether the stack frame layout has been computed yet. This
// is used for dumping the stack frame location of Variables.
bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); }
......@@ -147,6 +151,7 @@ void Cfg::genFrame() {
// completely with a single block. It is a quick single pass and
// doesn't need to iterate until convergence.
void Cfg::livenessLightweight() {
getVMetadata()->init();
for (NodeList::iterator I = Nodes.begin(), E = Nodes.end(); I != E; ++I) {
(*I)->livenessLightweight();
}
......@@ -154,6 +159,7 @@ void Cfg::livenessLightweight() {
void Cfg::liveness(LivenessMode Mode) {
Live.reset(new Liveness(this, Mode));
getVMetadata()->init();
Live->init();
// Initialize with all nodes needing to be processed.
llvm::BitVector NeedToProcess(Nodes.size(), true);
......@@ -361,9 +367,12 @@ void Cfg::dump(const IceString &Message) {
for (VarList::const_iterator I = Variables.begin(), E = Variables.end();
I != E; ++I) {
Variable *Var = *I;
Str << "//"
<< " multiblock=" << Var->isMultiblockLife() << " "
<< " weight=" << Var->getWeight() << " ";
Str << "// multiblock=";
if (getVMetadata()->isTracked(Var))
Str << getVMetadata()->isMultiBlock(Var);
else
Str << "?";
Str << " weight=" << Var->getWeight() << " ";
Var->dump(this);
if (Variable *Pref = Var->getPreferredRegister()) {
Str << " pref=";
......
......@@ -63,17 +63,15 @@ public:
// Manage Variables.
// Create a new Variable with a particular type and an optional
// name. The Node argument is the node where the variable is defined.
template <typename T>
T *makeVariable(Type Ty, const CfgNode *Node, const IceString &Name = "") {
template <typename T> T *makeVariable(Type Ty, const IceString &Name = "") {
SizeT Index = Variables.size();
T *Var = T::create(this, Ty, Node, Index, Name);
T *Var = T::create(this, Ty, Index, Name);
Variables.push_back(Var);
return Var;
}
// TODO(stichnot): Remove this function with C++11, and use default
// argument <typename T=Variable> above.
Variable *makeVariable(Type Ty, const CfgNode *Node,
const IceString &Name = "");
Variable *makeVariable(Type Ty, const IceString &Name = "");
SizeT getNumVariables() const { return Variables.size(); }
const VarList &getVariables() const { return Variables; }
......@@ -81,9 +79,12 @@ public:
void addArg(Variable *Arg);
const VarList &getArgs() const { return Args; }
VarList &getArgs() { return Args; }
void addImplicitArg(Variable *Arg);
const VarList &getImplicitArgs() const { return ImplicitArgs; }
// Miscellaneous accessors.
TargetLowering *getTarget() const { return Target.get(); }
VariablesMetadata *getVMetadata() const { return VMetadata.get(); }
Liveness *getLiveness() const { return Live.get(); }
bool hasComputedFrame() const;
......@@ -161,8 +162,10 @@ private:
InstNumberT NextInstNumber;
VarList Variables;
VarList Args; // subset of Variables, in argument order
VarList ImplicitArgs; // subset of Variables
llvm::OwningPtr<Liveness> Live;
llvm::OwningPtr<TargetLowering> Target;
llvm::OwningPtr<VariablesMetadata> VMetadata;
// CurrentNode is maintained during dumping/emitting just for
// validating Variable::DefNode. Normally, a traversal over
......
......@@ -47,7 +47,6 @@ void CfgNode::appendInst(Inst *Inst) {
} else {
Insts.push_back(Inst);
}
Inst->updateVars(this);
}
// Renumbers the non-deleted instructions in the node. This needs to
......@@ -92,9 +91,8 @@ void CfgNode::computePredecessors() {
// blocks. Note that this transformation preserves SSA form.
void CfgNode::placePhiLoads() {
for (PhiList::iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) {
Inst *Inst = (*I)->lower(Func, this);
Inst *Inst = (*I)->lower(Func);
Insts.insert(Insts.begin(), Inst);
Inst->updateVars(this);
}
}
......@@ -213,7 +211,6 @@ void CfgNode::placePhiStores() {
Insts.insert(SafeInsertionPoint, NewInst);
else
Insts.insert(InsertionPoint, NewInst);
NewInst->updateVars(this);
}
}
}
......@@ -281,12 +278,12 @@ void CfgNode::livenessLightweight() {
I != E; ++I) {
if ((*I)->isDeleted())
continue;
(*I)->livenessLightweight(Live);
(*I)->livenessLightweight(Func, Live);
}
for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) {
if ((*I)->isDeleted())
continue;
(*I)->livenessLightweight(Live);
(*I)->livenessLightweight(Func, Live);
}
}
......
......@@ -56,7 +56,7 @@ template <typename T> static std::string LLVMObjectAsString(const T *O) {
class LLVM2ICEConverter {
public:
LLVM2ICEConverter(Ice::GlobalContext *Ctx, LLVMContext &LLVMContext)
: Ctx(Ctx), Func(NULL), CurrentNode(NULL), TypeConverter(LLVMContext) {}
: Ctx(Ctx), Func(NULL), TypeConverter(LLVMContext) {}
// Caller is expected to delete the returned Ice::Cfg object.
Ice::Cfg *convertFunction(const Function *F) {
......@@ -68,7 +68,6 @@ public:
Func->setInternal(F->hasInternalLinkage());
// The initial definition/use of each arg is the entry node.
CurrentNode = mapBasicBlockToNode(&F->getEntryBlock());
for (Function::const_arg_iterator ArgI = F->arg_begin(),
ArgE = F->arg_end();
ArgI != ArgE; ++ArgI) {
......@@ -85,7 +84,6 @@ public:
}
for (Function::const_iterator BBI = F->begin(), BBE = F->end(); BBI != BBE;
++BBI) {
CurrentNode = mapBasicBlockToNode(BBI);
convertBasicBlock(BBI);
}
Func->setEntryNode(mapBasicBlockToNode(&F->getEntryBlock()));
......@@ -132,8 +130,7 @@ private:
if (IceTy == Ice::IceType_void)
return NULL;
if (VarMap.find(V) == VarMap.end()) {
assert(CurrentNode);
VarMap[V] = Func->makeVariable(IceTy, CurrentNode, V->getName());
VarMap[V] = Func->makeVariable(IceTy, V->getName());
}
return VarMap[V];
}
......@@ -614,7 +611,6 @@ private:
// Data
Ice::GlobalContext *Ctx;
Ice::Cfg *Func;
Ice::CfgNode *CurrentNode;
std::map<const Value *, Ice::Variable *> VarMap;
std::map<const BasicBlock *, Ice::CfgNode *> NodeMap;
Ice::TypeConverter TypeConverter;
......
......@@ -57,6 +57,7 @@ class Liveness;
class Operand;
class TargetLowering;
class Variable;
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
......
......@@ -111,21 +111,7 @@ bool Inst::isLastUse(const Operand *TestSrc) const {
return false;
}
void Inst::updateVars(CfgNode *Node) {
if (Dest)
Dest->setDefinition(this, Node);
for (SizeT I = 0; I < getSrcSize(); ++I) {
Operand *Src = getSrc(I);
SizeT NumVars = Src->getNumVars();
for (SizeT J = 0; J < NumVars; ++J) {
Variable *Var = Src->getVar(J);
Var->setUse(this, Node);
}
}
}
void Inst::livenessLightweight(llvm::BitVector &Live) {
void Inst::livenessLightweight(Cfg *Func, llvm::BitVector &Live) {
assert(!isDeleted());
if (llvm::isa<InstFakeKill>(this))
return;
......@@ -136,7 +122,7 @@ void Inst::livenessLightweight(llvm::BitVector &Live) {
SizeT NumVars = Src->getNumVars();
for (SizeT J = 0; J < NumVars; ++J, ++VarIndex) {
const Variable *Var = Src->getVar(J);
if (Var->isMultiblockLife())
if (Func->getVMetadata()->isMultiBlock(Var))
continue;
SizeT Index = Var->getIndex();
if (Live[Index])
......@@ -354,19 +340,17 @@ void InstPhi::livenessPhiOperand(llvm::BitVector &Live, CfgNode *Target,
// Change "a=phi(...)" to "a_phi=phi(...)" and return a new
// instruction "a=a_phi".
Inst *InstPhi::lower(Cfg *Func, CfgNode *Node) {
Inst *InstPhi::lower(Cfg *Func) {
Variable *Dest = getDest();
assert(Dest);
IceString PhiName = Dest->getName() + "_phi";
Variable *NewSrc = Func->makeVariable(Dest->getType(), Node, PhiName);
NewSrc->setIsMultidef();
Variable *NewSrc = Func->makeVariable(Dest->getType(), PhiName);
this->Dest = NewSrc;
InstAssign *NewInst = InstAssign::create(Func, Dest, NewSrc);
// Set Dest and NewSrc to have affinity with each other, as a hint
// for register allocation.
Dest->setPreferredRegister(NewSrc, false);
NewSrc->setPreferredRegister(Dest, false);
Dest->replaceDefinition(NewInst, Node);
return NewInst;
}
......
......@@ -92,13 +92,7 @@ public:
return NodeList();
}
// Updates the status of the Variables contained within the
// instruction. In particular, it marks where the Dest variable is
// first assigned, and it tracks whether variables are live across
// basic blocks, i.e. used in a different block from their definition.
void updateVars(CfgNode *Node);
void livenessLightweight(llvm::BitVector &Live);
void livenessLightweight(Cfg *Func, llvm::BitVector &Live);
void liveness(InstNumberT InstNumber, llvm::BitVector &Live,
Liveness *Liveness, const CfgNode *Node);
......@@ -520,7 +514,7 @@ public:
Operand *getOperandForTarget(CfgNode *Target) const;
void livenessPhiOperand(llvm::BitVector &Live, CfgNode *Target,
Liveness *Liveness);
Inst *lower(Cfg *Func, CfgNode *Node);
Inst *lower(Cfg *Func);
virtual void dump(const Cfg *Func) const;
static bool classof(const Inst *Inst) { return Inst->getKind() == Phi; }
......
......@@ -95,8 +95,11 @@ OperandX8632Mem::OperandX8632Mem(Cfg *Func, Type Ty, Variable *Base,
}
}
InstX8632AdjustStack::InstX8632AdjustStack(Cfg *Func, SizeT Amount)
: InstX8632(Func, InstX8632::Adjuststack, 0, NULL), Amount(Amount) {}
InstX8632AdjustStack::InstX8632AdjustStack(Cfg *Func, SizeT Amount,
Variable *Esp)
: InstX8632(Func, InstX8632::Adjuststack, 1, Esp), Amount(Amount) {
addSource(Esp);
}
InstX8632Mul::InstX8632Mul(Cfg *Func, Variable *Dest, Variable *Source1,
Operand *Source2)
......@@ -1497,8 +1500,6 @@ void OperandX8632Mem::dump(const Cfg *Func, Ostream &Str) const {
void VariableSplit::emit(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit();
assert(Var->getLocalUseNode() == NULL ||
Var->getLocalUseNode() == Func->getCurrentNode());
assert(!Var->hasReg());
// The following is copied/adapted from TargetX8632::emitVariable().
const TargetLowering *Target = Func->getTarget();
......
......@@ -142,10 +142,9 @@ private:
// Variable and SpillVariable share that slot.
class SpillVariable : public Variable {
public:
static SpillVariable *create(Cfg *Func, Type Ty, const CfgNode *Node,
SizeT Index, const IceString &Name) {
return new (Func->allocate<SpillVariable>())
SpillVariable(Ty, Node, Index, Name);
static SpillVariable *create(Cfg *Func, Type Ty, SizeT Index,
const IceString &Name) {
return new (Func->allocate<SpillVariable>()) SpillVariable(Ty, Index, Name);
}
const static OperandKind SpillVariableKind =
static_cast<OperandKind>(kVariable_Target);
......@@ -156,9 +155,8 @@ public:
Variable *getLinkedTo() const { return LinkedTo; }
// Inherit dump() and emit() from Variable.
private:
SpillVariable(Type Ty, const CfgNode *Node, SizeT Index,
const IceString &Name)
: Variable(SpillVariableKind, Ty, Node, Index, Name), LinkedTo(NULL) {}
SpillVariable(Type Ty, SizeT Index, const IceString &Name)
: Variable(SpillVariableKind, Ty, Index, Name), LinkedTo(NULL) {}
Variable *LinkedTo;
};
......@@ -393,16 +391,16 @@ private:
// updates the stack offset during code emission.
class InstX8632AdjustStack : public InstX8632 {
public:
static InstX8632AdjustStack *create(Cfg *Func, SizeT Amount) {
static InstX8632AdjustStack *create(Cfg *Func, SizeT Amount, Variable *Esp) {
return new (Func->allocate<InstX8632AdjustStack>())
InstX8632AdjustStack(Func, Amount);
InstX8632AdjustStack(Func, Amount, Esp);
}
virtual void emit(const Cfg *Func) const;
virtual void dump(const Cfg *Func) const;
static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); }
private:
InstX8632AdjustStack(Cfg *Func, SizeT Amount);
InstX8632AdjustStack(Cfg *Func, SizeT Amount, Variable *Esp);
InstX8632AdjustStack(const InstX8632AdjustStack &) LLVM_DELETED_FUNCTION;
InstX8632AdjustStack &operator=(const InstX8632AdjustStack &)
LLVM_DELETED_FUNCTION;
......
......@@ -41,10 +41,10 @@ void Liveness::init() {
// block.
for (SizeT i = 0; i < NumVars; ++i) {
Variable *Var = Func->getVariables()[i];
if (Var->isMultiblockLife()) {
if (Func->getVMetadata()->isMultiBlock(Var)) {
++NumGlobals;
} else {
SizeT Index = Var->getLocalUseNode()->getIndex();
SizeT Index = Func->getVMetadata()->getLocalUseNode(Var)->getIndex();
++Nodes[Index].NumLocals;
}
}
......@@ -64,11 +64,11 @@ void Liveness::init() {
Variable *Var = Func->getVariables()[i];
SizeT VarIndex = Var->getIndex();
SizeT LiveIndex;
if (Var->isMultiblockLife()) {
if (Func->getVMetadata()->isMultiBlock(Var)) {
LiveIndex = TmpNumGlobals++;
LiveToVarMap[LiveIndex] = Var;
} else {
SizeT NodeIndex = Var->getLocalUseNode()->getIndex();
SizeT NodeIndex = Func->getVMetadata()->getLocalUseNode(Var)->getIndex();
LiveIndex = Nodes[NodeIndex].NumLocals++;
Nodes[NodeIndex].LiveToVarMap[LiveIndex] = Var;
LiveIndex += NumGlobals;
......
......@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "IceCfg.h"
#include "IceCfgNode.h"
#include "IceInst.h"
#include "IceOperand.h"
#include "IceTargetLowering.h" // dumping stack/frame pointer register
......@@ -138,48 +139,6 @@ bool LiveRange::containsValue(InstNumberT Value) const {
return false;
}
void Variable::setUse(const Inst *Inst, const CfgNode *Node) {
if (DefNode == NULL)
return;
if (llvm::isa<InstPhi>(Inst) || Node != DefNode)
DefNode = NULL;
}
void Variable::setDefinition(Inst *Inst, const CfgNode *Node) {
if (DefInst && !DefInst->isDeleted() && DefInst != Inst) {
// Detect when a variable is being defined multiple times,
// particularly for Phi instruction lowering. If this happens, we
// need to lock DefInst to NULL.
DefInst = NULL;
DefNode = NULL;
return;
}
if (DefNode == NULL)
return;
DefInst = Inst;
if (Node != DefNode)
DefNode = NULL;
}
void Variable::replaceDefinition(Inst *Inst, const CfgNode *Node) {
DefInst = NULL;
setDefinition(Inst, Node);
}
void Variable::setIsArg(Cfg *Func, bool IsArg) {
if (IsArg) {
IsArgument = true;
if (DefNode == NULL)
return;
CfgNode *Entry = Func->getEntryNode();
if (DefNode == Entry)
return;
DefNode = NULL;
} else {
IsArgument = false;
}
}
IceString Variable::getName() const {
if (!Name.empty())
return Name;
......@@ -191,16 +150,156 @@ IceString Variable::getName() const {
Variable Variable::asType(Type Ty) {
// Note: This returns a Variable, even if the "this" object is a
// subclass of Variable.
Variable V(kVariable, Ty, DefNode, Number, Name);
Variable V(kVariable, Ty, Number, Name);
V.RegNum = RegNum;
V.StackOffset = StackOffset;
return V;
}
void VariableTracking::markUse(const Inst *Instr, const CfgNode *Node,
bool IsFromDef, bool IsImplicit) {
// TODO(stichnot): If the use occurs as a source operand in the
// first instruction of the block, and its definition is in this
// block's only predecessor, we might consider not marking this as a
// separate use. This may also apply if it's the first instruction
// of the block that actually uses a Variable.
assert(Node);
bool MakeMulti = false;
// A phi source variable conservatively needs to be marked as
// multi-block, even if its definition is in the same block. This
// is because there can be additional control flow before branching
// back to this node, and the variable is live throughout those
// nodes.
if (IsImplicit)
MakeMulti = true;
if (!IsFromDef && Instr && llvm::isa<InstPhi>(Instr))
MakeMulti = true;
if (!MakeMulti) {
switch (MultiBlock) {
case MBS_Unknown:
MultiBlock = MBS_SingleBlock;
SingleUseNode = Node;
break;
case MBS_SingleBlock:
if (SingleUseNode != Node)
MakeMulti = true;
break;
case MBS_MultiBlock:
break;
}
}
if (MakeMulti) {
MultiBlock = MBS_MultiBlock;
SingleUseNode = NULL;
}
}
void VariableTracking::markDef(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.
const bool IsFromDef = true;
const bool IsImplicit = false;
markUse(Instr, Node, IsFromDef, IsImplicit);
switch (MultiDef) {
case MDS_Unknown:
MultiDef = MDS_SingleDef;
SingleDefInst = Instr;
break;
case MDS_SingleDef:
MultiDef = MDS_MultiDef;
SingleDefInst = NULL;
break;
case MDS_MultiDef:
break;
}
}
void VariablesMetadata::init() {
Metadata.clear();
Metadata.resize(Func->getNumVariables());
// Mark implicit args as being used in the entry node.
const VarList &ImplicitArgList = Func->getImplicitArgs();
for (VarList::const_iterator I = ImplicitArgList.begin(),
E = ImplicitArgList.end();
I != E; ++I) {
const Variable *Var = *I;
const Inst *NoInst = NULL;
const CfgNode *EntryNode = Func->getEntryNode();
const bool IsFromDef = false;
const bool IsImplicit = true;
Metadata[Var->getIndex()].markUse(NoInst, EntryNode, IsFromDef, IsImplicit);
}
SizeT NumNodes = Func->getNumNodes();
for (SizeT N = 0; N < NumNodes; ++N) {
CfgNode *Node = Func->getNodes()[N];
const InstList &Insts = Node->getInsts();
for (InstList::const_iterator I = Insts.begin(), E = Insts.end(); I != E;
++I) {
if ((*I)->isDeleted())
continue;
if (Variable *Dest = (*I)->getDest()) {
SizeT DestNum = Dest->getIndex();
assert(DestNum < Metadata.size());
Metadata[DestNum].markDef(*I, Node);
}
for (SizeT SrcNum = 0; SrcNum < (*I)->getSrcSize(); ++SrcNum) {
Operand *Src = (*I)->getSrc(SrcNum);
SizeT NumVars = Src->getNumVars();
for (SizeT J = 0; J < NumVars; ++J) {
const Variable *Var = Src->getVar(J);
SizeT VarNum = Var->getIndex();
assert(VarNum < Metadata.size());
const bool IsFromDef = false;
const bool IsImplicit = false;
Metadata[VarNum].markUse(*I, Node, IsFromDef, IsImplicit);
}
}
}
}
}
bool VariablesMetadata::isMultiDef(const Variable *Var) const {
if (Var->getIsArg())
return false;
if (!isTracked(Var))
return true; // conservative answer
SizeT VarNum = Var->getIndex();
// Conservatively return true if the state is unknown.
return Metadata[VarNum].getMultiDef() != VariableTracking::MDS_SingleDef;
}
bool VariablesMetadata::isMultiBlock(const Variable *Var) const {
if (getDefinition(Var) == NULL)
return true;
SizeT VarNum = Var->getIndex();
// Conservatively return true if the state is unknown.
return Metadata[VarNum].getMultiBlock() != VariableTracking::MBS_SingleBlock;
}
const Inst *VariablesMetadata::getDefinition(const Variable *Var) const {
if (!isTracked(Var))
return NULL; // conservative answer
SizeT VarNum = Var->getIndex();
return Metadata[VarNum].getDefinition();
}
const CfgNode *VariablesMetadata::getLocalUseNode(const Variable *Var) const {
if (!isTracked(Var))
return NULL; // conservative answer
SizeT VarNum = Var->getIndex();
return Metadata[VarNum].getNode();
}
// ======================== dump routines ======================== //
void Variable::emit(const Cfg *Func) const {
Func->getTarget()->emitVariable(this, Func);
Func->getTarget()->emitVariable(this);
}
void Variable::dump(const Cfg *Func, Ostream &Str) const {
......@@ -208,9 +307,6 @@ void Variable::dump(const Cfg *Func, Ostream &Str) const {
Str << "%" << getName();
return;
}
const CfgNode *CurrentNode = Func->getCurrentNode();
(void)CurrentNode; // used only in assert()
assert(CurrentNode == NULL || DefNode == NULL || DefNode == CurrentNode);
if (Func->getContext()->isVerbose(IceV_RegOrigins) ||
(!hasReg() && !Func->getTarget()->hasComputedFrame()))
Str << "%" << getName();
......
......@@ -347,10 +347,10 @@ class Variable : public Operand {
Variable &operator=(const Variable &) LLVM_DELETED_FUNCTION;
public:
static Variable *create(Cfg *Func, Type Ty, const CfgNode *Node, SizeT Index,
static Variable *create(Cfg *Func, Type Ty, SizeT Index,
const IceString &Name) {
return new (Func->allocate<Variable>())
Variable(kVariable, Ty, Node, Index, Name);
Variable(kVariable, Ty, Index, Name);
}
SizeT getIndex() const { return Number; }
......@@ -361,24 +361,10 @@ public:
Name = NewName;
}
Inst *getDefinition() const { return DefInst; }
void setDefinition(Inst *Inst, const CfgNode *Node);
void replaceDefinition(Inst *Inst, const CfgNode *Node);
const CfgNode *getLocalUseNode() const { return DefNode; }
bool isMultiblockLife() const { return (DefNode == NULL); }
void setUse(const Inst *Inst, const CfgNode *Node);
// Multidef means a variable is non-SSA and has multiple defining
// instructions. Currently this classification is limited to SSA
// lowering temporaries where the definitions are in different basic
// blocks, and it is not maintained during target lowering when the
// same temporary may be updated in consecutive instructions.
bool getIsMultidef() const { return IsMultidef; }
void setIsMultidef() { IsMultidef = true; }
bool getIsArg() const { return IsArgument; }
void setIsArg(Cfg *Func, bool IsArg = true);
void setIsArg(bool Val = true) { IsArgument = Val; }
bool getIsImplicitArg() const { return IsImplicitArgument; }
void setIsImplicitArg(bool Val = true) { IsImplicitArgument = Val; }
int32_t getStackOffset() const { return StackOffset; }
void setStackOffset(int32_t Offset) { StackOffset = Offset; }
......@@ -447,13 +433,11 @@ public:
virtual ~Variable() {}
protected:
Variable(OperandKind K, Type Ty, const CfgNode *Node, SizeT Index,
const IceString &Name)
: Operand(K, Ty), Number(Index), Name(Name), DefInst(NULL), DefNode(Node),
IsMultidef(false), IsArgument(false), StackOffset(0),
RegNum(NoRegister), RegNumTmp(NoRegister), Weight(1),
RegisterPreference(NULL), AllowRegisterOverlap(false), LoVar(NULL),
HiVar(NULL) {
Variable(OperandKind K, Type Ty, SizeT Index, const IceString &Name)
: Operand(K, Ty), Number(Index), Name(Name), IsArgument(false),
IsImplicitArgument(false), StackOffset(0), RegNum(NoRegister),
RegNumTmp(NoRegister), Weight(1), RegisterPreference(NULL),
AllowRegisterOverlap(false), LoVar(NULL), HiVar(NULL) {
Vars = VarsReal;
Vars[0] = this;
NumVars = 1;
......@@ -463,18 +447,8 @@ protected:
const SizeT Number;
// Name is optional.
IceString Name;
// DefInst is the instruction that produces this variable as its
// dest.
Inst *DefInst;
// DefNode is the node where this variable was produced, and is
// reset to NULL if it is used outside that node. This is used for
// detecting isMultiblockLife(). TODO: Collapse this to a single
// bit and use a separate pass to calculate the values across the
// Cfg. This saves space in the Variable, and removes the fragility
// of incrementally computing and maintaining the information.
const CfgNode *DefNode;
bool IsMultidef;
bool IsArgument;
bool IsImplicitArgument;
// StackOffset is the canonical location on stack (only if
// RegNum<0 || IsArgument).
int32_t StackOffset;
......@@ -509,6 +483,60 @@ protected:
Variable *VarsReal[1];
};
// VariableTracking tracks the metadata for a single variable.
class VariableTracking {
public:
enum MultiDefState {
// TODO(stichnot): Consider using just a simple counter.
MDS_Unknown,
MDS_SingleDef,
MDS_MultiDef
};
enum MultiBlockState {
MBS_Unknown,
MBS_SingleBlock,
MBS_MultiBlock
};
VariableTracking()
: MultiDef(MDS_Unknown), MultiBlock(MBS_Unknown), SingleUseNode(NULL),
SingleDefInst(NULL) {}
MultiDefState getMultiDef() const { return MultiDef; }
MultiBlockState getMultiBlock() const { return MultiBlock; }
const Inst *getDefinition() const { return SingleDefInst; }
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);
private:
VariableTracking &operator=(const VariableTracking &) LLVM_DELETED_FUNCTION;
MultiDefState MultiDef;
MultiBlockState MultiBlock;
const CfgNode *SingleUseNode;
const Inst *SingleDefInst;
};
// VariablesMetadata analyzes and summarizes the metadata for the
// complete set of Variables.
class VariablesMetadata {
public:
VariablesMetadata(const Cfg *Func) : Func(Func) {}
void init();
bool isTracked(const Variable *Var) const {
return Var->getIndex() < Metadata.size();
}
bool isMultiDef(const Variable *Var) const;
const Inst *getDefinition(const Variable *Var) const;
bool isMultiBlock(const Variable *Var) const;
const CfgNode *getLocalUseNode(const Variable *Var) const;
private:
const Cfg *Func;
std::vector<VariableTracking> Metadata;
VariablesMetadata(const VariablesMetadata &) LLVM_DELETED_FUNCTION;
VariablesMetadata &operator=(const VariablesMetadata &) LLVM_DELETED_FUNCTION;
};
} // end of namespace Ice
#endif // SUBZERO_SRC_ICEOPERAND_H
......@@ -53,7 +53,6 @@ void LoweringContext::init(CfgNode *N) {
void LoweringContext::insert(Inst *Inst) {
getNode()->getInsts().insert(Next, Inst);
Inst->updateVars(getNode());
}
void LoweringContext::skipDeleted(InstList::iterator &I) const {
......
......@@ -172,7 +172,7 @@ public:
virtual const llvm::SmallBitVector &getRegisterSetForType(Type Ty) const = 0;
void regAlloc();
virtual void emitVariable(const Variable *Var, const Cfg *Func) const = 0;
virtual void emitVariable(const Variable *Var) const = 0;
// Performs target-specific argument lowering.
virtual void lowerArguments() = 0;
......
......@@ -52,7 +52,7 @@ public:
static const uint8_t Padding[] = { 0xF4 };
return llvm::ArrayRef<uint8_t>(Padding, 1);
}
virtual void emitVariable(const Variable *Var, const Cfg *Func) const;
virtual void emitVariable(const Variable *Var) const;
virtual void lowerArguments();
virtual void addProlog(CfgNode *Node);
virtual void addEpilog(CfgNode *Node);
......@@ -190,7 +190,8 @@ protected:
Context.insert(InstX8632Add::create(Func, Dest, Src0));
}
void _adjust_stack(int32_t Amount) {
Context.insert(InstX8632AdjustStack::create(Func, Amount));
Context.insert(InstX8632AdjustStack::create(
Func, Amount, getPhysicalRegister(RegX8632::Reg_esp)));
}
void _addps(Variable *Dest, Operand *Src0) {
Context.insert(InstX8632Addps::create(Func, Dest, Src0));
......
......@@ -948,7 +948,7 @@ private:
// Recover since we can't throw an exception.
Ty = Ice::IceType_i32;
}
return Func->makeVariable(Ty, CurrentNode);
return Func->makeVariable(Ty);
}
// Generates the next available local variable using the given type.
......
......@@ -78,8 +78,8 @@ block:
ret <4 x i32> %vec.local
; CHECK-LABEL: align_local_vector_and_global_float:
; CHECK: cvtsi2ss xmm0, eax
; CHECK-NEXT: movss dword ptr [esp+28], xmm0
; CHECK: movups xmm0, xmmword ptr [esp]
; CHECK-NEXT: movss dword ptr [esp+{{12|28}}], xmm0
; CHECK: movups xmm0, xmmword ptr [{{esp|esp\+16}}]
; CHECK-NEXT: add esp, 44
; CHECK-NEXT: ret
}
......
......@@ -55,6 +55,9 @@ NonZero:
; CHECK: mov dword ptr [esp + [[OFF:.*]]], [[REG1]]
; CHECK: add [[REG2:.*]], 54321
; Now there should be sharing of the stack slot (OFF is the same).
; CHECK: mov dword ptr [esp + [[OFF]]], [[REG2]]
; Commenting out after disabling simple coalescing for -Om1.
; TODO(stichnot): Add it back if/when we add a flag to enable simple
; coalescing.
; xCHECK: mov dword ptr [esp + [[OFF]]], [[REG2]]
; ERRORS-NOT: ICE translation error
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