• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   // Removes all decorations (direct and through groups) where |pred| is
40   // true and that apply to |id| so that they no longer apply to |id|.  Returns
41   // true if something changed.
42   //
43   // If |id| is part of a group, it will be removed from the group if it
44   // does not use all of the group's decorations, or, if there are no
45   // decorations that apply to the group.
46   //
47   // If decoration groups become empty, the |OpGroupDecorate| and
48   // |OpGroupMemberDecorate| instructions will be killed.
49   //
50   // Decoration instructions that apply directly to |id| will be killed.
51   //
52   // If |id| is a decoration group and all of the group's decorations are
53   // removed, then the |OpGroupDecorate| and
54   // |OpGroupMemberDecorate| for the group will be killed, but not the defining
55   // |OpDecorationGroup| instruction.
56   bool RemoveDecorationsFrom(
57       uint32_t id, std::function<bool(const Instruction&)> pred =
58                        [](const Instruction&) { return true; });
59 
60   // Removes all decorations from the result id of |inst|.
61   //
62   // NOTE: This is only meant to be called from ir_context, as only metadata
63   // will be removed, and no actual instruction.
64   void RemoveDecoration(Instruction* inst);
65 
66   // Returns a vector of all decorations affecting |id|. If a group is applied
67   // to |id|, the decorations of that group are returned rather than the group
68   // decoration instruction. If |include_linkage| is not set, linkage
69   // decorations won't be returned.
70   std::vector<Instruction*> GetDecorationsFor(uint32_t id,
71                                               bool include_linkage);
72   std::vector<const Instruction*> GetDecorationsFor(uint32_t id,
73                                                     bool include_linkage) const;
74   // Returns whether two IDs have the same decorations. Two SpvOpGroupDecorate
75   // instructions that apply the same decorations but to different IDs, still
76   // count as being the same.
77   bool HaveTheSameDecorations(uint32_t id1, uint32_t id2) const;
78 
79   // Returns whether two IDs have the same decorations. Two SpvOpGroupDecorate
80   // instructions that apply the same decorations but to different IDs, still
81   // count as being the same.
82   bool HaveSubsetOfDecorations(uint32_t id1, uint32_t id2) const;
83 
84   // Returns whether the two decorations instructions are the same and are
85   // applying the same decorations; unless |ignore_target| is false, the targets
86   // to which they are applied to does not matter, except for the member part.
87   //
88   // This is only valid for OpDecorate, OpMemberDecorate and OpDecorateId; it
89   // will return false for other opcodes.
90   bool AreDecorationsTheSame(const Instruction* inst1, const Instruction* inst2,
91                              bool ignore_target) const;
92 
93   // Returns whether a decoration instruction for |id| with decoration
94   // |decoration| exists or not.
95   bool HasDecoration(uint32_t id, uint32_t decoration);
96 
97   // |f| is run on each decoration instruction for |id| with decoration
98   // |decoration|. Processed are all decorations which target |id| either
99   // directly or indirectly by Decoration Groups.
100   void ForEachDecoration(uint32_t id, uint32_t decoration,
101                          std::function<void(const Instruction&)> f);
102 
103   // |f| is run on each decoration instruction for |id| with decoration
104   // |decoration|. Processes all decoration which target |id| either directly or
105   // indirectly through decoration groups. If |f| returns false, iteration is
106   // terminated and this function returns false.
107   bool WhileEachDecoration(uint32_t id, uint32_t decoration,
108                            std::function<bool(const Instruction&)> f);
109 
110   // |f| is run on each decoration instruction for |id| with decoration
111   // |decoration|. Processes all decoration which target |id| either directly or
112   // indirectly through decoration groups. If |f| returns true, iteration is
113   // terminated and this function returns true. Otherwise returns false.
114   bool FindDecoration(uint32_t id, uint32_t decoration,
115                       std::function<bool(const Instruction&)> f);
116 
117   // Clone all decorations from one id |from|.
118   // The cloned decorations are assigned to the given id |to| and are
119   // added to the module. The purpose is to decorate cloned instructions.
120   // This function does not check if the id |to| is already decorated.
121   void CloneDecorations(uint32_t from, uint32_t to);
122 
123   // Same as above, but only clone the decoration if the decoration operand is
124   // in |decorations_to_copy|.  This function has the extra restriction that
125   // |from| and |to| must not be an object, not a type.
126   void CloneDecorations(uint32_t from, uint32_t to,
127                         const std::vector<SpvDecoration>& decorations_to_copy);
128 
129   // Informs the decoration manager of a new decoration that it needs to track.
130   void AddDecoration(Instruction* inst);
131 
132   // Add decoration with |opcode| and operands |opnds|.
133   void AddDecoration(SpvOp opcode, const std::vector<Operand> opnds);
134 
135   // Add |decoration| of |inst_id| to module.
136   void AddDecoration(uint32_t inst_id, uint32_t decoration);
137 
138   // Add |decoration, decoration_value| of |inst_id| to module.
139   void AddDecorationVal(uint32_t inst_id, uint32_t decoration,
140                         uint32_t decoration_value);
141 
142   // Add |decoration, decoration_value| of |inst_id, member| to module.
143   void AddMemberDecoration(uint32_t member, uint32_t inst_id,
144                            uint32_t decoration, uint32_t decoration_value);
145 
146   friend bool operator==(const DecorationManager&, const DecorationManager&);
147   friend bool operator!=(const DecorationManager& lhs,
148                          const DecorationManager& rhs) {
149     return !(lhs == rhs);
150   }
151 
152  private:
153   // Analyzes the defs and uses in the given |module| and populates data
154   // structures in this class. Does nothing if |module| is nullptr.
155   void AnalyzeDecorations();
156 
157   template <typename T>
158   std::vector<T> InternalGetDecorationsFor(uint32_t id, bool include_linkage);
159 
160   // Tracks decoration information of an ID.
161   struct TargetData {
162     std::vector<Instruction*> direct_decorations;    // All decorate
163                                                      // instructions applied
164                                                      // to the tracked ID.
165     std::vector<Instruction*> indirect_decorations;  // All instructions
166                                                      // applying a group to
167                                                      // the tracked ID.
168     std::vector<Instruction*> decorate_insts;  // All decorate instructions
169                                                // applying the decorations
170                                                // of the tracked ID to
171                                                // targets.
172                                                // It is empty if the
173                                                // tracked ID is not a
174                                                // group.
175   };
176 
177   friend bool operator==(const TargetData& lhs, const TargetData& rhs) {
178     if (!std::is_permutation(lhs.direct_decorations.begin(),
179                              lhs.direct_decorations.end(),
180                              rhs.direct_decorations.begin())) {
181       return false;
182     }
183     if (!std::is_permutation(lhs.indirect_decorations.begin(),
184                              lhs.indirect_decorations.end(),
185                              rhs.indirect_decorations.begin())) {
186       return false;
187     }
188     if (!std::is_permutation(lhs.decorate_insts.begin(),
189                              lhs.decorate_insts.end(),
190                              rhs.decorate_insts.begin())) {
191       return false;
192     }
193     return true;
194   }
195 
196   // Mapping from ids to the instructions applying a decoration to those ids.
197   // In other words, for each id you get all decoration instructions
198   // referencing that id, be it directly (SpvOpDecorate, SpvOpMemberDecorate
199   // and SpvOpDecorateId), or indirectly (SpvOpGroupDecorate,
200   // SpvOpMemberGroupDecorate).
201   std::unordered_map<uint32_t, TargetData> id_to_decoration_insts_;
202   // The enclosing module.
203   Module* module_;
204 };
205 
206 }  // namespace analysis
207 }  // namespace opt
208 }  // namespace spvtools
209 
210 #endif  // SOURCE_OPT_DECORATION_MANAGER_H_
211