// Copyright (c) 2017 Pierre Moreau // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef SOURCE_OPT_DECORATION_MANAGER_H_ #define SOURCE_OPT_DECORATION_MANAGER_H_ #include #include #include #include #include "source/opt/instruction.h" #include "source/opt/module.h" namespace spvtools { namespace opt { namespace analysis { // A class for analyzing and managing decorations in an Module. class DecorationManager { public: // Constructs a decoration manager from the given |module| explicit DecorationManager(Module* module) : module_(module) { AnalyzeDecorations(); } DecorationManager() = delete; // Removes all decorations (direct and through groups) where |pred| is // true and that apply to |id| so that they no longer apply to |id|. Returns // true if something changed. // // If |id| is part of a group, it will be removed from the group if it // does not use all of the group's decorations, or, if there are no // decorations that apply to the group. // // If decoration groups become empty, the |OpGroupDecorate| and // |OpGroupMemberDecorate| instructions will be killed. // // Decoration instructions that apply directly to |id| will be killed. // // If |id| is a decoration group and all of the group's decorations are // removed, then the |OpGroupDecorate| and // |OpGroupMemberDecorate| for the group will be killed, but not the defining // |OpDecorationGroup| instruction. bool RemoveDecorationsFrom( uint32_t id, std::function pred = [](const Instruction&) { return true; }); // Removes all decorations from the result id of |inst|. // // NOTE: This is only meant to be called from ir_context, as only metadata // will be removed, and no actual instruction. void RemoveDecoration(Instruction* inst); // Returns a vector of all decorations affecting |id|. If a group is applied // to |id|, the decorations of that group are returned rather than the group // decoration instruction. If |include_linkage| is not set, linkage // decorations won't be returned. std::vector GetDecorationsFor(uint32_t id, bool include_linkage); std::vector GetDecorationsFor(uint32_t id, bool include_linkage) const; // Returns whether two IDs have the same decorations. Two SpvOpGroupDecorate // instructions that apply the same decorations but to different IDs, still // count as being the same. bool HaveTheSameDecorations(uint32_t id1, uint32_t id2) const; // Returns whether two IDs have the same decorations. Two SpvOpGroupDecorate // instructions that apply the same decorations but to different IDs, still // count as being the same. bool HaveSubsetOfDecorations(uint32_t id1, uint32_t id2) const; // Returns whether the two decorations instructions are the same and are // applying the same decorations; unless |ignore_target| is false, the targets // to which they are applied to does not matter, except for the member part. // // This is only valid for OpDecorate, OpMemberDecorate and OpDecorateId; it // will return false for other opcodes. bool AreDecorationsTheSame(const Instruction* inst1, const Instruction* inst2, bool ignore_target) const; // Returns whether a decoration instruction for |id| with decoration // |decoration| exists or not. bool HasDecoration(uint32_t id, uint32_t decoration); // |f| is run on each decoration instruction for |id| with decoration // |decoration|. Processed are all decorations which target |id| either // directly or indirectly by Decoration Groups. void ForEachDecoration(uint32_t id, uint32_t decoration, std::function f); // |f| is run on each decoration instruction for |id| with decoration // |decoration|. Processes all decoration which target |id| either directly or // indirectly through decoration groups. If |f| returns false, iteration is // terminated and this function returns false. bool WhileEachDecoration(uint32_t id, uint32_t decoration, std::function f); // |f| is run on each decoration instruction for |id| with decoration // |decoration|. Processes all decoration which target |id| either directly or // indirectly through decoration groups. If |f| returns true, iteration is // terminated and this function returns true. Otherwise returns false. bool FindDecoration(uint32_t id, uint32_t decoration, std::function f); // Clone all decorations from one id |from|. // The cloned decorations are assigned to the given id |to| and are // added to the module. The purpose is to decorate cloned instructions. // This function does not check if the id |to| is already decorated. void CloneDecorations(uint32_t from, uint32_t to); // Same as above, but only clone the decoration if the decoration operand is // in |decorations_to_copy|. This function has the extra restriction that // |from| and |to| must not be an object, not a type. void CloneDecorations(uint32_t from, uint32_t to, const std::vector& decorations_to_copy); // Informs the decoration manager of a new decoration that it needs to track. void AddDecoration(Instruction* inst); // Add decoration with |opcode| and operands |opnds|. void AddDecoration(SpvOp opcode, const std::vector opnds); // Add |decoration| of |inst_id| to module. void AddDecoration(uint32_t inst_id, uint32_t decoration); // Add |decoration, decoration_value| of |inst_id| to module. void AddDecorationVal(uint32_t inst_id, uint32_t decoration, uint32_t decoration_value); // Add |decoration, decoration_value| of |inst_id, member| to module. void AddMemberDecoration(uint32_t member, uint32_t inst_id, uint32_t decoration, uint32_t decoration_value); friend bool operator==(const DecorationManager&, const DecorationManager&); friend bool operator!=(const DecorationManager& lhs, const DecorationManager& rhs) { return !(lhs == rhs); } private: // Analyzes the defs and uses in the given |module| and populates data // structures in this class. Does nothing if |module| is nullptr. void AnalyzeDecorations(); template std::vector InternalGetDecorationsFor(uint32_t id, bool include_linkage); // Tracks decoration information of an ID. struct TargetData { std::vector direct_decorations; // All decorate // instructions applied // to the tracked ID. std::vector indirect_decorations; // All instructions // applying a group to // the tracked ID. std::vector decorate_insts; // All decorate instructions // applying the decorations // of the tracked ID to // targets. // It is empty if the // tracked ID is not a // group. }; friend bool operator==(const TargetData& lhs, const TargetData& rhs) { if (!std::is_permutation(lhs.direct_decorations.begin(), lhs.direct_decorations.end(), rhs.direct_decorations.begin())) { return false; } if (!std::is_permutation(lhs.indirect_decorations.begin(), lhs.indirect_decorations.end(), rhs.indirect_decorations.begin())) { return false; } if (!std::is_permutation(lhs.decorate_insts.begin(), lhs.decorate_insts.end(), rhs.decorate_insts.begin())) { return false; } return true; } // Mapping from ids to the instructions applying a decoration to those ids. // In other words, for each id you get all decoration instructions // referencing that id, be it directly (SpvOpDecorate, SpvOpMemberDecorate // and SpvOpDecorateId), or indirectly (SpvOpGroupDecorate, // SpvOpMemberGroupDecorate). std::unordered_map id_to_decoration_insts_; // The enclosing module. Module* module_; }; } // namespace analysis } // namespace opt } // namespace spvtools #endif // SOURCE_OPT_DECORATION_MANAGER_H_