mirror of
https://github.com/KhronosGroup/SPIRV-Tools
synced 2024-11-30 15:00:06 +00:00
241dcacc04
This patch adds a new constant manager class to interface with analysis::Constant. The new constant manager lives in ir::IRContext together with the type manager (analysis::TypeManager). The new analysis::ConstantManager is used by the spec constant folder and the constant propagator (in progress). Another cleanup introduced by this patch removes the ID management from the fold spec constant pass, and ir::IRContext and moves it to ir::Module. SSA IDs were maintained by IRContext and Module. That's pointless and leads to mismatch IDs. Fixed by moving all the bookkeeping to ir::Module.
122 lines
4.0 KiB
C++
122 lines
4.0 KiB
C++
// 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) {}
|
|
|
|
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) {
|
|
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
|