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+ AllocaInst *Alloca;
64+ return I->isMemDepCandidate () ||
65+ ((Alloca = dyn_cast<AllocaInst>(I)) &&
66+ Alloca->isUsedWithInAlloca ()) ||
67+ I->isStackSaveOrRestoreIntrinsic ();
68+ }
69+
4870 Instruction *getInstruction () const { return I; }
4971 void addMemPred (DGNode *PredN) { MemPreds.insert (PredN); }
5072 // / \Returns all memory dependency predecessors.
@@ -53,11 +75,9 @@ class DGNode {
5375 }
5476 // / \Returns true if there is a memory dependency N->this.
5577 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; }
78+
5979#ifndef NDEBUG
60- void print (raw_ostream &OS, bool PrintDeps = true ) const ;
80+ virtual void print (raw_ostream &OS, bool PrintDeps = true ) const ;
6181 friend raw_ostream &operator <<(DGNode &N, raw_ostream &OS) {
6282 N.print (OS);
6383 return OS;
@@ -66,9 +86,94 @@ class DGNode {
6686#endif // NDEBUG
6787};
6888
89+ // / A DependencyGraph Node for instructiosn that may read/write memory, or have
90+ // / some ordering constraints, like with stacksave/stackrestore and
91+ // / alloca/inalloca.
92+ class MemDGNode final : public DGNode {
93+ MemDGNode *PrevMemN = nullptr ;
94+ MemDGNode *NextMemN = nullptr ;
95+
96+ void setNextNode (MemDGNode *N) { NextMemN = N; }
97+ void setPrevNode (MemDGNode *N) { PrevMemN = N; }
98+ friend class DependencyGraph ; // For setNextNode(), setPrevNode().
99+
100+ public:
101+ MemDGNode (Instruction *I) : DGNode(I, DGNodeID::MemDGNode) {
102+ assert (isMemDepCandidate (I) && " Expected Mem instruction!" );
103+ }
104+ static bool classof (const DGNode *Other) {
105+ return Other->SubclassID == DGNodeID::MemDGNode;
106+ }
107+ // / \Returns the previous Mem DGNode in instruction order.
108+ MemDGNode *getPrevNode () const { return PrevMemN; }
109+ // / \Returns the next Mem DGNode in instruction order.
110+ MemDGNode *getNextNode () const { return NextMemN; }
111+ };
112+
113+ // / Walks in the order of the instruction chain but skips non-mem Nodes.
114+ // / This is used for building/updating the DAG.
115+ class MemDGNodeIterator {
116+ MemDGNode *N;
117+
118+ public:
119+ using difference_type = std::ptrdiff_t ;
120+ using value_type = DGNode;
121+ using pointer = value_type *;
122+ using reference = value_type &;
123+ using iterator_category = std::bidirectional_iterator_tag;
124+ MemDGNodeIterator (MemDGNode *N) : N(N) {}
125+ MemDGNodeIterator &operator ++() {
126+ assert (N != nullptr && " Already at end!" );
127+ N = N->getNextNode ();
128+ return *this ;
129+ }
130+ MemDGNodeIterator operator ++(int ) {
131+ auto ItCopy = *this ;
132+ ++*this ;
133+ return ItCopy;
134+ }
135+ MemDGNodeIterator &operator --() {
136+ N = N->getPrevNode ();
137+ return *this ;
138+ }
139+ MemDGNodeIterator operator --(int ) {
140+ auto ItCopy = *this ;
141+ --*this ;
142+ return ItCopy;
143+ }
144+ pointer operator *() { return N; }
145+ const DGNode *operator *() const { return N; }
146+ bool operator ==(const MemDGNodeIterator &Other) const { return N == Other.N ; }
147+ bool operator !=(const MemDGNodeIterator &Other) const {
148+ return !(*this == Other);
149+ }
150+ };
151+
152+ // / A MemDGNodeIterator with convenience builders and dump().
153+ class DGNodeRange : public iterator_range <MemDGNodeIterator> {
154+ public:
155+ DGNodeRange (MemDGNodeIterator Begin, MemDGNodeIterator End)
156+ : iterator_range(Begin, End) {}
157+ // / An empty range.
158+ DGNodeRange ()
159+ : iterator_range(MemDGNodeIterator(nullptr ), MemDGNodeIterator(nullptr )) {
160+ }
161+ // / Given \p Instrs it finds their closest mem nodes in the interval and
162+ // / returns the corresponding mem range. Note: BotN (or its neighboring mem
163+ // / node) is included in the range.
164+ static DGNodeRange makeMemRange (const Interval<Instruction> &Instrs,
165+ DependencyGraph &DAG);
166+ static DGNodeRange makeEmptyMemRange () { return DGNodeRange (); }
167+ #ifndef NDEBUG
168+ LLVM_DUMP_METHOD void dump () const ;
169+ #endif
170+ };
171+
69172class DependencyGraph {
70173private:
71174 DenseMap<Instruction *, std::unique_ptr<DGNode>> InstrToNodeMap;
175+ // / The DAG spans across all instructions in this interval.
176+ Interval<Instruction> DAGInterval;
72177
73178public:
74179 DependencyGraph () {}
@@ -77,10 +182,20 @@ class DependencyGraph {
77182 auto It = InstrToNodeMap.find (I);
78183 return It != InstrToNodeMap.end () ? It->second .get () : nullptr ;
79184 }
185+ // / Like getNode() but returns nullptr if \p I is nullptr.
186+ DGNode *getNodeOrNull (Instruction *I) const {
187+ if (I == nullptr )
188+ return nullptr ;
189+ return getNode (I);
190+ }
80191 DGNode *getOrCreateNode (Instruction *I) {
81192 auto [It, NotInMap] = InstrToNodeMap.try_emplace (I);
82- if (NotInMap)
83- It->second = std::make_unique<DGNode>(I);
193+ if (NotInMap) {
194+ if (I->isMemDepCandidate () || I->isStackSaveOrRestoreIntrinsic ())
195+ It->second = std::make_unique<MemDGNode>(I);
196+ else
197+ It->second = std::make_unique<DGNode>(I);
198+ }
84199 return It->second .get ();
85200 }
86201 // / Build/extend the dependency graph such that it includes \p Instrs. Returns
0 commit comments