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
26namespace spvtools {
27namespace opt {
28namespace analysis {
29
30// A class for analyzing and managing decorations in an Module.
31class 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