| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711 |
- // Copyright (c) 2019 Google LLC
- //
- // 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_members_pass.h"
- #include "ir_builder.h"
- #include "source/opt/ir_context.h"
- namespace spvtools {
- namespace opt {
- namespace {
- constexpr uint32_t kRemovedMember = 0xFFFFFFFF;
- constexpr uint32_t kSpecConstOpOpcodeIdx = 0;
- constexpr uint32_t kArrayElementTypeIdx = 0;
- } // namespace
- Pass::Status EliminateDeadMembersPass::Process() {
- if (!context()->get_feature_mgr()->HasCapability(spv::Capability::Shader))
- return Status::SuccessWithoutChange;
- FindLiveMembers();
- if (RemoveDeadMembers()) {
- return Status::SuccessWithChange;
- }
- return Status::SuccessWithoutChange;
- }
- void EliminateDeadMembersPass::FindLiveMembers() {
- // Until we have implemented the rewriting of OpSpecConsantOp instructions,
- // we have to mark them as fully used just to be safe.
- for (auto& inst : get_module()->types_values()) {
- if (inst.opcode() == spv::Op::OpSpecConstantOp) {
- switch (spv::Op(inst.GetSingleWordInOperand(kSpecConstOpOpcodeIdx))) {
- case spv::Op::OpCompositeExtract:
- MarkMembersAsLiveForExtract(&inst);
- break;
- case spv::Op::OpCompositeInsert:
- // Nothing specific to do.
- break;
- case spv::Op::OpAccessChain:
- case spv::Op::OpInBoundsAccessChain:
- case spv::Op::OpPtrAccessChain:
- case spv::Op::OpInBoundsPtrAccessChain:
- assert(false && "Not implemented yet.");
- break;
- default:
- break;
- }
- } else if (inst.opcode() == spv::Op::OpVariable) {
- switch (spv::StorageClass(inst.GetSingleWordInOperand(0))) {
- case spv::StorageClass::Input:
- case spv::StorageClass::Output:
- MarkPointeeTypeAsFullUsed(inst.type_id());
- break;
- default:
- // Ignore structured buffers as layout(offset) qualifiers cannot be
- // applied to structure fields
- if (inst.IsVulkanStorageBufferVariable())
- MarkPointeeTypeAsFullUsed(inst.type_id());
- break;
- }
- } else if (inst.opcode() == spv::Op::OpTypePointer) {
- uint32_t storage_class = inst.GetSingleWordInOperand(0);
- if (storage_class == uint32_t(spv::StorageClass::PhysicalStorageBuffer)) {
- MarkTypeAsFullyUsed(inst.GetSingleWordInOperand(1));
- }
- }
- }
- for (const Function& func : *get_module()) {
- FindLiveMembers(func);
- }
- }
- void EliminateDeadMembersPass::FindLiveMembers(const Function& function) {
- function.ForEachInst(
- [this](const Instruction* inst) { FindLiveMembers(inst); });
- }
- void EliminateDeadMembersPass::FindLiveMembers(const Instruction* inst) {
- switch (inst->opcode()) {
- case spv::Op::OpStore:
- MarkMembersAsLiveForStore(inst);
- break;
- case spv::Op::OpCopyMemory:
- case spv::Op::OpCopyMemorySized:
- MarkMembersAsLiveForCopyMemory(inst);
- break;
- case spv::Op::OpCompositeExtract:
- MarkMembersAsLiveForExtract(inst);
- break;
- case spv::Op::OpAccessChain:
- case spv::Op::OpInBoundsAccessChain:
- case spv::Op::OpPtrAccessChain:
- case spv::Op::OpInBoundsPtrAccessChain:
- MarkMembersAsLiveForAccessChain(inst);
- break;
- case spv::Op::OpReturnValue:
- // This should be an issue only if we are returning from the entry point.
- // However, for now I will keep it more conservative because functions are
- // often inlined leaving only the entry points.
- MarkOperandTypeAsFullyUsed(inst, 0);
- break;
- case spv::Op::OpArrayLength:
- MarkMembersAsLiveForArrayLength(inst);
- break;
- case spv::Op::OpLoad:
- case spv::Op::OpCompositeInsert:
- case spv::Op::OpCompositeConstruct:
- break;
- default:
- // This path is here for safety. All instructions that can reference
- // structs in a function body should be handled above. However, this will
- // keep the pass valid, but not optimal, as new instructions get added
- // or if something was missed.
- MarkStructOperandsAsFullyUsed(inst);
- break;
- }
- }
- void EliminateDeadMembersPass::MarkMembersAsLiveForStore(
- const Instruction* inst) {
- // We should only have to mark the members as live if the store is to
- // memory that is read outside of the shader. Other passes can remove all
- // store to memory that is not visible outside of the shader, so we do not
- // complicate the code for now.
- assert(inst->opcode() == spv::Op::OpStore);
- uint32_t object_id = inst->GetSingleWordInOperand(1);
- Instruction* object_inst = context()->get_def_use_mgr()->GetDef(object_id);
- uint32_t object_type_id = object_inst->type_id();
- MarkTypeAsFullyUsed(object_type_id);
- }
- void EliminateDeadMembersPass::MarkTypeAsFullyUsed(uint32_t type_id) {
- Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
- assert(type_inst != nullptr);
- switch (type_inst->opcode()) {
- case spv::Op::OpTypeStruct:
- // Mark every member and its type as fully used.
- for (uint32_t i = 0; i < type_inst->NumInOperands(); ++i) {
- used_members_[type_id].insert(i);
- MarkTypeAsFullyUsed(type_inst->GetSingleWordInOperand(i));
- }
- break;
- case spv::Op::OpTypeArray:
- case spv::Op::OpTypeRuntimeArray:
- MarkTypeAsFullyUsed(
- type_inst->GetSingleWordInOperand(kArrayElementTypeIdx));
- break;
- default:
- break;
- }
- }
- void EliminateDeadMembersPass::MarkPointeeTypeAsFullUsed(uint32_t ptr_type_id) {
- Instruction* ptr_type_inst = get_def_use_mgr()->GetDef(ptr_type_id);
- assert(ptr_type_inst->opcode() == spv::Op::OpTypePointer);
- MarkTypeAsFullyUsed(ptr_type_inst->GetSingleWordInOperand(1));
- }
- void EliminateDeadMembersPass::MarkMembersAsLiveForCopyMemory(
- const Instruction* inst) {
- uint32_t target_id = inst->GetSingleWordInOperand(0);
- Instruction* target_inst = get_def_use_mgr()->GetDef(target_id);
- uint32_t pointer_type_id = target_inst->type_id();
- Instruction* pointer_type_inst = get_def_use_mgr()->GetDef(pointer_type_id);
- uint32_t type_id = pointer_type_inst->GetSingleWordInOperand(1);
- MarkTypeAsFullyUsed(type_id);
- }
- void EliminateDeadMembersPass::MarkMembersAsLiveForExtract(
- const Instruction* inst) {
- assert(inst->opcode() == spv::Op::OpCompositeExtract ||
- (inst->opcode() == spv::Op::OpSpecConstantOp &&
- spv::Op(inst->GetSingleWordInOperand(kSpecConstOpOpcodeIdx)) ==
- spv::Op::OpCompositeExtract));
- uint32_t first_operand =
- (inst->opcode() == spv::Op::OpSpecConstantOp ? 1 : 0);
- uint32_t composite_id = inst->GetSingleWordInOperand(first_operand);
- Instruction* composite_inst = get_def_use_mgr()->GetDef(composite_id);
- uint32_t type_id = composite_inst->type_id();
- for (uint32_t i = first_operand + 1; i < inst->NumInOperands(); ++i) {
- Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
- uint32_t member_idx = inst->GetSingleWordInOperand(i);
- switch (type_inst->opcode()) {
- case spv::Op::OpTypeStruct:
- used_members_[type_id].insert(member_idx);
- type_id = type_inst->GetSingleWordInOperand(member_idx);
- break;
- case spv::Op::OpTypeArray:
- case spv::Op::OpTypeRuntimeArray:
- case spv::Op::OpTypeVector:
- case spv::Op::OpTypeMatrix:
- case spv::Op::OpTypeCooperativeMatrixNV:
- case spv::Op::OpTypeCooperativeMatrixKHR:
- case spv::Op::OpTypeCooperativeVectorNV:
- type_id = type_inst->GetSingleWordInOperand(0);
- break;
- default:
- assert(false);
- }
- }
- }
- void EliminateDeadMembersPass::MarkMembersAsLiveForAccessChain(
- const Instruction* inst) {
- assert(inst->opcode() == spv::Op::OpAccessChain ||
- inst->opcode() == spv::Op::OpInBoundsAccessChain ||
- inst->opcode() == spv::Op::OpPtrAccessChain ||
- inst->opcode() == spv::Op::OpInBoundsPtrAccessChain);
- uint32_t pointer_id = inst->GetSingleWordInOperand(0);
- Instruction* pointer_inst = get_def_use_mgr()->GetDef(pointer_id);
- uint32_t pointer_type_id = pointer_inst->type_id();
- Instruction* pointer_type_inst = get_def_use_mgr()->GetDef(pointer_type_id);
- uint32_t type_id = pointer_type_inst->GetSingleWordInOperand(1);
- analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
- // For a pointer access chain, we need to skip the |element| index. It is not
- // a reference to the member of a struct, and it does not change the type.
- uint32_t i = (inst->opcode() == spv::Op::OpAccessChain ||
- inst->opcode() == spv::Op::OpInBoundsAccessChain
- ? 1
- : 2);
- for (; i < inst->NumInOperands(); ++i) {
- Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
- switch (type_inst->opcode()) {
- case spv::Op::OpTypeStruct: {
- const analysis::IntConstant* member_idx =
- const_mgr->FindDeclaredConstant(inst->GetSingleWordInOperand(i))
- ->AsIntConstant();
- assert(member_idx);
- uint32_t index =
- static_cast<uint32_t>(member_idx->GetZeroExtendedValue());
- used_members_[type_id].insert(index);
- type_id = type_inst->GetSingleWordInOperand(index);
- } break;
- case spv::Op::OpTypeArray:
- case spv::Op::OpTypeRuntimeArray:
- case spv::Op::OpTypeVector:
- case spv::Op::OpTypeMatrix:
- case spv::Op::OpTypeCooperativeMatrixNV:
- case spv::Op::OpTypeCooperativeMatrixKHR:
- case spv::Op::OpTypeCooperativeVectorNV:
- type_id = type_inst->GetSingleWordInOperand(0);
- break;
- default:
- assert(false);
- }
- }
- }
- void EliminateDeadMembersPass::MarkOperandTypeAsFullyUsed(
- const Instruction* inst, uint32_t in_idx) {
- uint32_t op_id = inst->GetSingleWordInOperand(in_idx);
- Instruction* op_inst = get_def_use_mgr()->GetDef(op_id);
- MarkTypeAsFullyUsed(op_inst->type_id());
- }
- void EliminateDeadMembersPass::MarkMembersAsLiveForArrayLength(
- const Instruction* inst) {
- assert(inst->opcode() == spv::Op::OpArrayLength);
- uint32_t object_id = inst->GetSingleWordInOperand(0);
- Instruction* object_inst = get_def_use_mgr()->GetDef(object_id);
- uint32_t pointer_type_id = object_inst->type_id();
- Instruction* pointer_type_inst = get_def_use_mgr()->GetDef(pointer_type_id);
- uint32_t type_id = pointer_type_inst->GetSingleWordInOperand(1);
- used_members_[type_id].insert(inst->GetSingleWordInOperand(1));
- }
- bool EliminateDeadMembersPass::RemoveDeadMembers() {
- bool modified = false;
- // First update all of the OpTypeStruct instructions.
- get_module()->ForEachInst([&modified, this](Instruction* inst) {
- switch (inst->opcode()) {
- case spv::Op::OpTypeStruct:
- modified |= UpdateOpTypeStruct(inst);
- break;
- default:
- break;
- }
- });
- // Now update all of the instructions that reference the OpTypeStructs.
- get_module()->ForEachInst([&modified, this](Instruction* inst) {
- switch (inst->opcode()) {
- case spv::Op::OpMemberName:
- modified |= UpdateOpMemberNameOrDecorate(inst);
- break;
- case spv::Op::OpMemberDecorate:
- modified |= UpdateOpMemberNameOrDecorate(inst);
- break;
- case spv::Op::OpGroupMemberDecorate:
- modified |= UpdateOpGroupMemberDecorate(inst);
- break;
- case spv::Op::OpSpecConstantComposite:
- case spv::Op::OpConstantComposite:
- case spv::Op::OpCompositeConstruct:
- modified |= UpdateConstantComposite(inst);
- break;
- case spv::Op::OpAccessChain:
- case spv::Op::OpInBoundsAccessChain:
- case spv::Op::OpPtrAccessChain:
- case spv::Op::OpInBoundsPtrAccessChain:
- modified |= UpdateAccessChain(inst);
- break;
- case spv::Op::OpCompositeExtract:
- modified |= UpdateCompsiteExtract(inst);
- break;
- case spv::Op::OpCompositeInsert:
- modified |= UpdateCompositeInsert(inst);
- break;
- case spv::Op::OpArrayLength:
- modified |= UpdateOpArrayLength(inst);
- break;
- case spv::Op::OpSpecConstantOp:
- switch (spv::Op(inst->GetSingleWordInOperand(kSpecConstOpOpcodeIdx))) {
- case spv::Op::OpCompositeExtract:
- modified |= UpdateCompsiteExtract(inst);
- break;
- case spv::Op::OpCompositeInsert:
- modified |= UpdateCompositeInsert(inst);
- break;
- case spv::Op::OpAccessChain:
- case spv::Op::OpInBoundsAccessChain:
- case spv::Op::OpPtrAccessChain:
- case spv::Op::OpInBoundsPtrAccessChain:
- assert(false && "Not implemented yet.");
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- });
- return modified;
- }
- bool EliminateDeadMembersPass::UpdateOpTypeStruct(Instruction* inst) {
- assert(inst->opcode() == spv::Op::OpTypeStruct);
- const auto& live_members = used_members_[inst->result_id()];
- if (live_members.size() == inst->NumInOperands()) {
- return false;
- }
- Instruction::OperandList new_operands;
- for (uint32_t idx : live_members) {
- new_operands.emplace_back(inst->GetInOperand(idx));
- }
- inst->SetInOperands(std::move(new_operands));
- context()->UpdateDefUse(inst);
- return true;
- }
- bool EliminateDeadMembersPass::UpdateOpMemberNameOrDecorate(Instruction* inst) {
- assert(inst->opcode() == spv::Op::OpMemberName ||
- inst->opcode() == spv::Op::OpMemberDecorate);
- uint32_t type_id = inst->GetSingleWordInOperand(0);
- auto live_members = used_members_.find(type_id);
- if (live_members == used_members_.end()) {
- return false;
- }
- uint32_t orig_member_idx = inst->GetSingleWordInOperand(1);
- uint32_t new_member_idx = GetNewMemberIndex(type_id, orig_member_idx);
- if (new_member_idx == kRemovedMember) {
- context()->KillInst(inst);
- return true;
- }
- if (new_member_idx == orig_member_idx) {
- return false;
- }
- inst->SetInOperand(1, {new_member_idx});
- return true;
- }
- bool EliminateDeadMembersPass::UpdateOpGroupMemberDecorate(Instruction* inst) {
- assert(inst->opcode() == spv::Op::OpGroupMemberDecorate);
- bool modified = false;
- Instruction::OperandList new_operands;
- new_operands.emplace_back(inst->GetInOperand(0));
- for (uint32_t i = 1; i < inst->NumInOperands(); i += 2) {
- uint32_t type_id = inst->GetSingleWordInOperand(i);
- uint32_t member_idx = inst->GetSingleWordInOperand(i + 1);
- uint32_t new_member_idx = GetNewMemberIndex(type_id, member_idx);
- if (new_member_idx == kRemovedMember) {
- modified = true;
- continue;
- }
- new_operands.emplace_back(inst->GetOperand(i));
- if (new_member_idx != member_idx) {
- new_operands.emplace_back(
- Operand({SPV_OPERAND_TYPE_LITERAL_INTEGER, {new_member_idx}}));
- modified = true;
- } else {
- new_operands.emplace_back(inst->GetOperand(i + 1));
- }
- }
- if (!modified) {
- return false;
- }
- if (new_operands.size() == 1) {
- context()->KillInst(inst);
- return true;
- }
- inst->SetInOperands(std::move(new_operands));
- context()->UpdateDefUse(inst);
- return true;
- }
- bool EliminateDeadMembersPass::UpdateConstantComposite(Instruction* inst) {
- assert(inst->opcode() == spv::Op::OpSpecConstantComposite ||
- inst->opcode() == spv::Op::OpConstantComposite ||
- inst->opcode() == spv::Op::OpCompositeConstruct);
- uint32_t type_id = inst->type_id();
- bool modified = false;
- Instruction::OperandList new_operands;
- for (uint32_t i = 0; i < inst->NumInOperands(); ++i) {
- uint32_t new_idx = GetNewMemberIndex(type_id, i);
- if (new_idx == kRemovedMember) {
- modified = true;
- } else {
- new_operands.emplace_back(inst->GetInOperand(i));
- }
- }
- inst->SetInOperands(std::move(new_operands));
- context()->UpdateDefUse(inst);
- return modified;
- }
- bool EliminateDeadMembersPass::UpdateAccessChain(Instruction* inst) {
- assert(inst->opcode() == spv::Op::OpAccessChain ||
- inst->opcode() == spv::Op::OpInBoundsAccessChain ||
- inst->opcode() == spv::Op::OpPtrAccessChain ||
- inst->opcode() == spv::Op::OpInBoundsPtrAccessChain);
- uint32_t pointer_id = inst->GetSingleWordInOperand(0);
- Instruction* pointer_inst = get_def_use_mgr()->GetDef(pointer_id);
- uint32_t pointer_type_id = pointer_inst->type_id();
- Instruction* pointer_type_inst = get_def_use_mgr()->GetDef(pointer_type_id);
- uint32_t type_id = pointer_type_inst->GetSingleWordInOperand(1);
- analysis::ConstantManager* const_mgr = context()->get_constant_mgr();
- Instruction::OperandList new_operands;
- bool modified = false;
- new_operands.emplace_back(inst->GetInOperand(0));
- // For pointer access chains we want to copy the element operand.
- if (inst->opcode() == spv::Op::OpPtrAccessChain ||
- inst->opcode() == spv::Op::OpInBoundsPtrAccessChain) {
- new_operands.emplace_back(inst->GetInOperand(1));
- }
- for (uint32_t i = static_cast<uint32_t>(new_operands.size());
- i < inst->NumInOperands(); ++i) {
- Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
- switch (type_inst->opcode()) {
- case spv::Op::OpTypeStruct: {
- const analysis::IntConstant* member_idx =
- const_mgr->FindDeclaredConstant(inst->GetSingleWordInOperand(i))
- ->AsIntConstant();
- assert(member_idx);
- uint32_t orig_member_idx =
- static_cast<uint32_t>(member_idx->GetZeroExtendedValue());
- uint32_t new_member_idx = GetNewMemberIndex(type_id, orig_member_idx);
- assert(new_member_idx != kRemovedMember);
- if (orig_member_idx != new_member_idx) {
- InstructionBuilder ir_builder(
- context(), inst,
- IRContext::kAnalysisDefUse |
- IRContext::kAnalysisInstrToBlockMapping);
- uint32_t const_id =
- ir_builder.GetUintConstant(new_member_idx)->result_id();
- new_operands.emplace_back(Operand({SPV_OPERAND_TYPE_ID, {const_id}}));
- modified = true;
- } else {
- new_operands.emplace_back(inst->GetInOperand(i));
- }
- // The type will have already been rewritten, so use the new member
- // index.
- type_id = type_inst->GetSingleWordInOperand(new_member_idx);
- } break;
- case spv::Op::OpTypeArray:
- case spv::Op::OpTypeRuntimeArray:
- case spv::Op::OpTypeVector:
- case spv::Op::OpTypeMatrix:
- case spv::Op::OpTypeCooperativeMatrixNV:
- case spv::Op::OpTypeCooperativeMatrixKHR:
- case spv::Op::OpTypeCooperativeVectorNV:
- new_operands.emplace_back(inst->GetInOperand(i));
- type_id = type_inst->GetSingleWordInOperand(0);
- break;
- default:
- assert(false);
- break;
- }
- }
- if (!modified) {
- return false;
- }
- inst->SetInOperands(std::move(new_operands));
- context()->UpdateDefUse(inst);
- return true;
- }
- uint32_t EliminateDeadMembersPass::GetNewMemberIndex(uint32_t type_id,
- uint32_t member_idx) {
- auto live_members = used_members_.find(type_id);
- if (live_members == used_members_.end()) {
- return member_idx;
- }
- auto current_member = live_members->second.find(member_idx);
- if (current_member == live_members->second.end()) {
- return kRemovedMember;
- }
- return static_cast<uint32_t>(
- std::distance(live_members->second.begin(), current_member));
- }
- bool EliminateDeadMembersPass::UpdateCompsiteExtract(Instruction* inst) {
- assert(inst->opcode() == spv::Op::OpCompositeExtract ||
- (inst->opcode() == spv::Op::OpSpecConstantOp &&
- spv::Op(inst->GetSingleWordInOperand(kSpecConstOpOpcodeIdx)) ==
- spv::Op::OpCompositeExtract));
- uint32_t first_operand = 0;
- if (inst->opcode() == spv::Op::OpSpecConstantOp) {
- first_operand = 1;
- }
- uint32_t object_id = inst->GetSingleWordInOperand(first_operand);
- Instruction* object_inst = get_def_use_mgr()->GetDef(object_id);
- uint32_t type_id = object_inst->type_id();
- Instruction::OperandList new_operands;
- bool modified = false;
- for (uint32_t i = 0; i < first_operand + 1; i++) {
- new_operands.emplace_back(inst->GetInOperand(i));
- }
- for (uint32_t i = first_operand + 1; i < inst->NumInOperands(); ++i) {
- uint32_t member_idx = inst->GetSingleWordInOperand(i);
- uint32_t new_member_idx = GetNewMemberIndex(type_id, member_idx);
- assert(new_member_idx != kRemovedMember);
- if (member_idx != new_member_idx) {
- modified = true;
- }
- new_operands.emplace_back(
- Operand({SPV_OPERAND_TYPE_LITERAL_INTEGER, {new_member_idx}}));
- Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
- switch (type_inst->opcode()) {
- case spv::Op::OpTypeStruct:
- // The type will have already been rewritten, so use the new member
- // index.
- type_id = type_inst->GetSingleWordInOperand(new_member_idx);
- break;
- case spv::Op::OpTypeArray:
- case spv::Op::OpTypeRuntimeArray:
- case spv::Op::OpTypeVector:
- case spv::Op::OpTypeMatrix:
- case spv::Op::OpTypeCooperativeMatrixNV:
- case spv::Op::OpTypeCooperativeMatrixKHR:
- case spv::Op::OpTypeCooperativeVectorNV:
- type_id = type_inst->GetSingleWordInOperand(0);
- break;
- default:
- assert(false);
- }
- }
- if (!modified) {
- return false;
- }
- inst->SetInOperands(std::move(new_operands));
- context()->UpdateDefUse(inst);
- return true;
- }
- bool EliminateDeadMembersPass::UpdateCompositeInsert(Instruction* inst) {
- assert(inst->opcode() == spv::Op::OpCompositeInsert ||
- (inst->opcode() == spv::Op::OpSpecConstantOp &&
- spv::Op(inst->GetSingleWordInOperand(kSpecConstOpOpcodeIdx)) ==
- spv::Op::OpCompositeInsert));
- uint32_t first_operand = 0;
- if (inst->opcode() == spv::Op::OpSpecConstantOp) {
- first_operand = 1;
- }
- uint32_t composite_id = inst->GetSingleWordInOperand(first_operand + 1);
- Instruction* composite_inst = get_def_use_mgr()->GetDef(composite_id);
- uint32_t type_id = composite_inst->type_id();
- Instruction::OperandList new_operands;
- bool modified = false;
- for (uint32_t i = 0; i < first_operand + 2; ++i) {
- new_operands.emplace_back(inst->GetInOperand(i));
- }
- for (uint32_t i = first_operand + 2; i < inst->NumInOperands(); ++i) {
- uint32_t member_idx = inst->GetSingleWordInOperand(i);
- uint32_t new_member_idx = GetNewMemberIndex(type_id, member_idx);
- if (new_member_idx == kRemovedMember) {
- context()->KillInst(inst);
- return true;
- }
- if (member_idx != new_member_idx) {
- modified = true;
- }
- new_operands.emplace_back(
- Operand({SPV_OPERAND_TYPE_LITERAL_INTEGER, {new_member_idx}}));
- Instruction* type_inst = get_def_use_mgr()->GetDef(type_id);
- switch (type_inst->opcode()) {
- case spv::Op::OpTypeStruct:
- // The type will have already been rewritten, so use the new member
- // index.
- type_id = type_inst->GetSingleWordInOperand(new_member_idx);
- break;
- case spv::Op::OpTypeArray:
- case spv::Op::OpTypeRuntimeArray:
- case spv::Op::OpTypeVector:
- case spv::Op::OpTypeMatrix:
- case spv::Op::OpTypeCooperativeMatrixNV:
- case spv::Op::OpTypeCooperativeMatrixKHR:
- case spv::Op::OpTypeCooperativeVectorNV:
- type_id = type_inst->GetSingleWordInOperand(0);
- break;
- default:
- assert(false);
- }
- }
- if (!modified) {
- return false;
- }
- inst->SetInOperands(std::move(new_operands));
- context()->UpdateDefUse(inst);
- return true;
- }
- bool EliminateDeadMembersPass::UpdateOpArrayLength(Instruction* inst) {
- uint32_t struct_id = inst->GetSingleWordInOperand(0);
- Instruction* struct_inst = get_def_use_mgr()->GetDef(struct_id);
- uint32_t pointer_type_id = struct_inst->type_id();
- Instruction* pointer_type_inst = get_def_use_mgr()->GetDef(pointer_type_id);
- uint32_t type_id = pointer_type_inst->GetSingleWordInOperand(1);
- uint32_t member_idx = inst->GetSingleWordInOperand(1);
- uint32_t new_member_idx = GetNewMemberIndex(type_id, member_idx);
- assert(new_member_idx != kRemovedMember);
- if (member_idx == new_member_idx) {
- return false;
- }
- inst->SetInOperand(1, {new_member_idx});
- context()->UpdateDefUse(inst);
- return true;
- }
- void EliminateDeadMembersPass::MarkStructOperandsAsFullyUsed(
- const Instruction* inst) {
- if (inst->type_id() != 0) {
- MarkTypeAsFullyUsed(inst->type_id());
- }
- inst->ForEachInId([this](const uint32_t* id) {
- Instruction* instruction = get_def_use_mgr()->GetDef(*id);
- if (instruction->type_id() != 0) {
- MarkTypeAsFullyUsed(instruction->type_id());
- }
- });
- }
- } // namespace opt
- } // namespace spvtools
|