SpirvRoutine: Use SIMD::Pointers for pointers map.

The split of intermediate + base pointer in two maps was ugly.
This is also required for tracking bounds on pointers, required for robustness tests.

Change-Id: I782aeee8caab43ce58ba948dcca97afa2e07482c
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29273
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: 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 32d8bd7..66bdb8d 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -1155,10 +1155,10 @@
 		{
 			case Object::Kind::NonDivergentPointer:
 			case Object::Kind::InterfaceVariable:
-				return SIMD::Pointer(routine->getPointer(id));
+				return routine->getPointer(id);
 
 			case Object::Kind::DivergentPointer:
-				return SIMD::Pointer(routine->getPointer(id), routine->getIntermediate(id).Int(0));
+				return routine->getPointer(id);
 
 			case Object::Kind::DescriptorSet:
 			{
@@ -1167,10 +1167,12 @@
 				ASSERT(d.Binding >= 0);
 
 				auto set = routine->getPointer(id);
+				ASSERT(set.uniform);
+
 				auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet);
 				int bindingOffset = static_cast<int>(setLayout->getBindingOffset(d.Binding, arrayIndex));
 
-				Pointer<Byte> bufferInfo = Pointer<Byte>(set + bindingOffset); // VkDescriptorBufferInfo*
+				Pointer<Byte> bufferInfo = Pointer<Byte>(set.base) + bindingOffset; // VkDescriptorBufferInfo*
 				Pointer<Byte> buffer = *Pointer<Pointer<Byte>>(bufferInfo + OFFSET(VkDescriptorBufferInfo, buffer)); // vk::Buffer*
 				Pointer<Byte> data = *Pointer<Pointer<Byte>>(buffer + vk::Buffer::DataOffset); // void*
 				Int offset = *Pointer<Int>(bufferInfo + OFFSET(VkDescriptorBufferInfo, offset));
@@ -1278,9 +1280,13 @@
 				ASSERT(d.HasArrayStride);
 				auto & obj = getObject(indexIds[i]);
 				if (obj.kind == Object::Kind::Constant)
+				{
 					constantOffset += d.ArrayStride/sizeof(float) * GetConstantInt(indexIds[i]);
+				}
 				else
-					ptr.offset += SIMD::Int(d.ArrayStride / sizeof(float)) * routine->getIntermediate(indexIds[i]).Int(0);
+				{
+					ptr.addOffset(SIMD::Int(d.ArrayStride / sizeof(float)) * routine->getIntermediate(indexIds[i]).Int(0));
+				}
 				typeId = type.element;
 				break;
 			}
@@ -1292,9 +1298,13 @@
 				auto columnStride = (d.HasRowMajor && d.RowMajor) ? 1 : d.MatrixStride/sizeof(float);
 				auto & obj = getObject(indexIds[i]);
 				if (obj.kind == Object::Kind::Constant)
+				{
 					constantOffset += columnStride * GetConstantInt(indexIds[i]);
+				}
 				else
-					ptr.offset += SIMD::Int(columnStride) * routine->getIntermediate(indexIds[i]).Int(0);
+				{
+					ptr.addOffset(SIMD::Int(columnStride) * routine->getIntermediate(indexIds[i]).Int(0));
+				}
 				typeId = type.element;
 				break;
 			}
@@ -1303,9 +1313,13 @@
 				auto elemStride = (d.InsideMatrix && d.HasRowMajor && d.RowMajor) ? d.MatrixStride / sizeof(float) : 1;
 				auto & obj = getObject(indexIds[i]);
 				if (obj.kind == Object::Kind::Constant)
+				{
 					constantOffset += elemStride * GetConstantInt(indexIds[i]);
+				}
 				else
-					ptr.offset += SIMD::Int(elemStride) * routine->getIntermediate(indexIds[i]).Int(0);
+				{
+					ptr.addOffset(SIMD::Int(elemStride) * routine->getIntermediate(indexIds[i]).Int(0));
+				}
 				typeId = type.element;
 				break;
 			}
@@ -1314,27 +1328,23 @@
 			}
 		}
 
-		ptr.offset += SIMD::Int(constantOffset);
-
+		if (constantOffset != 0)
+		{
+			ptr.addOffset(constantOffset);
+		}
 		return ptr;
 	}
 
-	SIMD::Int SpirvShader::WalkAccessChain(Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
+	SIMD::Pointer SpirvShader::WalkAccessChain(Object::ID baseId, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
 	{
 		// TODO: avoid doing per-lane work in some cases if we can?
-		// Produce a *component* offset into location-oriented memory
 
-		int constantOffset = 0;
-		SIMD::Int dynamicOffset = SIMD::Int(0);
 		auto &baseObject = getObject(baseId);
 		Type::ID typeId = getType(baseObject.type).element;
 
-		// The <base> operand is a divergent pointer itself.
-		// Start with its offset and build from there.
-		if (baseObject.kind == Object::Kind::DivergentPointer)
-		{
-			dynamicOffset += routine->getIntermediate(baseId).Int(0);
-		}
+		auto ptr = routine->getPointer(baseId);
+
+		int constantOffset = 0;
 
 		for (auto i = 0u; i < numIndexes; i++)
 		{
@@ -1363,9 +1373,13 @@
 				auto stride = getType(type.element).sizeInComponents;
 				auto & obj = getObject(indexIds[i]);
 				if (obj.kind == Object::Kind::Constant)
+				{
 					constantOffset += stride * GetConstantInt(indexIds[i]);
+				}
 				else
-					dynamicOffset += SIMD::Int(stride) * routine->getIntermediate(indexIds[i]).Int(0);
+				{
+					ptr.addOffset(SIMD::Int(stride) * routine->getIntermediate(indexIds[i]).Int(0));
+				}
 				typeId = type.element;
 				break;
 			}
@@ -1375,7 +1389,11 @@
 			}
 		}
 
-		return dynamicOffset + SIMD::Int(constantOffset);
+		if (constantOffset != 0)
+		{
+			ptr.addOffset(SIMD::Int(constantOffset));
+		}
+		return ptr;
 	}
 
 	uint32_t SpirvShader::WalkLiteralAccessChain(Type::ID typeId, uint32_t numIndexes, uint32_t const *indexes) const
@@ -2196,7 +2214,8 @@
 		case spv::StorageClassPrivate:
 		case spv::StorageClassFunction:
 		{
-			routine->createPointer(resultId, &routine->getVariable(resultId)[0]);
+			auto base = &routine->getVariable(resultId)[0];
+			routine->createPointer(resultId, SIMD::Pointer(base));
 			break;
 		}
 		case spv::StorageClassInput:
@@ -2211,7 +2230,8 @@
 									dst[offset++] = routine->inputs[scalarSlot];
 								});
 			}
-			routine->createPointer(resultId, &routine->getVariable(resultId)[0]);
+			auto base = &routine->getVariable(resultId)[0];
+			routine->createPointer(resultId, SIMD::Pointer(base));
 			break;
 		}
 		case spv::StorageClassUniformConstant:
@@ -2224,8 +2244,8 @@
 			auto setLayout = routine->pipelineLayout->getDescriptorSetLayout(d.DescriptorSet);
 			size_t bindingOffset = setLayout->getBindingOffset(d.Binding, arrayIndex);
 			Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet];  // DescriptorSet*
-			Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset);    // SampledImageDescriptor*
-			routine->createPointer(resultId, binding);
+			Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset);    // vk::SampledImageDescriptor*
+			routine->createPointer(resultId, SIMD::Pointer(binding));
 			break;
 		}
 		case spv::StorageClassUniform:
@@ -2234,12 +2254,12 @@
 			const auto &d = descriptorDecorations.at(resultId);
 			ASSERT(d.DescriptorSet >= 0 && d.DescriptorSet < vk::MAX_BOUND_DESCRIPTOR_SETS);
 
-			routine->createPointer(resultId, routine->descriptorSets[d.DescriptorSet]);
+			routine->createPointer(resultId, SIMD::Pointer(routine->descriptorSets[d.DescriptorSet]));
 			break;
 		}
 		case spv::StorageClassPushConstant:
 		{
-			routine->createPointer(resultId, routine->pushConstants);
+			routine->createPointer(resultId, SIMD::Pointer(routine->pushConstants));
 			break;
 		}
 		default:
@@ -2469,14 +2489,12 @@
 		   type.storageClass == spv::StorageClassStorageBuffer)
 		{
 			auto ptr = WalkExplicitLayoutAccessChain(baseId, numIndexes, indexes, routine);
-			routine->createPointer(resultId, ptr.base);
-			routine->createIntermediate(resultId, type.sizeInComponents).move(0, ptr.offset);
+			routine->createPointer(resultId, ptr);
 		}
 		else
 		{
-			auto offset = WalkAccessChain(baseId, numIndexes, indexes, routine);
-			routine->createPointer(resultId, routine->getPointer(baseId));
-			routine->createIntermediate(resultId, type.sizeInComponents).move(0, offset);
+			auto ptr = WalkAccessChain(baseId, numIndexes, indexes, routine);
+			routine->createPointer(resultId, ptr);
 		}
 
 		return EmitResult::Continue;
@@ -4340,7 +4358,7 @@
 		in[1] = coordinate.Float(1);
 
 		Array<SIMD::Float> out(4);
-		Call<ImageSampler>(samplerFunc, sampledImage, &in[0], &out[0]);
+		Call<ImageSampler>(samplerFunc, sampledImage.base, &in[0], &out[0]);
 
 		for (int i = 0; i < 4; i++) { result.move(i, out[i]); }
 
@@ -4717,12 +4735,10 @@
 		Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset);
 		Pointer<Byte> imageBase = *Pointer<Pointer<Byte>>(binding + OFFSET(vk::StorageImageDescriptor, ptr));
 
-		state->routine->createPointer(resultId, imageBase);
-
-		// TODO: texelOffset is in bytes. get rid of shift once Ben's changes for DivergentPointer land
+		// TODO: texelOffset is in bytes - remove shift when SIMD::Pointer is offset by bytes.
 		SIMD::Int texelOffset = GetTexelOffset(coordinate, imageType, binding, sizeof(uint32_t)) >> 2;
-		auto &dst = state->routine->createIntermediate(resultId, resultType.sizeInComponents);
-		dst.move(0, texelOffset);
+
+		state->routine->createPointer(resultId, SIMD::Pointer(imageBase, texelOffset));
 
 		return EmitResult::Continue;
 	}
@@ -4736,45 +4752,44 @@
 		auto memoryOrder = MemoryOrder(memorySemantics);
 		auto value = GenericValue(this, state->routine, insn.word(6));
 		auto &dst = state->routine->createIntermediate(resultId, resultType.sizeInComponents);
-		auto ptr = Pointer<UInt>(state->routine->getPointer(insn.word(3)));
-		auto offsets = state->routine->getIntermediate(insn.word(3)).UInt(0);
+		auto ptr = state->routine->getPointer(insn.word(3));
 
 		SIMD::UInt x;
 		for (int j = 0; j < SIMD::Width; j++)
 		{
 			If(Extract(state->activeLaneMask(), j) != 0)
 			{
-				auto offset = Extract(offsets, j);
+				auto offset = Extract(ptr.offset, j);
 				auto laneValue = Extract(value.UInt(0), j);
 				UInt v;
 				switch (insn.opcode())
 				{
 				case spv::OpAtomicIAdd:
-					v = AddAtomic(&ptr[offset], laneValue, memoryOrder);
+					v = AddAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
 					break;
 				case spv::OpAtomicAnd:
-					v = AndAtomic(&ptr[offset], laneValue, memoryOrder);
+					v = AndAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
 					break;
 				case spv::OpAtomicOr:
-					v = OrAtomic(&ptr[offset], laneValue, memoryOrder);
+					v = OrAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
 					break;
 				case spv::OpAtomicXor:
-					v = XorAtomic(&ptr[offset], laneValue, memoryOrder);
+					v = XorAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
 					break;
 				case spv::OpAtomicSMin:
-					v = As<UInt>(MinAtomic(As<Pointer<Int>>(&ptr[offset]), As<Int>(laneValue), memoryOrder));
+					v = As<UInt>(MinAtomic(Pointer<Int>(&ptr.base[offset]), As<Int>(laneValue), memoryOrder));
 					break;
 				case spv::OpAtomicSMax:
-					v = As<UInt>(MaxAtomic(As<Pointer<Int>>(&ptr[offset]), As<Int>(laneValue), memoryOrder));
+					v = As<UInt>(MaxAtomic(Pointer<Int>(&ptr.base[offset]), As<Int>(laneValue), memoryOrder));
 					break;
 				case spv::OpAtomicUMin:
-					v = MinAtomic(&ptr[offset], laneValue, memoryOrder);
+					v = MinAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
 					break;
 				case spv::OpAtomicUMax:
-					v = MaxAtomic(&ptr[offset], laneValue, memoryOrder);
+					v = MaxAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
 					break;
 				case spv::OpAtomicExchange:
-					v = ExchangeAtomic(&ptr[offset], laneValue, memoryOrder);
+					v = ExchangeAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, memoryOrder);
 					break;
 				default:
 					UNIMPLEMENTED("Atomic op", OpcodeName(insn.opcode()).c_str());
@@ -4802,18 +4817,17 @@
 		auto value = GenericValue(this, state->routine, insn.word(7));
 		auto comparator = GenericValue(this, state->routine, insn.word(8));
 		auto &dst = state->routine->createIntermediate(resultId, resultType.sizeInComponents);
-		auto ptr = Pointer<UInt>(state->routine->getPointer(insn.word(3)));
-		auto offsets = state->routine->getIntermediate(insn.word(3)).UInt(0);
+		auto ptr = state->routine->getPointer(insn.word(3));
 
 		SIMD::UInt x;
 		for (int j = 0; j < SIMD::Width; j++)
 		{
 			If(Extract(state->activeLaneMask(), j) != 0)
 			{
-				auto offset = Extract(offsets, j);
+				auto offset = Extract(ptr.offset, j);
 				auto laneValue = Extract(value.UInt(0), j);
 				auto laneComparator = Extract(comparator.UInt(0), j);
-				UInt v = CompareExchangeAtomic(&ptr[offset], laneValue, laneComparator, memoryOrderEqual, memoryOrderUnequal);
+				UInt v = CompareExchangeAtomic(Pointer<UInt>(&ptr.base[offset]), laneValue, laneComparator, memoryOrderEqual, memoryOrderUnequal);
 				x = Insert(x, v, j);
 			}
 		}
diff --git a/src/Pipeline/SpirvShader.hpp b/src/Pipeline/SpirvShader.hpp
index 4b0879c..7a0b30e 100644
--- a/src/Pipeline/SpirvShader.hpp
+++ b/src/Pipeline/SpirvShader.hpp
@@ -68,11 +68,13 @@
 			Pointer(rr::Pointer<Byte> base) : base(base), offset(0), uniform(true) {}
 			Pointer(rr::Pointer<Byte> base, SIMD::Int offset) : base(base), offset(offset), uniform(false) {}
 
+			inline void addOffset(Int delta) { offset += delta; uniform = false; }
+
 			// Base address for the pointer, common across all lanes.
 			rr::Pointer<rr::Float> base;
 
 			// Per lane offsets from base.
-			// If uniform is false, all offsets are considered zero.
+			// If uniform is true, all offsets are considered zero.
 			Int offset;
 
 			// True if all offsets are zero.
@@ -274,8 +276,7 @@
 				Intermediate,
 
 				// DivergentPointer formed from a base pointer and per-lane offset.
-				// Base pointer held by SpirvRoutine::pointers
-				// Per-lane offset held by SpirvRoutine::intermediates.
+				// Pointer held by SpirvRoutine::pointers
 				DivergentPointer,
 
 				// Pointer with uniform address across all lanes.
@@ -287,6 +288,7 @@
 				DescriptorSet,
 
 				// Pointer to an image/sampler descriptor.
+				// Pointer held by SpirvRoutine::pointers.
 				SampledImage,
 			};
 
@@ -621,7 +623,7 @@
 		SIMD::Pointer GetPointerToData(Object::ID id, int arrayIndex, SpirvRoutine *routine) const;
 
 		SIMD::Pointer WalkExplicitLayoutAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
-		SIMD::Int WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
+		SIMD::Pointer WalkAccessChain(Object::ID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const;
 		uint32_t WalkLiteralAccessChain(Type::ID id, uint32_t numIndexes, uint32_t const *indexes) const;
 
 		// EmitState holds control-flow state for the emit() pass.
@@ -772,7 +774,7 @@
 
 		std::unordered_map<SpirvShader::Object::ID, Intermediate> intermediates;
 
-		std::unordered_map<SpirvShader::Object::ID, Pointer<Byte> > pointers;
+		std::unordered_map<SpirvShader::Object::ID, SIMD::Pointer> pointers;
 
 		Variable inputs = Variable{MAX_INTERFACE_COMPONENTS};
 		Variable outputs = Variable{MAX_INTERFACE_COMPONENTS};
@@ -788,25 +790,12 @@
 			ASSERT_MSG(added, "Variable %d created twice", id.value());
 		}
 
-		template <typename T>
-		void createPointer(SpirvShader::Object::ID id, Pointer<T> ptrBase)
+		void createPointer(SpirvShader::Object::ID id, SIMD::Pointer ptr)
 		{
-			bool added = pointers.emplace(id, ptrBase).second;
+			bool added = pointers.emplace(id, ptr).second;
 			ASSERT_MSG(added, "Pointer %d created twice", id.value());
 		}
 
-		template <typename T>
-		void createPointer(SpirvShader::Object::ID id, RValue<Pointer<T>> ptrBase)
-		{
-			createPointer(id, Pointer<T>(ptrBase));
-		}
-
-		template <typename T>
-		void createPointer(SpirvShader::Object::ID id, Reference<Pointer<T>> ptrBase)
-		{
-			createPointer(id, Pointer<T>(ptrBase));
-		}
-
 		Intermediate& createIntermediate(SpirvShader::Object::ID id, uint32_t size)
 		{
 			auto it = intermediates.emplace(std::piecewise_construct,
@@ -830,7 +819,7 @@
 			return it->second;
 		}
 
-		Pointer<Byte>& getPointer(SpirvShader::Object::ID id)
+		SIMD::Pointer const& getPointer(SpirvShader::Object::ID id) const
 		{
 			auto it = pointers.find(id);
 			ASSERT_MSG(it != pointers.end(), "Unknown pointer %d", id.value());