SpirvShader: Consider OpEntryPoint interface IDs

Bug: swiftshader:161
Change-Id: Ib26cb1f6edb2549fc42420e7cc1579ce4ae36952
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/55148
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index f82f1e8..58c7ca5 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -61,8 +61,8 @@
 		}
 	}
 
-	// Simplifying assumptions (to be satisfied by earlier transformations)
-	// - The only input/output OpVariables present are those used by the entrypoint
+	// The identifiers of all OpVariables that define the entry point's IO variables.
+	std::unordered_set<Object::ID> interfaceIds;
 
 	Function::ID currentFunction;
 	Block::ID currentBlock;
@@ -84,6 +84,12 @@
 				{
 					ASSERT_MSG(entryPoint == 0, "Duplicate entry point with name '%s' and stage %d", name, int(stage));
 					entryPoint = id;
+
+					auto interfaceIdsOffset = 3 + insn.stringSizeInWords(3);
+					for(uint32_t i = interfaceIdsOffset; i < insn.wordCount(); i++)
+					{
+						interfaceIds.emplace(insn.word(i));
+					}
 				}
 			}
 			break;
@@ -271,7 +277,10 @@
 				{
 				case spv::StorageClassInput:
 				case spv::StorageClassOutput:
-					ProcessInterfaceVariable(object);
+					if(interfaceIds.count(resultId))
+					{
+						ProcessInterfaceVariable(object);
+					}
 					break;
 
 				case spv::StorageClassUniform:
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index da9cf63..900199b 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -204,6 +204,35 @@
 			return reinterpret_cast<const char *>(wordPointer(n));
 		}
 
+		// Returns the number of whole-words that a string literal starting at
+		// word n consumes. If the end of the intruction is reached before the
+		// null-terminator is found, then the function DABORT()s and 0 is
+		// returned.
+		uint32_t stringSizeInWords(uint32_t n) const
+		{
+			uint32_t c = wordCount();
+			for(uint32_t i = n; n < c; i++)
+			{
+				auto *u32 = wordPointer(i);
+				auto *u8 = reinterpret_cast<const uint8_t *>(u32);
+				// SPIR-V spec 2.2.1. Instructions:
+				// A string is interpreted as a nul-terminated stream of
+				// characters. The character set is Unicode in the UTF-8
+				// encoding scheme. The UTF-8 octets (8-bit bytes) are packed
+				// four per word, following the little-endian convention (i.e.,
+				// the first octet is in the lowest-order 8 bits of the word).
+				// The final word contains the string’s nul-termination
+				// character (0), and all contents past the end of the string in
+				// the final word are padded with 0.
+				if(u8[3] == 0)
+				{
+					return 1 + i - n;
+				}
+			}
+			DABORT("SPIR-V string literal was not null-terminated");
+			return 0;
+		}
+
 		bool hasResultAndType() const
 		{
 			bool hasResult = false, hasResultType = false;