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