| // Copyright (c) 2017 The Khronos Group Inc. |
| // Copyright (c) 2017 Valve Corporation |
| // Copyright (c) 2017 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 "pass.h" |
| |
| #include "iterator.h" |
| |
| namespace spvtools { |
| 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(ir::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, ir::Module* module) { |
| // Map from function's result id to function |
| std::unordered_map<uint32_t, ir::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, |
| ir::IRContext* irContext) { |
| // Map from function's result id to function |
| std::unordered_map<uint32_t, ir::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, ir::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) { |
| ir::Function* fn = id2function.at(fi); |
| modified = pfn(fn) || modified; |
| AddCalls(fn, roots); |
| } |
| } |
| return modified; |
| } |
| |
| Pass::Status Pass::Run(ir::IRContext* ctx) { |
| if (already_run_) { |
| return Status::Failure; |
| } |
| already_run_ = true; |
| |
| Pass::Status status = Process(ctx); |
| if (status == Status::SuccessWithChange) { |
| ctx->InvalidateAnalysesExceptFor(GetPreservedAnalyses()); |
| } |
| assert(ctx->IsConsistent()); |
| return status; |
| } |
| |
| uint32_t Pass::GetPointeeTypeId(const ir::Instruction* ptrInst) const { |
| const uint32_t ptrTypeId = ptrInst->type_id(); |
| const ir::Instruction* ptrTypeInst = get_def_use_mgr()->GetDef(ptrTypeId); |
| return ptrTypeInst->GetSingleWordInOperand(kTypePointerTypeIdInIdx); |
| } |
| |
| } // namespace opt |
| } // namespace spvtools |