Pipeline/SpirvShader: Support more OpExtInsts

Previously `OpExtInst` and `OpExtInstImport` was hard-coded to only support `GLSL.std.450`.
We will want to support `OpenCL.Debug.100`, so put in the plumbing to properly support other extensions.

Bug: b/145351270
Change-Id: I60fbb8c45bb57b747067437641676946129b1251
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/39885
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index a4ef814..55ea1c3 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -416,13 +416,25 @@
 
 			case spv::OpExtInstImport:
 			{
-				// We will only support the GLSL 450 extended instruction set, so no point in tracking the ID we assign it.
-				// Valid shaders will not attempt to import any other instruction sets.
-				auto ext = insn.string(2);
-				if(0 != strcmp("GLSL.std.450", ext))
+				auto id = Extension::ID(insn.word(1));
+				auto name = insn.string(2);
+				auto ext = Extension{ Extension::Unknown };
+				for(auto it : std::initializer_list<std::pair<const char *, Extension::Name>>{
+				        { "GLSL.std.450", Extension::GLSLstd450 },
+				    })
 				{
-					UNSUPPORTED("SPIR-V Extension: %s", ext);
+					if(0 == strcmp(name, it.first))
+					{
+						ext = Extension{ it.second };
+						break;
+					}
 				}
+				if(ext.name == Extension::Unknown)
+				{
+					UNSUPPORTED("SPIR-V Extension: %s", name);
+					break;
+				}
+				extensions.emplace(id, ext);
 				break;
 			}
 			case spv::OpName:
@@ -573,7 +585,6 @@
 			case spv::OpConvertUToF:
 			case spv::OpBitcast:
 			case spv::OpSelect:
-			case spv::OpExtInst:
 			case spv::OpIsInf:
 			case spv::OpIsNan:
 			case spv::OpAny:
@@ -658,6 +669,18 @@
 				DefineResult(insn);
 				break;
 
+			case spv::OpExtInst:
+				switch(getExtension(insn.word(3)).name)
+				{
+					case Extension::GLSLstd450:
+						DefineResult(insn);
+						break;
+					default:
+						UNREACHABLE("Unexpected Extension name %d", int(getExtension(insn.word(3)).name));
+						break;
+				}
+				break;
+
 			case spv::OpStore:
 			case spv::OpAtomicStore:
 			case spv::OpImageWrite:
@@ -2293,6 +2316,19 @@
 	return EmitResult::Continue;
 }
 
+SpirvShader::EmitResult SpirvShader::EmitExtendedInstruction(InsnIterator insn, EmitState *state) const
+{
+	auto ext = getExtension(insn.word(3));
+	switch(ext.name)
+	{
+		case Extension::GLSLstd450:
+			return EmitExtGLSLstd450(insn, state);
+		default:
+			UNREACHABLE("Unknown Extension::Name<%d>", int(ext.name));
+	}
+	return EmitResult::Continue;
+}
+
 uint32_t SpirvShader::GetConstScalarInt(Object::ID id) const
 {
 	auto &scopeObj = getObject(id);
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index d74fb14..696c47f 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -380,6 +380,20 @@
 	using String = std::string;
 	using StringID = SpirvID<std::string>;
 
+	class Extension
+	{
+	public:
+		using ID = SpirvID<Extension>;
+
+		enum Name
+		{
+			Unknown,
+			GLSLstd450,
+		};
+
+		Name name;
+	};
+
 	struct TypeOrObject
 	{};  // Dummy struct to represent a Type or Object.
 
@@ -732,6 +746,7 @@
 	HandleMap<Object> defs;
 	HandleMap<Function> functions;
 	std::unordered_map<StringID, String> strings;
+	HandleMap<Extension> extensions;
 	Function::ID entryPoint;
 
 	const bool robustBufferAccess = true;
@@ -1017,6 +1032,13 @@
 		return it->second;
 	}
 
+	Extension const &getExtension(Extension::ID id) const
+	{
+		auto it = extensions.find(id);
+		ASSERT_MSG(it != extensions.end(), "Unknown extension %d", id.value());
+		return it->second;
+	}
+
 	// Returns a SIMD::Pointer to the underlying data for the given pointer
 	// object.
 	// Handles objects of the following kinds:
@@ -1069,6 +1091,7 @@
 	EmitResult EmitDot(InsnIterator insn, EmitState *state) const;
 	EmitResult EmitSelect(InsnIterator insn, EmitState *state) const;
 	EmitResult EmitExtendedInstruction(InsnIterator insn, EmitState *state) const;
+	EmitResult EmitExtGLSLstd450(InsnIterator insn, EmitState *state) const;
 	EmitResult EmitAny(InsnIterator insn, EmitState *state) const;
 	EmitResult EmitAll(InsnIterator insn, EmitState *state) const;
 	EmitResult EmitBranch(InsnIterator insn, EmitState *state) const;
diff --git a/src/Pipeline/SpirvShaderGLSLstd450.cpp b/src/Pipeline/SpirvShaderGLSLstd450.cpp
index f6aaeca..0b0de23 100644
--- a/src/Pipeline/SpirvShaderGLSLstd450.cpp
+++ b/src/Pipeline/SpirvShaderGLSLstd450.cpp
@@ -25,7 +25,7 @@
 
 namespace sw {
 
-SpirvShader::EmitResult SpirvShader::EmitExtendedInstruction(InsnIterator insn, EmitState *state) const
+SpirvShader::EmitResult SpirvShader::EmitExtGLSLstd450(InsnIterator insn, EmitState *state) const
 {
 	auto &type = getType(insn.word(1));
 	auto &dst = state->createIntermediate(insn.word(2), type.sizeInComponents);