mirror of https://github.com/bkaradzic/bgfx
Updated spirv-tools.
This commit is contained in:
parent
7f7c8a9bc0
commit
bc166c21b5
|
@ -1 +1 @@
|
|||
"v2020.3-dev", "SPIRV-Tools v2020.3-dev ad8e2138c256f6fb0b38e883fe1ae0e2a59c7620"
|
||||
"v2020.3-dev", "SPIRV-Tools v2020.3-dev 7f7c8a9bc032be95861952467a66f0c77560ec04"
|
||||
|
|
|
@ -430,6 +430,9 @@ class FactManager::DataSynonymAndIdEquationFacts {
|
|||
uint32_t maximum_equivalence_class_size);
|
||||
|
||||
private:
|
||||
using OperationSet =
|
||||
std::unordered_set<Operation, OperationHash, OperationEquals>;
|
||||
|
||||
// Adds the synonym |dd1| = |dd2| to the set of managed facts, and recurses
|
||||
// into sub-components of the data descriptors, if they are composites, to
|
||||
// record that their components are pairwise-synonymous.
|
||||
|
@ -448,6 +451,8 @@ class FactManager::DataSynonymAndIdEquationFacts {
|
|||
opt::IRContext* context, const protobufs::DataDescriptor& dd1,
|
||||
const protobufs::DataDescriptor& dd2) const;
|
||||
|
||||
OperationSet GetEquations(const protobufs::DataDescriptor* lhs) const;
|
||||
|
||||
// Requires that |lhs_dd| and every element of |rhs_dds| is present in the
|
||||
// |synonymous_| equivalence relation, but is not necessarily its own
|
||||
// representative. Records the fact that the equation
|
||||
|
@ -480,9 +485,7 @@ class FactManager::DataSynonymAndIdEquationFacts {
|
|||
// All data descriptors occurring in equations are required to be present in
|
||||
// the |synonymous_| equivalence relation, and to be their own representatives
|
||||
// in that relation.
|
||||
std::unordered_map<
|
||||
const protobufs::DataDescriptor*,
|
||||
std::unordered_set<Operation, OperationHash, OperationEquals>>
|
||||
std::unordered_map<const protobufs::DataDescriptor*, OperationSet>
|
||||
id_equations_;
|
||||
};
|
||||
|
||||
|
@ -520,6 +523,16 @@ void FactManager::DataSynonymAndIdEquationFacts::AddFact(
|
|||
rhs_dd_ptrs, context);
|
||||
}
|
||||
|
||||
FactManager::DataSynonymAndIdEquationFacts::OperationSet
|
||||
FactManager::DataSynonymAndIdEquationFacts::GetEquations(
|
||||
const protobufs::DataDescriptor* lhs) const {
|
||||
auto existing = id_equations_.find(lhs);
|
||||
if (existing == id_equations_.end()) {
|
||||
return OperationSet();
|
||||
}
|
||||
return existing->second;
|
||||
}
|
||||
|
||||
void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||
const protobufs::DataDescriptor& lhs_dd, SpvOp opcode,
|
||||
const std::vector<const protobufs::DataDescriptor*>& rhs_dds,
|
||||
|
@ -538,9 +551,7 @@ void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
|||
if (id_equations_.count(lhs_dd_representative) == 0) {
|
||||
// We have not seen an equation with this LHS before, so associate the LHS
|
||||
// with an initially empty set.
|
||||
id_equations_.insert(
|
||||
{lhs_dd_representative,
|
||||
std::unordered_set<Operation, OperationHash, OperationEquals>()});
|
||||
id_equations_.insert({lhs_dd_representative, OperationSet()});
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -562,44 +573,29 @@ void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
|||
switch (opcode) {
|
||||
case SpvOpIAdd: {
|
||||
// Equation form: "a = b + c"
|
||||
{
|
||||
auto existing_first_operand_equations = id_equations_.find(rhs_dds[0]);
|
||||
if (existing_first_operand_equations != id_equations_.end()) {
|
||||
for (auto equation : existing_first_operand_equations->second) {
|
||||
if (equation.opcode == SpvOpISub) {
|
||||
// Equation form: "a = (d - e) + c"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[1],
|
||||
*rhs_dds[1])) {
|
||||
// Equation form: "a = (d - c) + c"
|
||||
// We can thus infer "a = d"
|
||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0],
|
||||
context);
|
||||
}
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0],
|
||||
*rhs_dds[1])) {
|
||||
// Equation form: "a = (c - e) + c"
|
||||
// We can thus infer "a = -e"
|
||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||
{equation.operands[1]}, context);
|
||||
}
|
||||
}
|
||||
for (auto equation : GetEquations(rhs_dds[0])) {
|
||||
if (equation.opcode == SpvOpISub) {
|
||||
// Equation form: "a = (d - e) + c"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[1])) {
|
||||
// Equation form: "a = (d - c) + c"
|
||||
// We can thus infer "a = d"
|
||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context);
|
||||
}
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) {
|
||||
// Equation form: "a = (c - e) + c"
|
||||
// We can thus infer "a = -e"
|
||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||
{equation.operands[1]}, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
auto existing_second_operand_equations = id_equations_.find(rhs_dds[1]);
|
||||
if (existing_second_operand_equations != id_equations_.end()) {
|
||||
for (auto equation : existing_second_operand_equations->second) {
|
||||
if (equation.opcode == SpvOpISub) {
|
||||
// Equation form: "a = b + (d - e)"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[1],
|
||||
*rhs_dds[0])) {
|
||||
// Equation form: "a = b + (d - b)"
|
||||
// We can thus infer "a = d"
|
||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0],
|
||||
context);
|
||||
}
|
||||
}
|
||||
for (auto equation : GetEquations(rhs_dds[1])) {
|
||||
if (equation.opcode == SpvOpISub) {
|
||||
// Equation form: "a = b + (d - e)"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[0])) {
|
||||
// Equation form: "a = b + (d - b)"
|
||||
// We can thus infer "a = d"
|
||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -607,73 +603,54 @@ void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
|||
}
|
||||
case SpvOpISub: {
|
||||
// Equation form: "a = b - c"
|
||||
{
|
||||
auto existing_first_operand_equations = id_equations_.find(rhs_dds[0]);
|
||||
if (existing_first_operand_equations != id_equations_.end()) {
|
||||
for (auto equation : existing_first_operand_equations->second) {
|
||||
if (equation.opcode == SpvOpIAdd) {
|
||||
// Equation form: "a = (d + e) - c"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0],
|
||||
*rhs_dds[1])) {
|
||||
// Equation form: "a = (c + e) - c"
|
||||
// We can thus infer "a = e"
|
||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1],
|
||||
context);
|
||||
}
|
||||
if (synonymous_.IsEquivalent(*equation.operands[1],
|
||||
*rhs_dds[1])) {
|
||||
// Equation form: "a = (d + c) - c"
|
||||
// We can thus infer "a = d"
|
||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0],
|
||||
context);
|
||||
}
|
||||
}
|
||||
for (auto equation : GetEquations(rhs_dds[0])) {
|
||||
if (equation.opcode == SpvOpIAdd) {
|
||||
// Equation form: "a = (d + e) - c"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) {
|
||||
// Equation form: "a = (c + e) - c"
|
||||
// We can thus infer "a = e"
|
||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1], context);
|
||||
}
|
||||
if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[1])) {
|
||||
// Equation form: "a = (d + c) - c"
|
||||
// We can thus infer "a = d"
|
||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context);
|
||||
}
|
||||
}
|
||||
|
||||
if (equation.opcode == SpvOpISub) {
|
||||
// Equation form: "a = (d - e) - c"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0],
|
||||
*rhs_dds[1])) {
|
||||
// Equation form: "a = (c - e) - c"
|
||||
// We can thus infer "a = -e"
|
||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||
{equation.operands[1]}, context);
|
||||
}
|
||||
}
|
||||
if (equation.opcode == SpvOpISub) {
|
||||
// Equation form: "a = (d - e) - c"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) {
|
||||
// Equation form: "a = (c - e) - c"
|
||||
// We can thus infer "a = -e"
|
||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||
{equation.operands[1]}, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto existing_second_operand_equations = id_equations_.find(rhs_dds[1]);
|
||||
if (existing_second_operand_equations != id_equations_.end()) {
|
||||
for (auto equation : existing_second_operand_equations->second) {
|
||||
if (equation.opcode == SpvOpIAdd) {
|
||||
// Equation form: "a = b - (d + e)"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0],
|
||||
*rhs_dds[0])) {
|
||||
// Equation form: "a = b - (b + e)"
|
||||
// We can thus infer "a = -e"
|
||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||
{equation.operands[1]}, context);
|
||||
}
|
||||
if (synonymous_.IsEquivalent(*equation.operands[1],
|
||||
*rhs_dds[0])) {
|
||||
// Equation form: "a = b - (d + b)"
|
||||
// We can thus infer "a = -d"
|
||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||
{equation.operands[0]}, context);
|
||||
}
|
||||
}
|
||||
if (equation.opcode == SpvOpISub) {
|
||||
// Equation form: "a = b - (d - e)"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0],
|
||||
*rhs_dds[0])) {
|
||||
// Equation form: "a = b - (b - e)"
|
||||
// We can thus infer "a = e"
|
||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1],
|
||||
context);
|
||||
}
|
||||
}
|
||||
for (auto equation : GetEquations(rhs_dds[1])) {
|
||||
if (equation.opcode == SpvOpIAdd) {
|
||||
// Equation form: "a = b - (d + e)"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[0])) {
|
||||
// Equation form: "a = b - (b + e)"
|
||||
// We can thus infer "a = -e"
|
||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||
{equation.operands[1]}, context);
|
||||
}
|
||||
if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[0])) {
|
||||
// Equation form: "a = b - (d + b)"
|
||||
// We can thus infer "a = -d"
|
||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||
{equation.operands[0]}, context);
|
||||
}
|
||||
}
|
||||
if (equation.opcode == SpvOpISub) {
|
||||
// Equation form: "a = b - (d - e)"
|
||||
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[0])) {
|
||||
// Equation form: "a = b - (b - e)"
|
||||
// We can thus infer "a = e"
|
||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1], context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -682,14 +659,11 @@ void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
|||
case SpvOpLogicalNot:
|
||||
case SpvOpSNegate: {
|
||||
// Equation form: "a = !b" or "a = -b"
|
||||
auto existing_equations = id_equations_.find(rhs_dds[0]);
|
||||
if (existing_equations != id_equations_.end()) {
|
||||
for (auto equation : existing_equations->second) {
|
||||
if (equation.opcode == opcode) {
|
||||
// Equation form: "a = !!b" or "a = -(-b)"
|
||||
// We can thus infer "a = b"
|
||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context);
|
||||
}
|
||||
for (auto equation : GetEquations(rhs_dds[0])) {
|
||||
if (equation.opcode == opcode) {
|
||||
// Equation form: "a = !!b" or "a = -(-b)"
|
||||
// We can thus infer "a = b"
|
||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1116,9 +1090,7 @@ void FactManager::DataSynonymAndIdEquationFacts::MakeEquivalent(
|
|||
// equations about |still_representative|; create an empty set of equations
|
||||
// if this is the case.
|
||||
if (!id_equations_.count(still_representative)) {
|
||||
id_equations_.insert(
|
||||
{still_representative,
|
||||
std::unordered_set<Operation, OperationHash, OperationEquals>()});
|
||||
id_equations_.insert({still_representative, OperationSet()});
|
||||
}
|
||||
auto still_representative_id_equations =
|
||||
id_equations_.find(still_representative);
|
||||
|
|
|
@ -68,9 +68,8 @@ void FuzzerPassAddStores::Apply() {
|
|||
// Not a pointer.
|
||||
return false;
|
||||
}
|
||||
if (type_inst->GetSingleWordInOperand(0) ==
|
||||
SpvStorageClassInput) {
|
||||
// Read-only: cannot store to it.
|
||||
if (instruction->IsReadOnlyPointer()) {
|
||||
// Read only: cannot store to it.
|
||||
return false;
|
||||
}
|
||||
switch (instruction->result_id()) {
|
||||
|
|
|
@ -107,7 +107,8 @@ Shrinker::ShrinkerResultStatus Shrinker::Run(
|
|||
}
|
||||
|
||||
// Initial binary should be valid.
|
||||
if (!tools.Validate(&binary_in[0], binary_in.size())) {
|
||||
if (!tools.Validate(&binary_in[0], binary_in.size(),
|
||||
impl_->validator_options)) {
|
||||
impl_->consumer(SPV_MSG_INFO, nullptr, {},
|
||||
"Initial binary is invalid; stopping.");
|
||||
return Shrinker::ShrinkerResultStatus::kInitialBinaryInvalid;
|
||||
|
|
|
@ -810,8 +810,10 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
|
|||
->GetType(index_type_inst->result_id())
|
||||
->AsInteger();
|
||||
|
||||
if (index_inst->opcode() != SpvOpConstant) {
|
||||
// The index is non-constant so we need to clamp it.
|
||||
if (index_inst->opcode() != SpvOpConstant ||
|
||||
index_inst->GetSingleWordInOperand(0) >= bound) {
|
||||
// The index is either non-constant or an out-of-bounds constant, so we
|
||||
// need to clamp it.
|
||||
assert(should_be_composite_type->opcode() != SpvOpTypeStruct &&
|
||||
"Access chain indices into structures are required to be "
|
||||
"constants.");
|
||||
|
@ -864,21 +866,6 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
|
|||
access_chain_inst->SetInOperand(index, {select_id});
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, compare_id);
|
||||
fuzzerutil::UpdateModuleIdBound(ir_context, select_id);
|
||||
} else {
|
||||
// TODO(afd): At present the SPIR-V spec is not clear on whether
|
||||
// statically out-of-bounds indices mean that a module is invalid (so
|
||||
// that it should be rejected by the validator), or that such accesses
|
||||
// yield undefined results. Via the following assertion, we assume that
|
||||
// functions added to the module do not feature statically out-of-bounds
|
||||
// accesses.
|
||||
// Assert that the index is smaller (unsigned) than this value.
|
||||
// Return false if it is not (to keep compilers happy).
|
||||
if (index_inst->GetSingleWordInOperand(0) >= bound) {
|
||||
assert(false &&
|
||||
"The function has a statically out-of-bounds access; "
|
||||
"this should not occur.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
should_be_composite_type =
|
||||
FollowCompositeIndex(ir_context, *should_be_composite_type, index_id);
|
||||
|
|
|
@ -200,21 +200,13 @@ bool TransformationOutlineFunction::IsApplicable(
|
|||
// It is OK (and typically expected) for the exit block of the region to
|
||||
// have successors outside the region.
|
||||
//
|
||||
// It is also OK for the exit block to head a structured control flow
|
||||
// construct - the block containing the call to the outlined function will
|
||||
// end up heading this construct if outlining takes place. However, we
|
||||
// must ensure that if the exit block heads a loop, the continue target
|
||||
// for this loop is outside the region.
|
||||
if (auto loop_merge = block.GetLoopMergeInst()) {
|
||||
// The exit block heads a loop
|
||||
auto continue_target =
|
||||
ir_context->cfg()->block(loop_merge->GetSingleWordOperand(1));
|
||||
if (region_set.count(continue_target)) {
|
||||
// The continue target for the loop is in the region.
|
||||
return false;
|
||||
}
|
||||
// It is also OK for the exit block to head a selection construct: the
|
||||
// block containing the call to the outlined function will end up heading
|
||||
// this construct if outlining takes place. However, it is not OK for
|
||||
// the exit block to head a loop construct.
|
||||
if (block.GetLoopMergeInst()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -170,6 +170,15 @@ bool TransformationReplaceIdWithSynonym::UseCanBeReplacedWithSynonym(
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_instruction->opcode() == SpvOpImageTexelPointer &&
|
||||
use_in_operand_index == 2) {
|
||||
// The OpImageTexelPointer instruction has a Sample parameter that in some
|
||||
// situations must be an id for the value 0. To guard against disrupting
|
||||
// that requirement, we do not replace this argument to that instruction.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ bool TransformationStore::IsApplicable(
|
|||
}
|
||||
|
||||
// The pointer must not be read only.
|
||||
if (pointer_type->GetSingleWordInOperand(0) == SpvStorageClassInput) {
|
||||
if (pointer->IsReadOnlyPointer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
|
|||
dead_variable_elimination.h
|
||||
decompose_initialized_variables_pass.h
|
||||
decoration_manager.h
|
||||
debug_info_manager.h
|
||||
def_use_manager.h
|
||||
desc_sroa.h
|
||||
dominator_analysis.h
|
||||
|
@ -141,6 +142,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
|
|||
dead_variable_elimination.cpp
|
||||
decompose_initialized_variables_pass.cpp
|
||||
decoration_manager.cpp
|
||||
debug_info_manager.cpp
|
||||
def_use_manager.cpp
|
||||
desc_sroa.cpp
|
||||
dominator_analysis.cpp
|
||||
|
|
|
@ -177,7 +177,7 @@ bool CodeSinkingPass::ReferencesMutableMemory(Instruction* inst) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (base_ptr->IsReadOnlyVariable()) {
|
||||
if (base_ptr->IsReadOnlyPointer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,208 @@
|
|||
// Copyright (c) 2020 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/debug_info_manager.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "source/opt/ir_context.h"
|
||||
|
||||
// Constants for OpenCL.DebugInfo.100 extension instructions.
|
||||
|
||||
static const uint32_t kOpLineOperandLineIndex = 1;
|
||||
static const uint32_t kLineOperandIndexDebugFunction = 7;
|
||||
static const uint32_t kLineOperandIndexDebugLexicalBlock = 5;
|
||||
static const uint32_t kDebugFunctionOperandFunctionIndex = 13;
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace analysis {
|
||||
|
||||
DebugInfoManager::DebugInfoManager(IRContext* c) : context_(c) {
|
||||
AnalyzeDebugInsts(*c->module());
|
||||
}
|
||||
|
||||
Instruction* DebugInfoManager::GetDbgInst(uint32_t id) {
|
||||
auto dbg_inst_it = id_to_dbg_inst_.find(id);
|
||||
return dbg_inst_it == id_to_dbg_inst_.end() ? nullptr : dbg_inst_it->second;
|
||||
}
|
||||
|
||||
void DebugInfoManager::RegisterDbgInst(Instruction* inst) {
|
||||
assert(
|
||||
inst->NumInOperands() != 0 &&
|
||||
context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() ==
|
||||
inst->GetInOperand(0).words[0] &&
|
||||
"Given instruction is not a debug instruction");
|
||||
id_to_dbg_inst_[inst->result_id()] = inst;
|
||||
}
|
||||
|
||||
void DebugInfoManager::RegisterDbgFunction(Instruction* inst) {
|
||||
assert(inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction &&
|
||||
"inst is not a DebugFunction");
|
||||
auto fn_id = inst->GetSingleWordOperand(kDebugFunctionOperandFunctionIndex);
|
||||
assert(
|
||||
fn_id_to_dbg_fn_.find(fn_id) == fn_id_to_dbg_fn_.end() &&
|
||||
"Register DebugFunction for a function that already has DebugFunction");
|
||||
fn_id_to_dbg_fn_[fn_id] = inst;
|
||||
}
|
||||
|
||||
uint32_t DebugInfoManager::CreateDebugInlinedAt(const Instruction* line,
|
||||
const DebugScope& scope) {
|
||||
if (context()->get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() ==
|
||||
0)
|
||||
return kNoInlinedAt;
|
||||
|
||||
uint32_t line_number = 0;
|
||||
if (line == nullptr) {
|
||||
auto* lexical_scope_inst = GetDbgInst(scope.GetLexicalScope());
|
||||
if (lexical_scope_inst == nullptr) return kNoInlinedAt;
|
||||
OpenCLDebugInfo100Instructions debug_opcode =
|
||||
lexical_scope_inst->GetOpenCL100DebugOpcode();
|
||||
switch (debug_opcode) {
|
||||
case OpenCLDebugInfo100DebugFunction:
|
||||
line_number = lexical_scope_inst->GetSingleWordOperand(
|
||||
kLineOperandIndexDebugFunction);
|
||||
break;
|
||||
case OpenCLDebugInfo100DebugLexicalBlock:
|
||||
line_number = lexical_scope_inst->GetSingleWordOperand(
|
||||
kLineOperandIndexDebugLexicalBlock);
|
||||
break;
|
||||
case OpenCLDebugInfo100DebugTypeComposite:
|
||||
case OpenCLDebugInfo100DebugCompilationUnit:
|
||||
assert(false &&
|
||||
"DebugTypeComposite and DebugCompilationUnit are lexical "
|
||||
"scopes, but we inline functions into a function or a block "
|
||||
"of a function, not into a struct/class or a global scope.");
|
||||
break;
|
||||
default:
|
||||
assert(false &&
|
||||
"Unreachable. a debug extension instruction for a "
|
||||
"lexical scope must be DebugFunction, DebugTypeComposite, "
|
||||
"DebugLexicalBlock, or DebugCompilationUnit.");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
line_number = line->GetSingleWordOperand(kOpLineOperandLineIndex);
|
||||
}
|
||||
|
||||
uint32_t result_id = context()->TakeNextId();
|
||||
std::unique_ptr<Instruction> inlined_at(new Instruction(
|
||||
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
|
||||
result_id,
|
||||
{
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID,
|
||||
{context()
|
||||
->get_feature_mgr()
|
||||
->GetExtInstImportId_OpenCL100DebugInfo()}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100DebugInlinedAt)}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_LITERAL_INTEGER, {line_number}},
|
||||
{spv_operand_type_t::SPV_OPERAND_TYPE_ID, {scope.GetLexicalScope()}},
|
||||
}));
|
||||
// |scope| already has DebugInlinedAt. We put the existing DebugInlinedAt
|
||||
// into the Inlined operand of this new DebugInlinedAt.
|
||||
if (scope.GetInlinedAt() != kNoInlinedAt) {
|
||||
inlined_at->AddOperand({spv_operand_type_t::SPV_OPERAND_TYPE_RESULT_ID,
|
||||
{scope.GetInlinedAt()}});
|
||||
}
|
||||
RegisterDbgInst(inlined_at.get());
|
||||
context()->module()->AddExtInstDebugInfo(std::move(inlined_at));
|
||||
return result_id;
|
||||
}
|
||||
|
||||
Instruction* DebugInfoManager::GetDebugInfoNone() {
|
||||
if (debug_info_none_inst_ != nullptr) return debug_info_none_inst_;
|
||||
|
||||
uint32_t result_id = context()->TakeNextId();
|
||||
std::unique_ptr<Instruction> dbg_info_none_inst(new Instruction(
|
||||
context(), SpvOpExtInst, context()->get_type_mgr()->GetVoidTypeId(),
|
||||
result_id,
|
||||
{
|
||||
{SPV_OPERAND_TYPE_RESULT_ID,
|
||||
{context()
|
||||
->get_feature_mgr()
|
||||
->GetExtInstImportId_OpenCL100DebugInfo()}},
|
||||
{SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100DebugInfoNone)}},
|
||||
}));
|
||||
|
||||
// Add to the front of |ext_inst_debuginfo_|.
|
||||
debug_info_none_inst_ =
|
||||
context()->module()->ext_inst_debuginfo_begin()->InsertBefore(
|
||||
std::move(dbg_info_none_inst));
|
||||
|
||||
RegisterDbgInst(debug_info_none_inst_);
|
||||
return debug_info_none_inst_;
|
||||
}
|
||||
|
||||
Instruction* DebugInfoManager::GetDebugInlinedAt(uint32_t dbg_inlined_at_id) {
|
||||
auto* inlined_at = GetDbgInst(dbg_inlined_at_id);
|
||||
if (inlined_at == nullptr) return nullptr;
|
||||
if (inlined_at->GetOpenCL100DebugOpcode() !=
|
||||
OpenCLDebugInfo100DebugInlinedAt) {
|
||||
return nullptr;
|
||||
}
|
||||
return inlined_at;
|
||||
}
|
||||
|
||||
Instruction* DebugInfoManager::CloneDebugInlinedAt(uint32_t clone_inlined_at_id,
|
||||
Instruction* insert_before) {
|
||||
auto* inlined_at = GetDebugInlinedAt(clone_inlined_at_id);
|
||||
if (inlined_at == nullptr) return nullptr;
|
||||
std::unique_ptr<Instruction> new_inlined_at(inlined_at->Clone(context()));
|
||||
new_inlined_at->SetResultId(context()->TakeNextId());
|
||||
RegisterDbgInst(new_inlined_at.get());
|
||||
if (insert_before != nullptr)
|
||||
return insert_before->InsertBefore(std::move(new_inlined_at));
|
||||
return context()->module()->ext_inst_debuginfo_end()->InsertBefore(
|
||||
std::move(new_inlined_at));
|
||||
}
|
||||
|
||||
void DebugInfoManager::AnalyzeDebugInst(Instruction* dbg_inst) {
|
||||
if (dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100InstructionsMax)
|
||||
return;
|
||||
|
||||
RegisterDbgInst(dbg_inst);
|
||||
|
||||
if (dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugFunction) {
|
||||
assert(GetDebugFunction(dbg_inst->GetSingleWordOperand(
|
||||
kDebugFunctionOperandFunctionIndex)) == nullptr &&
|
||||
"Two DebugFunction instruction exists for a single OpFunction.");
|
||||
RegisterDbgFunction(dbg_inst);
|
||||
}
|
||||
|
||||
if (debug_info_none_inst_ == nullptr &&
|
||||
dbg_inst->GetOpenCL100DebugOpcode() == OpenCLDebugInfo100DebugInfoNone) {
|
||||
debug_info_none_inst_ = dbg_inst;
|
||||
}
|
||||
}
|
||||
|
||||
void DebugInfoManager::AnalyzeDebugInsts(Module& module) {
|
||||
debug_info_none_inst_ = nullptr;
|
||||
module.ForEachInst([this](Instruction* cpi) { AnalyzeDebugInst(cpi); });
|
||||
|
||||
// Move |debug_info_none_inst_| to the beginning of the debug instruction
|
||||
// list.
|
||||
if (debug_info_none_inst_ != nullptr &&
|
||||
debug_info_none_inst_->PreviousNode() != nullptr &&
|
||||
debug_info_none_inst_->PreviousNode()->GetOpenCL100DebugOpcode() !=
|
||||
OpenCLDebugInfo100InstructionsMax) {
|
||||
debug_info_none_inst_->InsertBefore(
|
||||
&*context()->module()->ext_inst_debuginfo_begin());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace analysis
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) 2020 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.
|
||||
|
||||
#ifndef SOURCE_OPT_DEBUG_INFO_MANAGER_H_
|
||||
#define SOURCE_OPT_DEBUG_INFO_MANAGER_H_
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "source/opt/instruction.h"
|
||||
#include "source/opt/module.h"
|
||||
|
||||
namespace spvtools {
|
||||
namespace opt {
|
||||
namespace analysis {
|
||||
|
||||
// A class for analyzing, managing, and creating OpenCL.DebugInfo.100 extension
|
||||
// instructions.
|
||||
class DebugInfoManager {
|
||||
public:
|
||||
// Constructs a debug information manager from the given |context|.
|
||||
DebugInfoManager(IRContext* context);
|
||||
|
||||
DebugInfoManager(const DebugInfoManager&) = delete;
|
||||
DebugInfoManager(DebugInfoManager&&) = delete;
|
||||
DebugInfoManager& operator=(const DebugInfoManager&) = delete;
|
||||
DebugInfoManager& operator=(DebugInfoManager&&) = delete;
|
||||
|
||||
friend bool operator==(const DebugInfoManager&, const DebugInfoManager&);
|
||||
friend bool operator!=(const DebugInfoManager& lhs,
|
||||
const DebugInfoManager& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
// Analyzes OpenCL.DebugInfo.100 instruction |dbg_inst|.
|
||||
void AnalyzeDebugInst(Instruction* dbg_inst);
|
||||
|
||||
// Creates new DebugInlinedAt and returns its id. Its line operand is the
|
||||
// line number of |line| if |line| is not nullptr. Otherwise, its line operand
|
||||
// is the line number of lexical scope of |scope|. Its Scope and Inlined
|
||||
// operands are Scope and Inlined of |scope|.
|
||||
uint32_t CreateDebugInlinedAt(const Instruction* line,
|
||||
const DebugScope& scope);
|
||||
|
||||
// Returns a DebugInfoNone instruction.
|
||||
Instruction* GetDebugInfoNone();
|
||||
|
||||
// Returns DebugInlinedAt whose id is |dbg_inlined_at_id|. If it does not
|
||||
// exist or it is not a DebugInlinedAt instruction, return nullptr.
|
||||
Instruction* GetDebugInlinedAt(uint32_t dbg_inlined_at_id);
|
||||
|
||||
// Returns DebugFunction whose Function operand is |fn_id|. If it does not
|
||||
// exist, return nullptr.
|
||||
Instruction* GetDebugFunction(uint32_t fn_id) {
|
||||
auto dbg_fn_it = fn_id_to_dbg_fn_.find(fn_id);
|
||||
return dbg_fn_it == fn_id_to_dbg_fn_.end() ? nullptr : dbg_fn_it->second;
|
||||
}
|
||||
|
||||
// Clones DebugInlinedAt whose id is |clone_inlined_at_id|. If
|
||||
// |clone_inlined_at_id| is not an id of DebugInlinedAt, returns nullptr.
|
||||
// If |insert_before| is given, inserts the new DebugInlinedAt before it.
|
||||
// Otherwise, inserts the new DebugInlinedAt into the debug instruction
|
||||
// section of the module.
|
||||
Instruction* CloneDebugInlinedAt(uint32_t clone_inlined_at_id,
|
||||
Instruction* insert_before = nullptr);
|
||||
|
||||
private:
|
||||
IRContext* context() { return context_; }
|
||||
|
||||
// Analyzes OpenCL.DebugInfo.100 instructions in the given |module| and
|
||||
// populates data structures in this class.
|
||||
void AnalyzeDebugInsts(Module& module);
|
||||
|
||||
// Returns the debug instruction whose id is |id|. Returns |nullptr| if one
|
||||
// does not exists.
|
||||
Instruction* GetDbgInst(uint32_t id);
|
||||
|
||||
// Registers the debug instruction |inst| into |id_to_dbg_inst_| using id of
|
||||
// |inst| as a key.
|
||||
void RegisterDbgInst(Instruction* inst);
|
||||
|
||||
// Register the DebugFunction instruction |inst|. The function referenced
|
||||
// in |inst| must not already be registered.
|
||||
void RegisterDbgFunction(Instruction* inst);
|
||||
|
||||
IRContext* context_;
|
||||
|
||||
// Mapping from ids of OpenCL.DebugInfo.100 extension instructions
|
||||
// to their Instruction instances.
|
||||
std::unordered_map<uint32_t, Instruction*> id_to_dbg_inst_;
|
||||
|
||||
// Mapping from function's ids to DebugFunction instructions whose
|
||||
// operand is the function.
|
||||
std::unordered_map<uint32_t, Instruction*> fn_id_to_dbg_fn_;
|
||||
|
||||
// DebugInfoNone instruction. We need only a single DebugInfoNone.
|
||||
// To reuse the existing one, we keep it using this member variable.
|
||||
Instruction* debug_info_none_inst_;
|
||||
};
|
||||
|
||||
} // namespace analysis
|
||||
} // namespace opt
|
||||
} // namespace spvtools
|
||||
|
||||
#endif // SOURCE_OPT_DEBUG_INFO_MANAGER_H_
|
|
@ -192,13 +192,13 @@ inline void Function::AddBasicBlocks(T src_begin, T src_end, iterator ip) {
|
|||
}
|
||||
|
||||
inline void Function::MoveBasicBlockToAfter(uint32_t id, BasicBlock* ip) {
|
||||
auto block_to_move = std::move(*FindBlock(id).Get());
|
||||
std::unique_ptr<BasicBlock> block_to_move = std::move(*FindBlock(id).Get());
|
||||
blocks_.erase(std::find(std::begin(blocks_), std::end(blocks_), nullptr));
|
||||
|
||||
assert(block_to_move->GetParent() == ip->GetParent() &&
|
||||
"Both blocks have to be in the same function.");
|
||||
|
||||
InsertBasicBlockAfter(std::move(block_to_move), ip);
|
||||
blocks_.erase(std::find(std::begin(blocks_), std::end(blocks_), nullptr));
|
||||
}
|
||||
|
||||
inline void Function::RemoveEmptyBlocks() {
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace {
|
|||
// Indices used to get particular operands out of instructions using InOperand.
|
||||
const uint32_t kTypeImageDimIndex = 1;
|
||||
const uint32_t kLoadBaseIndex = 0;
|
||||
const uint32_t kVariableStorageClassIndex = 0;
|
||||
const uint32_t kPointerTypeStorageClassIndex = 0;
|
||||
const uint32_t kTypeImageSampledIndex = 5;
|
||||
|
||||
// Constants for OpenCL.DebugInfo.100 extension instructions.
|
||||
|
@ -187,7 +187,7 @@ bool Instruction::IsReadOnlyLoad() const {
|
|||
}
|
||||
|
||||
if (address_def->opcode() == SpvOpVariable) {
|
||||
if (address_def->IsReadOnlyVariable()) {
|
||||
if (address_def->IsReadOnlyPointer()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -232,11 +232,11 @@ Instruction* Instruction::GetBaseAddress() const {
|
|||
return base_inst;
|
||||
}
|
||||
|
||||
bool Instruction::IsReadOnlyVariable() const {
|
||||
bool Instruction::IsReadOnlyPointer() const {
|
||||
if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
|
||||
return IsReadOnlyVariableShaders();
|
||||
return IsReadOnlyPointerShaders();
|
||||
else
|
||||
return IsReadOnlyVariableKernel();
|
||||
return IsReadOnlyPointerKernel();
|
||||
}
|
||||
|
||||
bool Instruction::IsVulkanStorageImage() const {
|
||||
|
@ -244,7 +244,8 @@ bool Instruction::IsVulkanStorageImage() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
||||
uint32_t storage_class =
|
||||
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
|
||||
if (storage_class != SpvStorageClassUniformConstant) {
|
||||
return false;
|
||||
}
|
||||
|
@ -278,7 +279,8 @@ bool Instruction::IsVulkanSampledImage() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
||||
uint32_t storage_class =
|
||||
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
|
||||
if (storage_class != SpvStorageClassUniformConstant) {
|
||||
return false;
|
||||
}
|
||||
|
@ -312,7 +314,8 @@ bool Instruction::IsVulkanStorageTexelBuffer() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
||||
uint32_t storage_class =
|
||||
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
|
||||
if (storage_class != SpvStorageClassUniformConstant) {
|
||||
return false;
|
||||
}
|
||||
|
@ -361,7 +364,8 @@ bool Instruction::IsVulkanStorageBuffer() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
||||
uint32_t storage_class =
|
||||
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
|
||||
if (storage_class == SpvStorageClassUniform) {
|
||||
bool is_buffer_block = false;
|
||||
context()->get_decoration_mgr()->ForEachDecoration(
|
||||
|
@ -383,7 +387,8 @@ bool Instruction::IsVulkanUniformBuffer() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
||||
uint32_t storage_class =
|
||||
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
|
||||
if (storage_class != SpvStorageClassUniform) {
|
||||
return false;
|
||||
}
|
||||
|
@ -409,9 +414,18 @@ bool Instruction::IsVulkanUniformBuffer() const {
|
|||
return is_block;
|
||||
}
|
||||
|
||||
bool Instruction::IsReadOnlyVariableShaders() const {
|
||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
||||
bool Instruction::IsReadOnlyPointerShaders() const {
|
||||
if (type_id() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
|
||||
if (type_def->opcode() != SpvOpTypePointer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t storage_class =
|
||||
type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex);
|
||||
|
||||
switch (storage_class) {
|
||||
case SpvStorageClassUniformConstant:
|
||||
|
@ -439,8 +453,19 @@ bool Instruction::IsReadOnlyVariableShaders() const {
|
|||
return is_nonwritable;
|
||||
}
|
||||
|
||||
bool Instruction::IsReadOnlyVariableKernel() const {
|
||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
||||
bool Instruction::IsReadOnlyPointerKernel() const {
|
||||
if (type_id() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
|
||||
if (type_def->opcode() != SpvOpTypePointer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t storage_class =
|
||||
type_def->GetSingleWordInOperand(kPointerTypeStorageClassIndex);
|
||||
|
||||
return storage_class == SpvStorageClassUniformConstant;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,19 @@ struct Operand {
|
|||
// Returns a string operand as a std::string.
|
||||
std::string AsString() const { return AsCString(); }
|
||||
|
||||
// Returns a literal integer operand as a uint64_t
|
||||
uint64_t AsLiteralUint64() const {
|
||||
assert(type == SPV_OPERAND_TYPE_TYPED_LITERAL_NUMBER);
|
||||
assert(1 <= words.size());
|
||||
assert(words.size() <= 2);
|
||||
// Load the low word.
|
||||
uint64_t result = uint64_t(words[0]);
|
||||
if (words.size() > 1) {
|
||||
result = result | (uint64_t(words[1]) << 32);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
friend bool operator==(const Operand& o1, const Operand& o2) {
|
||||
return o1.type == o2.type && o1.words == o2.words;
|
||||
}
|
||||
|
@ -383,8 +396,14 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
|
|||
// Memory-to-memory instructions are not considered loads.
|
||||
inline bool IsLoad() const;
|
||||
|
||||
// Returns true if the instruction declares a variable that is read-only.
|
||||
bool IsReadOnlyVariable() const;
|
||||
// Returns true if the instruction generates a pointer that is definitely
|
||||
// read-only. This is determined by analysing the pointer type's storage
|
||||
// class and decorations that target the pointer's id. It does not analyse
|
||||
// other instructions that the pointer may be derived from. Thus if 'true' is
|
||||
// returned, the pointer is definitely read-only, while if 'false' is returned
|
||||
// it is possible that the pointer may actually be read-only if it is derived
|
||||
// from another pointer that is decorated as read-only.
|
||||
bool IsReadOnlyPointer() const;
|
||||
|
||||
// The following functions check for the various descriptor types defined in
|
||||
// the Vulkan specification section 13.1.
|
||||
|
@ -513,11 +532,12 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Returns true if the instruction declares a variable that is read-only. The
|
||||
// first version assumes the module is a shader module. The second assumes a
|
||||
// Returns true if the instruction generates a read-only pointer, with the
|
||||
// same caveats documented in the comment for IsReadOnlyPointer. The first
|
||||
// version assumes the module is a shader module. The second assumes a
|
||||
// kernel.
|
||||
bool IsReadOnlyVariableShaders() const;
|
||||
bool IsReadOnlyVariableKernel() const;
|
||||
bool IsReadOnlyPointerShaders() const;
|
||||
bool IsReadOnlyPointerKernel() const;
|
||||
|
||||
// Returns true if the result of |inst| can be used as the base image for an
|
||||
// instruction that samples a image, reads an image, or writes to an image.
|
||||
|
|
|
@ -85,6 +85,9 @@ void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) {
|
|||
if (set & kAnalysisTypes) {
|
||||
BuildTypeManager();
|
||||
}
|
||||
if (set & kAnalysisDebugInfo) {
|
||||
BuildDebugInfoManager();
|
||||
}
|
||||
}
|
||||
|
||||
void IRContext::InvalidateAnalysesExceptFor(
|
||||
|
@ -98,6 +101,7 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
|
|||
// away, the ConstantManager has to go away.
|
||||
if (analyses_to_invalidate & kAnalysisTypes) {
|
||||
analyses_to_invalidate |= kAnalysisConstants;
|
||||
analyses_to_invalidate |= kAnalysisDebugInfo;
|
||||
}
|
||||
|
||||
// The dominator analysis hold the psuedo entry and exit nodes from the CFG.
|
||||
|
@ -148,6 +152,10 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
|
|||
type_mgr_.reset(nullptr);
|
||||
}
|
||||
|
||||
if (analyses_to_invalidate & kAnalysisDebugInfo) {
|
||||
debug_info_mgr_.reset(nullptr);
|
||||
}
|
||||
|
||||
valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate);
|
||||
}
|
||||
|
||||
|
@ -373,27 +381,6 @@ void IRContext::KillNamesAndDecorates(Instruction* inst) {
|
|||
KillNamesAndDecorates(rId);
|
||||
}
|
||||
|
||||
Instruction* IRContext::GetOpenCL100DebugInfoNone() {
|
||||
if (debug_info_none_inst_) return debug_info_none_inst_;
|
||||
assert(get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo() &&
|
||||
"Module does not include debug info extension instruction.");
|
||||
|
||||
// Create a new DebugInfoNone.
|
||||
std::unique_ptr<Instruction> dbg_info_none(new Instruction(
|
||||
this, SpvOpExtInst, get_type_mgr()->GetVoidTypeId(), TakeNextId(),
|
||||
{
|
||||
{SPV_OPERAND_TYPE_RESULT_ID,
|
||||
{get_feature_mgr()->GetExtInstImportId_OpenCL100DebugInfo()}},
|
||||
{SPV_OPERAND_TYPE_EXTENSION_INSTRUCTION_NUMBER,
|
||||
{static_cast<uint32_t>(OpenCLDebugInfo100DebugInfoNone)}},
|
||||
}));
|
||||
|
||||
// Add to the front of |ext_inst_debuginfo_|.
|
||||
debug_info_none_inst_ = module()->ext_inst_debuginfo_begin()->InsertBefore(
|
||||
std::move(dbg_info_none));
|
||||
return debug_info_none_inst_;
|
||||
}
|
||||
|
||||
void IRContext::KillOperandFromDebugInstructions(Instruction* inst) {
|
||||
const auto opcode = inst->opcode();
|
||||
const uint32_t id = inst->result_id();
|
||||
|
@ -405,7 +392,8 @@ void IRContext::KillOperandFromDebugInstructions(Instruction* inst) {
|
|||
continue;
|
||||
auto& operand = it->GetOperand(kDebugFunctionOperandFunctionIndex);
|
||||
if (operand.words[0] == id) {
|
||||
operand.words[0] = GetOpenCL100DebugInfoNone()->result_id();
|
||||
operand.words[0] =
|
||||
get_debug_info_mgr()->GetDebugInfoNone()->result_id();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -418,7 +406,8 @@ void IRContext::KillOperandFromDebugInstructions(Instruction* inst) {
|
|||
continue;
|
||||
auto& operand = it->GetOperand(kDebugGlobalVariableOperandVariableIndex);
|
||||
if (operand.words[0] == id) {
|
||||
operand.words[0] = GetOpenCL100DebugInfoNone()->result_id();
|
||||
operand.words[0] =
|
||||
get_debug_info_mgr()->GetDebugInfoNone()->result_id();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "source/assembly_grammar.h"
|
||||
#include "source/opt/cfg.h"
|
||||
#include "source/opt/constants.h"
|
||||
#include "source/opt/debug_info_manager.h"
|
||||
#include "source/opt/decoration_manager.h"
|
||||
#include "source/opt/def_use_manager.h"
|
||||
#include "source/opt/dominator_analysis.h"
|
||||
|
@ -78,7 +79,8 @@ class IRContext {
|
|||
kAnalysisIdToFuncMapping = 1 << 13,
|
||||
kAnalysisConstants = 1 << 14,
|
||||
kAnalysisTypes = 1 << 15,
|
||||
kAnalysisEnd = 1 << 16
|
||||
kAnalysisDebugInfo = 1 << 16,
|
||||
kAnalysisEnd = 1 << 17
|
||||
};
|
||||
|
||||
using ProcessFunction = std::function<bool(Function*)>;
|
||||
|
@ -102,8 +104,7 @@ class IRContext {
|
|||
id_to_name_(nullptr),
|
||||
max_id_bound_(kDefaultMaxIdBound),
|
||||
preserve_bindings_(false),
|
||||
preserve_spec_constants_(false),
|
||||
debug_info_none_inst_(nullptr) {
|
||||
preserve_spec_constants_(false) {
|
||||
SetContextMessageConsumer(syntax_context_, consumer_);
|
||||
module_->SetContext(this);
|
||||
}
|
||||
|
@ -120,8 +121,7 @@ class IRContext {
|
|||
id_to_name_(nullptr),
|
||||
max_id_bound_(kDefaultMaxIdBound),
|
||||
preserve_bindings_(false),
|
||||
preserve_spec_constants_(false),
|
||||
debug_info_none_inst_(nullptr) {
|
||||
preserve_spec_constants_(false) {
|
||||
SetContextMessageConsumer(syntax_context_, consumer_);
|
||||
module_->SetContext(this);
|
||||
InitializeCombinators();
|
||||
|
@ -328,6 +328,17 @@ class IRContext {
|
|||
return type_mgr_.get();
|
||||
}
|
||||
|
||||
// Returns a pointer to the debug information manager. If no debug
|
||||
// information manager has been created yet, it creates one.
|
||||
// NOTE: Once created, the debug information manager remains active
|
||||
// it is never re-built.
|
||||
analysis::DebugInfoManager* get_debug_info_mgr() {
|
||||
if (!AreAnalysesValid(kAnalysisDebugInfo)) {
|
||||
BuildDebugInfoManager();
|
||||
}
|
||||
return debug_info_mgr_.get();
|
||||
}
|
||||
|
||||
// Returns a pointer to the scalar evolution analysis. If it is invalid it
|
||||
// will be rebuilt first.
|
||||
ScalarEvolutionAnalysis* GetScalarEvolutionAnalysis() {
|
||||
|
@ -657,6 +668,13 @@ class IRContext {
|
|||
valid_analyses_ = valid_analyses_ | kAnalysisTypes;
|
||||
}
|
||||
|
||||
// Builds the debug information manager from scratch, even if it was
|
||||
// already valid.
|
||||
void BuildDebugInfoManager() {
|
||||
debug_info_mgr_ = MakeUnique<analysis::DebugInfoManager>(this);
|
||||
valid_analyses_ = valid_analyses_ | kAnalysisDebugInfo;
|
||||
}
|
||||
|
||||
// Removes all computed dominator and post-dominator trees. This will force
|
||||
// the context to rebuild the trees on demand.
|
||||
void ResetDominatorAnalysis() {
|
||||
|
@ -710,9 +728,6 @@ class IRContext {
|
|||
// Add |var_id| to all entry points in module.
|
||||
void AddVarToEntryPoints(uint32_t var_id);
|
||||
|
||||
// Get the existing DebugInfoNone. If it is null, create one and keep it.
|
||||
Instruction* GetOpenCL100DebugInfoNone();
|
||||
|
||||
// The SPIR-V syntax context containing grammar tables for opcodes and
|
||||
// operands.
|
||||
spv_context syntax_context_;
|
||||
|
@ -782,6 +797,9 @@ class IRContext {
|
|||
// Type manager for |module_|.
|
||||
std::unique_ptr<analysis::TypeManager> type_mgr_;
|
||||
|
||||
// Debug information manager for |module_|.
|
||||
std::unique_ptr<analysis::DebugInfoManager> debug_info_mgr_;
|
||||
|
||||
// A map from an id to its corresponding OpName and OpMemberName instructions.
|
||||
std::unique_ptr<std::multimap<uint32_t, Instruction*>> id_to_name_;
|
||||
|
||||
|
@ -806,10 +824,6 @@ class IRContext {
|
|||
// Whether all specialization constants within |module_|
|
||||
// should be preserved.
|
||||
bool preserve_spec_constants_;
|
||||
|
||||
// DebugInfoNone instruction. We need only a single DebugInfoNone.
|
||||
// To reuse the existing one, we keep it using this member variable.
|
||||
Instruction* debug_info_none_inst_;
|
||||
};
|
||||
|
||||
inline IRContext::Analysis operator|(IRContext::Analysis lhs,
|
||||
|
|
|
@ -135,6 +135,8 @@ bool IrLoader::AddInstruction(const spv_parsed_instruction_t* inst) {
|
|||
Error(consumer_, src, loc, "terminator instruction outside basic block");
|
||||
return false;
|
||||
}
|
||||
if (last_dbg_scope_.GetLexicalScope() != kNoDebugScope)
|
||||
spv_inst->SetDebugScope(last_dbg_scope_);
|
||||
block_->AddInstruction(std::move(spv_inst));
|
||||
function_->AddBasicBlock(std::move(block_));
|
||||
block_ = nullptr;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
namespace {
|
||||
// The default maximum number of steps the reducer will take before giving up.
|
||||
const uint32_t kDefaultStepLimit = 250;
|
||||
const uint32_t kDefaultStepLimit = 2500;
|
||||
} // namespace
|
||||
|
||||
spv_reducer_options_t::spv_reducer_options_t()
|
||||
|
|
Loading…
Reference in New Issue