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);
|
uint32_t maximum_equivalence_class_size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using OperationSet =
|
||||||
|
std::unordered_set<Operation, OperationHash, OperationEquals>;
|
||||||
|
|
||||||
// Adds the synonym |dd1| = |dd2| to the set of managed facts, and recurses
|
// 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
|
// into sub-components of the data descriptors, if they are composites, to
|
||||||
// record that their components are pairwise-synonymous.
|
// record that their components are pairwise-synonymous.
|
||||||
|
@ -448,6 +451,8 @@ class FactManager::DataSynonymAndIdEquationFacts {
|
||||||
opt::IRContext* context, const protobufs::DataDescriptor& dd1,
|
opt::IRContext* context, const protobufs::DataDescriptor& dd1,
|
||||||
const protobufs::DataDescriptor& dd2) const;
|
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
|
// Requires that |lhs_dd| and every element of |rhs_dds| is present in the
|
||||||
// |synonymous_| equivalence relation, but is not necessarily its own
|
// |synonymous_| equivalence relation, but is not necessarily its own
|
||||||
// representative. Records the fact that the equation
|
// 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
|
// All data descriptors occurring in equations are required to be present in
|
||||||
// the |synonymous_| equivalence relation, and to be their own representatives
|
// the |synonymous_| equivalence relation, and to be their own representatives
|
||||||
// in that relation.
|
// in that relation.
|
||||||
std::unordered_map<
|
std::unordered_map<const protobufs::DataDescriptor*, OperationSet>
|
||||||
const protobufs::DataDescriptor*,
|
|
||||||
std::unordered_set<Operation, OperationHash, OperationEquals>>
|
|
||||||
id_equations_;
|
id_equations_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -520,6 +523,16 @@ void FactManager::DataSynonymAndIdEquationFacts::AddFact(
|
||||||
rhs_dd_ptrs, context);
|
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(
|
void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||||
const protobufs::DataDescriptor& lhs_dd, SpvOp opcode,
|
const protobufs::DataDescriptor& lhs_dd, SpvOp opcode,
|
||||||
const std::vector<const protobufs::DataDescriptor*>& rhs_dds,
|
const std::vector<const protobufs::DataDescriptor*>& rhs_dds,
|
||||||
|
@ -538,9 +551,7 @@ void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||||
if (id_equations_.count(lhs_dd_representative) == 0) {
|
if (id_equations_.count(lhs_dd_representative) == 0) {
|
||||||
// We have not seen an equation with this LHS before, so associate the LHS
|
// We have not seen an equation with this LHS before, so associate the LHS
|
||||||
// with an initially empty set.
|
// with an initially empty set.
|
||||||
id_equations_.insert(
|
id_equations_.insert({lhs_dd_representative, OperationSet()});
|
||||||
{lhs_dd_representative,
|
|
||||||
std::unordered_set<Operation, OperationHash, OperationEquals>()});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -562,44 +573,29 @@ void FactManager::DataSynonymAndIdEquationFacts::AddEquationFactRecursive(
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case SpvOpIAdd: {
|
case SpvOpIAdd: {
|
||||||
// Equation form: "a = b + c"
|
// Equation form: "a = b + c"
|
||||||
{
|
for (auto equation : GetEquations(rhs_dds[0])) {
|
||||||
auto existing_first_operand_equations = id_equations_.find(rhs_dds[0]);
|
if (equation.opcode == SpvOpISub) {
|
||||||
if (existing_first_operand_equations != id_equations_.end()) {
|
// Equation form: "a = (d - e) + c"
|
||||||
for (auto equation : existing_first_operand_equations->second) {
|
if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[1])) {
|
||||||
if (equation.opcode == SpvOpISub) {
|
// Equation form: "a = (d - c) + c"
|
||||||
// Equation form: "a = (d - e) + c"
|
// We can thus infer "a = d"
|
||||||
if (synonymous_.IsEquivalent(*equation.operands[1],
|
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context);
|
||||||
*rhs_dds[1])) {
|
}
|
||||||
// Equation form: "a = (d - c) + c"
|
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) {
|
||||||
// We can thus infer "a = d"
|
// Equation form: "a = (c - e) + c"
|
||||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0],
|
// We can thus infer "a = -e"
|
||||||
context);
|
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||||
}
|
{equation.operands[1]}, 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[1])) {
|
||||||
auto existing_second_operand_equations = id_equations_.find(rhs_dds[1]);
|
if (equation.opcode == SpvOpISub) {
|
||||||
if (existing_second_operand_equations != id_equations_.end()) {
|
// Equation form: "a = b + (d - e)"
|
||||||
for (auto equation : existing_second_operand_equations->second) {
|
if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[0])) {
|
||||||
if (equation.opcode == SpvOpISub) {
|
// Equation form: "a = b + (d - b)"
|
||||||
// Equation form: "a = b + (d - e)"
|
// We can thus infer "a = d"
|
||||||
if (synonymous_.IsEquivalent(*equation.operands[1],
|
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context);
|
||||||
*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: {
|
case SpvOpISub: {
|
||||||
// Equation form: "a = b - c"
|
// Equation form: "a = b - c"
|
||||||
{
|
for (auto equation : GetEquations(rhs_dds[0])) {
|
||||||
auto existing_first_operand_equations = id_equations_.find(rhs_dds[0]);
|
if (equation.opcode == SpvOpIAdd) {
|
||||||
if (existing_first_operand_equations != id_equations_.end()) {
|
// Equation form: "a = (d + e) - c"
|
||||||
for (auto equation : existing_first_operand_equations->second) {
|
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) {
|
||||||
if (equation.opcode == SpvOpIAdd) {
|
// Equation form: "a = (c + e) - c"
|
||||||
// Equation form: "a = (d + e) - c"
|
// We can thus infer "a = e"
|
||||||
if (synonymous_.IsEquivalent(*equation.operands[0],
|
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1], context);
|
||||||
*rhs_dds[1])) {
|
}
|
||||||
// Equation form: "a = (c + e) - c"
|
if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[1])) {
|
||||||
// We can thus infer "a = e"
|
// Equation form: "a = (d + c) - c"
|
||||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1],
|
// We can thus infer "a = d"
|
||||||
context);
|
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], 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) {
|
if (equation.opcode == SpvOpISub) {
|
||||||
// Equation form: "a = (d - e) - c"
|
// Equation form: "a = (d - e) - c"
|
||||||
if (synonymous_.IsEquivalent(*equation.operands[0],
|
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[1])) {
|
||||||
*rhs_dds[1])) {
|
// Equation form: "a = (c - e) - c"
|
||||||
// Equation form: "a = (c - e) - c"
|
// We can thus infer "a = -e"
|
||||||
// We can thus infer "a = -e"
|
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
{equation.operands[1]}, context);
|
||||||
{equation.operands[1]}, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
for (auto equation : GetEquations(rhs_dds[1])) {
|
||||||
auto existing_second_operand_equations = id_equations_.find(rhs_dds[1]);
|
if (equation.opcode == SpvOpIAdd) {
|
||||||
if (existing_second_operand_equations != id_equations_.end()) {
|
// Equation form: "a = b - (d + e)"
|
||||||
for (auto equation : existing_second_operand_equations->second) {
|
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[0])) {
|
||||||
if (equation.opcode == SpvOpIAdd) {
|
// Equation form: "a = b - (b + e)"
|
||||||
// Equation form: "a = b - (d + e)"
|
// We can thus infer "a = -e"
|
||||||
if (synonymous_.IsEquivalent(*equation.operands[0],
|
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||||
*rhs_dds[0])) {
|
{equation.operands[1]}, context);
|
||||||
// Equation form: "a = b - (b + e)"
|
}
|
||||||
// We can thus infer "a = -e"
|
if (synonymous_.IsEquivalent(*equation.operands[1], *rhs_dds[0])) {
|
||||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
// Equation form: "a = b - (d + b)"
|
||||||
{equation.operands[1]}, context);
|
// We can thus infer "a = -d"
|
||||||
}
|
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
||||||
if (synonymous_.IsEquivalent(*equation.operands[1],
|
{equation.operands[0]}, context);
|
||||||
*rhs_dds[0])) {
|
}
|
||||||
// Equation form: "a = b - (d + b)"
|
}
|
||||||
// We can thus infer "a = -d"
|
if (equation.opcode == SpvOpISub) {
|
||||||
AddEquationFactRecursive(lhs_dd, SpvOpSNegate,
|
// Equation form: "a = b - (d - e)"
|
||||||
{equation.operands[0]}, context);
|
if (synonymous_.IsEquivalent(*equation.operands[0], *rhs_dds[0])) {
|
||||||
}
|
// Equation form: "a = b - (b - e)"
|
||||||
}
|
// We can thus infer "a = e"
|
||||||
if (equation.opcode == SpvOpISub) {
|
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[1], context);
|
||||||
// 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 SpvOpLogicalNot:
|
||||||
case SpvOpSNegate: {
|
case SpvOpSNegate: {
|
||||||
// Equation form: "a = !b" or "a = -b"
|
// Equation form: "a = !b" or "a = -b"
|
||||||
auto existing_equations = id_equations_.find(rhs_dds[0]);
|
for (auto equation : GetEquations(rhs_dds[0])) {
|
||||||
if (existing_equations != id_equations_.end()) {
|
if (equation.opcode == opcode) {
|
||||||
for (auto equation : existing_equations->second) {
|
// Equation form: "a = !!b" or "a = -(-b)"
|
||||||
if (equation.opcode == opcode) {
|
// We can thus infer "a = b"
|
||||||
// Equation form: "a = !!b" or "a = -(-b)"
|
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context);
|
||||||
// We can thus infer "a = b"
|
|
||||||
AddDataSynonymFactRecursive(lhs_dd, *equation.operands[0], context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1116,9 +1090,7 @@ void FactManager::DataSynonymAndIdEquationFacts::MakeEquivalent(
|
||||||
// equations about |still_representative|; create an empty set of equations
|
// equations about |still_representative|; create an empty set of equations
|
||||||
// if this is the case.
|
// if this is the case.
|
||||||
if (!id_equations_.count(still_representative)) {
|
if (!id_equations_.count(still_representative)) {
|
||||||
id_equations_.insert(
|
id_equations_.insert({still_representative, OperationSet()});
|
||||||
{still_representative,
|
|
||||||
std::unordered_set<Operation, OperationHash, OperationEquals>()});
|
|
||||||
}
|
}
|
||||||
auto still_representative_id_equations =
|
auto still_representative_id_equations =
|
||||||
id_equations_.find(still_representative);
|
id_equations_.find(still_representative);
|
||||||
|
|
|
@ -68,9 +68,8 @@ void FuzzerPassAddStores::Apply() {
|
||||||
// Not a pointer.
|
// Not a pointer.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (type_inst->GetSingleWordInOperand(0) ==
|
if (instruction->IsReadOnlyPointer()) {
|
||||||
SpvStorageClassInput) {
|
// Read only: cannot store to it.
|
||||||
// Read-only: cannot store to it.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (instruction->result_id()) {
|
switch (instruction->result_id()) {
|
||||||
|
|
|
@ -107,7 +107,8 @@ Shrinker::ShrinkerResultStatus Shrinker::Run(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial binary should be valid.
|
// 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, {},
|
impl_->consumer(SPV_MSG_INFO, nullptr, {},
|
||||||
"Initial binary is invalid; stopping.");
|
"Initial binary is invalid; stopping.");
|
||||||
return Shrinker::ShrinkerResultStatus::kInitialBinaryInvalid;
|
return Shrinker::ShrinkerResultStatus::kInitialBinaryInvalid;
|
||||||
|
|
|
@ -810,8 +810,10 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
|
||||||
->GetType(index_type_inst->result_id())
|
->GetType(index_type_inst->result_id())
|
||||||
->AsInteger();
|
->AsInteger();
|
||||||
|
|
||||||
if (index_inst->opcode() != SpvOpConstant) {
|
if (index_inst->opcode() != SpvOpConstant ||
|
||||||
// The index is non-constant so we need to clamp it.
|
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 &&
|
assert(should_be_composite_type->opcode() != SpvOpTypeStruct &&
|
||||||
"Access chain indices into structures are required to be "
|
"Access chain indices into structures are required to be "
|
||||||
"constants.");
|
"constants.");
|
||||||
|
@ -864,21 +866,6 @@ bool TransformationAddFunction::TryToClampAccessChainIndices(
|
||||||
access_chain_inst->SetInOperand(index, {select_id});
|
access_chain_inst->SetInOperand(index, {select_id});
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, compare_id);
|
fuzzerutil::UpdateModuleIdBound(ir_context, compare_id);
|
||||||
fuzzerutil::UpdateModuleIdBound(ir_context, select_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 =
|
should_be_composite_type =
|
||||||
FollowCompositeIndex(ir_context, *should_be_composite_type, index_id);
|
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
|
// It is OK (and typically expected) for the exit block of the region to
|
||||||
// have successors outside the region.
|
// have successors outside the region.
|
||||||
//
|
//
|
||||||
// It is also OK for the exit block to head a structured control flow
|
// It is also OK for the exit block to head a selection construct: the
|
||||||
// construct - the block containing the call to the outlined function will
|
// block containing the call to the outlined function will end up heading
|
||||||
// end up heading this construct if outlining takes place. However, we
|
// this construct if outlining takes place. However, it is not OK for
|
||||||
// must ensure that if the exit block heads a loop, the continue target
|
// the exit block to head a loop construct.
|
||||||
// for this loop is outside the region.
|
if (block.GetLoopMergeInst()) {
|
||||||
if (auto loop_merge = block.GetLoopMergeInst()) {
|
return false;
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,6 +170,15 @@ bool TransformationReplaceIdWithSynonym::UseCanBeReplacedWithSynonym(
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ bool TransformationStore::IsApplicable(
|
||||||
}
|
}
|
||||||
|
|
||||||
// The pointer must not be read only.
|
// The pointer must not be read only.
|
||||||
if (pointer_type->GetSingleWordInOperand(0) == SpvStorageClassInput) {
|
if (pointer->IsReadOnlyPointer()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
|
||||||
dead_variable_elimination.h
|
dead_variable_elimination.h
|
||||||
decompose_initialized_variables_pass.h
|
decompose_initialized_variables_pass.h
|
||||||
decoration_manager.h
|
decoration_manager.h
|
||||||
|
debug_info_manager.h
|
||||||
def_use_manager.h
|
def_use_manager.h
|
||||||
desc_sroa.h
|
desc_sroa.h
|
||||||
dominator_analysis.h
|
dominator_analysis.h
|
||||||
|
@ -141,6 +142,7 @@ set(SPIRV_TOOLS_OPT_SOURCES
|
||||||
dead_variable_elimination.cpp
|
dead_variable_elimination.cpp
|
||||||
decompose_initialized_variables_pass.cpp
|
decompose_initialized_variables_pass.cpp
|
||||||
decoration_manager.cpp
|
decoration_manager.cpp
|
||||||
|
debug_info_manager.cpp
|
||||||
def_use_manager.cpp
|
def_use_manager.cpp
|
||||||
desc_sroa.cpp
|
desc_sroa.cpp
|
||||||
dominator_analysis.cpp
|
dominator_analysis.cpp
|
||||||
|
|
|
@ -177,7 +177,7 @@ bool CodeSinkingPass::ReferencesMutableMemory(Instruction* inst) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base_ptr->IsReadOnlyVariable()) {
|
if (base_ptr->IsReadOnlyPointer()) {
|
||||||
return false;
|
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) {
|
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() &&
|
assert(block_to_move->GetParent() == ip->GetParent() &&
|
||||||
"Both blocks have to be in the same function.");
|
"Both blocks have to be in the same function.");
|
||||||
|
|
||||||
InsertBasicBlockAfter(std::move(block_to_move), ip);
|
InsertBasicBlockAfter(std::move(block_to_move), ip);
|
||||||
blocks_.erase(std::find(std::begin(blocks_), std::end(blocks_), nullptr));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Function::RemoveEmptyBlocks() {
|
inline void Function::RemoveEmptyBlocks() {
|
||||||
|
|
|
@ -29,7 +29,7 @@ namespace {
|
||||||
// Indices used to get particular operands out of instructions using InOperand.
|
// Indices used to get particular operands out of instructions using InOperand.
|
||||||
const uint32_t kTypeImageDimIndex = 1;
|
const uint32_t kTypeImageDimIndex = 1;
|
||||||
const uint32_t kLoadBaseIndex = 0;
|
const uint32_t kLoadBaseIndex = 0;
|
||||||
const uint32_t kVariableStorageClassIndex = 0;
|
const uint32_t kPointerTypeStorageClassIndex = 0;
|
||||||
const uint32_t kTypeImageSampledIndex = 5;
|
const uint32_t kTypeImageSampledIndex = 5;
|
||||||
|
|
||||||
// Constants for OpenCL.DebugInfo.100 extension instructions.
|
// Constants for OpenCL.DebugInfo.100 extension instructions.
|
||||||
|
@ -187,7 +187,7 @@ bool Instruction::IsReadOnlyLoad() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address_def->opcode() == SpvOpVariable) {
|
if (address_def->opcode() == SpvOpVariable) {
|
||||||
if (address_def->IsReadOnlyVariable()) {
|
if (address_def->IsReadOnlyPointer()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -232,11 +232,11 @@ Instruction* Instruction::GetBaseAddress() const {
|
||||||
return base_inst;
|
return base_inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Instruction::IsReadOnlyVariable() const {
|
bool Instruction::IsReadOnlyPointer() const {
|
||||||
if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
|
if (context()->get_feature_mgr()->HasCapability(SpvCapabilityShader))
|
||||||
return IsReadOnlyVariableShaders();
|
return IsReadOnlyPointerShaders();
|
||||||
else
|
else
|
||||||
return IsReadOnlyVariableKernel();
|
return IsReadOnlyPointerKernel();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Instruction::IsVulkanStorageImage() const {
|
bool Instruction::IsVulkanStorageImage() const {
|
||||||
|
@ -244,7 +244,8 @@ bool Instruction::IsVulkanStorageImage() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
uint32_t storage_class =
|
||||||
|
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
|
||||||
if (storage_class != SpvStorageClassUniformConstant) {
|
if (storage_class != SpvStorageClassUniformConstant) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -278,7 +279,8 @@ bool Instruction::IsVulkanSampledImage() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
uint32_t storage_class =
|
||||||
|
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
|
||||||
if (storage_class != SpvStorageClassUniformConstant) {
|
if (storage_class != SpvStorageClassUniformConstant) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -312,7 +314,8 @@ bool Instruction::IsVulkanStorageTexelBuffer() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
uint32_t storage_class =
|
||||||
|
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
|
||||||
if (storage_class != SpvStorageClassUniformConstant) {
|
if (storage_class != SpvStorageClassUniformConstant) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -361,7 +364,8 @@ bool Instruction::IsVulkanStorageBuffer() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
uint32_t storage_class =
|
||||||
|
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
|
||||||
if (storage_class == SpvStorageClassUniform) {
|
if (storage_class == SpvStorageClassUniform) {
|
||||||
bool is_buffer_block = false;
|
bool is_buffer_block = false;
|
||||||
context()->get_decoration_mgr()->ForEachDecoration(
|
context()->get_decoration_mgr()->ForEachDecoration(
|
||||||
|
@ -383,7 +387,8 @@ bool Instruction::IsVulkanUniformBuffer() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
uint32_t storage_class =
|
||||||
|
GetSingleWordInOperand(kPointerTypeStorageClassIndex);
|
||||||
if (storage_class != SpvStorageClassUniform) {
|
if (storage_class != SpvStorageClassUniform) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -409,9 +414,18 @@ bool Instruction::IsVulkanUniformBuffer() const {
|
||||||
return is_block;
|
return is_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Instruction::IsReadOnlyVariableShaders() const {
|
bool Instruction::IsReadOnlyPointerShaders() const {
|
||||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
if (type_id() == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Instruction* type_def = context()->get_def_use_mgr()->GetDef(type_id());
|
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) {
|
switch (storage_class) {
|
||||||
case SpvStorageClassUniformConstant:
|
case SpvStorageClassUniformConstant:
|
||||||
|
@ -439,8 +453,19 @@ bool Instruction::IsReadOnlyVariableShaders() const {
|
||||||
return is_nonwritable;
|
return is_nonwritable;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Instruction::IsReadOnlyVariableKernel() const {
|
bool Instruction::IsReadOnlyPointerKernel() const {
|
||||||
uint32_t storage_class = GetSingleWordInOperand(kVariableStorageClassIndex);
|
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;
|
return storage_class == SpvStorageClassUniformConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,19 @@ struct Operand {
|
||||||
// Returns a string operand as a std::string.
|
// Returns a string operand as a std::string.
|
||||||
std::string AsString() const { return AsCString(); }
|
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) {
|
friend bool operator==(const Operand& o1, const Operand& o2) {
|
||||||
return o1.type == o2.type && o1.words == o2.words;
|
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.
|
// Memory-to-memory instructions are not considered loads.
|
||||||
inline bool IsLoad() const;
|
inline bool IsLoad() const;
|
||||||
|
|
||||||
// Returns true if the instruction declares a variable that is read-only.
|
// Returns true if the instruction generates a pointer that is definitely
|
||||||
bool IsReadOnlyVariable() const;
|
// 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 following functions check for the various descriptor types defined in
|
||||||
// the Vulkan specification section 13.1.
|
// the Vulkan specification section 13.1.
|
||||||
|
@ -513,11 +532,12 @@ class Instruction : public utils::IntrusiveNodeBase<Instruction> {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the instruction declares a variable that is read-only. The
|
// Returns true if the instruction generates a read-only pointer, with the
|
||||||
// first version assumes the module is a shader module. The second assumes a
|
// same caveats documented in the comment for IsReadOnlyPointer. The first
|
||||||
|
// version assumes the module is a shader module. The second assumes a
|
||||||
// kernel.
|
// kernel.
|
||||||
bool IsReadOnlyVariableShaders() const;
|
bool IsReadOnlyPointerShaders() const;
|
||||||
bool IsReadOnlyVariableKernel() const;
|
bool IsReadOnlyPointerKernel() const;
|
||||||
|
|
||||||
// Returns true if the result of |inst| can be used as the base image for an
|
// 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.
|
// 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) {
|
if (set & kAnalysisTypes) {
|
||||||
BuildTypeManager();
|
BuildTypeManager();
|
||||||
}
|
}
|
||||||
|
if (set & kAnalysisDebugInfo) {
|
||||||
|
BuildDebugInfoManager();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IRContext::InvalidateAnalysesExceptFor(
|
void IRContext::InvalidateAnalysesExceptFor(
|
||||||
|
@ -98,6 +101,7 @@ void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
|
||||||
// away, the ConstantManager has to go away.
|
// away, the ConstantManager has to go away.
|
||||||
if (analyses_to_invalidate & kAnalysisTypes) {
|
if (analyses_to_invalidate & kAnalysisTypes) {
|
||||||
analyses_to_invalidate |= kAnalysisConstants;
|
analyses_to_invalidate |= kAnalysisConstants;
|
||||||
|
analyses_to_invalidate |= kAnalysisDebugInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The dominator analysis hold the psuedo entry and exit nodes from the CFG.
|
// 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);
|
type_mgr_.reset(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (analyses_to_invalidate & kAnalysisDebugInfo) {
|
||||||
|
debug_info_mgr_.reset(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate);
|
valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,27 +381,6 @@ void IRContext::KillNamesAndDecorates(Instruction* inst) {
|
||||||
KillNamesAndDecorates(rId);
|
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) {
|
void IRContext::KillOperandFromDebugInstructions(Instruction* inst) {
|
||||||
const auto opcode = inst->opcode();
|
const auto opcode = inst->opcode();
|
||||||
const uint32_t id = inst->result_id();
|
const uint32_t id = inst->result_id();
|
||||||
|
@ -405,7 +392,8 @@ void IRContext::KillOperandFromDebugInstructions(Instruction* inst) {
|
||||||
continue;
|
continue;
|
||||||
auto& operand = it->GetOperand(kDebugFunctionOperandFunctionIndex);
|
auto& operand = it->GetOperand(kDebugFunctionOperandFunctionIndex);
|
||||||
if (operand.words[0] == id) {
|
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;
|
continue;
|
||||||
auto& operand = it->GetOperand(kDebugGlobalVariableOperandVariableIndex);
|
auto& operand = it->GetOperand(kDebugGlobalVariableOperandVariableIndex);
|
||||||
if (operand.words[0] == id) {
|
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/assembly_grammar.h"
|
||||||
#include "source/opt/cfg.h"
|
#include "source/opt/cfg.h"
|
||||||
#include "source/opt/constants.h"
|
#include "source/opt/constants.h"
|
||||||
|
#include "source/opt/debug_info_manager.h"
|
||||||
#include "source/opt/decoration_manager.h"
|
#include "source/opt/decoration_manager.h"
|
||||||
#include "source/opt/def_use_manager.h"
|
#include "source/opt/def_use_manager.h"
|
||||||
#include "source/opt/dominator_analysis.h"
|
#include "source/opt/dominator_analysis.h"
|
||||||
|
@ -78,7 +79,8 @@ class IRContext {
|
||||||
kAnalysisIdToFuncMapping = 1 << 13,
|
kAnalysisIdToFuncMapping = 1 << 13,
|
||||||
kAnalysisConstants = 1 << 14,
|
kAnalysisConstants = 1 << 14,
|
||||||
kAnalysisTypes = 1 << 15,
|
kAnalysisTypes = 1 << 15,
|
||||||
kAnalysisEnd = 1 << 16
|
kAnalysisDebugInfo = 1 << 16,
|
||||||
|
kAnalysisEnd = 1 << 17
|
||||||
};
|
};
|
||||||
|
|
||||||
using ProcessFunction = std::function<bool(Function*)>;
|
using ProcessFunction = std::function<bool(Function*)>;
|
||||||
|
@ -102,8 +104,7 @@ class IRContext {
|
||||||
id_to_name_(nullptr),
|
id_to_name_(nullptr),
|
||||||
max_id_bound_(kDefaultMaxIdBound),
|
max_id_bound_(kDefaultMaxIdBound),
|
||||||
preserve_bindings_(false),
|
preserve_bindings_(false),
|
||||||
preserve_spec_constants_(false),
|
preserve_spec_constants_(false) {
|
||||||
debug_info_none_inst_(nullptr) {
|
|
||||||
SetContextMessageConsumer(syntax_context_, consumer_);
|
SetContextMessageConsumer(syntax_context_, consumer_);
|
||||||
module_->SetContext(this);
|
module_->SetContext(this);
|
||||||
}
|
}
|
||||||
|
@ -120,8 +121,7 @@ class IRContext {
|
||||||
id_to_name_(nullptr),
|
id_to_name_(nullptr),
|
||||||
max_id_bound_(kDefaultMaxIdBound),
|
max_id_bound_(kDefaultMaxIdBound),
|
||||||
preserve_bindings_(false),
|
preserve_bindings_(false),
|
||||||
preserve_spec_constants_(false),
|
preserve_spec_constants_(false) {
|
||||||
debug_info_none_inst_(nullptr) {
|
|
||||||
SetContextMessageConsumer(syntax_context_, consumer_);
|
SetContextMessageConsumer(syntax_context_, consumer_);
|
||||||
module_->SetContext(this);
|
module_->SetContext(this);
|
||||||
InitializeCombinators();
|
InitializeCombinators();
|
||||||
|
@ -328,6 +328,17 @@ class IRContext {
|
||||||
return type_mgr_.get();
|
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
|
// Returns a pointer to the scalar evolution analysis. If it is invalid it
|
||||||
// will be rebuilt first.
|
// will be rebuilt first.
|
||||||
ScalarEvolutionAnalysis* GetScalarEvolutionAnalysis() {
|
ScalarEvolutionAnalysis* GetScalarEvolutionAnalysis() {
|
||||||
|
@ -657,6 +668,13 @@ class IRContext {
|
||||||
valid_analyses_ = valid_analyses_ | kAnalysisTypes;
|
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
|
// Removes all computed dominator and post-dominator trees. This will force
|
||||||
// the context to rebuild the trees on demand.
|
// the context to rebuild the trees on demand.
|
||||||
void ResetDominatorAnalysis() {
|
void ResetDominatorAnalysis() {
|
||||||
|
@ -710,9 +728,6 @@ class IRContext {
|
||||||
// Add |var_id| to all entry points in module.
|
// Add |var_id| to all entry points in module.
|
||||||
void AddVarToEntryPoints(uint32_t var_id);
|
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
|
// The SPIR-V syntax context containing grammar tables for opcodes and
|
||||||
// operands.
|
// operands.
|
||||||
spv_context syntax_context_;
|
spv_context syntax_context_;
|
||||||
|
@ -782,6 +797,9 @@ class IRContext {
|
||||||
// Type manager for |module_|.
|
// Type manager for |module_|.
|
||||||
std::unique_ptr<analysis::TypeManager> type_mgr_;
|
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.
|
// A map from an id to its corresponding OpName and OpMemberName instructions.
|
||||||
std::unique_ptr<std::multimap<uint32_t, Instruction*>> id_to_name_;
|
std::unique_ptr<std::multimap<uint32_t, Instruction*>> id_to_name_;
|
||||||
|
|
||||||
|
@ -806,10 +824,6 @@ class IRContext {
|
||||||
// Whether all specialization constants within |module_|
|
// Whether all specialization constants within |module_|
|
||||||
// should be preserved.
|
// should be preserved.
|
||||||
bool preserve_spec_constants_;
|
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,
|
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");
|
Error(consumer_, src, loc, "terminator instruction outside basic block");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (last_dbg_scope_.GetLexicalScope() != kNoDebugScope)
|
||||||
|
spv_inst->SetDebugScope(last_dbg_scope_);
|
||||||
block_->AddInstruction(std::move(spv_inst));
|
block_->AddInstruction(std::move(spv_inst));
|
||||||
function_->AddBasicBlock(std::move(block_));
|
function_->AddBasicBlock(std::move(block_));
|
||||||
block_ = nullptr;
|
block_ = nullptr;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// The default maximum number of steps the reducer will take before giving up.
|
// The default maximum number of steps the reducer will take before giving up.
|
||||||
const uint32_t kDefaultStepLimit = 250;
|
const uint32_t kDefaultStepLimit = 2500;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
spv_reducer_options_t::spv_reducer_options_t()
|
spv_reducer_options_t::spv_reducer_options_t()
|
||||||
|
|
Loading…
Reference in New Issue