diff options
Diffstat (limited to '3rdparty/bgfx/3rdparty/spirv-tools/source/opt/pass.cpp')
-rw-r--r-- | 3rdparty/bgfx/3rdparty/spirv-tools/source/opt/pass.cpp | 174 |
1 files changed, 100 insertions, 74 deletions
diff --git a/3rdparty/bgfx/3rdparty/spirv-tools/source/opt/pass.cpp b/3rdparty/bgfx/3rdparty/spirv-tools/source/opt/pass.cpp index 4c4a232c6c5..09b78af933c 100644 --- a/3rdparty/bgfx/3rdparty/spirv-tools/source/opt/pass.cpp +++ b/3rdparty/bgfx/3rdparty/spirv-tools/source/opt/pass.cpp @@ -16,6 +16,7 @@ #include "source/opt/pass.h" +#include "source/opt/ir_builder.h" #include "source/opt/iterator.h" namespace spvtools { @@ -23,85 +24,12 @@ namespace opt { namespace { -const uint32_t kEntryPointFunctionIdInIdx = 1; const uint32_t kTypePointerTypeIdInIdx = 1; } // namespace Pass::Pass() : consumer_(nullptr), context_(nullptr), already_run_(false) {} -void Pass::AddCalls(Function* func, std::queue<uint32_t>* todo) { - for (auto bi = func->begin(); bi != func->end(); ++bi) - for (auto ii = bi->begin(); ii != bi->end(); ++ii) - if (ii->opcode() == SpvOpFunctionCall) - todo->push(ii->GetSingleWordInOperand(0)); -} - -bool Pass::ProcessEntryPointCallTree(ProcessFunction& pfn, Module* module) { - // Map from function's result id to function - std::unordered_map<uint32_t, Function*> id2function; - for (auto& fn : *module) id2function[fn.result_id()] = &fn; - - // Collect all of the entry points as the roots. - std::queue<uint32_t> roots; - for (auto& e : module->entry_points()) - roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx)); - return ProcessCallTreeFromRoots(pfn, id2function, &roots); -} - -bool Pass::ProcessReachableCallTree(ProcessFunction& pfn, - IRContext* irContext) { - // Map from function's result id to function - std::unordered_map<uint32_t, Function*> id2function; - for (auto& fn : *irContext->module()) id2function[fn.result_id()] = &fn; - - std::queue<uint32_t> roots; - - // Add all entry points since they can be reached from outside the module. - for (auto& e : irContext->module()->entry_points()) - roots.push(e.GetSingleWordInOperand(kEntryPointFunctionIdInIdx)); - - // Add all exported functions since they can be reached from outside the - // module. - for (auto& a : irContext->annotations()) { - // TODO: Handle group decorations as well. Currently not generate by any - // front-end, but could be coming. - if (a.opcode() == SpvOp::SpvOpDecorate) { - if (a.GetSingleWordOperand(1) == - SpvDecoration::SpvDecorationLinkageAttributes) { - uint32_t lastOperand = a.NumOperands() - 1; - if (a.GetSingleWordOperand(lastOperand) == - SpvLinkageType::SpvLinkageTypeExport) { - uint32_t id = a.GetSingleWordOperand(0); - if (id2function.count(id) != 0) roots.push(id); - } - } - } - } - - return ProcessCallTreeFromRoots(pfn, id2function, &roots); -} - -bool Pass::ProcessCallTreeFromRoots( - ProcessFunction& pfn, - const std::unordered_map<uint32_t, Function*>& id2function, - std::queue<uint32_t>* roots) { - // Process call tree - bool modified = false; - std::unordered_set<uint32_t> done; - - while (!roots->empty()) { - const uint32_t fi = roots->front(); - roots->pop(); - if (done.insert(fi).second) { - Function* fn = id2function.at(fi); - modified = pfn(fn) || modified; - AddCalls(fn, roots); - } - } - return modified; -} - Pass::Status Pass::Run(IRContext* ctx) { if (already_run_) { return Status::Failure; @@ -115,7 +43,8 @@ Pass::Status Pass::Run(IRContext* ctx) { if (status == Status::SuccessWithChange) { ctx->InvalidateAnalysesExceptFor(GetPreservedAnalyses()); } - assert(ctx->IsConsistent()); + assert((status == Status::Failure || ctx->IsConsistent()) && + "An analysis in the context is out of date."); return status; } @@ -125,5 +54,102 @@ uint32_t Pass::GetPointeeTypeId(const Instruction* ptrInst) const { return ptrTypeInst->GetSingleWordInOperand(kTypePointerTypeIdInIdx); } +Instruction* Pass::GetBaseType(uint32_t ty_id) { + Instruction* ty_inst = get_def_use_mgr()->GetDef(ty_id); + if (ty_inst->opcode() == SpvOpTypeMatrix) { + uint32_t vty_id = ty_inst->GetSingleWordInOperand(0); + ty_inst = get_def_use_mgr()->GetDef(vty_id); + } + if (ty_inst->opcode() == SpvOpTypeVector) { + uint32_t cty_id = ty_inst->GetSingleWordInOperand(0); + ty_inst = get_def_use_mgr()->GetDef(cty_id); + } + return ty_inst; +} + +bool Pass::IsFloat(uint32_t ty_id, uint32_t width) { + Instruction* ty_inst = GetBaseType(ty_id); + if (ty_inst->opcode() != SpvOpTypeFloat) return false; + return ty_inst->GetSingleWordInOperand(0) == width; +} + +uint32_t Pass::GetNullId(uint32_t type_id) { + if (IsFloat(type_id, 16)) context()->AddCapability(SpvCapabilityFloat16); + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); + const analysis::Type* type = type_mgr->GetType(type_id); + const analysis::Constant* null_const = const_mgr->GetConstant(type, {}); + Instruction* null_inst = + const_mgr->GetDefiningInstruction(null_const, type_id); + return null_inst->result_id(); +} + +uint32_t Pass::GenerateCopy(Instruction* object_to_copy, uint32_t new_type_id, + Instruction* insertion_position) { + analysis::TypeManager* type_mgr = context()->get_type_mgr(); + analysis::ConstantManager* const_mgr = context()->get_constant_mgr(); + + uint32_t original_type_id = object_to_copy->type_id(); + if (original_type_id == new_type_id) { + return object_to_copy->result_id(); + } + + InstructionBuilder ir_builder( + context(), insertion_position, + IRContext::kAnalysisInstrToBlockMapping | IRContext::kAnalysisDefUse); + + analysis::Type* original_type = type_mgr->GetType(original_type_id); + analysis::Type* new_type = type_mgr->GetType(new_type_id); + + if (const analysis::Array* original_array_type = original_type->AsArray()) { + uint32_t original_element_type_id = + type_mgr->GetId(original_array_type->element_type()); + + analysis::Array* new_array_type = new_type->AsArray(); + assert(new_array_type != nullptr && "Can't copy an array to a non-array."); + uint32_t new_element_type_id = + type_mgr->GetId(new_array_type->element_type()); + + std::vector<uint32_t> element_ids; + const analysis::Constant* length_const = + const_mgr->FindDeclaredConstant(original_array_type->LengthId()); + assert(length_const->AsIntConstant()); + uint32_t array_length = length_const->AsIntConstant()->GetU32(); + for (uint32_t i = 0; i < array_length; i++) { + Instruction* extract = ir_builder.AddCompositeExtract( + original_element_type_id, object_to_copy->result_id(), {i}); + element_ids.push_back( + GenerateCopy(extract, new_element_type_id, insertion_position)); + } + + return ir_builder.AddCompositeConstruct(new_type_id, element_ids) + ->result_id(); + } else if (const analysis::Struct* original_struct_type = + original_type->AsStruct()) { + analysis::Struct* new_struct_type = new_type->AsStruct(); + + const std::vector<const analysis::Type*>& original_types = + original_struct_type->element_types(); + const std::vector<const analysis::Type*>& new_types = + new_struct_type->element_types(); + std::vector<uint32_t> element_ids; + for (uint32_t i = 0; i < original_types.size(); i++) { + Instruction* extract = ir_builder.AddCompositeExtract( + type_mgr->GetId(original_types[i]), object_to_copy->result_id(), {i}); + element_ids.push_back(GenerateCopy(extract, type_mgr->GetId(new_types[i]), + insertion_position)); + } + return ir_builder.AddCompositeConstruct(new_type_id, element_ids) + ->result_id(); + } else { + // If we do not have an aggregate type, then we have a problem. Either we + // found multiple instances of the same type, or we are copying to an + // incompatible type. Either way the code is illegal. + assert(false && + "Don't know how to copy this type. Code is likely illegal."); + } + return 0; +} + } // namespace opt } // namespace spvtools |