Fix support for OpKill as non-terminator

Fixing this issue required using the WrapOpKill SPIRV-Tools
pass. This pass wraps OpKill instructions inside a function.
See the following for the explanation:
https://github.com/KhronosGroup/SPIRV-Tools/issues/2726

dEQP-GLES2.functional.shaders.discard.function_always fails
on ANGLE on top of SwiftShader Vulkan without this fix.

Bug b/141246700

Change-Id: I48ce3c19a1b02160fd8f23b60a75e5f8f35a4d37
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/36450
Presubmit-Ready: Alexis Hétu <sugoi@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 0498c6c..b4b1f73 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -917,12 +917,15 @@
 				break;
 
 			case spv::OpFunctionParameter:
-			case spv::OpFunctionCall:
 				// These should have all been removed by preprocessing passes. If we see them here,
 				// our assumptions are wrong and we will probably generate wrong code.
 				UNREACHABLE("%s should have already been lowered.", OpcodeName(opcode).c_str());
 				break;
 
+			case spv::OpFunctionCall:
+				// TODO(b/141246700): Add full support for spv::OpFunctionCall
+				break;
+
 			case spv::OpFConvert:
 				UNSUPPORTED("SPIR-V Float16 or Float64 Capability (OpFConvert)");
 				break;
@@ -2693,6 +2696,9 @@
 		case spv::OpReturn:
 			return EmitReturn(insn, state);
 
+		case spv::OpFunctionCall:
+			return EmitFunctionCall(insn, state);
+
 		case spv::OpKill:
 			return EmitKill(insn, state);
 
@@ -4833,6 +4839,44 @@
 		return EmitResult::Terminator;
 	}
 
+	SpirvShader::EmitResult SpirvShader::EmitFunctionCall(InsnIterator insn, EmitState *state) const
+	{
+		auto functionId = Function::ID(insn.word(3));
+		const auto& functionIt = functions.find(functionId);
+		ASSERT(functionIt != functions.end());
+		auto& function = functionIt->second;
+
+		// TODO(b/141246700): Add full support for spv::OpFunctionCall
+		// The only supported function is a single OpKill wrapped in a
+		// function, as a result of the "wrap OpKill" SPIRV-Tools pass
+		ASSERT(function.blocks.size() == 1);
+		spv::Op wrapOpKill[] = { spv::OpLabel, spv::OpKill };
+
+		for (auto block : function.blocks)
+		{
+			int insnNumber = 0;
+			for (auto blockInsn : block.second)
+			{
+				if (insnNumber > 1)
+				{
+					UNIMPLEMENTED("Function block number of instructions: %d", insnNumber);
+					return EmitResult::Continue;
+				}
+				if (blockInsn.opcode() != wrapOpKill[insnNumber++])
+				{
+					UNIMPLEMENTED("Function block instruction %d : %s", insnNumber - 1, OpcodeName(blockInsn.opcode()).c_str());
+					return EmitResult::Continue;
+				}
+				if (blockInsn.opcode() == spv::OpKill)
+				{
+					EmitInstruction(blockInsn, state);
+				}
+			}
+		}
+
+		return EmitResult::Continue;
+	}
+
 	SpirvShader::EmitResult SpirvShader::EmitPhi(InsnIterator insn, EmitState *state) const
 	{
 		auto &function = getFunction(state->function);
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 4a28af6..34565cb 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -1224,6 +1224,7 @@
 		EmitResult EmitUnreachable(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitReturn(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitKill(InsnIterator insn, EmitState *state) const;
+		EmitResult EmitFunctionCall(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitPhi(InsnIterator insn, EmitState *state) const;
 		EmitResult EmitImageSampleImplicitLod(Variant variant, InsnIterator insn, EmitState *state) const;
 		EmitResult EmitImageSampleExplicitLod(Variant variant, InsnIterator insn, EmitState *state) const;
diff --git a/src/Vulkan/VkPipeline.cpp b/src/Vulkan/VkPipeline.cpp
index 7c55daa..ebee9f2 100644
--- a/src/Vulkan/VkPipeline.cpp
+++ b/src/Vulkan/VkPipeline.cpp
@@ -193,7 +193,8 @@
 	}
 
 	// Full optimization list taken from spirv-opt.
-	opt.RegisterPass(spvtools::CreateDeadBranchElimPass())
+	opt.RegisterPass(spvtools::CreateWrapOpKillPass())
+		.RegisterPass(spvtools::CreateDeadBranchElimPass())
 		.RegisterPass(spvtools::CreateMergeReturnPass())
 		.RegisterPass(spvtools::CreateInlineExhaustivePass())
 		.RegisterPass(spvtools::CreateAggressiveDCEPass())