diff options
-rw-r--r-- | llvm/lib/Target/Hexagon/RDFGraph.cpp | 31 | ||||
-rw-r--r-- | llvm/lib/Target/Hexagon/RDFGraph.h | 36 | ||||
-rw-r--r-- | llvm/lib/Target/Hexagon/RDFLiveness.cpp | 31 |
3 files changed, 74 insertions, 24 deletions
diff --git a/llvm/lib/Target/Hexagon/RDFGraph.cpp b/llvm/lib/Target/Hexagon/RDFGraph.cpp index aebcc22902a..77dd0d69a3d 100644 --- a/llvm/lib/Target/Hexagon/RDFGraph.cpp +++ b/llvm/lib/Target/Hexagon/RDFGraph.cpp @@ -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); diff --git a/llvm/lib/Target/Hexagon/RDFGraph.h b/llvm/lib/Target/Hexagon/RDFGraph.h index 56ae6a7c507..981ad1471e2 100644 --- a/llvm/lib/Target/Hexagon/RDFGraph.h +++ b/llvm/lib/Target/Hexagon/RDFGraph.h @@ -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(); diff --git a/llvm/lib/Target/Hexagon/RDFLiveness.cpp b/llvm/lib/Target/Hexagon/RDFLiveness.cpp index e25596bb7de..3d70e0aa627 100644 --- a/llvm/lib/Target/Hexagon/RDFLiveness.cpp +++ b/llvm/lib/Target/Hexagon/RDFLiveness.cpp @@ -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); |