diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc index d1c2cfcfa4..2e9ead9232 100644 --- a/src/reader/spirv/function.cc +++ b/src/reader/spirv/function.cc @@ -3142,6 +3142,12 @@ bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) { case SpvOpFunctionCall: return EmitFunctionCall(inst); + case SpvOpExtInst: + if (parser_impl_.IsIgnoredExtendedInstruction(inst)) { + return true; + } + break; + default: break; } @@ -3246,9 +3252,13 @@ TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue( } 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 97c2f878a2..5d7af748cb 100644 --- a/src/reader/spirv/parser_impl.cc +++ b/src/reader/spirv/parser_impl.cc @@ -613,6 +613,8 @@ bool ParserImpl::RegisterExtendedInstructionImports() { // 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 @@ bool ParserImpl::IsGlslExtendedInstruction( (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 bfe11de48d..a023a3c8b7 100644 --- a/src/reader/spirv/parser_impl.h +++ b/src/reader/spirv/parser_impl.h @@ -242,6 +242,13 @@ class ParserImpl : Reader { /// @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 @@ class ParserImpl : Reader { // The set of IDs that are imports of the GLSL.std.450 extended instruction // sets. std::unordered_set glsl_std_450_imports_; + // The set of IDs of imports that are ignored. For example, any + // "NonSemanticInfo." import is ignored. + std::unordered_set ignored_imports_; // Maps a SPIR-V type ID to the corresponding Tint type. std::unordered_map id_to_type_; diff --git a/src/reader/spirv/parser_impl_import_test.cc b/src/reader/spirv/parser_impl_import_test.cc index a949cda296..d45b83f7c0 100644 --- a/src/reader/spirv/parser_impl_import_test.cc +++ b/src/reader/spirv/parser_impl_import_test.cc @@ -46,6 +46,70 @@ TEST_F(SpvParserTest, Import_ImportGlslStd450) { 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.