| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | |
| 5 | #ifndef _LIR_H_ |
| 6 | #define _LIR_H_ |
| 7 | |
| 8 | class Compiler; |
| 9 | struct GenTree; |
| 10 | struct BasicBlock; |
| 11 | class Rationalizer; |
| 12 | |
| 13 | class LIR final |
| 14 | { |
| 15 | public: |
| 16 | class Range; |
| 17 | |
| 18 | //------------------------------------------------------------------------ |
| 19 | // LIR::Flags: Defines the set of flags that may appear in the |
| 20 | // GenTree::gtLIRFlags field. |
| 21 | class Flags final |
| 22 | { |
| 23 | // Disallow the creation of values of this type. |
| 24 | Flags() = delete; |
| 25 | |
| 26 | public: |
| 27 | enum : unsigned char |
| 28 | { |
| 29 | None = 0x00, |
| 30 | |
| 31 | Mark = 0x01, // An aribtrary "mark" bit that can be used in place of |
| 32 | // a more expensive data structure when processing a set |
| 33 | // of LIR nodes. See for example `LIR::GetTreeRange`. |
| 34 | |
| 35 | UnusedValue = 0x02, // Set on a node if it produces a value that is not |
| 36 | // subsequently used. Should never be set on nodes |
| 37 | // that return `false` for `GenTree::IsValue`. Note |
| 38 | // that this bit should not be assumed to be valid |
| 39 | // at all points during compilation: it is currently |
| 40 | // only computed during target-dependent lowering. |
| 41 | |
| 42 | RegOptional = 0x04, // Set on a node if it produces a value, but does not |
| 43 | // require a register (i.e. it can be used from memory). |
| 44 | }; |
| 45 | }; |
| 46 | |
| 47 | //------------------------------------------------------------------------ |
| 48 | // LIR::Use: Represents a use <-> def edge between two nodes in a range |
| 49 | // of LIR. Provides utilities to point the use to a different |
| 50 | // def. Note that because this type deals in edges between |
| 51 | // nodes, it represents the single use of the def. |
| 52 | // |
| 53 | class Use final |
| 54 | { |
| 55 | private: |
| 56 | Range* m_range; |
| 57 | GenTree** m_edge; |
| 58 | GenTree* m_user; |
| 59 | |
| 60 | public: |
| 61 | Use(); |
| 62 | Use(const Use& other); |
| 63 | Use(Range& range, GenTree** edge, GenTree* user); |
| 64 | |
| 65 | Use& operator=(const Use& other); |
| 66 | Use& operator=(Use&& other); |
| 67 | |
| 68 | static Use GetDummyUse(Range& range, GenTree* node); |
| 69 | |
| 70 | GenTree* Def() const; |
| 71 | GenTree* User() const; |
| 72 | |
| 73 | bool IsInitialized() const; |
| 74 | void AssertIsValid() const; |
| 75 | bool IsDummyUse() const; |
| 76 | |
| 77 | void ReplaceWith(Compiler* compiler, GenTree* replacement); |
| 78 | unsigned ReplaceWithLclVar(Compiler* compiler, unsigned blockWeight, unsigned lclNum = BAD_VAR_NUM); |
| 79 | }; |
| 80 | |
| 81 | //------------------------------------------------------------------------ |
| 82 | // LIR::ReadOnlyRange: |
| 83 | // |
| 84 | // Represents a contiguous range of LIR nodes that may be a subrange of |
| 85 | // a containing range. Provides a small set of utilities for iteration. |
| 86 | // Instances of this type are primarily created by and provided to |
| 87 | // analysis and utility methods on LIR::Range. |
| 88 | // |
| 89 | // Although some pains have been taken to help guard against the existence |
| 90 | // of invalid subranges, it remains possible to create them. For example, |
| 91 | // consider the following: |
| 92 | // |
| 93 | // // View the block as a range |
| 94 | // LIR::Range& blockRange = LIR::AsRange(block); |
| 95 | // |
| 96 | // // Create a range from the first non-phi node in the block to the |
| 97 | // // last node in the block |
| 98 | // LIR::ReadOnlyRange nonPhis = blockRange.NonPhiNodes(); |
| 99 | // |
| 100 | // // Remove the last node from the block |
| 101 | // blockRange.Remove(blockRange.LastNode()); |
| 102 | // |
| 103 | // After the removal of the last node in the block, the last node of |
| 104 | // nonPhis is no longer linked to any of the other nodes in nonPhis. Due |
| 105 | // to issues such as the above, some care must be taken in order to |
| 106 | // ensure that ranges are not used once they have been invalidated. |
| 107 | // |
| 108 | class ReadOnlyRange |
| 109 | { |
| 110 | friend class LIR; |
| 111 | friend class Range; |
| 112 | friend struct BasicBlock; |
| 113 | |
| 114 | private: |
| 115 | GenTree* m_firstNode; |
| 116 | GenTree* m_lastNode; |
| 117 | |
| 118 | ReadOnlyRange(const ReadOnlyRange& other) = delete; |
| 119 | ReadOnlyRange& operator=(const ReadOnlyRange& other) = delete; |
| 120 | |
| 121 | public: |
| 122 | ReadOnlyRange(GenTree* firstNode, GenTree* lastNode); |
| 123 | |
| 124 | class Iterator |
| 125 | { |
| 126 | friend class ReadOnlyRange; |
| 127 | |
| 128 | GenTree* m_node; |
| 129 | |
| 130 | Iterator(GenTree* begin) : m_node(begin) |
| 131 | { |
| 132 | } |
| 133 | |
| 134 | public: |
| 135 | Iterator() : m_node(nullptr) |
| 136 | { |
| 137 | } |
| 138 | |
| 139 | inline GenTree* operator*() |
| 140 | { |
| 141 | return m_node; |
| 142 | } |
| 143 | |
| 144 | inline GenTree* operator->() |
| 145 | { |
| 146 | return m_node; |
| 147 | } |
| 148 | |
| 149 | inline bool operator==(const Iterator& other) const |
| 150 | { |
| 151 | return m_node == other.m_node; |
| 152 | } |
| 153 | |
| 154 | inline bool operator!=(const Iterator& other) const |
| 155 | { |
| 156 | return m_node != other.m_node; |
| 157 | } |
| 158 | |
| 159 | inline Iterator& operator++() |
| 160 | { |
| 161 | m_node = (m_node == nullptr) ? nullptr : m_node->gtNext; |
| 162 | return *this; |
| 163 | } |
| 164 | }; |
| 165 | |
| 166 | class ReverseIterator |
| 167 | { |
| 168 | friend class ReadOnlyRange; |
| 169 | |
| 170 | GenTree* m_node; |
| 171 | |
| 172 | ReverseIterator(GenTree* begin) : m_node(begin) |
| 173 | { |
| 174 | } |
| 175 | |
| 176 | public: |
| 177 | ReverseIterator() : m_node(nullptr) |
| 178 | { |
| 179 | } |
| 180 | |
| 181 | inline GenTree* operator*() |
| 182 | { |
| 183 | return m_node; |
| 184 | } |
| 185 | |
| 186 | inline GenTree* operator->() |
| 187 | { |
| 188 | return m_node; |
| 189 | } |
| 190 | |
| 191 | inline bool operator==(const ReverseIterator& other) const |
| 192 | { |
| 193 | return m_node == other.m_node; |
| 194 | } |
| 195 | |
| 196 | inline bool operator!=(const ReverseIterator& other) const |
| 197 | { |
| 198 | return m_node != other.m_node; |
| 199 | } |
| 200 | |
| 201 | inline ReverseIterator& operator++() |
| 202 | { |
| 203 | m_node = (m_node == nullptr) ? nullptr : m_node->gtPrev; |
| 204 | return *this; |
| 205 | } |
| 206 | }; |
| 207 | |
| 208 | ReadOnlyRange(); |
| 209 | ReadOnlyRange(ReadOnlyRange&& other); |
| 210 | |
| 211 | GenTree* FirstNode() const; |
| 212 | GenTree* LastNode() const; |
| 213 | |
| 214 | bool IsEmpty() const; |
| 215 | |
| 216 | Iterator begin() const; |
| 217 | Iterator end() const; |
| 218 | |
| 219 | ReverseIterator rbegin() const; |
| 220 | ReverseIterator rend() const; |
| 221 | |
| 222 | #ifdef DEBUG |
| 223 | bool Contains(GenTree* node) const; |
| 224 | #endif |
| 225 | }; |
| 226 | |
| 227 | //------------------------------------------------------------------------ |
| 228 | // LIR::Range: |
| 229 | // |
| 230 | // Represents a contiguous range of LIR nodes. Provides a variety of |
| 231 | // variety of utilites that modify the LIR contained in the range. Unlike |
| 232 | // `ReadOnlyRange`, values of this type may be edited. |
| 233 | // |
| 234 | // Because it is not a final class, it is possible to slice values of this |
| 235 | // type; this is especially dangerous when the Range value is actually of |
| 236 | // type `BasicBlock`. As a result, this type is not copyable and it is |
| 237 | // not possible to view a `BasicBlock` as anything other than a `Range&`. |
| 238 | // |
| 239 | class Range : public ReadOnlyRange |
| 240 | { |
| 241 | friend class LIR; |
| 242 | friend struct BasicBlock; |
| 243 | friend class Rationalizer; |
| 244 | |
| 245 | private: |
| 246 | Range(GenTree* firstNode, GenTree* lastNode); |
| 247 | |
| 248 | Range(const Range& other) = delete; |
| 249 | Range& operator=(const Range& other) = delete; |
| 250 | |
| 251 | ReadOnlyRange GetMarkedRange(unsigned markCount, GenTree* start, bool* isClosed, unsigned* sideEffects) const; |
| 252 | |
| 253 | void FinishInsertBefore(GenTree* insertionPoint, GenTree* first, GenTree* last); |
| 254 | void FinishInsertAfter(GenTree* insertionPoint, GenTree* first, GenTree* last); |
| 255 | |
| 256 | public: |
| 257 | Range(); |
| 258 | Range(Range&& other); |
| 259 | |
| 260 | GenTree* LastPhiNode() const; |
| 261 | GenTree* FirstNonPhiNode() const; |
| 262 | GenTree* FirstNonPhiOrCatchArgNode() const; |
| 263 | |
| 264 | ReadOnlyRange PhiNodes() const; |
| 265 | ReadOnlyRange NonPhiNodes() const; |
| 266 | |
| 267 | void InsertBefore(GenTree* insertionPoint, GenTree* node); |
| 268 | void InsertAfter(GenTree* insertionPoint, GenTree* node); |
| 269 | |
| 270 | void InsertBefore(GenTree* insertionPoint, GenTree* node1, GenTree* node2); |
| 271 | void InsertBefore(GenTree* insertionPoint, GenTree* node1, GenTree* node2, GenTree* node3); |
| 272 | void InsertBefore(GenTree* insertionPoint, GenTree* node1, GenTree* node2, GenTree* node3, GenTree* node4); |
| 273 | |
| 274 | void InsertAfter(GenTree* insertionPoint, GenTree* node1, GenTree* node2); |
| 275 | void InsertAfter(GenTree* insertionPoint, GenTree* node1, GenTree* node2, GenTree* node3); |
| 276 | void InsertAfter(GenTree* insertionPoint, GenTree* node1, GenTree* node2, GenTree* node3, GenTree* node4); |
| 277 | |
| 278 | void InsertBefore(GenTree* insertionPoint, Range&& range); |
| 279 | void InsertAfter(GenTree* insertionPoint, Range&& range); |
| 280 | |
| 281 | void InsertAtBeginning(GenTree* node); |
| 282 | void InsertAtEnd(GenTree* node); |
| 283 | |
| 284 | void InsertAtBeginning(Range&& range); |
| 285 | void InsertAtEnd(Range&& range); |
| 286 | |
| 287 | void Remove(GenTree* node, bool markOperandsUnused = false); |
| 288 | Range Remove(GenTree* firstNode, GenTree* lastNode); |
| 289 | Range Remove(ReadOnlyRange&& range); |
| 290 | |
| 291 | void Delete(Compiler* compiler, BasicBlock* block, GenTree* node); |
| 292 | void Delete(Compiler* compiler, BasicBlock* block, GenTree* firstNode, GenTree* lastNode); |
| 293 | void Delete(Compiler* compiler, BasicBlock* block, ReadOnlyRange&& range); |
| 294 | |
| 295 | bool TryGetUse(GenTree* node, Use* use); |
| 296 | |
| 297 | ReadOnlyRange GetTreeRange(GenTree* root, bool* isClosed) const; |
| 298 | ReadOnlyRange GetTreeRange(GenTree* root, bool* isClosed, unsigned* sideEffects) const; |
| 299 | ReadOnlyRange GetRangeOfOperandTrees(GenTree* root, bool* isClosed, unsigned* sideEffects) const; |
| 300 | |
| 301 | #ifdef DEBUG |
| 302 | bool CheckLIR(Compiler* compiler, bool checkUnusedValues = false) const; |
| 303 | #endif |
| 304 | }; |
| 305 | |
| 306 | public: |
| 307 | static Range& AsRange(BasicBlock* block); |
| 308 | |
| 309 | static Range EmptyRange(); |
| 310 | static Range SeqTree(Compiler* compiler, GenTree* tree); |
| 311 | |
| 312 | static void InsertBeforeTerminator(BasicBlock* block, LIR::Range&& range); |
| 313 | }; |
| 314 | |
| 315 | inline void GenTree::SetUnusedValue() |
| 316 | { |
| 317 | gtLIRFlags |= LIR::Flags::UnusedValue; |
| 318 | ClearContained(); |
| 319 | } |
| 320 | |
| 321 | inline void GenTree::ClearUnusedValue() |
| 322 | { |
| 323 | gtLIRFlags &= ~LIR::Flags::UnusedValue; |
| 324 | } |
| 325 | |
| 326 | inline bool GenTree::IsUnusedValue() const |
| 327 | { |
| 328 | return (gtLIRFlags & LIR::Flags::UnusedValue) != 0; |
| 329 | } |
| 330 | |
| 331 | inline void GenTree::SetRegOptional() |
| 332 | { |
| 333 | gtLIRFlags |= LIR::Flags::RegOptional; |
| 334 | } |
| 335 | |
| 336 | inline void GenTree::ClearRegOptional() |
| 337 | { |
| 338 | gtLIRFlags &= ~LIR::Flags::RegOptional; |
| 339 | } |
| 340 | |
| 341 | inline bool GenTree::IsRegOptional() const |
| 342 | { |
| 343 | return (gtLIRFlags & LIR::Flags::RegOptional) != 0; |
| 344 | } |
| 345 | |
| 346 | #endif // _LIR_H_ |
| 347 | |