29
29
30
30
namespace llvm ::sandboxir {
31
31
32
+ class DependencyGraph ;
33
+ class MemDGNode ;
34
+
35
+ // / SubclassIDs for isa/dyn_cast etc.
36
+ enum class DGNodeID {
37
+ DGNode,
38
+ MemDGNode,
39
+ };
40
+
32
41
// / A DependencyGraph Node that points to an Instruction and contains memory
33
42
// / dependency edges.
34
43
class DGNode {
44
+ protected:
35
45
Instruction *I;
46
+ // TODO: Use a PointerIntPair for SubclassID and I.
47
+ // / For isa/dyn_cast etc.
48
+ DGNodeID SubclassID;
36
49
// / Memory predecessors.
37
50
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.
41
54
42
55
public:
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, " );
47
58
}
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
+
48
70
Instruction *getInstruction () const { return I; }
49
71
void addMemPred (DGNode *PredN) { MemPreds.insert (PredN); }
50
72
// / \Returns all memory dependency predecessors.
@@ -53,11 +75,9 @@ class DGNode {
53
75
}
54
76
// / \Returns true if there is a memory dependency N->this.
55
77
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
+
59
79
#ifndef NDEBUG
60
- void print (raw_ostream &OS, bool PrintDeps = true ) const ;
80
+ virtual void print (raw_ostream &OS, bool PrintDeps = true ) const ;
61
81
friend raw_ostream &operator <<(DGNode &N, raw_ostream &OS) {
62
82
N.print (OS);
63
83
return OS;
@@ -66,9 +86,94 @@ class DGNode {
66
86
#endif // NDEBUG
67
87
};
68
88
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
+
69
172
class DependencyGraph {
70
173
private:
71
174
DenseMap<Instruction *, std::unique_ptr<DGNode>> InstrToNodeMap;
175
+ // / The DAG spans across all instructions in this interval.
176
+ Interval<Instruction> DAGInterval;
72
177
73
178
public:
74
179
DependencyGraph () {}
@@ -77,10 +182,20 @@ class DependencyGraph {
77
182
auto It = InstrToNodeMap.find (I);
78
183
return It != InstrToNodeMap.end () ? It->second .get () : nullptr ;
79
184
}
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
+ }
80
191
DGNode *getOrCreateNode (Instruction *I) {
81
192
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
+ }
84
199
return It->second .get ();
85
200
}
86
201
// / Build/extend the dependency graph such that it includes \p Instrs. Returns
0 commit comments