mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-06 21:25:58 +00:00
[spirv-reader] Track line numbers
If OpLine debug instructions are present, use their line and column numbers. Otherwise, use the instruction number as the line number, starting counting from 1. Bug: tint:3 Change-Id: Ia46c10732922b80b5737b13af1ef71f4259a3555 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/27680 Commit-Queue: David Neto <dneto@google.com> Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
25b856aa64
commit
6c2a7b712c
@ -460,6 +460,7 @@ bool ParserImpl::ParseInternalModule() {
|
|||||||
if (!success_) {
|
if (!success_) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
RegisterLineNumbers();
|
||||||
if (!ParseInternalModuleExceptFunctions()) {
|
if (!ParseInternalModuleExceptFunctions()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -469,6 +470,47 @@ bool ParserImpl::ParseInternalModule() {
|
|||||||
return success_;
|
return success_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ParserImpl::RegisterLineNumbers() {
|
||||||
|
Source instruction_number{0, 0};
|
||||||
|
|
||||||
|
// Has there been an OpLine since the last OpNoLine or start of the module?
|
||||||
|
bool in_op_line_scope = false;
|
||||||
|
// The source location provided by the most recent OpLine instruction.
|
||||||
|
Source op_line_source{0, 0};
|
||||||
|
const bool run_on_debug_insts = true;
|
||||||
|
module_->ForEachInst(
|
||||||
|
[this, &in_op_line_scope, &op_line_source,
|
||||||
|
&instruction_number](const spvtools::opt::Instruction* inst) {
|
||||||
|
++instruction_number.line;
|
||||||
|
switch (inst->opcode()) {
|
||||||
|
case SpvOpLine:
|
||||||
|
in_op_line_scope = true;
|
||||||
|
// TODO(dneto): This ignores the File ID (operand 0), since the Tint
|
||||||
|
// Source concept doesn't represent that.
|
||||||
|
op_line_source.line = inst->GetSingleWordInOperand(1);
|
||||||
|
op_line_source.column = inst->GetSingleWordInOperand(2);
|
||||||
|
break;
|
||||||
|
case SpvOpNoLine:
|
||||||
|
in_op_line_scope = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this->inst_source_[inst] =
|
||||||
|
in_op_line_scope ? op_line_source : instruction_number;
|
||||||
|
},
|
||||||
|
run_on_debug_insts);
|
||||||
|
}
|
||||||
|
|
||||||
|
Source ParserImpl::GetSourceForResultIdForTest(uint32_t id) {
|
||||||
|
const auto* inst = def_use_mgr_->GetDef(id);
|
||||||
|
auto where = inst_source_.find(inst);
|
||||||
|
if (where == inst_source_.end()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return where->second;
|
||||||
|
}
|
||||||
|
|
||||||
bool ParserImpl::ParseInternalModuleExceptFunctions() {
|
bool ParserImpl::ParseInternalModuleExceptFunctions() {
|
||||||
if (!success_) {
|
if (!success_) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "src/reader/spirv/enum_converter.h"
|
#include "src/reader/spirv/enum_converter.h"
|
||||||
#include "src/reader/spirv/fail_stream.h"
|
#include "src/reader/spirv/fail_stream.h"
|
||||||
#include "src/reader/spirv/namer.h"
|
#include "src/reader/spirv/namer.h"
|
||||||
|
#include "src/source.h"
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
namespace reader {
|
namespace reader {
|
||||||
@ -214,6 +215,9 @@ class ParserImpl : Reader {
|
|||||||
/// @returns true if the parser is still successful.
|
/// @returns true if the parser is still successful.
|
||||||
bool ParseInternalModule();
|
bool ParseInternalModule();
|
||||||
|
|
||||||
|
/// Records line numbers for each instruction.
|
||||||
|
void RegisterLineNumbers();
|
||||||
|
|
||||||
/// Walks the internal representation of the module, except for function
|
/// Walks the internal representation of the module, except for function
|
||||||
/// definitions, to populate the AST form of the module.
|
/// definitions, to populate the AST form of the module.
|
||||||
/// This is a no-op if the parser has already failed.
|
/// This is a no-op if the parser has already failed.
|
||||||
@ -358,6 +362,12 @@ class ParserImpl : Reader {
|
|||||||
return builtin_position_;
|
return builtin_position_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Look up the source record for the SPIR-V instruction with the given
|
||||||
|
/// result ID.
|
||||||
|
/// @param id the SPIR-V result id.
|
||||||
|
/// @return the Source record, or a default one
|
||||||
|
Source GetSourceForResultIdForTest(uint32_t id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Converts a specific SPIR-V type to a Tint type. Integer case
|
/// Converts a specific SPIR-V type to a Tint type. Integer case
|
||||||
ast::type::Type* ConvertType(const spvtools::opt::analysis::Integer* int_ty);
|
ast::type::Type* ConvertType(const spvtools::opt::analysis::Integer* int_ty);
|
||||||
@ -435,6 +445,12 @@ class ParserImpl : Reader {
|
|||||||
spvtools::opt::analysis::TypeManager* type_mgr_ = nullptr;
|
spvtools::opt::analysis::TypeManager* type_mgr_ = nullptr;
|
||||||
spvtools::opt::analysis::DecorationManager* deco_mgr_ = nullptr;
|
spvtools::opt::analysis::DecorationManager* deco_mgr_ = nullptr;
|
||||||
|
|
||||||
|
// Maps an instruction to its source location. If no OpLine information
|
||||||
|
// is in effect for the instruction, map the instruction to its position
|
||||||
|
// in the SPIR-V module, counting by instructions, where the first
|
||||||
|
// instruction is line 1.
|
||||||
|
std::unordered_map<const spvtools::opt::Instruction*, Source> inst_source_;
|
||||||
|
|
||||||
/// Maps a SPIR-V ID for an external instruction import to an AST import
|
/// Maps a SPIR-V ID for an external instruction import to an AST import
|
||||||
std::unordered_map<uint32_t, ast::Import*> import_map_;
|
std::unordered_map<uint32_t, ast::Import*> import_map_;
|
||||||
// The set of IDs that are imports of the GLSL.std.450 extended instruction
|
// The set of IDs that are imports of the GLSL.std.450 extended instruction
|
||||||
|
@ -119,6 +119,92 @@ TEST_F(SpvParserTest, Impl_OpenCLKernel_Fails) {
|
|||||||
EXPECT_THAT(p->error(), HasSubstr("Capability Kernel is not allowed"));
|
EXPECT_THAT(p->error(), HasSubstr("Capability Kernel is not allowed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvParserTest, Impl_Source_NoOpLine) {
|
||||||
|
auto spv = test::Assemble(R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical Simple
|
||||||
|
OpEntryPoint GLCompute %main "main"
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%voidfn = OpTypeFunction %void
|
||||||
|
%5 = OpTypeInt 32 0
|
||||||
|
%60 = OpConstantNull %5
|
||||||
|
%main = OpFunction %void None %voidfn
|
||||||
|
%1 = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)");
|
||||||
|
auto* p = parser(spv);
|
||||||
|
EXPECT_TRUE(p->Parse());
|
||||||
|
EXPECT_TRUE(p->error().empty());
|
||||||
|
// Use instruction counting.
|
||||||
|
auto s5 = p->GetSourceForResultIdForTest(5);
|
||||||
|
EXPECT_EQ(7u, s5.line);
|
||||||
|
EXPECT_EQ(0u, s5.column);
|
||||||
|
auto s60 = p->GetSourceForResultIdForTest(60);
|
||||||
|
EXPECT_EQ(8u, s60.line);
|
||||||
|
EXPECT_EQ(0u, s60.column);
|
||||||
|
auto s1 = p->GetSourceForResultIdForTest(1);
|
||||||
|
EXPECT_EQ(10u, s1.line);
|
||||||
|
EXPECT_EQ(0u, s1.column);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvParserTest, Impl_Source_WithOpLine_WithOpNoLine) {
|
||||||
|
auto spv = test::Assemble(R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical Simple
|
||||||
|
OpEntryPoint GLCompute %main "main"
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
%15 = OpString "myfile"
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%voidfn = OpTypeFunction %void
|
||||||
|
OpLine %15 42 53
|
||||||
|
%5 = OpTypeInt 32 0
|
||||||
|
%60 = OpConstantNull %5
|
||||||
|
OpNoLine
|
||||||
|
%main = OpFunction %void None %voidfn
|
||||||
|
%1 = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)");
|
||||||
|
auto* p = parser(spv);
|
||||||
|
EXPECT_TRUE(p->Parse());
|
||||||
|
EXPECT_TRUE(p->error().empty());
|
||||||
|
// Use the information from the OpLine that is still in scope.
|
||||||
|
auto s5 = p->GetSourceForResultIdForTest(5);
|
||||||
|
EXPECT_EQ(42u, s5.line);
|
||||||
|
EXPECT_EQ(53u, s5.column);
|
||||||
|
auto s60 = p->GetSourceForResultIdForTest(60);
|
||||||
|
EXPECT_EQ(42u, s60.line);
|
||||||
|
EXPECT_EQ(53u, s60.column);
|
||||||
|
// After OpNoLine, revert back to instruction counting.
|
||||||
|
auto s1 = p->GetSourceForResultIdForTest(1);
|
||||||
|
EXPECT_EQ(13u, s1.line);
|
||||||
|
EXPECT_EQ(0u, s1.column);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SpvParserTest, Impl_Source_InvalidId) {
|
||||||
|
auto spv = test::Assemble(R"(
|
||||||
|
OpCapability Shader
|
||||||
|
OpMemoryModel Logical Simple
|
||||||
|
OpEntryPoint GLCompute %main "main"
|
||||||
|
OpExecutionMode %main LocalSize 1 1 1
|
||||||
|
%15 = OpString "myfile"
|
||||||
|
%void = OpTypeVoid
|
||||||
|
%voidfn = OpTypeFunction %void
|
||||||
|
%main = OpFunction %void None %voidfn
|
||||||
|
%1 = OpLabel
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
|
)");
|
||||||
|
auto* p = parser(spv);
|
||||||
|
EXPECT_TRUE(p->Parse());
|
||||||
|
EXPECT_TRUE(p->error().empty());
|
||||||
|
auto s99 = p->GetSourceForResultIdForTest(99);
|
||||||
|
EXPECT_EQ(0u, s99.line);
|
||||||
|
EXPECT_EQ(0u, s99.column);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace spirv
|
} // namespace spirv
|
||||||
} // namespace reader
|
} // namespace reader
|
||||||
|
Loading…
x
Reference in New Issue
Block a user