1 | // Copyright (c) 2017 Pierre Moreau |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | #ifndef SOURCE_OPT_DECORATION_MANAGER_H_ |
16 | #define SOURCE_OPT_DECORATION_MANAGER_H_ |
17 | |
18 | #include <functional> |
19 | #include <unordered_map> |
20 | #include <unordered_set> |
21 | #include <vector> |
22 | |
23 | #include "source/opt/instruction.h" |
24 | #include "source/opt/module.h" |
25 | |
26 | namespace spvtools { |
27 | namespace opt { |
28 | namespace analysis { |
29 | |
30 | // A class for analyzing and managing decorations in an Module. |
31 | class DecorationManager { |
32 | public: |
33 | // Constructs a decoration manager from the given |module| |
34 | explicit DecorationManager(Module* module) : module_(module) { |
35 | AnalyzeDecorations(); |
36 | } |
37 | DecorationManager() = delete; |
38 | |
39 | // Changes all of the decorations (direct and through groups) where |pred| is |
40 | // true and that apply to |id| so that they no longer apply to |id|. |
41 | // |
42 | // If |id| is part of a group, it will be removed from the group if it |
43 | // does not use all of the group's decorations, or, if there are no |
44 | // decorations that apply to the group. |
45 | // |
46 | // If decoration groups become empty, the |OpGroupDecorate| and |
47 | // |OpGroupMemberDecorate| instructions will be killed. |
48 | // |
49 | // Decoration instructions that apply directly to |id| will be killed. |
50 | // |
51 | // If |id| is a decoration group and all of the group's decorations are |
52 | // removed, then the |OpGroupDecorate| and |
53 | // |OpGroupMemberDecorate| for the group will be killed, but not the defining |
54 | // |OpDecorationGroup| instruction. |
55 | void RemoveDecorationsFrom(uint32_t id, |
56 | std::function<bool(const Instruction&)> pred = |
57 | [](const Instruction&) { return true; }); |
58 | |
59 | // Removes all decorations from the result id of |inst|. |
60 | // |
61 | // NOTE: This is only meant to be called from ir_context, as only metadata |
62 | // will be removed, and no actual instruction. |
63 | void RemoveDecoration(Instruction* inst); |
64 | |
65 | // Returns a vector of all decorations affecting |id|. If a group is applied |
66 | // to |id|, the decorations of that group are returned rather than the group |
67 | // decoration instruction. If |include_linkage| is not set, linkage |
68 | // decorations won't be returned. |
69 | std::vector<Instruction*> GetDecorationsFor(uint32_t id, |
70 | bool include_linkage); |
71 | std::vector<const Instruction*> GetDecorationsFor(uint32_t id, |
72 | bool include_linkage) const; |
73 | // Returns whether two IDs have the same decorations. Two SpvOpGroupDecorate |
74 | // instructions that apply the same decorations but to different IDs, still |
75 | // count as being the same. |
76 | bool HaveTheSameDecorations(uint32_t id1, uint32_t id2) const; |
77 | |
78 | // Returns whether two IDs have the same decorations. Two SpvOpGroupDecorate |
79 | // instructions that apply the same decorations but to different IDs, still |
80 | // count as being the same. |
81 | bool HaveSubsetOfDecorations(uint32_t id1, uint32_t id2) const; |
82 | |
83 | // Returns whether the two decorations instructions are the same and are |
84 | // applying the same decorations; unless |ignore_target| is false, the targets |
85 | // to which they are applied to does not matter, except for the member part. |
86 | // |
87 | // This is only valid for OpDecorate, OpMemberDecorate and OpDecorateId; it |
88 | // will return false for other opcodes. |
89 | bool AreDecorationsTheSame(const Instruction* inst1, const Instruction* inst2, |
90 | bool ignore_target) const; |
91 | |
92 | // |f| is run on each decoration instruction for |id| with decoration |
93 | // |decoration|. Processed are all decorations which target |id| either |
94 | // directly or indirectly by Decoration Groups. |
95 | void ForEachDecoration(uint32_t id, uint32_t decoration, |
96 | std::function<void(const Instruction&)> f); |
97 | |
98 | // |f| is run on each decoration instruction for |id| with decoration |
99 | // |decoration|. Processes all decoration which target |id| either directly or |
100 | // indirectly through decoration groups. If |f| returns false, iteration is |
101 | // terminated and this function returns false. |
102 | bool WhileEachDecoration(uint32_t id, uint32_t decoration, |
103 | std::function<bool(const Instruction&)> f); |
104 | |
105 | // Clone all decorations from one id |from|. |
106 | // The cloned decorations are assigned to the given id |to| and are |
107 | // added to the module. The purpose is to decorate cloned instructions. |
108 | // This function does not check if the id |to| is already decorated. |
109 | void CloneDecorations(uint32_t from, uint32_t to); |
110 | |
111 | // Same as above, but only clone the decoration if the decoration operand is |
112 | // in |decorations_to_copy|. This function has the extra restriction that |
113 | // |from| and |to| must not be an object, not a type. |
114 | void CloneDecorations(uint32_t from, uint32_t to, |
115 | const std::vector<SpvDecoration>& decorations_to_copy); |
116 | |
117 | // Informs the decoration manager of a new decoration that it needs to track. |
118 | void AddDecoration(Instruction* inst); |
119 | |
120 | // Add decoration with |opcode| and operands |opnds|. |
121 | void AddDecoration(SpvOp opcode, const std::vector<Operand> opnds); |
122 | |
123 | // Add |decoration| of |inst_id| to module. |
124 | void AddDecoration(uint32_t inst_id, uint32_t decoration); |
125 | |
126 | // Add |decoration, decoration_value| of |inst_id| to module. |
127 | void AddDecorationVal(uint32_t inst_id, uint32_t decoration, |
128 | uint32_t decoration_value); |
129 | |
130 | // Add |decoration, decoration_value| of |inst_id, member| to module. |
131 | void AddMemberDecoration(uint32_t member, uint32_t inst_id, |
132 | uint32_t decoration, uint32_t decoration_value); |
133 | |
134 | friend bool operator==(const DecorationManager&, const DecorationManager&); |
135 | friend bool operator!=(const DecorationManager& lhs, |
136 | const DecorationManager& rhs) { |
137 | return !(lhs == rhs); |
138 | } |
139 | |
140 | private: |
141 | // Analyzes the defs and uses in the given |module| and populates data |
142 | // structures in this class. Does nothing if |module| is nullptr. |
143 | void AnalyzeDecorations(); |
144 | |
145 | template <typename T> |
146 | std::vector<T> InternalGetDecorationsFor(uint32_t id, bool include_linkage); |
147 | |
148 | // Tracks decoration information of an ID. |
149 | struct TargetData { |
150 | std::vector<Instruction*> direct_decorations; // All decorate |
151 | // instructions applied |
152 | // to the tracked ID. |
153 | std::vector<Instruction*> indirect_decorations; // All instructions |
154 | // applying a group to |
155 | // the tracked ID. |
156 | std::vector<Instruction*> decorate_insts; // All decorate instructions |
157 | // applying the decorations |
158 | // of the tracked ID to |
159 | // targets. |
160 | // It is empty if the |
161 | // tracked ID is not a |
162 | // group. |
163 | }; |
164 | |
165 | friend bool operator==(const TargetData& lhs, const TargetData& rhs) { |
166 | if (!std::is_permutation(lhs.direct_decorations.begin(), |
167 | lhs.direct_decorations.end(), |
168 | rhs.direct_decorations.begin())) { |
169 | return false; |
170 | } |
171 | if (!std::is_permutation(lhs.indirect_decorations.begin(), |
172 | lhs.indirect_decorations.end(), |
173 | rhs.indirect_decorations.begin())) { |
174 | return false; |
175 | } |
176 | if (!std::is_permutation(lhs.decorate_insts.begin(), |
177 | lhs.decorate_insts.end(), |
178 | rhs.decorate_insts.begin())) { |
179 | return false; |
180 | } |
181 | return true; |
182 | } |
183 | |
184 | // Mapping from ids to the instructions applying a decoration to those ids. |
185 | // In other words, for each id you get all decoration instructions |
186 | // referencing that id, be it directly (SpvOpDecorate, SpvOpMemberDecorate |
187 | // and SpvOpDecorateId), or indirectly (SpvOpGroupDecorate, |
188 | // SpvOpMemberGroupDecorate). |
189 | std::unordered_map<uint32_t, TargetData> id_to_decoration_insts_; |
190 | // The enclosing module. |
191 | Module* module_; |
192 | }; |
193 | |
194 | } // namespace analysis |
195 | } // namespace opt |
196 | } // namespace spvtools |
197 | |
198 | #endif // SOURCE_OPT_DECORATION_MANAGER_H_ |
199 | |