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
+ return I->isMemDepCandidate () ||
64
+ (isa<AllocaInst>(I) && cast<AllocaInst>(I)->isUsedWithInAlloca ()) ||
65
+ I->isStackSaveOrRestoreIntrinsic ();
66
+ }
67
+
48
68
Instruction *getInstruction () const { return I; }
49
69
void addMemPred (DGNode *PredN) { MemPreds.insert (PredN); }
50
70
// / \Returns all memory dependency predecessors.
@@ -53,11 +73,9 @@ class DGNode {
53
73
}
54
74
// / \Returns true if there is a memory dependency N->this.
55
75
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
+
59
77
#ifndef NDEBUG
60
- void print (raw_ostream &OS, bool PrintDeps = true ) const ;
78
+ virtual void print (raw_ostream &OS, bool PrintDeps = true ) const ;
61
79
friend raw_ostream &operator <<(DGNode &N, raw_ostream &OS) {
62
80
N.print (OS);
63
81
return OS;
@@ -66,9 +84,94 @@ class DGNode {
66
84
#endif // NDEBUG
67
85
};
68
86
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 (MemDGNode *N) { NextMemN = N; }
95
+ void setPrevNode (MemDGNode *N) { PrevMemN = 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 previous 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 Interval<Instruction> &Instrs,
163
+ DependencyGraph &DAG);
164
+ static DGNodeRange makeEmptyMemRange () { return DGNodeRange (); }
165
+ #ifndef NDEBUG
166
+ LLVM_DUMP_METHOD void dump () const ;
167
+ #endif
168
+ };
169
+
69
170
class DependencyGraph {
70
171
private:
71
172
DenseMap<Instruction *, std::unique_ptr<DGNode>> InstrToNodeMap;
173
+ // / The DAG spans across all instructions in this interval.
174
+ Interval<Instruction> DAGInterval;
72
175
73
176
public:
74
177
DependencyGraph () {}
@@ -77,10 +180,20 @@ class DependencyGraph {
77
180
auto It = InstrToNodeMap.find (I);
78
181
return It != InstrToNodeMap.end () ? It->second .get () : nullptr ;
79
182
}
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
+ }
80
189
DGNode *getOrCreateNode (Instruction *I) {
81
190
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
+ }
84
197
return It->second .get ();
85
198
}
86
199
// / Build/extend the dependency graph such that it includes \p Instrs. Returns
0 commit comments