1 | /** |
2 | * Copyright (c) Glow Contributors. See CONTRIBUTORS file. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | #ifndef GLOW_IR_IRUTILS_H |
17 | #define GLOW_IR_IRUTILS_H |
18 | |
19 | #include "glow/IR/IR.h" |
20 | #include "glow/IR/Instrs.h" |
21 | |
22 | #include <iterator> |
23 | |
24 | namespace glow { |
25 | |
26 | /// \returns true if the value \v is a tensor view. |
27 | bool isTensorView(Value *v); |
28 | |
29 | /// \returns the offset for \p TVI into the underlying alloc activation. |
30 | size_t calculateTensorViewOffset(const TensorViewInst *TVI); |
31 | |
32 | /// A helper class to iterate over all uses of a given Value. |
33 | /// It also recursively iterates over uses of any tensorview |
34 | /// instructions aliasing this value. |
35 | /// Iteration is performed by means of const iterators. |
36 | class ValueUses { |
37 | /// The value whose uses are to be iterated over. |
38 | const Value *v_; |
39 | |
40 | public: |
41 | /// The actual iterator implementation. |
42 | template <bool is_const_iter = true> |
43 | class ValueUsesIterator |
44 | : public std::iterator< |
45 | std::forward_iterator_tag, |
46 | typename std::conditional<is_const_iter, const Use, Use>::type> { |
47 | friend ValueUses; |
48 | using BASE = std::iterator< |
49 | std::forward_iterator_tag, |
50 | typename std::conditional<is_const_iter, const Use, Use>::type>; |
51 | using reference = typename BASE::reference; |
52 | using UseList = std::list<Use>; |
53 | using value = |
54 | typename std::conditional<is_const_iter, const Value, Value>::type; |
55 | using iterator = |
56 | typename std::conditional<is_const_iter, UseList::const_iterator, |
57 | UseList::iterator>::type; |
58 | |
59 | private: |
60 | /// Set of values to iterate over. It includes the original value and |
61 | /// eventually any tensor views directly or indirectly based on it. |
62 | llvm::SmallVector<value *, 4> vals_; |
63 | /// Current iterator. |
64 | iterator it_; |
65 | /// End of the use-list for the current value. |
66 | iterator end_; |
67 | /// Index of the value whose use-list is being iterated. |
68 | int idx_; |
69 | |
70 | /// This constructor is used to create the begin iterator. |
71 | ValueUsesIterator(value *v) |
72 | : vals_{v}, it_(v->getUsers().begin()), end_(v->getUsers().end()), |
73 | idx_(v->getUsers().begin() == v->getUsers().end() ? -1 : 0) {} |
74 | |
75 | /// This constructor is used to create the end iterator. |
76 | ValueUsesIterator(value *v, int) |
77 | : vals_{v}, it_(v->getUsers().end()), end_(v->getUsers().end()), |
78 | idx_(-1) {} |
79 | |
80 | public: |
81 | ValueUsesIterator &operator++() { |
82 | if (it_ == end_) { |
83 | llvm_unreachable("Cannot increment the end iterator" ); |
84 | } |
85 | ++it_; |
86 | if (it_ != end_) |
87 | return *this; |
88 | for (; it_ == end_;) { |
89 | // Reached the end of uses for the current value. |
90 | // Try to iterate over another value if available. |
91 | if (++idx_ >= (int)vals_.size()) { |
92 | // Form the end iterator. |
93 | *this = ValueUsesIterator{vals_[0], 1}; |
94 | return *this; |
95 | } |
96 | it_ = vals_[idx_]->getUsers().begin(); |
97 | end_ = vals_[idx_]->getUsers().end(); |
98 | } |
99 | return *this; |
100 | } |
101 | |
102 | reference operator*() { |
103 | if (it_ == end_) { |
104 | llvm_unreachable("An attempt to dereference the end iterator" ); |
105 | } |
106 | // If it is a tensorview instruction, add it is the set of |
107 | // values to be procssed, because all uses of a tensorview |
108 | // are considered to be uses of the tensorview's original |
109 | // allocation. |
110 | if (isTensorView(it_->get()) && vals_.back() != it_->get()) { |
111 | vals_.push_back(it_->get()); |
112 | } |
113 | return *it_; |
114 | } |
115 | |
116 | bool operator!=(const ValueUsesIterator &Other) const { |
117 | return idx_ != Other.idx_ || it_ != Other.it_ || end_ != Other.end_ || |
118 | vals_ != Other.vals_; |
119 | } |
120 | }; |
121 | |
122 | using const_iterator = ValueUsesIterator<true>; |
123 | |
124 | ValueUses(const Value *v) : v_(v) {} |
125 | ValueUses(ValueUses &VU) = default; |
126 | const_iterator begin() const { return const_iterator{v_}; } |
127 | const_iterator end() const { return const_iterator{v_, 1}; } |
128 | }; |
129 | |
130 | /// Get the allocation corrsponding to th value \p V. It can look through |
131 | /// tensorview instructions. \returns found allocation or nullptr. |
132 | Value *getAllocationOrigin(Value *V); |
133 | |
134 | /// \returns peels off the layers of tensorviews from a value \p V. |
135 | Value *getOrigin(Value *V); |
136 | |
137 | /// \returns the offset into the Value returned by getOrigin. |
138 | size_t getOriginOffset(Value *V); |
139 | |
140 | /// \returns peels off the layers of tensorviews from a value \p V. |
141 | const Value *getOrigin(const Value *V); |
142 | } // namespace glow |
143 | |
144 | #endif // GLOW_IR_IRUTILS_H |
145 | |