// Phase 4: Find the import/export pairs
LinkageTable linkings_to_do;
- DecorationManager decoration_manager(linked_context.module());
- res = GetImportExportPairs(consumer, linked_context,
- *linked_context.get_def_use_mgr(),
- decoration_manager, &linkings_to_do);
+ res = GetImportExportPairs(
+ consumer, linked_context, *linked_context.get_def_use_mgr(),
+ *linked_context.get_decoration_mgr(), &linkings_to_do);
if (res != SPV_SUCCESS) return res;
// Phase 5: Ensure the import and export have the same types and decorations.
res = CheckImportExportCompatibility(consumer, linkings_to_do,
*linked_context.get_def_use_mgr(),
- decoration_manager);
+ *linked_context.get_decoration_mgr());
if (res != SPV_SUCCESS) return res;
// Phase 6: Remove duplicates
// Phase 7: Remove linkage specific instructions, such as import/export
// attributes, linkage capability, etc. if applicable
- res = RemoveLinkageSpecificInstructions(consumer, !options.GetCreateLibrary(),
- linkings_to_do, &decoration_manager,
- &linked_context);
+ res = RemoveLinkageSpecificInstructions(
+ consumer, !options.GetCreateLibrary(), linkings_to_do,
+ linked_context.get_decoration_mgr(), &linked_context);
if (res != SPV_SUCCESS) return res;
// Phase 8: Rematch import variables/functions to export variables/functions
}
return 0;
}
+
+bool spvOpcodeIsDecoration(const SpvOp opcode) {
+ switch(opcode) {
+ case SpvOpDecorate:
+ case SpvOpDecorateId:
+ case SpvOpMemberDecorate:
+ case SpvOpGroupDecorate:
+ case SpvOpGroupMemberDecorate:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
// non-zero otherwise.
int32_t spvOpcodeGeneratesType(SpvOp opcode);
+// Returns true if the opcode add a decoration to an id.
+bool spvOpcodeIsDecoration(const SpvOp opcode);
+
#endif // LIBSPIRV_OPCODE_H_
bool CommonUniformElimPass::IsVolatileStruct(uint32_t type_id) {
assert(get_def_use_mgr()->GetDef(type_id)->opcode() == SpvOpTypeStruct);
bool has_volatile_deco = false;
- dec_mgr_->ForEachDecoration(type_id, SpvDecorationVolatile,
+ get_decoration_mgr()->ForEachDecoration(type_id, SpvDecorationVolatile,
[&has_volatile_deco](const ir::Instruction&) {
has_volatile_deco = true;
});
return true;
}
-void CommonUniformElimPass::KillNamesAndDecorates(uint32_t id) {
- // TODO(greg-lunarg): Remove id from any OpGroupDecorate and
- // kill if no other operands.
- analysis::UseList* uses = get_def_use_mgr()->GetUses(id);
- if (uses == nullptr) return;
- std::list<ir::Instruction*> killList;
- for (auto u : *uses) {
- const SpvOp op = u.inst->opcode();
- if (op != SpvOpName && !IsNonTypeDecorate(op)) continue;
- killList.push_back(u.inst);
- }
- for (auto kip : killList) context()->KillInst(kip);
-}
-
-void CommonUniformElimPass::KillNamesAndDecorates(ir::Instruction* inst) {
- // TODO(greg-lunarg): Remove inst from any OpGroupDecorate and
- // kill if not other operands.
- const uint32_t rId = inst->result_id();
- if (rId == 0) return;
- KillNamesAndDecorates(rId);
-}
-
void CommonUniformElimPass::DeleteIfUseless(ir::Instruction* inst) {
const uint32_t resId = inst->result_id();
assert(resId != 0);
if (HasOnlyNamesAndDecorates(resId)) {
- KillNamesAndDecorates(resId);
context()->KillInst(inst);
}
}
uint32_t replId,
ir::Instruction* ptrInst) {
const uint32_t loadId = loadInst->result_id();
- KillNamesAndDecorates(loadId);
+ context()->KillNamesAndDecorates(loadId);
(void)context()->ReplaceAllUsesWith(loadId, replId);
// remove load instruction
context()->KillInst(loadInst);
ii = ii.InsertBefore(std::move(newExtract));
for (auto instItr : idxItr.second) {
uint32_t resId = instItr->result_id();
- KillNamesAndDecorates(resId);
+ context()->KillNamesAndDecorates(resId);
(void)context()->ReplaceAllUsesWith(resId, replId);
context()->KillInst(instItr);
}
// Clear collections.
comp2idx2inst_.clear();
- dec_mgr_.reset(new analysis::DecorationManager(get_module()));
// Initialize extension whitelist
InitExtensions();
// Return true if all uses of |id| are only name or decorate ops.
bool HasOnlyNamesAndDecorates(uint32_t id) const;
- // Kill all name and decorate ops using |inst|
- void KillNamesAndDecorates(ir::Instruction* inst);
-
- // Kill all name and decorate ops using |id|
- void KillNamesAndDecorates(uint32_t id);
-
// Delete inst if it has no uses. Assumes inst has a resultId.
void DeleteIfUseless(ir::Instruction* inst);
void Initialize(ir::IRContext* c);
Pass::Status ProcessImpl();
- // Decorations for the module we are processing
- std::unique_ptr<analysis::DecorationManager> dec_mgr_;
-
// Map from uniform variable id to its common load id
std::unordered_map<uint32_t, uint32_t> uniform2load_id_;
#include "cfa.h"
#include "iterator.h"
+#include "ir_context.h"
namespace spvtools {
namespace opt {
++pii;
}
const uint32_t phiId = pii->result_id();
- KillNamesAndDecorates(phiId);
+ context()->KillNamesAndDecorates(phiId);
(void)context()->ReplaceAllUsesWith(phiId, replId);
context()->KillInst(&*pii);
}
#include "dead_variable_elimination.h"
#include "reflect.h"
+#include "ir_context.h"
namespace spvtools {
namespace opt {
// value kMustKeep as the reference count.
InitializeProcessing(c);
- // Decoration manager to help organize decorations.
- analysis::DecorationManager decoration_manager(context()->module());
-
std::vector<uint32_t> ids_to_remove;
// Get the reference count for all of the global OpVariable instructions.
// Check the linkage. If it is exported, it could be reference somewhere
// else, so we must keep the variable around.
- decoration_manager.ForEachDecoration(
+ get_decoration_mgr()->ForEachDecoration(
result_id, SpvDecorationLinkageAttributes,
[&count](const ir::Instruction& linkage_instruction) {
uint32_t last_operand = linkage_instruction.NumOperands() - 1;
}
}
}
- this->KillNamesAndDecorates(result_id);
context()->KillDef(result_id);
}
} // namespace opt
#include "decoration_manager.h"
-#include <stack>
+#include <algorithm>
#include <iostream>
+#include <stack>
namespace spvtools {
namespace opt {
namespace analysis {
-void DecorationManager::RemoveDecorationsFrom(uint32_t id, bool keep_linkage) {
+void DecorationManager::RemoveDecorationsFrom(uint32_t id) {
auto const ids_iter = id_to_decoration_insts_.find(id);
if (ids_iter == id_to_decoration_insts_.end()) return;
-
- for (ir::Instruction* inst : ids_iter->second) {
- switch (inst->opcode()) {
- case SpvOpDecorate:
- case SpvOpDecorateId:
- case SpvOpMemberDecorate:
- if (!(keep_linkage &&
- inst->GetSingleWordInOperand(1u) ==
- SpvDecorationLinkageAttributes))
- inst->ToNop();
- break;
- case SpvOpGroupDecorate:
- for (uint32_t i = 1u; i < inst->NumInOperands(); ++i) {
- if (inst->GetSingleWordInOperand(i) == inst->result_id()) {
- // TODO(pierremoreau): This could be optimised by copying the last
- // operand over this one, or using a compacting
- // filtering algorithm over all other IDs
- inst->RemoveInOperand(i);
- }
- }
- break;
- case SpvOpGroupMemberDecorate:
- for (uint32_t i = 1u; i < inst->NumInOperands(); i += 2u) {
- if (inst->GetSingleWordInOperand(i) == inst->result_id()) {
- // TODO(pierremoreau): Same optimisation opportunity as above.
- inst->RemoveInOperand(i);
- }
- }
- break;
- default:
- break;
- }
- }
+ id_to_decoration_insts_.erase(ids_iter);
}
std::vector<ir::Instruction*> DecorationManager::GetDecorationsFor(
// For each group and instruction, collect all their decoration instructions.
for (ir::Instruction& inst : module_->annotations()) {
- switch (inst.opcode()) {
- case SpvOpDecorate:
- case SpvOpDecorateId:
- case SpvOpMemberDecorate: {
- auto const target_id = inst.GetSingleWordInOperand(0u);
+ AddDecoration(&inst);
+ }
+}
+void DecorationManager::AddDecoration(ir::Instruction* inst) {
+ switch (inst->opcode()) {
+ case SpvOpDecorate:
+ case SpvOpDecorateId:
+ case SpvOpMemberDecorate: {
+ auto const target_id = inst->GetSingleWordInOperand(0u);
+ auto const group_iter = group_to_decoration_insts_.find(target_id);
+ if (group_iter != group_to_decoration_insts_.end())
+ group_iter->second.push_back(inst);
+ else
+ id_to_decoration_insts_[target_id].push_back(inst);
+ break;
+ }
+ case SpvOpGroupDecorate:
+ for (uint32_t i = 1u; i < inst->NumInOperands(); ++i) {
+ auto const target_id = inst->GetSingleWordInOperand(i);
auto const group_iter = group_to_decoration_insts_.find(target_id);
if (group_iter != group_to_decoration_insts_.end())
- group_iter->second.push_back(&inst);
+ group_iter->second.push_back(inst);
else
- id_to_decoration_insts_[target_id].push_back(&inst);
- break;
+ id_to_decoration_insts_[target_id].push_back(inst);
}
- case SpvOpGroupDecorate:
- for (uint32_t i = 1u; i < inst.NumInOperands(); ++i) {
- auto const target_id = inst.GetSingleWordInOperand(i);
- auto const group_iter = group_to_decoration_insts_.find(target_id);
- if (group_iter != group_to_decoration_insts_.end())
- group_iter->second.push_back(&inst);
- else
- id_to_decoration_insts_[target_id].push_back(&inst);
- }
- break;
- case SpvOpGroupMemberDecorate:
- for (uint32_t i = 1u; i < inst.NumInOperands(); i += 2u) {
- auto const target_id = inst.GetSingleWordInOperand(i);
- auto const group_iter = group_to_decoration_insts_.find(target_id);
- if (group_iter != group_to_decoration_insts_.end())
- group_iter->second.push_back(&inst);
- else
- id_to_decoration_insts_[target_id].push_back(&inst);
- }
- break;
- default:
- break;
- }
+ break;
+ case SpvOpGroupMemberDecorate:
+ for (uint32_t i = 1u; i < inst->NumInOperands(); i += 2u) {
+ auto const target_id = inst->GetSingleWordInOperand(i);
+ auto const group_iter = group_to_decoration_insts_.find(target_id);
+ if (group_iter != group_to_decoration_insts_.end())
+ group_iter->second.push_back(inst);
+ else
+ id_to_decoration_insts_[target_id].push_back(inst);
+ }
+ break;
+ default:
+ break;
}
}
return decorations;
}
-void DecorationManager::ForEachDecoration(uint32_t id,
- uint32_t decoration,
- std::function<void(const ir::Instruction&)> f) {
+void DecorationManager::ForEachDecoration(
+ uint32_t id, uint32_t decoration,
+ std::function<void(const ir::Instruction&)> f) {
for (const ir::Instruction* inst : GetDecorationsFor(id, true)) {
switch (inst->opcode()) {
case SpvOpMemberDecorate:
}
}
-void DecorationManager::CloneDecorations(uint32_t from, uint32_t to,
- std::function<void(ir::Instruction&, bool)> f) {
+void DecorationManager::CloneDecorations(
+ uint32_t from, uint32_t to, std::function<void(ir::Instruction&, bool)> f) {
assert(f && "Missing function parameter f");
auto const decoration_list = id_to_decoration_insts_.find(from);
if (decoration_list == id_to_decoration_insts_.end()) return;
case SpvOpGroupDecorate:
f(*inst, false);
// add |to| to list of decorated id's
- inst->AddOperand(ir::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {to}));
+ inst->AddOperand(
+ ir::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {to}));
id_to_decoration_insts_[to].push_back(inst);
f(*inst, true);
break;
const uint32_t num_operands = inst->NumOperands();
for (uint32_t i = 1; i < num_operands; i += 2) {
ir::Operand op = inst->GetOperand(i);
- if (op.words[0] == from) { // add new pair of operands: (to, literal)
- inst->AddOperand(ir::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {to}));
+ if (op.words[0] == from) { // add new pair of operands: (to, literal)
+ inst->AddOperand(
+ ir::Operand(spv_operand_type_t::SPV_OPERAND_TYPE_ID, {to}));
op = inst->GetOperand(i + 1);
inst->AddOperand(std::move(op));
}
}
}
+void DecorationManager::RemoveDecoration(ir::Instruction* inst) {
+ switch (inst->opcode()) {
+ case SpvOpDecorate:
+ case SpvOpDecorateId:
+ case SpvOpMemberDecorate: {
+ auto const target_id = inst->GetSingleWordInOperand(0u);
+ RemoveInstructionFromTarget(inst, target_id);
+ } break;
+ case SpvOpGroupDecorate:
+ for (uint32_t i = 1u; i < inst->NumInOperands(); ++i) {
+ auto const target_id = inst->GetSingleWordInOperand(i);
+ RemoveInstructionFromTarget(inst, target_id);
+ }
+ break;
+ case SpvOpGroupMemberDecorate:
+ for (uint32_t i = 1u; i < inst->NumInOperands(); i += 2u) {
+ auto const target_id = inst->GetSingleWordInOperand(i);
+ RemoveInstructionFromTarget(inst, target_id);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void DecorationManager::RemoveInstructionFromTarget(ir::Instruction* inst,
+ const uint32_t target_id) {
+ auto const group_iter = group_to_decoration_insts_.find(target_id);
+ if (group_iter != group_to_decoration_insts_.end()) {
+ remove(group_iter->second.begin(), group_iter->second.end(), inst);
+ } else {
+ auto target_list_iter = id_to_decoration_insts_.find(target_id);
+ if (target_list_iter != id_to_decoration_insts_.end()) {
+ remove(target_list_iter->second.begin(), target_list_iter->second.end(),
+ inst);
+ }
+ }
+}
} // namespace analysis
} // namespace opt
} // namespace spvtools
}
DecorationManager() = delete;
- // Removes all decorations from |id|, which should not be a group ID, except
- // for linkage decorations if |keep_linkage| is set.
- void RemoveDecorationsFrom(uint32_t id, bool keep_linkage);
+ // Removes all decorations from |id|, which should not be a group ID.
+ void RemoveDecorationsFrom(uint32_t id);
+
+ // Removes all decorations from the result id of |inst|.
+ void RemoveDecoration(ir::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
// with |true| afterwards.
void CloneDecorations(uint32_t from, uint32_t to, std::function<void(ir::Instruction&, bool)> f);
+ // Informs the decoration manager of a new decoration that it needs to track.
+ void AddDecoration(ir::Instruction* inst);
+
private:
+ // Removes the instruction from the set of decorations targeting |target_id|.
+ void RemoveInstructionFromTarget(ir::Instruction* inst,
+ const uint32_t target_id);
+
using IdToDecorationInstsMap =
std::unordered_map<uint32_t, std::vector<ir::Instruction*>>;
// Analyzes the defs and uses in the given |module| and populates data
// limitations under the License.
#include "eliminate_dead_functions_pass.h"
+#include "ir_context.h"
#include <unordered_set>
// Remove all of the instruction in the function body
func->ForEachInst(
[this](ir::Instruction* inst) {
- KillNamesAndDecorates(inst);
context()->KillInst(inst);
},
true);
while (callee_var_itr->opcode() == SpvOp::SpvOpVariable) {
std::unique_ptr<ir::Instruction> var_inst(callee_var_itr->Clone());
uint32_t newId = TakeNextId();
- dec_mgr_->CloneDecorations(callee_var_itr->result_id(), newId, update_def_use_mgr_);
+ get_decoration_mgr()->CloneDecorations(callee_var_itr->result_id(), newId, update_def_use_mgr_);
var_inst->SetResultId(newId);
(*callee2caller)[callee_var_itr->result_id()] = newId;
new_vars->push_back(std::move(var_inst));
{SpvStorageClassFunction}}}));
new_vars->push_back(std::move(var_inst));
}
- dec_mgr_->CloneDecorations(calleeFn->result_id(), returnVarId, update_def_use_mgr_);
+ get_decoration_mgr()->CloneDecorations(calleeFn->result_id(), returnVarId, update_def_use_mgr_);
return returnVarId;
}
CloneSameBlockOps(&sb_inst, postCallSB, preCallSB, block_ptr);
const uint32_t rid = sb_inst->result_id();
const uint32_t nid = this->TakeNextId();
- dec_mgr_->CloneDecorations(rid, nid, update_def_use_mgr_);
+ get_decoration_mgr()->CloneDecorations(rid, nid, update_def_use_mgr_);
sb_inst->SetResultId(nid);
(*postCallSB)[rid] = nid;
*iid = nid;
callee2caller[rid] = nid;
}
cp_inst->SetResultId(nid);
- dec_mgr_->CloneDecorations(rid, nid, update_def_use_mgr_);
+ get_decoration_mgr()->CloneDecorations(rid, nid, update_def_use_mgr_);
}
new_blk_ptr->AddInstruction(std::move(cp_inst));
} break;
void InlinePass::InitializeInline(ir::IRContext* c) {
InitializeProcessing(c);
- dec_mgr_.reset(new analysis::DecorationManager(c->module()));
update_def_use_mgr_ = [this] (ir::Instruction& inst, bool has_changed) {
if (has_changed)
get_def_use_mgr()->AnalyzeInstDefUse(&inst);
// Update the DefUseManager when cloning decorations.
std::function<void(ir::Instruction&, bool)> update_def_use_mgr_;
- // Decorations for the module we are processing TODO: move this to ir_context as well
- std::unique_ptr<analysis::DecorationManager> dec_mgr_;
-
// Map from function's result id to function.
std::unordered_map<uint32_t, ir::Function*> id2function_;
operands_.insert(operands_.begin(), new_operands.begin(), new_operands.end());
operands_.shrink_to_fit();
}
-
} // namespace ir
} // namespace spvtools
#include <functional>
#include <utility>
#include <vector>
+#include <opcode.h>
#include "operand.h"
#include "util/ilist_node.h"
// this instruction.
void ReplaceOperands(const std::vector<Operand>& new_operands);
+ // Returns true if the instruction annotates an id with a decoration.
+ inline bool IsDecoration();
+
private:
// Returns the total count of result type id and result id.
uint32_t TypeResultIdCount() const {
return false;
}
+bool Instruction::IsDecoration() {
+ return spvOpcodeIsDecoration(opcode());
+}
+
} // namespace ir
} // namespace spvtools
#include "ir_context.h"
#include "log.h"
+#include "mem_pass.h"
namespace spvtools {
namespace ir {
if (set & kAnalysisInstrToBlockMapping) {
BuildInstrToBlockMapping();
}
+ if (set & kAnalysisDecorations) {
+ BuildDecorationManager();
+ }
}
void IRContext::InvalidateAnalysesExceptFor(
if (analyses_to_invalidate & kAnalysisInstrToBlockMapping) {
instr_to_block_.clear();
}
+ if (analyses_to_invalidate & kAnalysisDecorations) {
+ decoration_mgr_.reset(nullptr);
+ }
valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate);
}
return;
}
+ KillNamesAndDecorates(inst);
+
if (AreAnalysesValid(kAnalysisDefUse)) {
get_def_use_mgr()->ClearInst(inst);
}
if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
instr_to_block_.erase(inst);
}
+ if (AreAnalysesValid(kAnalysisDecorations)) {
+ if (inst->result_id() != 0) {
+ decoration_mgr_->RemoveDecorationsFrom(inst->result_id());
+ }
+ if (inst->IsDecoration()) {
+ decoration_mgr_->RemoveDecoration(inst);
+ }
+ }
inst->ToNop();
}
if (AreAnalysesValid(kAnalysisDefUse)) {
get_def_use_mgr()->EraseUseRecordsOfOperandIds(inst);
}
+ if (AreAnalysesValid(kAnalysisDecorations)) {
+ if (inst->IsDecoration()) {
+ get_decoration_mgr()->RemoveDecoration(inst);
+ }
+ }
}
void IRContext::AnalyzeUses(Instruction* inst) {
if (AreAnalysesValid(kAnalysisDefUse)) {
get_def_use_mgr()->AnalyzeInstUse(inst);
}
+ if (AreAnalysesValid(kAnalysisDecorations)) {
+ if (inst->IsDecoration()) {
+ get_decoration_mgr()->AddDecoration(inst);
+ }
+ }
+}
+
+void IRContext::KillNamesAndDecorates(uint32_t id) {
+ std::vector<ir::Instruction*> decorations =
+ get_decoration_mgr()->GetDecorationsFor(id, true);
+
+ for (Instruction* inst : decorations) {
+ KillInst(inst);
+ }
+
+ for (auto& di : debugs2()) {
+ if (di.opcode() == SpvOpMemberName || di.opcode() == SpvOpName) {
+ if (di.GetSingleWordInOperand(0) == id) {
+ KillInst(&di);
+ }
+ }
+ }
+}
+
+void IRContext::KillNamesAndDecorates(Instruction* inst) {
+ const uint32_t rId = inst->result_id();
+ if (rId == 0) return;
+ KillNamesAndDecorates(rId);
}
} // namespace ir
#ifndef SPIRV_TOOLS_IR_CONTEXT_H
#define SPIRV_TOOLS_IR_CONTEXT_H
+#include "decoration_manager.h"
#include "def_use_manager.h"
#include "module.h"
+#include <algorithm>
#include <iostream>
namespace spvtools {
kAnalysisBegin = 1 << 0,
kAnalysisDefUse = kAnalysisBegin,
kAnalysisInstrToBlockMapping = 1 << 1,
- kAnalysisEnd = 1 << 2
+ kAnalysisDecorations = 1 << 2,
+ kAnalysisEnd = 1 << 3
};
friend inline Analysis operator|(Analysis lhs, Analysis rhs);
return (entry != instr_to_block_.end()) ? entry->second : nullptr;
}
+ // Returns a pointer the decoration manager. If the decoration manger is
+ // invalid, it is rebuilt first.
+ opt::analysis::DecorationManager* get_decoration_mgr() {
+ if (!AreAnalysesValid(kAnalysisDecorations)) {
+ BuildDecorationManager();
+ }
+ return decoration_mgr_.get();
+ };
+
// Sets the message consumer to the given |consumer|. |consumer| which will be
// invoked every time there is a message to be communicated to the outside.
void SetMessageConsumer(spvtools::MessageConsumer c) {
// will be updated accordingly.
void AnalyzeUses(Instruction* inst);
+ // Kill all name and decorate ops targeting |id|.
+ void KillNamesAndDecorates(uint32_t id);
+
+ // Kill all name and decorate ops targeting the result id of |inst|.
+ void KillNamesAndDecorates(ir::Instruction* inst);
+
private:
// Builds the def-use manager from scratch, even if it was already valid.
void BuildDefUseManager() {
valid_analyses_ = valid_analyses_ | kAnalysisInstrToBlockMapping;
}
+ void BuildDecorationManager() {
+ decoration_mgr_.reset(new opt::analysis::DecorationManager(module()));
+ valid_analyses_ = valid_analyses_ | kAnalysisDecorations;
+ }
+
std::unique_ptr<Module> module_;
spvtools::MessageConsumer consumer_;
std::unique_ptr<opt::analysis::DefUseManager> def_use_mgr_;
+ std::unique_ptr<opt::analysis::DecorationManager> decoration_mgr_;
// A map from instructions the the basic block they belong to. This mapping is
// built on-demand when get_instr_block() is called.
}
void IRContext::AddAnnotationInst(std::unique_ptr<Instruction>&& a) {
+ if (AreAnalysesValid(kAnalysisDecorations)) {
+ get_decoration_mgr()->AddDecoration(a.get());
+ }
module()->AddAnnotationInst(std::move(a));
}
#include "local_access_chain_convert_pass.h"
#include "iterator.h"
+#include "ir_context.h"
namespace spvtools {
namespace opt {
const uint32_t resId = inst->result_id();
assert(resId != 0);
if (HasOnlyNamesAndDecorates(resId)) {
- KillNamesAndDecorates(resId);
context()->KillInst(inst);
}
}
#include "basic_block.h"
#include "cfa.h"
#include "iterator.h"
+#include "ir_context.h"
namespace spvtools {
namespace opt {
return GetPtr(ptrId, varId);
}
-void MemPass::FindNamedOrDecoratedIds() {
- named_or_decorated_ids_.clear();
- for (auto& di : get_module()->debugs2())
- if (di.opcode() == SpvOpName)
- named_or_decorated_ids_.insert(di.GetSingleWordInOperand(0));
- for (auto& ai : get_module()->annotations())
- if (ai.opcode() == SpvOpDecorate || ai.opcode() == SpvOpDecorateId)
- named_or_decorated_ids_.insert(ai.GetSingleWordInOperand(0));
-}
-
bool MemPass::HasOnlyNamesAndDecorates(uint32_t id) const {
analysis::UseList* uses = get_def_use_mgr()->GetUses(id);
if (uses == nullptr) return true;
- if (named_or_decorated_ids_.find(id) == named_or_decorated_ids_.end())
- return false;
for (auto u : *uses) {
const SpvOp op = u.inst->opcode();
if (op != SpvOpName && !IsNonTypeDecorate(op)) return false;
return true;
}
-void MemPass::KillNamesAndDecorates(uint32_t id) {
- // TODO(greg-lunarg): Remove id from any OpGroupDecorate and
- // kill if no other operands.
- if (named_or_decorated_ids_.find(id) == named_or_decorated_ids_.end()) return;
- analysis::UseList* uses = get_def_use_mgr()->GetUses(id);
- if (uses == nullptr) return;
- std::list<ir::Instruction*> killList;
- for (auto u : *uses) {
- const SpvOp op = u.inst->opcode();
- if (op == SpvOpName || IsNonTypeDecorate(op)) killList.push_back(u.inst);
- }
- for (auto kip : killList) context()->KillInst(kip);
-}
-
-void MemPass::KillNamesAndDecorates(ir::Instruction* inst) {
- const uint32_t rId = inst->result_id();
- if (rId == 0) return;
- KillNamesAndDecorates(rId);
-}
-
void MemPass::KillAllInsts(ir::BasicBlock* bp) {
bp->ForEachInst([this](ir::Instruction* ip) {
- KillNamesAndDecorates(ip);
context()->KillInst(ip);
});
}
uint32_t varId = 0;
// Remember variable if dead load
if (di->opcode() == SpvOpLoad) (void)GetPtr(di, &varId);
- KillNamesAndDecorates(di);
context()->KillInst(di);
// For all operands with no remaining uses, add their instruction
// to the dead instruction queue.
void MemPass::ReplaceAndDeleteLoad(ir::Instruction* loadInst, uint32_t replId) {
const uint32_t loadId = loadInst->result_id();
- KillNamesAndDecorates(loadId);
+ context()->KillNamesAndDecorates(loadId);
(void)context()->ReplaceAllUsesWith(loadId, replId);
DCEInst(loadInst);
}
// and delete load. Kill any names or decorates using id before
// replacing to prevent incorrect replacement in those instructions.
const uint32_t loadId = ii->result_id();
- KillNamesAndDecorates(loadId);
+ context()->KillNamesAndDecorates(loadId);
(void)context()->ReplaceAllUsesWith(loadId, replId);
context()->KillInst(&*ii);
} break;
// instruction is needed to identify the block, which is needed by the
// removal of phi operands.
if (inst != rm_block.GetLabelInst()) {
- KillNamesAndDecorates(inst);
context()->KillInst(inst);
}
});
// Remove the label instruction last.
auto label = rm_block.GetLabelInst();
- KillNamesAndDecorates(label);
context()->KillInst(label);
*bi = bi->Erase();
virtual ~MemPass() = default;
protected:
- // Initialize basic data structures for the pass.
- void InitializeProcessing(ir::IRContext* c) {
- Pass::InitializeProcessing(c);
- FindNamedOrDecoratedIds();
- }
-
// Returns true if |typeInst| is a scalar type
// or a vector or matrix
bool IsBaseTargetType(const ir::Instruction* typeInst) const;
// Return true if all uses of |id| are only name or decorate ops.
bool HasOnlyNamesAndDecorates(uint32_t id) const;
- // Kill all name and decorate ops using |inst|
- void KillNamesAndDecorates(ir::Instruction* inst);
-
- // Kill all name and decorate ops using |id|
- void KillNamesAndDecorates(uint32_t id);
-
// Kill all instructions in block |bp|.
void KillAllInsts(ir::BasicBlock* bp);
- // Collect all named or decorated ids in module
- void FindNamedOrDecoratedIds();
-
// Return true if any instruction loads from |varId|
bool HasLoads(uint32_t varId) const;
// |reachable_blocks|.
void RemovePhiOperands(ir::Instruction* phi,
std::unordered_set<ir::BasicBlock*> reachable_blocks);
- // named or decorated ids
- std::unordered_set<uint32_t> named_or_decorated_ids_;
// Map from block's label id to a map of a variable to its value at the
// end of the block.
return context()->get_def_use_mgr();
}
+ analysis::DecorationManager* get_decoration_mgr() const {
+ return context()->get_decoration_mgr();
+ }
+
// Returns a pointer to the current module for this pass.
ir::Module* get_module() const { return context_->module(); }
using opt::analysis::DecorationManager;
Pass::Status RemoveDuplicatesPass::Process(ir::IRContext* irContext) {
- DecorationManager decManager(irContext->module());
-
bool modified = RemoveDuplicateCapabilities(irContext);
modified |= RemoveDuplicatesExtInstImports(irContext);
- modified |= RemoveDuplicateTypes(irContext, decManager);
+ modified |= RemoveDuplicateTypes(irContext);
modified |= RemoveDuplicateDecorations(irContext);
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
return modified;
}
-bool RemoveDuplicatesPass::RemoveDuplicateTypes(
- ir::IRContext* irContext, DecorationManager& decManager) const {
+bool RemoveDuplicatesPass::RemoveDuplicateTypes(ir::IRContext* irContext) const {
bool modified = false;
std::vector<Instruction> visitedTypes;
// Is the current type equal to one of the types we have aready visited?
SpvId idToKeep = 0u;
for (auto j : visitedTypes) {
- if (AreTypesEqual(*i, j, *irContext->get_def_use_mgr(), decManager)) {
+ if (AreTypesEqual(*i, j, *irContext->get_def_use_mgr(), *irContext->get_decoration_mgr())) {
idToKeep = j.result_id();
break;
}
private:
bool RemoveDuplicateCapabilities(ir::IRContext* irContext) const;
bool RemoveDuplicatesExtInstImports(ir::IRContext* irContext) const;
- bool RemoveDuplicateTypes(ir::IRContext* irContext,
- analysis::DecorationManager& decManager) const;
+ bool RemoveDuplicateTypes(ir::IRContext* irContext) const;
bool RemoveDuplicateDecorations(ir::IRContext* irContext) const;
};
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <external/googletest/googlemock/include/gmock/gmock-matchers.h>
#include <gtest/gtest.h>
#include <algorithm>
using namespace spvtools;
using ir::IRContext;
using Analysis = IRContext::Analysis;
+using ::testing::Each;
class DummyPassPreservesNothing : public opt::Pass {
public:
}
}
-TEST_F(IRContextTest, AllPreserveFirstOnlyAfterPassWithChange) {
+TEST_F(IRContextTest, PreserveFirstOnlyAfterPassWithChange) {
std::unique_ptr<ir::Module> module = MakeUnique<ir::Module>();
IRContext context(std::move(module), spvtools::MessageConsumer());
EXPECT_FALSE(context.AreAnalysesValid(i));
}
}
+
+TEST_F(IRContextTest, KillMemberName) {
+ const std::string text = R"(
+ OpCapability Shader
+ %1 = OpExtInstImport "GLSL.std.450"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint Fragment %2 "main"
+ OpExecutionMode %2 OriginUpperLeft
+ OpSource GLSL 430
+ OpName %3 "stuff"
+ OpMemberName %3 0 "refZ"
+ OpMemberDecorate %3 0 Offset 0
+ OpDecorate %3 Block
+ %4 = OpTypeFloat 32
+ %3 = OpTypeStruct %4
+ %5 = OpTypeVoid
+ %6 = OpTypeFunction %5
+ %2 = OpFunction %5 None %6
+ %7 = OpLabel
+ OpReturn
+ OpFunctionEnd
+)";
+
+ std::unique_ptr<ir::Module> module =
+ BuildModule(SPV_ENV_UNIVERSAL_1_2, nullptr, text);
+ ir::IRContext context(std::move(module), spvtools::MessageConsumer());
+
+ // Build the decoration manager.
+ context.get_decoration_mgr();
+
+ // Delete the OpTypeStruct. Should delete the OpName, OpMemberName, and
+ // OpMemberDecorate associated with it.
+ context.KillDef(3);
+
+ // Make sure all of the name are removed.
+ for (auto& inst : context.debugs2()) {
+ EXPECT_EQ(inst.opcode(), SpvOpNop);
+ }
+
+ // Make sure all of the decorations are removed.
+ for (auto& inst : context.annotations()) {
+ EXPECT_EQ(inst.opcode(), SpvOpNop);
+ }
+}
} // anonymous namespace