[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_) {
|
||||
return false;
|
||||
}
|
||||
RegisterLineNumbers();
|
||||
if (!ParseInternalModuleExceptFunctions()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -469,6 +470,47 @@ bool ParserImpl::ParseInternalModule() {
|
|||
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() {
|
||||
if (!success_) {
|
||||
return false;
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "src/reader/spirv/enum_converter.h"
|
||||
#include "src/reader/spirv/fail_stream.h"
|
||||
#include "src/reader/spirv/namer.h"
|
||||
#include "src/source.h"
|
||||
|
||||
namespace tint {
|
||||
namespace reader {
|
||||
|
@ -214,6 +215,9 @@ class ParserImpl : Reader {
|
|||
/// @returns true if the parser is still successful.
|
||||
bool ParseInternalModule();
|
||||
|
||||
/// Records line numbers for each instruction.
|
||||
void RegisterLineNumbers();
|
||||
|
||||
/// Walks the internal representation of the module, except for function
|
||||
/// definitions, to populate the AST form of the module.
|
||||
/// This is a no-op if the parser has already failed.
|
||||
|
@ -358,6 +362,12 @@ class ParserImpl : Reader {
|
|||
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:
|
||||
/// Converts a specific SPIR-V type to a Tint type. Integer case
|
||||
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::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
|
||||
std::unordered_map<uint32_t, ast::Import*> import_map_;
|
||||
// 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"));
|
||||
}
|
||||
|
||||
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 spirv
|
||||
} // namespace reader
|
||||
|
|
Loading…
Reference in New Issue