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|
DecorationManager(Module * 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   // Returns whether the two decorations instructions are the same and are
78   // applying the same decorations; unless |ignore_target| is false, the targets
79   // to which they are applied to does not matter, except for the member part.
80   //
81   // This is only valid for OpDecorate, OpMemberDecorate and OpDecorateId; it
82   // will return false for other opcodes.
83   bool AreDecorationsTheSame(const Instruction* inst1, const Instruction* inst2,
84                              bool ignore_target) const;
85 
86   // |f| is run on each decoration instruction for |id| with decoration
87   // |decoration|. Processed are all decorations which target |id| either
88   // directly or indirectly by Decoration Groups.
89   void ForEachDecoration(uint32_t id, uint32_t decoration,
90                          std::function<void(const Instruction&)> f);
91 
92   // |f| is run on each decoration instruction for |id| with decoration
93   // |decoration|. Processes all decoration which target |id| either directly or
94   // indirectly through decoration groups. If |f| returns false, iteration is
95   // terminated and this function returns false.
96   bool WhileEachDecoration(uint32_t id, uint32_t decoration,
97                            std::function<bool(const Instruction&)> f);
98 
99   // Clone all decorations from one id |from|.
100   // The cloned decorations are assigned to the given id |to| and are
101   // added to the module. The purpose is to decorate cloned instructions.
102   // This function does not check if the id |to| is already decorated.
103   void CloneDecorations(uint32_t from, uint32_t to);
104 
105   // Same as above, but only clone the decoration if the decoration operand is
106   // in |decorations_to_copy|.  This function has the extra restriction that
107   // |from| and |to| must not be an object, not a type.
108   void CloneDecorations(uint32_t from, uint32_t to,
109                         const std::vector<SpvDecoration>& decorations_to_copy);
110 
111   // Informs the decoration manager of a new decoration that it needs to track.
112   void AddDecoration(Instruction* inst);
113 
114   // Add decoration with |opcode| and operands |opnds|.
115   void AddDecoration(SpvOp opcode, const std::vector<Operand> opnds);
116 
117   // Add |decoration| of |inst_id| to module.
118   void AddDecoration(uint32_t inst_id, uint32_t decoration);
119 
120   // Add |decoration, decoration_value| of |inst_id| to module.
121   void AddDecorationVal(uint32_t inst_id, uint32_t decoration,
122                         uint32_t decoration_value);
123 
124   // Add |decoration, decoration_value| of |inst_id, member| to module.
125   void AddMemberDecoration(uint32_t member, uint32_t inst_id,
126                            uint32_t decoration, uint32_t decoration_value);
127 
128   friend bool operator==(const DecorationManager&, const DecorationManager&);
129   friend bool operator!=(const DecorationManager& lhs,
130                          const DecorationManager& rhs) {
131     return !(lhs == rhs);
132   }
133 
134  private:
135   // Analyzes the defs and uses in the given |module| and populates data
136   // structures in this class. Does nothing if |module| is nullptr.
137   void AnalyzeDecorations();
138 
139   template <typename T>
140   std::vector<T> InternalGetDecorationsFor(uint32_t id, bool include_linkage);
141 
142   // Tracks decoration information of an ID.
143   struct TargetData {
144     std::vector<Instruction*> direct_decorations;    // All decorate
145                                                      // instructions applied
146                                                      // to the tracked ID.
147     std::vector<Instruction*> indirect_decorations;  // All instructions
148                                                      // applying a group to
149                                                      // the tracked ID.
150     std::vector<Instruction*> decorate_insts;  // All decorate instructions
151                                                // applying the decorations
152                                                // of the tracked ID to
153                                                // targets.
154                                                // It is empty if the
155                                                // tracked ID is not a
156                                                // group.
157   };
158 
159   friend bool operator==(const TargetData& lhs, const TargetData& rhs) {
160     if (!std::is_permutation(lhs.direct_decorations.begin(),
161                              lhs.direct_decorations.end(),
162                              rhs.direct_decorations.begin())) {
163       return false;
164     }
165     if (!std::is_permutation(lhs.indirect_decorations.begin(),
166                              lhs.indirect_decorations.end(),
167                              rhs.indirect_decorations.begin())) {
168       return false;
169     }
170     if (!std::is_permutation(lhs.decorate_insts.begin(),
171                              lhs.decorate_insts.end(),
172                              rhs.decorate_insts.begin())) {
173       return false;
174     }
175     return true;
176   }
177 
178   // Mapping from ids to the instructions applying a decoration to those ids.
179   // In other words, for each id you get all decoration instructions
180   // referencing that id, be it directly (SpvOpDecorate, SpvOpMemberDecorate
181   // and SpvOpDecorateId), or indirectly (SpvOpGroupDecorate,
182   // SpvOpMemberGroupDecorate).
183   std::unordered_map<uint32_t, TargetData> id_to_decoration_insts_;
184   // The enclosing module.
185   Module* module_;
186 };
187 
188 }  // namespace analysis
189 }  // namespace opt
190 }  // namespace spvtools
191 
192 #endif  // SOURCE_OPT_DECORATION_MANAGER_H_
193