Implement atomic load/store

SIMD vector load and store are already atomic on x86 and ARM, and
Vulkan only supports atomic operations on "scalar 32-bit integer type".

Memory order semantics are handled in a follow-up change.

Bug b/127472316

Test: dEQP-VK.spirv_assembly.instruction.compute.opatomic.load
Test: dEQP-VK.spirv_assembly.instruction.compute.opatomic.store
Change-Id: I4481fe7b7aa792b63f516bd3cb1aab1d773bbcbd
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/27649
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 15307d4..930cff6 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -410,6 +410,7 @@
 			case spv::OpDPdxFine:
 			case spv::OpDPdyFine:
 			case spv::OpFwidthFine:
+			case spv::OpAtomicLoad:
 				// Instructions that yield an intermediate value
 			{
 				Type::ID typeId = insn.word(1);
@@ -431,6 +432,7 @@
 			}
 
 			case spv::OpStore:
+			case spv::OpAtomicStore:
 				// Don't need to do anything during analysis pass
 				break;
 
@@ -1187,10 +1189,12 @@
 			break;
 
 		case spv::OpLoad:
+		case spv::OpAtomicLoad:
 			EmitLoad(insn, routine);
 			break;
 
 		case spv::OpStore:
+		case spv::OpAtomicStore:
 			EmitStore(insn, routine);
 			break;
 
@@ -1393,6 +1397,7 @@
 
 		ASSERT(getType(pointer.type).element == object.type);
 		ASSERT(Type::ID(insn.word(1)) == object.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)
 		{
@@ -1490,8 +1495,9 @@
 
 	void SpirvShader::EmitStore(InsnIterator insn, SpirvRoutine *routine) const
 	{
+		bool atomic = (insn.opcode() == spv::OpAtomicStore);
 		Object::ID pointerId = insn.word(1);
-		Object::ID objectId = insn.word(2);
+		Object::ID objectId = insn.word(atomic ? 4 : 2);
 		auto &object = getObject(objectId);
 		auto &pointer = getObject(pointerId);
 		auto &pointerTy = getType(pointer.type);
@@ -1499,6 +1505,8 @@
 		auto &pointerBase = getObject(pointer.pointerBase);
 		auto &pointerBaseTy = getType(pointerBase.type);
 
+		ASSERT(!atomic || elementTy.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)
 		{
 			UNIMPLEMENTED("StorageClassImage store not yet implemented");