diff options
Diffstat (limited to 'source/opt/eliminate_dead_io_components_pass.cpp')
-rw-r--r-- | source/opt/eliminate_dead_io_components_pass.cpp | 258 |
1 files changed, 0 insertions, 258 deletions
diff --git a/source/opt/eliminate_dead_io_components_pass.cpp b/source/opt/eliminate_dead_io_components_pass.cpp deleted file mode 100644 index 916fc27a..00000000 --- a/source/opt/eliminate_dead_io_components_pass.cpp +++ /dev/null @@ -1,258 +0,0 @@ -// Copyright (c) 2022 The Khronos Group Inc. -// Copyright (c) 2022 LunarG Inc. -// -// 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. - -#include "source/opt/eliminate_dead_io_components_pass.h" - -#include <set> -#include <vector> - -#include "source/opt/instruction.h" -#include "source/opt/ir_builder.h" -#include "source/opt/ir_context.h" -#include "source/util/bit_vector.h" - -namespace spvtools { -namespace opt { -namespace { -constexpr uint32_t kAccessChainBaseInIdx = 0; -constexpr uint32_t kAccessChainIndex0InIdx = 1; -constexpr uint32_t kAccessChainIndex1InIdx = 2; -constexpr uint32_t kConstantValueInIdx = 0; -} // namespace - -Pass::Status EliminateDeadIOComponentsPass::Process() { - // Only process input and output variables - if (elim_sclass_ != spv::StorageClass::Input && - elim_sclass_ != spv::StorageClass::Output) { - if (consumer()) { - std::string message = - "EliminateDeadIOComponentsPass only valid for input and output " - "variables."; - consumer()(SPV_MSG_ERROR, 0, {0, 0, 0}, message.c_str()); - } - return Status::Failure; - } - // If safe mode, only process Input variables in vertex shader - const auto stage = context()->GetStage(); - if (safe_mode_ && !(stage == spv::ExecutionModel::Vertex && - elim_sclass_ == spv::StorageClass::Input)) - return Status::SuccessWithoutChange; - // Current functionality assumes shader capability. - if (!context()->get_feature_mgr()->HasCapability(spv::Capability::Shader)) - return Status::SuccessWithoutChange; - // Current functionality assumes vert, frag, tesc, tese or geom shader. - // TODO(issue #4988): Add GLCompute. - if (stage != spv::ExecutionModel::Vertex && - stage != spv::ExecutionModel::Fragment && - stage != spv::ExecutionModel::TessellationControl && - stage != spv::ExecutionModel::TessellationEvaluation && - stage != spv::ExecutionModel::Geometry) - return Status::SuccessWithoutChange; - analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - bool modified = false; - std::vector<Instruction*> vars_to_move; - for (auto& var : context()->types_values()) { - if (var.opcode() != spv::Op::OpVariable) { - continue; - } - analysis::Type* var_type = type_mgr->GetType(var.type_id()); - analysis::Pointer* ptr_type = var_type->AsPointer(); - if (ptr_type == nullptr) { - continue; - } - const auto sclass = ptr_type->storage_class(); - if (sclass != elim_sclass_) { - continue; - } - // For tesc, or input variables in tese or geom shaders, - // there is a outer per-vertex-array that must be ignored - // for the purposes of this analysis/optimization. Do the - // analysis on the inner type in these cases. - bool skip_first_index = false; - auto core_type = ptr_type->pointee_type(); - if (stage == spv::ExecutionModel::TessellationControl || - (sclass == spv::StorageClass::Input && - (stage == spv::ExecutionModel::TessellationEvaluation || - stage == spv::ExecutionModel::Geometry))) { - auto arr_type = core_type->AsArray(); - if (!arr_type) continue; - core_type = arr_type->element_type(); - skip_first_index = true; - } - const analysis::Array* arr_type = core_type->AsArray(); - if (arr_type != nullptr) { - // Only process array if input of vertex shader, or output of - // fragment shader. Otherwise, if one shader has a runtime index and the - // other does not, interface incompatibility can occur. - if (!((sclass == spv::StorageClass::Input && - stage == spv::ExecutionModel::Vertex) || - (sclass == spv::StorageClass::Output && - stage == spv::ExecutionModel::Fragment))) - continue; - unsigned arr_len_id = arr_type->LengthId(); - Instruction* arr_len_inst = def_use_mgr->GetDef(arr_len_id); - if (arr_len_inst->opcode() != spv::Op::OpConstant) { - continue; - } - // SPIR-V requires array size is >= 1, so this works for signed or - // unsigned size. - unsigned original_max = - arr_len_inst->GetSingleWordInOperand(kConstantValueInIdx) - 1; - 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; - } - const analysis::Struct* struct_type = core_type->AsStruct(); - if (struct_type == nullptr) continue; - const auto elt_types = struct_type->element_types(); - unsigned original_max = static_cast<unsigned>(elt_types.size()) - 1; - unsigned max_idx = FindMaxIndex(var, original_max, skip_first_index); - if (max_idx != original_max) { - ChangeIOVarStructLength(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; -} - -unsigned EliminateDeadIOComponentsPass::FindMaxIndex( - const Instruction& var, const unsigned original_max, - const bool skip_first_index) { - unsigned max = 0; - bool seen_non_const_ac = false; - assert(var.opcode() == spv::Op::OpVariable && "must be variable"); - context()->get_def_use_mgr()->WhileEachUser( - var.result_id(), [&max, &seen_non_const_ac, var, skip_first_index, - this](Instruction* use) { - auto use_opcode = use->opcode(); - 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) { - seen_non_const_ac = true; - return false; - } - if (use->opcode() != spv::Op::OpAccessChain && - use->opcode() != spv::Op::OpInBoundsAccessChain) { - return true; - } - // OpAccessChain with no indices currently not optimized - if (use->NumInOperands() == 1 || - (skip_first_index && use->NumInOperands() == 2)) { - seen_non_const_ac = true; - return false; - } - const unsigned base_id = - use->GetSingleWordInOperand(kAccessChainBaseInIdx); - USE_ASSERT(base_id == var.result_id() && "unexpected base"); - const unsigned in_idx = skip_first_index ? kAccessChainIndex1InIdx - : kAccessChainIndex0InIdx; - const unsigned idx_id = use->GetSingleWordInOperand(in_idx); - Instruction* idx_inst = context()->get_def_use_mgr()->GetDef(idx_id); - if (idx_inst->opcode() != spv::Op::OpConstant) { - seen_non_const_ac = true; - return false; - } - unsigned value = idx_inst->GetSingleWordInOperand(kConstantValueInIdx); - if (value > max) max = value; - return true; - }); - return seen_non_const_ac ? original_max : max; -} - -void EliminateDeadIOComponentsPass::ChangeArrayLength(Instruction& arr_var, - unsigned length) { - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); - analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); - analysis::Pointer* ptr_type = - type_mgr->GetType(arr_var.type_id())->AsPointer(); - const analysis::Array* arr_ty = ptr_type->pointee_type()->AsArray(); - assert(arr_ty && "expecting array type"); - uint32_t length_id = const_mgr->GetUIntConstId(length); - 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, 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); -} - -void EliminateDeadIOComponentsPass::ChangeIOVarStructLength(Instruction& io_var, - unsigned length) { - analysis::TypeManager* type_mgr = context()->get_type_mgr(); - analysis::Pointer* ptr_type = - type_mgr->GetType(io_var.type_id())->AsPointer(); - auto core_type = ptr_type->pointee_type(); - // Check for per-vertex-array of struct from tesc, tese and geom and grab - // embedded struct type. - const auto arr_type = core_type->AsArray(); - if (arr_type) core_type = arr_type->element_type(); - const analysis::Struct* struct_ty = core_type->AsStruct(); - assert(struct_ty && "expecting struct type"); - const auto orig_elt_types = struct_ty->element_types(); - std::vector<const analysis::Type*> new_elt_types; - 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); - } - // Clone name instructions for new struct type - analysis::Type* reg_new_str_ty = type_mgr->GetRegisteredType(&new_struct_ty); - uint32_t new_struct_ty_id = type_mgr->GetTypeInstruction(reg_new_str_ty); - context()->CloneNames(old_struct_ty_id, new_struct_ty_id, length); - // Attach new type to var - analysis::Type* reg_new_var_ty = reg_new_str_ty; - if (arr_type) { - analysis::Array new_arr_ty(reg_new_var_ty, arr_type->length_info()); - reg_new_var_ty = type_mgr->GetRegisteredType(&new_arr_ty); - } - analysis::Pointer new_ptr_ty(reg_new_var_ty, elim_sclass_); - 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); - io_var.SetResultType(new_ptr_ty_id); - analysis::DefUseManager* def_use_mgr = context()->get_def_use_mgr(); - def_use_mgr->AnalyzeInstUse(&io_var); -} - -} // namespace opt -} // namespace spvtools |