Use a C array for temporary load results

Array<> emits GEP instructions on every access, which aren't necessary.
Note that these temporaries are required because the If/Else blocks
both write to them, while the destination intermediate object is an
rvalue which can only be initialized once to maintain SSA form.

Also EmitAccessChain was moved to match the declaration order.

Bug b/128539387

Change-Id: I726fb0fd28b0a19a61e8759679e30bc699f3279d
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/27788
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 930cff6..29e55b4 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -1387,16 +1387,16 @@
 
 	void SpirvShader::EmitLoad(InsnIterator insn, SpirvRoutine *routine) const
 	{
-		Object::ID objectId = insn.word(2);
+		Object::ID resultId = insn.word(2);
 		Object::ID pointerId = insn.word(3);
-		auto &object = getObject(objectId);
-		auto &objectTy = getType(object.type);
+		auto &result = getObject(resultId);
+		auto &resultTy = getType(result.type);
 		auto &pointer = getObject(pointerId);
 		auto &pointerBase = getObject(pointer.pointerBase);
 		auto &pointerBaseTy = getType(pointerBase.type);
 
-		ASSERT(getType(pointer.type).element == object.type);
-		ASSERT(Type::ID(insn.word(1)) == object.type);
+		ASSERT(getType(pointer.type).element == result.type);
+		ASSERT(Type::ID(insn.word(1)) == result.type);
 		ASSERT((insn.opcode() != spv::OpAtomicLoad) || getType(getType(pointer.type).element).opcode() == spv::OpTypeInt);  // Vulkan 1.1: "Atomic instructions must declare a scalar 32-bit integer type, for the value pointed to by Pointer."
 
 		if (pointerBaseTy.storageClass == spv::StorageClassImage)
@@ -1417,7 +1417,7 @@
 		bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
 		auto anyInactiveLanes = SignMask(~routine->activeLaneMask) != 0;
 
-		auto load = SpirvRoutine::Value(objectTy.sizeInComponents);
+		auto load = std::unique_ptr<SIMD::Float[]>(new SIMD::Float[resultTy.sizeInComponents]);
 
 		If(pointer.kind == Object::Kind::Value || anyInactiveLanes)
 		{
@@ -1425,7 +1425,7 @@
 			auto offsets = pointer.kind == Object::Kind::Value ?
 					As<SIMD::Int>(routine->getIntermediate(pointerId).Int(0)) :
 					RValue<SIMD::Int>(SIMD::Int(0));
-			for (auto i = 0u; i < objectTy.sizeInComponents; i++)
+			for (auto i = 0u; i < resultTy.sizeInComponents; i++)
 			{
 				// i wish i had a Float,Float,Float,Float constructor here..
 				for (int j = 0; j < SIMD::Width; j++)
@@ -1446,7 +1446,7 @@
 			{
 				// Lane-interleaved data.
 				Pointer<SIMD::Float> src = ptrBase;
-				for (auto i = 0u; i < objectTy.sizeInComponents; i++)
+				for (auto i = 0u; i < resultTy.sizeInComponents; i++)
 				{
 					load[i] = src[i];
 				}
@@ -1454,45 +1454,20 @@
 			else
 			{
 				// Non-interleaved data.
-				for (auto i = 0u; i < objectTy.sizeInComponents; i++)
+				for (auto i = 0u; i < resultTy.sizeInComponents; i++)
 				{
 					load[i] = RValue<SIMD::Float>(ptrBase[i]);
 				}
 			}
 		}
 
-		auto &dst = routine->createIntermediate(objectId, objectTy.sizeInComponents);
-		for (auto i = 0u; i < objectTy.sizeInComponents; i++)
+		auto &dst = routine->createIntermediate(resultId, resultTy.sizeInComponents);
+		for (auto i = 0u; i < resultTy.sizeInComponents; i++)
 		{
 			dst.move(i, load[i]);
 		}
 	}
 
-	void SpirvShader::EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const
-	{
-		Type::ID typeId = insn.word(1);
-		Object::ID resultId = insn.word(2);
-		Object::ID baseId = insn.word(3);
-		uint32_t numIndexes = insn.wordCount() - 4;
-		const uint32_t *indexes = insn.wordPointer(4);
-		auto &type = getType(typeId);
-		ASSERT(type.sizeInComponents == 1);
-		ASSERT(getObject(baseId).pointerBase == getObject(resultId).pointerBase);
-
-		auto &dst = routine->createIntermediate(resultId, type.sizeInComponents);
-
-		if(type.storageClass == spv::StorageClassPushConstant ||
-		   type.storageClass == spv::StorageClassUniform ||
-		   type.storageClass == spv::StorageClassStorageBuffer)
-		{
-			dst.move(0, WalkExplicitLayoutAccessChain(baseId, numIndexes, indexes, routine));
-		}
-		else
-		{
-			dst.move(0, WalkAccessChain(baseId, numIndexes, indexes, routine));
-		}
-	}
-
 	void SpirvShader::EmitStore(InsnIterator insn, SpirvRoutine *routine) const
 	{
 		bool atomic = (insn.opcode() == spv::OpAtomicStore);
@@ -1607,6 +1582,31 @@
 		}
 	}
 
+	void SpirvShader::EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const
+	{
+		Type::ID typeId = insn.word(1);
+		Object::ID resultId = insn.word(2);
+		Object::ID baseId = insn.word(3);
+		uint32_t numIndexes = insn.wordCount() - 4;
+		const uint32_t *indexes = insn.wordPointer(4);
+		auto &type = getType(typeId);
+		ASSERT(type.sizeInComponents == 1);
+		ASSERT(getObject(baseId).pointerBase == getObject(resultId).pointerBase);
+
+		auto &dst = routine->createIntermediate(resultId, type.sizeInComponents);
+
+		if(type.storageClass == spv::StorageClassPushConstant ||
+		   type.storageClass == spv::StorageClassUniform ||
+		   type.storageClass == spv::StorageClassStorageBuffer)
+		{
+			dst.move(0, WalkExplicitLayoutAccessChain(baseId, numIndexes, indexes, routine));
+		}
+		else
+		{
+			dst.move(0, WalkAccessChain(baseId, numIndexes, indexes, routine));
+		}
+	}
+
 	void SpirvShader::EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const
 	{
 		auto &type = getType(insn.word(1));