Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,8 @@ static_library("spvtools_opt") {
"source/opt/tree_iterator.h",
"source/opt/trim_capabilities_pass.cpp",
"source/opt/trim_capabilities_pass.h",
"source/opt/trim_variable_pointers_capabilities_pass.cpp",
"source/opt/trim_variable_pointers_capabilities_pass.h",
"source/opt/type_manager.cpp",
"source/opt/type_manager.h",
"source/opt/types.cpp",
Expand Down
20 changes: 20 additions & 0 deletions include/spirv-tools/optimizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ class Pass;
struct DescriptorSetAndBinding;
} // namespace opt

enum class SSARewriteMode {
None,
All,
OpaqueOnly,
SpecialTypes,
};

// C++ interface for SPIR-V optimization functionalities. It wraps the context
// (including target environment and the corresponding SPIR-V grammar) and
// provides methods for registering optimization passes and optimizing.
Expand Down Expand Up @@ -102,6 +109,8 @@ class SPIRV_TOOLS_EXPORT Optimizer {
// interface are considered live and are not eliminated.
Optimizer& RegisterPerformancePasses();
Optimizer& RegisterPerformancePasses(bool preserve_interface);
Optimizer& RegisterPerformancePassesFastCompile();
Optimizer& RegisterPerformancePassesFastCompile(bool preserve_interface);

// Registers passes that attempt to improve the size of generated code.
// This sequence of passes is subject to constant review and will change
Expand All @@ -125,6 +134,10 @@ class SPIRV_TOOLS_EXPORT Optimizer {
// interface are considered live and are not eliminated.
Optimizer& RegisterLegalizationPasses();
Optimizer& RegisterLegalizationPasses(bool preserve_interface);
Optimizer& RegisterLegalizationPassesFastCompile();
Optimizer& RegisterLegalizationPassesFastCompile(
bool preserve_interface, bool include_loop_unroll,
SSARewriteMode ssa_rewrite_mode);

// Register passes specified in the list of |flags|. Each flag must be a
// string of a form accepted by Optimizer::FlagHasValidForm().
Expand Down Expand Up @@ -710,6 +723,7 @@ Optimizer::PassToken CreateLoopUnrollPass(bool fully_unroll, int factor = 0);
// Only variables that are local to the function and of supported types are
// processed (see IsSSATargetVar for details).
Optimizer::PassToken CreateSSARewritePass();
Optimizer::PassToken CreateSSARewritePass(SSARewriteMode mode);

// Create pass to convert relaxed precision instructions to half precision.
// This pass converts as many relaxed float32 arithmetic operations to half as
Expand Down Expand Up @@ -949,6 +963,12 @@ Optimizer::PassToken CreateFixFuncCallArgumentsPass();
// the unknown capability interacts with one of the trimmed capabilities.
Optimizer::PassToken CreateTrimCapabilitiesPass();

// Creates a pass that trims unused VariablePointers capabilities.
// This pass is intended for targeted call-sites that need to remove stale
// VariablePointers / VariablePointersStorageBuffer declarations left after
// optimization when the final module no longer requires them.
Optimizer::PassToken CreateTrimVariablePointersCapabilitiesPass();

// Creates a struct-packing pass.
// This pass re-assigns all offset layout decorators to tightly pack
// the struct with OpName matching `structToPack` according to the given packing
Expand Down
2 changes: 2 additions & 0 deletions source/opt/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
switch_descriptorset_pass.h
tree_iterator.h
trim_capabilities_pass.h
trim_variable_pointers_capabilities_pass.h
type_manager.h
types.h
unify_const_pass.h
Expand Down Expand Up @@ -249,6 +250,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
struct_packing_pass.cpp
switch_descriptorset_pass.cpp
trim_capabilities_pass.cpp
trim_variable_pointers_capabilities_pass.cpp
type_manager.cpp
types.cpp
unify_const_pass.cpp
Expand Down
49 changes: 49 additions & 0 deletions source/opt/dead_variable_elimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "source/opt/dead_variable_elimination.h"

#include <unordered_set>
#include <vector>

#include "source/opt/ir_context.h"
Expand Down Expand Up @@ -77,9 +78,43 @@ Pass::Status DeadVariableElimination::Process() {
DeleteVariable(result_id);
}
}

ids_to_remove.clear();
for (auto& function : *get_module()) {
if (function.IsDeclaration()) continue;

auto& entry = *function.begin();
for (auto inst = entry.begin(); inst != entry.end(); ++inst) {
if (inst->opcode() != spv::Op::OpVariable) break;
if (!IsFunctionLocalVariable(&*inst)) continue;
if (IsLiveVar(inst->result_id())) continue;
ids_to_remove.push_back(inst->result_id());
}
}

if (!ids_to_remove.empty()) {
modified = true;
for (auto result_id : ids_to_remove) {
DeleteLocalVariable(result_id);
}
}

return (modified ? Status::SuccessWithChange : Status::SuccessWithoutChange);
}

bool DeadVariableElimination::IsFunctionLocalVariable(
const Instruction* inst) const {
if (inst->opcode() != spv::Op::OpVariable) return false;

const Instruction* type_inst = get_def_use_mgr()->GetDef(inst->type_id());
if (type_inst == nullptr || type_inst->opcode() != spv::Op::OpTypePointer) {
return false;
}

return spv::StorageClass(type_inst->GetSingleWordInOperand(0)) ==
spv::StorageClass::Function;
}

void DeadVariableElimination::DeleteVariable(uint32_t result_id) {
Instruction* inst = get_def_use_mgr()->GetDef(result_id);
assert(inst->opcode() == spv::Op::OpVariable &&
Expand Down Expand Up @@ -108,5 +143,19 @@ void DeadVariableElimination::DeleteVariable(uint32_t result_id) {
}
context()->KillDef(result_id);
}

void DeadVariableElimination::DeleteLocalVariable(uint32_t result_id) {
std::queue<Instruction*> dead_stores;
std::unordered_set<Instruction*> processed;
AddStores(result_id, &dead_stores);
while (!dead_stores.empty()) {
Instruction* inst = dead_stores.front();
dead_stores.pop();
if (!processed.insert(inst).second) continue;
DCEInst(inst, nullptr);
}

context()->KillDef(result_id);
}
} // namespace opt
} // namespace spvtools
2 changes: 2 additions & 0 deletions source/opt/dead_variable_elimination.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ class DeadVariableElimination : public MemPass {
private:
// Deletes the OpVariable instruction who result id is |result_id|.
void DeleteVariable(uint32_t result_id);
void DeleteLocalVariable(uint32_t result_id);
bool IsFunctionLocalVariable(const Instruction* inst) const;

// Keeps track of the number of references of an id. Once that value is 0, it
// is safe to remove the corresponding instruction.
Expand Down
23 changes: 23 additions & 0 deletions source/opt/local_single_store_elim_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,18 @@ bool LocalSingleStoreElimPass::RewriteLoads(
else
stored_id = store_inst->GetSingleWordInOperand(kVariableInitIdInIdx);

const auto get_image_pointer_id = [this](uint32_t value_id) {
Instruction* value_inst = context()->get_def_use_mgr()->GetDef(value_id);
while (value_inst && value_inst->opcode() == spv::Op::OpCopyObject) {
value_id = value_inst->GetSingleWordInOperand(0);
value_inst = context()->get_def_use_mgr()->GetDef(value_id);
}
if (!value_inst || value_inst->opcode() != spv::Op::OpLoad) {
return uint32_t{0};
}
return value_inst->GetSingleWordInOperand(0);
};

*all_rewritten = true;
bool modified = false;
for (Instruction* use : uses) {
Expand All @@ -319,6 +331,17 @@ bool LocalSingleStoreElimPass::RewriteLoads(
context()->KillNamesAndDecorates(use->result_id());
context()->ReplaceAllUsesWith(use->result_id(), stored_id);
context()->KillInst(use);
} else if (use->opcode() == spv::Op::OpImageTexelPointer &&
dominator_analysis->Dominates(store_inst, use)) {
const uint32_t image_ptr_id = get_image_pointer_id(stored_id);
if (image_ptr_id == 0) {
*all_rewritten = false;
continue;
}
modified = true;
context()->ForgetUses(use);
use->SetInOperand(0, {image_ptr_id});
context()->AnalyzeUses(use);
} else {
*all_rewritten = false;
}
Expand Down
27 changes: 25 additions & 2 deletions source/opt/mem_pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,27 @@ bool MemPass::IsBaseTargetType(const Instruction* typeInst) const {
}

bool MemPass::IsTargetType(const Instruction* typeInst) const {
if (IsBaseTargetType(typeInst)) return true;
switch (ssa_rewrite_mode_) {
case SSARewriteMode::None:
return false;
case SSARewriteMode::OpaqueOnly:
if (typeInst->IsOpaqueType()) return true;
break;
case SSARewriteMode::SpecialTypes:
switch (typeInst->opcode()) {
case spv::Op::OpTypePointer:
case spv::Op::OpTypeUntypedPointerKHR:
case spv::Op::OpTypeCooperativeMatrixNV:
case spv::Op::OpTypeCooperativeMatrixKHR:
return true;
default:
break;
}
break;
case SSARewriteMode::All:
if (IsBaseTargetType(typeInst)) return true;
break;
}
if (typeInst->opcode() == spv::Op::OpTypeArray) {
if (!IsTargetType(
get_def_use_mgr()->GetDef(typeInst->GetSingleWordOperand(1)))) {
Expand Down Expand Up @@ -198,7 +218,7 @@ bool MemPass::IsLiveVar(uint32_t varId) const {
void MemPass::AddStores(uint32_t ptr_id, std::queue<Instruction*>* insts) {
get_def_use_mgr()->ForEachUser(ptr_id, [this, insts](Instruction* user) {
spv::Op op = user->opcode();
if (IsNonPtrAccessChain(op)) {
if (IsNonPtrAccessChain(op) || op == spv::Op::OpCopyObject) {
AddStores(user->result_id(), insts);
} else if (op == spv::Op::OpStore) {
insts->push(user);
Expand Down Expand Up @@ -243,6 +263,9 @@ void MemPass::DCEInst(Instruction* inst,

MemPass::MemPass() {}

MemPass::MemPass(SSARewriteMode ssa_rewrite_mode)
: ssa_rewrite_mode_(ssa_rewrite_mode) {}

bool MemPass::HasOnlySupportedRefs(uint32_t varId) {
return get_def_use_mgr()->WhileEachUser(varId, [this](Instruction* user) {
auto dbg_op = user->GetCommonDebugOpcode();
Expand Down
6 changes: 5 additions & 1 deletion source/opt/mem_pass.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <unordered_set>
#include <utility>

#include "spirv-tools/optimizer.hpp"
#include "source/opt/basic_block.h"
#include "source/opt/def_use_manager.h"
#include "source/opt/dominator_analysis.h"
Expand Down Expand Up @@ -69,6 +70,7 @@ class MemPass : public Pass {

protected:
MemPass();
explicit MemPass(SSARewriteMode ssa_rewrite_mode);

// Returns true if |typeInst| is a scalar type
// or a vector or matrix
Expand Down Expand Up @@ -133,7 +135,9 @@ class MemPass : public Pass {
// Cache of verified non-target vars
std::unordered_set<uint32_t> seen_non_target_vars_;

private:
private:
SSARewriteMode ssa_rewrite_mode_ = SSARewriteMode::All;

// Return true if all uses of |varId| are only through supported reference
// operations ie. loads and store. Also cache in supported_ref_vars_.
// TODO(dnovillo): This function is replicated in other passes and it's
Expand Down
Loading
Loading