Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/KhronosGroup/SPIRV-Tools.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorGreg Fischer <greg@lunarg.com>2022-11-08 20:45:32 +0300
committerGitHub <noreply@github.com>2022-11-08 20:45:32 +0300
commit525bc38062ab082d5b540dfe9465231cfb94361d (patch)
tree2ac69614a5ca3f732692f3ce3368fb8dd56d968c /source
parent54d4e77fa5599b855f5c463646c0e8922d5e6064 (diff)
Add pass to eliminate dead output components (#4982)
This pass eliminates components of output variables that are not stored to. Currently this just eliminates trailing components of arrays and structs, all of which are dead. WARNING: This pass is not designed to be a standalone pass as it can cause interface incompatibiliies with the following shader in the pipeline. See the comment in optimizer.hpp for best usage. This pass is currently available only through the API; it is not available in the CLI. This commit also fixes a bug in CreateDecoration() which is part of the system of generating SPIR-V from the Type manager.
Diffstat (limited to 'source')
-rw-r--r--source/opt/eliminate_dead_input_components_pass.cpp59
-rw-r--r--source/opt/eliminate_dead_input_components_pass.h6
-rw-r--r--source/opt/optimizer.cpp6
-rw-r--r--source/opt/type_manager.cpp11
-rw-r--r--source/opt/type_manager.h17
5 files changed, 59 insertions, 40 deletions
diff --git a/source/opt/eliminate_dead_input_components_pass.cpp b/source/opt/eliminate_dead_input_components_pass.cpp
index de75abd59..f31b567b4 100644
--- a/source/opt/eliminate_dead_input_components_pass.cpp
+++ b/source/opt/eliminate_dead_input_components_pass.cpp
@@ -28,7 +28,6 @@ namespace {
const uint32_t kAccessChainBaseInIdx = 0;
const uint32_t kAccessChainIndex0InIdx = 1;
const uint32_t kConstantValueInIdx = 0;
-const uint32_t kVariableStorageClassInIdx = 0;
} // namespace
@@ -42,7 +41,7 @@ Pass::Status EliminateDeadInputComponentsPass::Process() {
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
analysis::TypeManager* type_mgr = context()->get_type_mgr();
bool modified = false;
- std::vector<std::pair<Instruction*, unsigned>> arrays_to_change;
+ std::vector<Instruction*> vars_to_move;
for (auto& var : context()->types_values()) {
if (var.opcode() != spv::Op::OpVariable) {
continue;
@@ -52,8 +51,14 @@ Pass::Status EliminateDeadInputComponentsPass::Process() {
if (ptr_type == nullptr) {
continue;
}
- if (ptr_type->storage_class() != spv::StorageClass::Input) {
- continue;
+ if (output_instead_) {
+ if (ptr_type->storage_class() != spv::StorageClass::Output) {
+ continue;
+ }
+ } else {
+ if (ptr_type->storage_class() != spv::StorageClass::Input) {
+ continue;
+ }
}
const analysis::Array* arr_type = ptr_type->pointee_type()->AsArray();
if (arr_type != nullptr) {
@@ -69,6 +74,7 @@ Pass::Status EliminateDeadInputComponentsPass::Process() {
unsigned max_idx = FindMaxIndex(var, original_max);
if (max_idx != original_max) {
ChangeArrayLength(var, max_idx + 1);
+ vars_to_move.push_back(&var);
modified = true;
}
continue;
@@ -80,10 +86,20 @@ Pass::Status EliminateDeadInputComponentsPass::Process() {
unsigned max_idx = FindMaxIndex(var, original_max);
if (max_idx != original_max) {
ChangeStructLength(var, max_idx + 1);
+ vars_to_move.push_back(&var);
modified = true;
}
}
+ // Move changed vars after their new type instruction to preserve backward
+ // referencing
+ for (auto var : vars_to_move) {
+ auto type_id = var->type_id();
+ auto type_inst = def_use_mgr->GetDef(type_id);
+ var->RemoveFromList();
+ var->InsertAfter(type_inst);
+ }
+
return modified ? Status::SuccessWithChange : Status::SuccessWithoutChange;
}
@@ -95,7 +111,7 @@ unsigned EliminateDeadInputComponentsPass::FindMaxIndex(Instruction& var,
context()->get_def_use_mgr()->WhileEachUser(
var.result_id(), [&max, &seen_non_const_ac, var, this](Instruction* use) {
auto use_opcode = use->opcode();
- if (use_opcode == spv::Op::OpLoad ||
+ if (use_opcode == spv::Op::OpLoad || use_opcode == spv::Op::OpStore ||
use_opcode == spv::Op::OpCopyMemory ||
use_opcode == spv::Op::OpCopyMemorySized ||
use_opcode == spv::Op::OpCopyObject) {
@@ -139,18 +155,11 @@ void EliminateDeadInputComponentsPass::ChangeArrayLength(Instruction& arr_var,
analysis::Array new_arr_ty(arr_ty->element_type(),
arr_ty->GetConstantLengthInfo(length_id, length));
analysis::Type* reg_new_arr_ty = type_mgr->GetRegisteredType(&new_arr_ty);
- analysis::Pointer new_ptr_ty(reg_new_arr_ty, spv::StorageClass::Input);
+ analysis::Pointer new_ptr_ty(reg_new_arr_ty, ptr_type->storage_class());
analysis::Type* reg_new_ptr_ty = type_mgr->GetRegisteredType(&new_ptr_ty);
uint32_t new_ptr_ty_id = type_mgr->GetTypeInstruction(reg_new_ptr_ty);
arr_var.SetResultType(new_ptr_ty_id);
def_use_mgr->AnalyzeInstUse(&arr_var);
- // Move arr_var after its new type to preserve order
- USE_ASSERT(spv::StorageClass(arr_var.GetSingleWordInOperand(
- kVariableStorageClassInIdx)) != spv::StorageClass::Function &&
- "cannot move Function variable");
- Instruction* new_ptr_ty_inst = def_use_mgr->GetDef(new_ptr_ty_id);
- arr_var.RemoveFromList();
- arr_var.InsertAfter(new_ptr_ty_inst);
}
void EliminateDeadInputComponentsPass::ChangeStructLength(
@@ -165,25 +174,25 @@ void EliminateDeadInputComponentsPass::ChangeStructLength(
for (unsigned u = 0; u < length; ++u)
new_elt_types.push_back(orig_elt_types[u]);
analysis::Struct new_struct_ty(new_elt_types);
+ uint32_t old_struct_ty_id = type_mgr->GetTypeInstruction(struct_ty);
+ std::vector<Instruction*> decorations =
+ context()->get_decoration_mgr()->GetDecorationsFor(old_struct_ty_id,
+ true);
+ for (auto dec : decorations) {
+ if (dec->opcode() == spv::Op::OpMemberDecorate) {
+ uint32_t midx = dec->GetSingleWordInOperand(1);
+ if (midx >= length) continue;
+ }
+ type_mgr->AttachDecoration(*dec, &new_struct_ty);
+ }
analysis::Type* reg_new_struct_ty =
type_mgr->GetRegisteredType(&new_struct_ty);
- uint32_t new_struct_ty_id = type_mgr->GetTypeInstruction(reg_new_struct_ty);
- uint32_t old_struct_ty_id = type_mgr->GetTypeInstruction(struct_ty);
- analysis::DecorationManager* deco_mgr = context()->get_decoration_mgr();
- deco_mgr->CloneDecorations(old_struct_ty_id, new_struct_ty_id);
- analysis::Pointer new_ptr_ty(reg_new_struct_ty, spv::StorageClass::Input);
+ analysis::Pointer new_ptr_ty(reg_new_struct_ty, ptr_type->storage_class());
analysis::Type* reg_new_ptr_ty = type_mgr->GetRegisteredType(&new_ptr_ty);
uint32_t new_ptr_ty_id = type_mgr->GetTypeInstruction(reg_new_ptr_ty);
struct_var.SetResultType(new_ptr_ty_id);
analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr();
def_use_mgr->AnalyzeInstUse(&struct_var);
- // Move struct_var after its new type to preserve order
- USE_ASSERT(spv::StorageClass(struct_var.GetSingleWordInOperand(
- kVariableStorageClassInIdx)) != spv::StorageClass::Function &&
- "cannot move Function variable");
- Instruction* new_ptr_ty_inst = def_use_mgr->GetDef(new_ptr_ty_id);
- struct_var.RemoveFromList();
- struct_var.InsertAfter(new_ptr_ty_inst);
}
} // namespace opt
diff --git a/source/opt/eliminate_dead_input_components_pass.h b/source/opt/eliminate_dead_input_components_pass.h
index a3a133c2b..16b454575 100644
--- a/source/opt/eliminate_dead_input_components_pass.h
+++ b/source/opt/eliminate_dead_input_components_pass.h
@@ -28,7 +28,8 @@ namespace opt {
// See optimizer.hpp for documentation.
class EliminateDeadInputComponentsPass : public Pass {
public:
- explicit EliminateDeadInputComponentsPass() {}
+ explicit EliminateDeadInputComponentsPass(bool output_instead = false)
+ : output_instead_(output_instead) {}
const char* name() const override {
return "eliminate-dead-input-components";
@@ -57,6 +58,9 @@ class EliminateDeadInputComponentsPass : public Pass {
// Change the length of the struct |struct_var| to |length|
void ChangeStructLength(Instruction& struct_var, unsigned length);
+
+ // Process output variables instead
+ bool output_instead_;
};
} // namespace opt
diff --git a/source/opt/optimizer.cpp b/source/opt/optimizer.cpp
index 75a47784c..7583bd1c6 100644
--- a/source/opt/optimizer.cpp
+++ b/source/opt/optimizer.cpp
@@ -1034,6 +1034,12 @@ Optimizer::PassToken CreateEliminateDeadOutputStoresPass(
MakeUnique<opt::EliminateDeadOutputStoresPass>(live_locs, live_builtins));
}
+Optimizer::PassToken CreateEliminateDeadOutputComponentsPass() {
+ return MakeUnique<Optimizer::PassToken::Impl>(
+ MakeUnique<opt::EliminateDeadInputComponentsPass>(
+ /* output_instead */ true));
+}
+
Optimizer::PassToken CreateConvertToSampledImagePass(
const std::vector<opt::DescriptorSetAndBinding>&
descriptor_set_binding_pairs) {
diff --git a/source/opt/type_manager.cpp b/source/opt/type_manager.cpp
index 4568c0d06..d25daa901 100644
--- a/source/opt/type_manager.cpp
+++ b/source/opt/type_manager.cpp
@@ -476,7 +476,7 @@ void TypeManager::AttachDecorations(uint32_t id, const Type* type) {
for (auto pair : structTy->element_decorations()) {
uint32_t element = pair.first;
for (auto vec : pair.second) {
- CreateDecoration(id, vec, element);
+ CreateDecoration(id, vec, /* is_member */ true, element);
}
}
}
@@ -484,10 +484,10 @@ void TypeManager::AttachDecorations(uint32_t id, const Type* type) {
void TypeManager::CreateDecoration(uint32_t target,
const std::vector<uint32_t>& decoration,
- uint32_t element) {
+ bool is_member, uint32_t element) {
std::vector<Operand> ops;
ops.push_back(Operand(SPV_OPERAND_TYPE_ID, {target}));
- if (element != 0) {
+ if (is_member) {
ops.push_back(Operand(SPV_OPERAND_TYPE_LITERAL_INTEGER, {element}));
}
ops.push_back(Operand(SPV_OPERAND_TYPE_DECORATION, {decoration[0]}));
@@ -495,9 +495,8 @@ void TypeManager::CreateDecoration(uint32_t target,
ops.push_back(Operand(SPV_OPERAND_TYPE_LITERAL_INTEGER, {decoration[i]}));
}
context()->AddAnnotationInst(MakeUnique<Instruction>(
- context(),
- (element == 0 ? spv::Op::OpDecorate : spv::Op::OpMemberDecorate), 0, 0,
- ops));
+ context(), (is_member ? spv::Op::OpMemberDecorate : spv::Op::OpDecorate),
+ 0, 0, ops));
Instruction* inst = &*--context()->annotation_end();
context()->get_def_use_mgr()->AnalyzeInstUse(inst);
}
diff --git a/source/opt/type_manager.h b/source/opt/type_manager.h
index 2417d4993..c49e19322 100644
--- a/source/opt/type_manager.h
+++ b/source/opt/type_manager.h
@@ -139,6 +139,11 @@ class TypeManager {
const Type* GetMemberType(const Type* parent_type,
const std::vector<uint32_t>& access_chain);
+ // Attaches the decoration encoded in |inst| to |type|. Does nothing if the
+ // given instruction is not a decoration instruction. Assumes the target is
+ // |type| (e.g. should be called in loop of |type|'s decorations).
+ void AttachDecoration(const Instruction& inst, Type* type);
+
Type* GetUIntType() {
Integer int_type(32, false);
return GetRegisteredType(&int_type);
@@ -243,19 +248,15 @@ class TypeManager {
// Create the annotation instruction.
//
- // If |element| is zero, an OpDecorate is created, other an OpMemberDecorate
- // is created. The annotation is registered with the DefUseManager and the
- // DecorationManager.
+ // If |is_member| is false, an OpDecorate of |decoration| on |id| is created,
+ // otherwise an OpMemberDecorate is created at |element|. The annotation is
+ // registered with the DefUseManager and the DecorationManager.
void CreateDecoration(uint32_t id, const std::vector<uint32_t>& decoration,
- uint32_t element = 0);
+ bool is_member = false, uint32_t element = 0);
// Creates and returns a type from the given SPIR-V |inst|. Returns nullptr if
// the given instruction is not for defining a type.
Type* RecordIfTypeDefinition(const Instruction& inst);
- // Attaches the decoration encoded in |inst| to |type|. Does nothing if the
- // given instruction is not a decoration instruction. Assumes the target is
- // |type| (e.g. should be called in loop of |type|'s decorations).
- void AttachDecoration(const Instruction& inst, Type* type);
// Returns an equivalent pointer to |type| built in terms of pointers owned by
// |type_pool_|. For example, if |type| is a vec3 of bool, it will be rebuilt