[RDF] Differentiate between defining and clobbering nodes

Defining nodes should not alias with one another, while clobbering
nodes can. When pushing defs on stacks, push clobbers first, link
non-clobbering defs, then push the defs.

The data flow in a statement is now: uses -> clobbers -> defs.

llvm-svn: 295356
This commit is contained in:
Krzysztof Parzyszek 2017-02-16 18:53:04 +00:00
parent 077081d4d5
commit 84cd4ea301
4 changed files with 88 additions and 13 deletions

View File

@ -617,7 +617,7 @@ bool HexagonOptAddrMode::constructDefMap(MachineBasicBlock *B) {
for (NodeAddr<InstrNode *> IA : BA.Addr->members(*DFG)) {
updateMap(IA);
DFG->pushDefs(IA, DefM);
DFG->pushAllDefs(IA, DefM);
}
MachineDomTreeNode *N = MDT->getNode(B);

View File

@ -104,7 +104,7 @@ bool CopyPropagation::scanBlock(MachineBasicBlock *B) {
}
updateMap(IA);
DFG.pushDefs(IA, DefM);
DFG.pushAllDefs(IA, DefM);
}
MachineDomTreeNode *N = MDT.getNode(B);

View File

@ -617,8 +617,12 @@ bool TargetOperandInfo::isPreserving(const MachineInstr &In, unsigned OpNum)
// Check if the definition of RR produces an unspecified value.
bool TargetOperandInfo::isClobbering(const MachineInstr &In, unsigned OpNum)
const {
const MachineOperand &Op = In.getOperand(OpNum);
if (Op.isRegMask())
return true;
assert(Op.isReg());
if (In.isCall())
if (In.getOperand(OpNum).isImplicit())
if (Op.isDef() && Op.isDead())
return true;
return false;
}
@ -1022,13 +1026,63 @@ void DataFlowGraph::releaseBlock(NodeId B, DefStackMap &DefM) {
}
}
// Push all definitions from the instruction node IA to an appropriate
// stack in DefM.
void DataFlowGraph::pushAllDefs(NodeAddr<InstrNode*> IA, DefStackMap &DefM) {
pushClobbers(IA, DefM);
pushDefs(IA, DefM);
}
// Push all definitions from the instruction node IA to an appropriate
// stack in DefM.
void DataFlowGraph::pushClobbers(NodeAddr<InstrNode*> IA, DefStackMap &DefM) {
NodeSet Visited;
std::set<RegisterId> Defined;
// The important objectives of this function are:
// - to be able to handle instructions both while the graph is being
// constructed, and after the graph has been constructed, and
// - maintain proper ordering of definitions on the stack for each
// register reference:
// - if there are two or more related defs in IA (i.e. coming from
// the same machine operand), then only push one def on the stack,
// - if there are multiple unrelated defs of non-overlapping
// subregisters of S, then the stack for S will have both (in an
// unspecified order), but the order does not matter from the data-
// -flow perspective.
for (NodeAddr<DefNode*> DA : IA.Addr->members_if(IsDef, *this)) {
if (Visited.count(DA.Id))
continue;
if (!(DA.Addr->getFlags() & NodeAttrs::Clobbering))
continue;
NodeList Rel = getRelatedRefs(IA, DA);
NodeAddr<DefNode*> PDA = Rel.front();
RegisterRef RR = PDA.Addr->getRegRef(*this);
// Push the definition on the stack for the register and all aliases.
// The def stack traversal in linkNodeUp will check the exact aliasing.
DefM[RR.Reg].push(DA);
Defined.insert(RR.Reg);
for (RegisterId A : PRI.getAliasSet(RR.Reg)) {
// Check that we don't push the same def twice.
assert(A != RR.Reg);
if (!Defined.count(A))
DefM[A].push(DA);
}
// Mark all the related defs as visited.
for (NodeAddr<NodeBase*> T : Rel)
Visited.insert(T.Id);
}
}
// Push all definitions from the instruction node IA to an appropriate
// stack in DefM.
void DataFlowGraph::pushDefs(NodeAddr<InstrNode*> IA, DefStackMap &DefM) {
NodeList Defs = IA.Addr->members_if(IsDef, *this);
NodeSet Visited;
#ifndef NDEBUG
RegisterSet Defined;
std::set<RegisterId> Defined;
#endif
// The important objectives of this function are:
@ -1043,9 +1097,11 @@ void DataFlowGraph::pushDefs(NodeAddr<InstrNode*> IA, DefStackMap &DefM) {
// unspecified order), but the order does not matter from the data-
// -flow perspective.
for (NodeAddr<DefNode*> DA : Defs) {
for (NodeAddr<DefNode*> DA : IA.Addr->members_if(IsDef, *this)) {
if (Visited.count(DA.Id))
continue;
if (DA.Addr->getFlags() & NodeAttrs::Clobbering)
continue;
NodeList Rel = getRelatedRefs(IA, DA);
NodeAddr<DefNode*> PDA = Rel.front();
@ -1053,7 +1109,7 @@ void DataFlowGraph::pushDefs(NodeAddr<InstrNode*> IA, DefStackMap &DefM) {
#ifndef NDEBUG
// Assert if the register is defined in two or more unrelated defs.
// This could happen if there are two or more def operands defining it.
if (!Defined.insert(RR).second) {
if (!Defined.insert(RR.Reg).second) {
MachineInstr *MI = NodeAddr<StmtNode*>(IA).Addr->getCode();
dbgs() << "Multiple definitions of register: "
<< Print<RegisterRef>(RR, *this) << " in\n " << *MI
@ -1611,13 +1667,15 @@ void DataFlowGraph::linkRefUp(NodeAddr<InstrNode*> IA, NodeAddr<T> TA,
}
// Create data-flow links for all reference nodes in the statement node SA.
void DataFlowGraph::linkStmtRefs(DefStackMap &DefM, NodeAddr<StmtNode*> SA) {
template <typename Predicate>
void DataFlowGraph::linkStmtRefs(DefStackMap &DefM, NodeAddr<StmtNode*> SA,
Predicate P) {
#ifndef NDEBUG
RegisterSet Defs;
#endif
// Link all nodes (upwards in the data-flow) with their reaching defs.
for (NodeAddr<RefNode*> RA : SA.Addr->members(*this)) {
for (NodeAddr<RefNode*> RA : SA.Addr->members_if(P, *this)) {
uint16_t Kind = RA.Addr->getKind();
assert(Kind == NodeAttrs::Def || Kind == NodeAttrs::Use);
RegisterRef RR = RA.Addr->getRegRef(*this);
@ -1646,6 +1704,13 @@ void DataFlowGraph::linkBlockRefs(DefStackMap &DefM, NodeAddr<BlockNode*> BA) {
// Push block delimiters.
markBlock(BA.Id, DefM);
auto IsClobber = [this] (NodeAddr<RefNode*> RA) -> bool {
return IsDef(RA) && (RA.Addr->getFlags() & NodeAttrs::Clobbering);
};
auto IsNoClobber = [this] (NodeAddr<RefNode*> RA) -> bool {
return IsDef(RA) && !(RA.Addr->getFlags() & NodeAttrs::Clobbering);
};
assert(BA.Addr && "block node address is needed to create a data-flow link");
// For each non-phi instruction in the block, link all the defs and uses
// to their reaching defs. For any member of the block (including phis),
@ -1653,10 +1718,17 @@ void DataFlowGraph::linkBlockRefs(DefStackMap &DefM, NodeAddr<BlockNode*> BA) {
for (NodeAddr<InstrNode*> IA : BA.Addr->members(*this)) {
// Ignore phi nodes here. They will be linked part by part from the
// predecessors.
if (IA.Addr->getKind() == NodeAttrs::Stmt)
linkStmtRefs(DefM, IA);
if (IA.Addr->getKind() == NodeAttrs::Stmt) {
linkStmtRefs(DefM, IA, IsUse);
linkStmtRefs(DefM, IA, IsClobber);
}
// Push the definitions on the stack.
pushClobbers(IA, DefM);
if (IA.Addr->getKind() == NodeAttrs::Stmt)
linkStmtRefs(DefM, IA, IsNoClobber);
pushDefs(IA, DefM);
}

View File

@ -729,7 +729,7 @@ namespace rdf {
typedef std::unordered_map<RegisterId,DefStack> DefStackMap;
void build(unsigned Options = BuildOptions::None);
void pushDefs(NodeAddr<InstrNode*> IA, DefStackMap &DM);
void pushAllDefs(NodeAddr<InstrNode*> IA, DefStackMap &DM);
void markBlock(NodeId B, DefStackMap &DefM);
void releaseBlock(NodeId B, DefStackMap &DefM);
@ -844,9 +844,12 @@ namespace rdf {
NodeAddr<BlockNode*> BA);
void removeUnusedPhis();
void pushClobbers(NodeAddr<InstrNode*> IA, DefStackMap &DM);
void pushDefs(NodeAddr<InstrNode*> IA, DefStackMap &DM);
template <typename T> void linkRefUp(NodeAddr<InstrNode*> IA,
NodeAddr<T> TA, DefStack &DS);
void linkStmtRefs(DefStackMap &DefM, NodeAddr<StmtNode*> SA);
template <typename Predicate> void linkStmtRefs(DefStackMap &DefM,
NodeAddr<StmtNode*> SA, Predicate P);
void linkBlockRefs(DefStackMap &DefM, NodeAddr<BlockNode*> BA);
void unlinkUseDF(NodeAddr<UseNode*> UA);