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