mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-29 22:41:03 +00:00
297723d75a
* Mark module as modified if convert-to-half removes decorations. If the convert-to-half pass does not change the body of the function, but removes decorations, it returns that nothing changed. This is incorrect, and will be fixed. Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/4117 * Update comment for RemoveDecorationsFrom
207 lines
9.1 KiB
C++
207 lines
9.1 KiB
C++
// 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 <functional>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
#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<bool(const Instruction&)> 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<Instruction*> GetDecorationsFor(uint32_t id,
|
|
bool include_linkage);
|
|
std::vector<const Instruction*> 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;
|
|
|
|
// |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<void(const Instruction&)> 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<bool(const Instruction&)> 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<bool(const Instruction&)> 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<SpvDecoration>& 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<Operand> 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 <typename T>
|
|
std::vector<T> InternalGetDecorationsFor(uint32_t id, bool include_linkage);
|
|
|
|
// Tracks decoration information of an ID.
|
|
struct TargetData {
|
|
std::vector<Instruction*> direct_decorations; // All decorate
|
|
// instructions applied
|
|
// to the tracked ID.
|
|
std::vector<Instruction*> indirect_decorations; // All instructions
|
|
// applying a group to
|
|
// the tracked ID.
|
|
std::vector<Instruction*> 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<uint32_t, TargetData> id_to_decoration_insts_;
|
|
// The enclosing module.
|
|
Module* module_;
|
|
};
|
|
|
|
} // namespace analysis
|
|
} // namespace opt
|
|
} // namespace spvtools
|
|
|
|
#endif // SOURCE_OPT_DECORATION_MANAGER_H_
|