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