spirv-reader: ignore NonSemantic. extended instructions
This is the first step in being able to read code generated
by Clspv.
Actively ignore the instructions instead of applying stripping
transform before hand. That way we have a chance at properly counting
instructions, which helps produce better diagnostics.
Bug: tint:3
Change-Id: I82bde88897485380d70dc8b287c3843eae5489b6
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/41641
Auto-Submit: David Neto <dneto@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index d1c2cfc..2e9ead9 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -3142,6 +3142,12 @@
case SpvOpFunctionCall:
return EmitFunctionCall(inst);
+ case SpvOpExtInst:
+ if (parser_impl_.IsIgnoredExtendedInstruction(inst)) {
+ return true;
+ }
+ break;
+
default:
break;
}
@@ -3246,9 +3252,13 @@
}
if (opcode == SpvOpExtInst) {
- const auto import = inst.GetSingleWordInOperand(0);
- if (parser_impl_.glsl_std_450_imports().count(import) == 0) {
- Fail() << "unhandled extended instruction import with ID " << import;
+ if (parser_impl_.IsIgnoredExtendedInstruction(inst)) {
+ // Ignore it but don't error out.
+ return {};
+ }
+ if (!parser_impl_.IsGlslExtendedInstruction(inst)) {
+ Fail() << "unhandled extended instruction import with ID "
+ << inst.GetSingleWordInOperand(0);
return {};
}
return EmitGlslStd450ExtInst(inst);
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index 97c2f87..5d7af74 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -613,6 +613,8 @@
// TODO(dneto): Handle other extended instruction sets when needed.
if (name == "GLSL.std.450") {
glsl_std_450_imports_.insert(import.result_id());
+ } else if (name.find("NonSemantic.") == 0) {
+ ignored_imports_.insert(import.result_id());
} else {
return Fail() << "Unrecognized extended instruction set: " << name;
}
@@ -626,6 +628,12 @@
(glsl_std_450_imports_.count(inst.GetSingleWordInOperand(0)) > 0);
}
+bool ParserImpl::IsIgnoredExtendedInstruction(
+ const spvtools::opt::Instruction& inst) const {
+ return (inst.opcode() == SpvOpExtInst) &&
+ (ignored_imports_.count(inst.GetSingleWordInOperand(0)) > 0);
+}
+
bool ParserImpl::RegisterUserAndStructMemberNames() {
if (!success_) {
return false;
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index bfe11de..a023a3c 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -242,6 +242,13 @@
/// @returns true if its an SpvOpExtInst for GLSL.std.450
bool IsGlslExtendedInstruction(const spvtools::opt::Instruction& inst) const;
+ /// Returns true when the given instruction is an extended instruction
+ /// from an ignored extended instruction set.
+ /// @param inst a SPIR-V instruction
+ /// @returns true if its an SpvOpExtInst for an ignored extended instruction
+ bool IsIgnoredExtendedInstruction(
+ const spvtools::opt::Instruction& inst) const;
+
/// Registers user names for SPIR-V objects, from OpName, and OpMemberName.
/// Also synthesizes struct field names. Ensures uniqueness for names for
/// SPIR-V IDs, and uniqueness of names of fields within any single struct.
@@ -596,6 +603,9 @@
// The set of IDs that are imports of the GLSL.std.450 extended instruction
// sets.
std::unordered_set<uint32_t> glsl_std_450_imports_;
+ // The set of IDs of imports that are ignored. For example, any
+ // "NonSemanticInfo." import is ignored.
+ std::unordered_set<uint32_t> ignored_imports_;
// Maps a SPIR-V type ID to the corresponding Tint type.
std::unordered_map<uint32_t, type::Type*> id_to_type_;
diff --git a/src/reader/spirv/parser_impl_import_test.cc b/src/reader/spirv/parser_impl_import_test.cc
index a949cda..d45b83f 100644
--- a/src/reader/spirv/parser_impl_import_test.cc
+++ b/src/reader/spirv/parser_impl_import_test.cc
@@ -46,6 +46,70 @@
EXPECT_THAT(p->glsl_std_450_imports(), ElementsAre(1));
}
+TEST_F(SpvParserTest, Import_NonSemantic_IgnoredImport) {
+ auto p = parser(test::Assemble(
+ R"(%40 = OpExtInstImport "NonSemantic.ClspvReflection.1")"));
+ EXPECT_TRUE(p->BuildAndParseInternalModule());
+ EXPECT_TRUE(p->error().empty());
+}
+
+TEST_F(SpvParserTest, Import_NonSemantic_IgnoredExtInsts) {
+ // This is the clspv-compiled output of this OpenCL C:
+ // kernel void foo(global int*A) { A=A; }
+ // It emits NonSemantic.ClspvReflection.1 extended instructions.
+ // But *tweaked*:
+ // - to remove gl_WorkgroupSize
+ // - to move one of the ExtInsts into the globals-and-constants
+ // section
+ // - to move one of the ExtInsts into the function body.
+ auto p = parser(test::Assemble(R"(
+ OpCapability Shader
+ OpExtension "SPV_KHR_storage_buffer_storage_class"
+ OpExtension "SPV_KHR_non_semantic_info"
+ %20 = OpExtInstImport "NonSemantic.ClspvReflection.1"
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %15 "foo"
+ OpSource OpenCL_C 120
+ %21 = OpString "foo"
+ %23 = OpString "A"
+ OpDecorate %_runtimearr_uint ArrayStride 4
+ OpMemberDecorate %_struct_3 0 Offset 0
+ OpDecorate %_struct_3 Block
+ OpDecorate %12 DescriptorSet 0
+ OpDecorate %12 Binding 0
+ OpDecorate %7 SpecId 0
+ OpDecorate %8 SpecId 1
+ OpDecorate %9 SpecId 2
+ %24 = OpExtInst %void %20 ArgumentInfo %23
+ %uint = OpTypeInt 32 0
+%_runtimearr_uint = OpTypeRuntimeArray %uint
+ %_struct_3 = OpTypeStruct %_runtimearr_uint
+%_ptr_StorageBuffer__struct_3 = OpTypePointer StorageBuffer %_struct_3
+ %v3uint = OpTypeVector %uint 3
+%_ptr_Private_v3uint = OpTypePointer Private %v3uint
+ %7 = OpSpecConstant %uint 1
+ %8 = OpSpecConstant %uint 1
+ %9 = OpSpecConstant %uint 1
+ %void = OpTypeVoid
+ %14 = OpTypeFunction %void
+%_ptr_StorageBuffer_uint = OpTypePointer StorageBuffer %uint
+ %uint_0 = OpConstant %uint 0
+ %uint_1 = OpConstant %uint 1
+ %uint_2 = OpConstant %uint 2
+ %12 = OpVariable %_ptr_StorageBuffer__struct_3 StorageBuffer
+ %15 = OpFunction %void Const %14
+ %16 = OpLabel
+ %19 = OpAccessChain %_ptr_StorageBuffer_uint %12 %uint_0 %uint_0
+ %22 = OpExtInst %void %20 Kernel %15 %21
+ OpReturn
+ OpFunctionEnd
+ %25 = OpExtInst %void %20 ArgumentStorageBuffer %22 %uint_0 %uint_0 %uint_0 %24
+ %28 = OpExtInst %void %20 SpecConstantWorkgroupSize %uint_0 %uint_1 %uint_2
+)"));
+ EXPECT_TRUE(p->BuildAndParseInternalModule());
+ EXPECT_TRUE(p->error().empty());
+}
+
// TODO(dneto): We don't currently support other kinds of extended instruction
// imports.