mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-12 06:06:32 +00:00
[RDF] Introduce "undef" flag for ref nodes
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@280851 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
f1708bca49
commit
80708afe43
@ -62,6 +62,8 @@ raw_ostream &operator<< (raw_ostream &OS, const Print<NodeId> &P) {
|
||||
}
|
||||
break;
|
||||
case NodeAttrs::Ref:
|
||||
if (Flags & NodeAttrs::Undef)
|
||||
OS << '/';
|
||||
if (Flags & NodeAttrs::Preserving)
|
||||
OS << '+';
|
||||
if (Flags & NodeAttrs::Clobbering)
|
||||
@ -1189,6 +1191,19 @@ void DataFlowGraph::buildStmt(NodeAddr<BlockNode*> BA, MachineInstr &In) {
|
||||
return false;
|
||||
};
|
||||
|
||||
auto isDefUndef = [this] (const MachineInstr &In, RegisterRef DR) -> bool {
|
||||
// This instruction defines DR. Check if there is a use operand that
|
||||
// would make DR live on entry to the instruction.
|
||||
for (const MachineOperand &UseOp : In.operands()) {
|
||||
if (!UseOp.isReg() || !UseOp.isUse() || UseOp.isUndef())
|
||||
continue;
|
||||
RegisterRef UR = { UseOp.getReg(), UseOp.getSubReg() };
|
||||
if (RAI.alias(DR, UR))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// Collect a set of registers that this instruction implicitly uses
|
||||
// or defines. Implicit operands from an instruction will be ignored
|
||||
// unless they are listed here.
|
||||
@ -1216,8 +1231,12 @@ void DataFlowGraph::buildStmt(NodeAddr<BlockNode*> BA, MachineInstr &In) {
|
||||
continue;
|
||||
RegisterRef RR = { Op.getReg(), Op.getSubReg() };
|
||||
uint16_t Flags = NodeAttrs::None;
|
||||
if (TOI.isPreserving(In, OpN))
|
||||
if (TOI.isPreserving(In, OpN)) {
|
||||
Flags |= NodeAttrs::Preserving;
|
||||
// If the def is preserving, check if it is also undefined.
|
||||
if (isDefUndef(In, RR))
|
||||
Flags |= NodeAttrs::Undef;
|
||||
}
|
||||
if (TOI.isClobbering(In, OpN))
|
||||
Flags |= NodeAttrs::Clobbering;
|
||||
if (TOI.isFixedReg(In, OpN))
|
||||
@ -1239,8 +1258,12 @@ void DataFlowGraph::buildStmt(NodeAddr<BlockNode*> BA, MachineInstr &In) {
|
||||
if (DoneDefs.count(RR))
|
||||
continue;
|
||||
uint16_t Flags = NodeAttrs::None;
|
||||
if (TOI.isPreserving(In, OpN))
|
||||
if (TOI.isPreserving(In, OpN)) {
|
||||
Flags |= NodeAttrs::Preserving;
|
||||
// If the def is preserving, check if it is also undefined.
|
||||
if (isDefUndef(In, RR))
|
||||
Flags |= NodeAttrs::Undef;
|
||||
}
|
||||
if (TOI.isClobbering(In, OpN))
|
||||
Flags |= NodeAttrs::Clobbering;
|
||||
if (TOI.isFixedReg(In, OpN))
|
||||
@ -1252,7 +1275,7 @@ void DataFlowGraph::buildStmt(NodeAddr<BlockNode*> BA, MachineInstr &In) {
|
||||
|
||||
for (unsigned OpN = 0; OpN < NumOps; ++OpN) {
|
||||
MachineOperand &Op = In.getOperand(OpN);
|
||||
if (!Op.isReg() || !Op.isUse() || Op.isUndef())
|
||||
if (!Op.isReg() || !Op.isUse())
|
||||
continue;
|
||||
RegisterRef RR = { Op.getReg(), Op.getSubReg() };
|
||||
// Add implicit uses on return and call instructions, and on predicated
|
||||
@ -1263,6 +1286,8 @@ void DataFlowGraph::buildStmt(NodeAddr<BlockNode*> BA, MachineInstr &In) {
|
||||
if (Implicit && !TakeImplicit && !ImpUses.count(RR))
|
||||
continue;
|
||||
uint16_t Flags = NodeAttrs::None;
|
||||
if (Op.isUndef())
|
||||
Flags |= NodeAttrs::Undef;
|
||||
if (TOI.isFixedReg(In, OpN))
|
||||
Flags |= NodeAttrs::Fixed;
|
||||
NodeAddr<UseNode*> UA = newUse(SA, Op, Flags);
|
||||
|
@ -175,7 +175,22 @@
|
||||
// - Clobbering: applied only to defs, indicates that the value generated
|
||||
// by this def is unspecified. A typical example would be volatile registers
|
||||
// after function calls.
|
||||
//
|
||||
// - Fixed: the register in this def/use cannot be replaced with any other
|
||||
// register. A typical case would be a parameter register to a call, or
|
||||
// the register with the return value from a function.
|
||||
// - Undef: the register in this reference the register is assumed to have
|
||||
// no pre-existing value, even if it appears to be reached by some def.
|
||||
// This is typically used to prevent keeping registers artificially live
|
||||
// in cases when they are defined via predicated instructions. For example:
|
||||
// r0 = add-if-true cond, r10, r11 (1)
|
||||
// r0 = add-if-false cond, r12, r13, r0<imp-use> (2)
|
||||
// ... = r0 (3)
|
||||
// Before (1), r0 is not intended to be live, and the use of r0 in (3) is
|
||||
// not meant to be reached by any def preceding (1). However, since the
|
||||
// defs in (1) and (2) are both preserving, these properties alone would
|
||||
// imply that the use in (3) may indeed be reached by some prior def.
|
||||
// Adding Undef flag to the def in (1) prevents that. The Undef flag
|
||||
// may be applied to both defs and uses.
|
||||
//
|
||||
// *** Shadow references
|
||||
//
|
||||
@ -244,13 +259,14 @@ namespace rdf {
|
||||
Block = 0x0005 << 2, // 101
|
||||
Func = 0x0006 << 2, // 110
|
||||
|
||||
// Flags: 5 bits for now
|
||||
FlagMask = 0x001F << 5,
|
||||
Shadow = 0x0001 << 5, // 00001, Has extra reaching defs.
|
||||
Clobbering = 0x0002 << 5, // 00010, Produces unspecified values.
|
||||
PhiRef = 0x0004 << 5, // 00100, Member of PhiNode.
|
||||
Preserving = 0x0008 << 5, // 01000, Def can keep original bits.
|
||||
Fixed = 0x0010 << 5, // 10000, Fixed register.
|
||||
// Flags: 6 bits for now
|
||||
FlagMask = 0x003F << 5,
|
||||
Shadow = 0x0001 << 5, // 000001, Has extra reaching defs.
|
||||
Clobbering = 0x0002 << 5, // 000010, Produces unspecified values.
|
||||
PhiRef = 0x0004 << 5, // 000100, Member of PhiNode.
|
||||
Preserving = 0x0008 << 5, // 001000, Def can keep original bits.
|
||||
Fixed = 0x0010 << 5, // 010000, Fixed register.
|
||||
Undef = 0x0020 << 5, // 100000, Has no pre-existing value.
|
||||
};
|
||||
|
||||
static uint16_t type(uint16_t T) { return T & TypeMask; }
|
||||
@ -742,6 +758,10 @@ namespace rdf {
|
||||
return BA.Addr->getType() == NodeAttrs::Code &&
|
||||
BA.Addr->getKind() == NodeAttrs::Phi;
|
||||
}
|
||||
static bool IsPreservingDef(const NodeAddr<DefNode*> DA) {
|
||||
uint16_t Flags = DA.Addr->getFlags();
|
||||
return (Flags & NodeAttrs::Preserving) && !(Flags & NodeAttrs::Undef);
|
||||
}
|
||||
|
||||
private:
|
||||
void reset();
|
||||
|
@ -109,11 +109,9 @@ NodeList Liveness::getAllReachingDefs(RegisterRef RefRR,
|
||||
continue;
|
||||
// Stop at the covering/overwriting def of the initial register reference.
|
||||
RegisterRef RR = TA.Addr->getRegRef();
|
||||
if (RAI.covers(RR, RefRR)) {
|
||||
uint16_t Flags = TA.Addr->getFlags();
|
||||
if (!(Flags & NodeAttrs::Preserving))
|
||||
if (RAI.covers(RR, RefRR))
|
||||
if (!DFG.IsPreservingDef(TA))
|
||||
continue;
|
||||
}
|
||||
// Get the next level of reaching defs. This will include multiple
|
||||
// reaching defs for shadows.
|
||||
for (auto S : DFG.getRelatedRefs(TA.Addr->getOwner(DFG), TA))
|
||||
@ -221,7 +219,7 @@ NodeList Liveness::getAllReachingDefs(RegisterRef RefRR,
|
||||
// defs to actually define a register.
|
||||
uint16_t Flags = DA.Addr->getFlags();
|
||||
if (!FullChain || !(Flags & NodeAttrs::PhiRef))
|
||||
if (!(Flags & NodeAttrs::Preserving))
|
||||
if (!(Flags & NodeAttrs::Preserving)) // Don't care about Undef here.
|
||||
RRs.insert(DA.Addr->getRegRef());
|
||||
}
|
||||
}
|
||||
@ -291,9 +289,11 @@ NodeSet Liveness::getAllReachedUses(RegisterRef RefRR,
|
||||
NodeId U = DefA.Addr->getReachedUse();
|
||||
while (U != 0) {
|
||||
auto UA = DFG.addr<UseNode*>(U);
|
||||
auto UR = UA.Addr->getRegRef();
|
||||
if (RAI.alias(RefRR, UR) && !RAI.covers(DefRRs, UR))
|
||||
Uses.insert(U);
|
||||
if (!(UA.Addr->getFlags() & NodeAttrs::Undef)) {
|
||||
auto UR = UA.Addr->getRegRef();
|
||||
if (RAI.alias(RefRR, UR) && !RAI.covers(DefRRs, UR))
|
||||
Uses.insert(U);
|
||||
}
|
||||
U = UA.Addr->getSibling();
|
||||
}
|
||||
|
||||
@ -307,7 +307,7 @@ NodeSet Liveness::getAllReachedUses(RegisterRef RefRR,
|
||||
if (RAI.covers(DefRRs, DR) || !RAI.alias(RefRR, DR))
|
||||
continue;
|
||||
NodeSet T;
|
||||
if (DA.Addr->getFlags() & NodeAttrs::Preserving) {
|
||||
if (DFG.IsPreservingDef(DA)) {
|
||||
// If it is a preserving def, do not update the set of intervening defs.
|
||||
T = getAllReachedUses(RefRR, DA, DefRRs);
|
||||
} else {
|
||||
@ -358,7 +358,8 @@ void Liveness::computePhiInfo() {
|
||||
NodeId UN = DA.Addr->getReachedUse();
|
||||
while (UN != 0) {
|
||||
NodeAddr<UseNode*> A = DFG.addr<UseNode*>(UN);
|
||||
if (!(A.Addr->getFlags() & NodeAttrs::PhiRef))
|
||||
uint16_t F = A.Addr->getFlags();
|
||||
if ((F & (NodeAttrs::Undef | NodeAttrs::PhiRef)) == 0)
|
||||
RealUses[getRestrictedRegRef(A)].insert(A.Id);
|
||||
UN = A.Addr->getSibling();
|
||||
}
|
||||
@ -847,14 +848,16 @@ void Liveness::traverse(MachineBasicBlock *B, RefMap &LiveIn) {
|
||||
if (B != BA.Addr->getCode())
|
||||
Defs.insert(R);
|
||||
else {
|
||||
bool IsPreserving = DA.Addr->getFlags() & NodeAttrs::Preserving;
|
||||
bool IsPreserving = DFG.IsPreservingDef(DA);
|
||||
if (IA.Addr->getKind() != NodeAttrs::Phi && !IsPreserving) {
|
||||
bool Covering = RAI.covers(DDR, I.first);
|
||||
NodeId U = DA.Addr->getReachedUse();
|
||||
while (U && Covering) {
|
||||
auto DUA = DFG.addr<UseNode*>(U);
|
||||
RegisterRef Q = DUA.Addr->getRegRef();
|
||||
Covering = RAI.covers(DA.Addr->getRegRef(), Q);
|
||||
if (!(DUA.Addr->getFlags() & NodeAttrs::Undef)) {
|
||||
RegisterRef Q = DUA.Addr->getRegRef();
|
||||
Covering = RAI.covers(DA.Addr->getRegRef(), Q);
|
||||
}
|
||||
U = DUA.Addr->getSibling();
|
||||
}
|
||||
if (!Covering)
|
||||
@ -898,6 +901,8 @@ void Liveness::traverse(MachineBasicBlock *B, RefMap &LiveIn) {
|
||||
continue;
|
||||
for (NodeAddr<UseNode*> UA : IA.Addr->members_if(DFG.IsUse, DFG)) {
|
||||
RegisterRef RR = UA.Addr->getRegRef();
|
||||
if (UA.Addr->getFlags() & NodeAttrs::Undef)
|
||||
continue;
|
||||
for (auto D : getAllReachingDefs(UA))
|
||||
if (getBlockWithRef(D.Id) != B)
|
||||
LiveIn[RR].insert(D.Id);
|
||||
|
Loading…
Reference in New Issue
Block a user