SPIRV-Tools/source/opt/pass.cpp
Steven Perron efe12ff5a1 Have all MemPasses preserve the def-use manager.
Originally the passes that extended from MemPass were those that are
of the def-use manager.  I am assuming they would be able to preserve
it because of that.

Added a check to verify consistency of the IRContext. The IRContext
relies on the pass to tell it if something is invalidated.
It is possible that the pass lied.  To help identify those situations,
we will check if the valid analyses are correct after each pass.

This will be enabled by default for the debug build, and disabled in the
production build.  It can be disabled in the debug build by adding
"-DSPIRV_CHECK_CONTEXT=OFF" to the cmake command.
2017-11-10 11:17:12 -05:00

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), next_id_(0), 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