2929
3030namespace llvm ::sandboxir {
3131
32+ class DependencyGraph ;
33+ class MemDGNode ;
34+
35+ // / SubclassIDs for isa/dyn_cast etc.
36+ enum class DGNodeID {
37+ DGNode,
38+ MemDGNode,
39+ };
40+
3241// / A DependencyGraph Node that points to an Instruction and contains memory
3342// / dependency edges.
3443class DGNode {
44+ protected:
3545 Instruction *I;
46+ // TODO: Use a PointerIntPair for SubclassID and I.
47+ // / For isa/dyn_cast etc.
48+ DGNodeID SubclassID;
3649 // / Memory predecessors.
3750 DenseSet<DGNode *> MemPreds;
38- // / This is true if this may read/write memory, or if it has some ordering
39- // / constraints, like with stacksave/stackrestore and alloca/inalloca.
40- bool IsMem;
51+
52+ DGNode (Instruction *I, DGNodeID ID) : I(I), SubclassID(ID) {}
53+ friend class MemDGNode ; // For constructor.
4154
4255public:
43- DGNode (Instruction *I) : I(I) {
44- IsMem = I->isMemDepCandidate () ||
45- (isa<AllocaInst>(I) && cast<AllocaInst>(I)->isUsedWithInAlloca ()) ||
46- I->isStackSaveOrRestoreIntrinsic ();
56+ DGNode (Instruction *I) : I(I), SubclassID(DGNodeID::DGNode) {
57+ assert (!isMemDepCandidate (I) && " Expected Non-Mem instruction, " );
4758 }
59+ DGNode (const DGNode &Other) = delete ;
60+ virtual ~DGNode () = default ;
61+ // / \Returns true if \p I is a memory dependency candidate instruction.
62+ static bool isMemDepCandidate (Instruction *I) {
63+ return I->isMemDepCandidate () ||
64+ (isa<AllocaInst>(I) && cast<AllocaInst>(I)->isUsedWithInAlloca ()) ||
65+ I->isStackSaveOrRestoreIntrinsic ();
66+ }
67+
4868 Instruction *getInstruction () const { return I; }
4969 void addMemPred (DGNode *PredN) { MemPreds.insert (PredN); }
5070 // / \Returns all memory dependency predecessors.
@@ -53,11 +73,9 @@ class DGNode {
5373 }
5474 // / \Returns true if there is a memory dependency N->this.
5575 bool hasMemPred (DGNode *N) const { return MemPreds.count (N); }
56- // / \Returns true if this may read/write memory, or if it has some ordering
57- // / constraints, like with stacksave/stackrestore and alloca/inalloca.
58- bool isMem () const { return IsMem; }
76+
5977#ifndef NDEBUG
60- void print (raw_ostream &OS, bool PrintDeps = true ) const ;
78+ virtual void print (raw_ostream &OS, bool PrintDeps = true ) const ;
6179 friend raw_ostream &operator <<(DGNode &N, raw_ostream &OS) {
6280 N.print (OS);
6381 return OS;
@@ -66,9 +84,94 @@ class DGNode {
6684#endif // NDEBUG
6785};
6886
87+ // / A DependencyGraph Node for instructiosn that may read/write memory, or have
88+ // / some ordering constraints, like with stacksave/stackrestore and
89+ // / alloca/inalloca.
90+ class MemDGNode final : public DGNode {
91+ MemDGNode *PrevMemN = nullptr ;
92+ MemDGNode *NextMemN = nullptr ;
93+
94+ void setNextNode (DGNode *N) { NextMemN = cast_or_null<MemDGNode>(N); }
95+ void setPrevNode (DGNode *N) { PrevMemN = cast_or_null<MemDGNode>(N); }
96+ friend class DependencyGraph ; // For setNextNode(), setPrevNode().
97+
98+ public:
99+ MemDGNode (Instruction *I) : DGNode(I, DGNodeID::MemDGNode) {
100+ assert (isMemDepCandidate (I) && " Expected Mem instruction!" );
101+ }
102+ static bool classof (const DGNode *Other) {
103+ return Other->SubclassID == DGNodeID::MemDGNode;
104+ }
105+ // / \Returns the previosu Mem DGNode in instruction order.
106+ MemDGNode *getPrevNode () const { return PrevMemN; }
107+ // / \Returns the next Mem DGNode in instruction order.
108+ MemDGNode *getNextNode () const { return NextMemN; }
109+ };
110+
111+ // / Walks in the order of the instruction chain but skips non-mem Nodes.
112+ // / This is used for building/updating the DAG.
113+ class MemDGNodeIterator {
114+ MemDGNode *N;
115+
116+ public:
117+ using difference_type = std::ptrdiff_t ;
118+ using value_type = DGNode;
119+ using pointer = value_type *;
120+ using reference = value_type &;
121+ using iterator_category = std::bidirectional_iterator_tag;
122+ MemDGNodeIterator (MemDGNode *N) : N(N) {}
123+ MemDGNodeIterator &operator ++() {
124+ assert (N != nullptr && " Already at end!" );
125+ N = N->getNextNode ();
126+ return *this ;
127+ }
128+ MemDGNodeIterator operator ++(int ) {
129+ auto ItCopy = *this ;
130+ ++*this ;
131+ return ItCopy;
132+ }
133+ MemDGNodeIterator &operator --() {
134+ N = N->getPrevNode ();
135+ return *this ;
136+ }
137+ MemDGNodeIterator operator --(int ) {
138+ auto ItCopy = *this ;
139+ --*this ;
140+ return ItCopy;
141+ }
142+ pointer operator *() { return N; }
143+ const DGNode *operator *() const { return N; }
144+ bool operator ==(const MemDGNodeIterator &Other) const { return N == Other.N ; }
145+ bool operator !=(const MemDGNodeIterator &Other) const {
146+ return !(*this == Other);
147+ }
148+ };
149+
150+ // / A MemDGNodeIterator with convenience builders and dump().
151+ class DGNodeRange : public iterator_range <MemDGNodeIterator> {
152+ public:
153+ DGNodeRange (MemDGNodeIterator Begin, MemDGNodeIterator End)
154+ : iterator_range(Begin, End) {}
155+ // / An empty range.
156+ DGNodeRange ()
157+ : iterator_range(MemDGNodeIterator(nullptr ), MemDGNodeIterator(nullptr )) {
158+ }
159+ // / Given \p Instrs it finds their closest mem nodes in the interval and
160+ // / returns the corresponding mem range. Note: BotN (or its neighboring mem
161+ // / node) is included in the range.
162+ static DGNodeRange makeMemRange (const InstrInterval &Instrs,
163+ DependencyGraph &DAG);
164+ static DGNodeRange makeEmptyMemRange () { return DGNodeRange (); }
165+ #ifndef NDEBUG
166+ LLVM_DUMP_METHOD void dump () const ;
167+ #endif
168+ };
169+
69170class DependencyGraph {
70171private:
71172 DenseMap<Instruction *, std::unique_ptr<DGNode>> InstrToNodeMap;
173+ // / The DAG spans across all instructions in this interval.
174+ InstrInterval DAGInterval;
72175
73176public:
74177 DependencyGraph () {}
@@ -77,10 +180,20 @@ class DependencyGraph {
77180 auto It = InstrToNodeMap.find (I);
78181 return It != InstrToNodeMap.end () ? It->second .get () : nullptr ;
79182 }
183+ // / Like getNode() but returns nullptr if \p I is nullptr.
184+ DGNode *getNodeOrNull (Instruction *I) const {
185+ if (I == nullptr )
186+ return nullptr ;
187+ return getNode (I);
188+ }
80189 DGNode *getOrCreateNode (Instruction *I) {
81190 auto [It, NotInMap] = InstrToNodeMap.try_emplace (I);
82- if (NotInMap)
83- It->second = std::make_unique<DGNode>(I);
191+ if (NotInMap) {
192+ if (I->isMemDepCandidate () || I->isStackSaveOrRestoreIntrinsic ())
193+ It->second = std::make_unique<MemDGNode>(I);
194+ else
195+ It->second = std::make_unique<DGNode>(I);
196+ }
84197 return It->second .get ();
85198 }
86199 // / Build/extend the dependency graph such that it includes \p Instrs. Returns
0 commit comments