Merge pull request #1996 from KhronosGroup/fix-1993

MSL: Fix various bugs with Ptr/U bitcasts.
diff --git a/reference/opt/shaders-msl/comp/buffer_device_address-packed-vec-and-cast-to-and-from-uvec2.msl23.comp b/reference/opt/shaders-msl/comp/buffer_device_address-packed-vec-and-cast-to-and-from-uvec2.msl23.comp
index f2ba541..fb56148 100644
--- a/reference/opt/shaders-msl/comp/buffer_device_address-packed-vec-and-cast-to-and-from-uvec2.msl23.comp
+++ b/reference/opt/shaders-msl/comp/buffer_device_address-packed-vec-and-cast-to-and-from-uvec2.msl23.comp
@@ -18,10 +18,10 @@
 
 kernel void main0(constant UBO& _10 [[buffer(0)]])
 {
-    ((device SSBO*)as_type<uint64_t>(_10.b))->a1 = float3(1.0, 2.0, 3.0);
-    uint2 _35 = as_type<uint2>((uint64_t)((device SSBO*)as_type<uint64_t>(_10.b + uint2(32u))));
+    (reinterpret_cast<device SSBO*>(as_type<ulong>(_10.b)))->a1 = float3(1.0, 2.0, 3.0);
+    uint2 _35 = as_type<uint2>(reinterpret_cast<ulong>(reinterpret_cast<device SSBO*>(as_type<ulong>(_10.b + uint2(32u)))));
     uint2 v2 = _35;
-    device SSBO* _39 = ((device SSBO*)as_type<uint64_t>(_35));
+    device SSBO* _39 = reinterpret_cast<device SSBO*>(as_type<ulong>(_35));
     float3 v3 = float3(_39->a1);
     _39->a1 = float3(_39->a1) + float3(1.0);
 }
diff --git a/reference/shaders-msl-no-opt/asm/comp/buffer-device-address-ptr-casting.msl24.asm.comp b/reference/shaders-msl-no-opt/asm/comp/buffer-device-address-ptr-casting.msl24.asm.comp
new file mode 100644
index 0000000..7446409
--- /dev/null
+++ b/reference/shaders-msl-no-opt/asm/comp/buffer-device-address-ptr-casting.msl24.asm.comp
@@ -0,0 +1,33 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct SomeBuffer;
+
+struct SomeBuffer
+{
+    float4 v;
+    ulong a;
+    uint2 b;
+};
+
+struct Registers
+{
+    ulong address;
+    uint2 address2;
+};
+
+kernel void main0(constant Registers& registers [[buffer(0)]])
+{
+    device SomeBuffer* _44 = reinterpret_cast<device SomeBuffer*>(registers.address);
+    device SomeBuffer* _45 = reinterpret_cast<device SomeBuffer*>(registers.address);
+    device SomeBuffer* _46 = reinterpret_cast<device SomeBuffer*>(as_type<ulong>(registers.address2));
+    _44->v = float4(1.0, 2.0, 3.0, 4.0);
+    _45->v = float4(1.0, 2.0, 3.0, 4.0);
+    _46->v = float4(1.0, 2.0, 3.0, 4.0);
+    _44->a = reinterpret_cast<ulong>(_44);
+    _45->a = reinterpret_cast<ulong>(_45);
+    _46->b = as_type<uint2>(reinterpret_cast<ulong>(_46));
+}
+
diff --git a/reference/shaders-msl/comp/buffer_device_address-packed-vec-and-cast-to-and-from-uvec2.msl23.comp b/reference/shaders-msl/comp/buffer_device_address-packed-vec-and-cast-to-and-from-uvec2.msl23.comp
index 474d509..f79a8b5 100644
--- a/reference/shaders-msl/comp/buffer_device_address-packed-vec-and-cast-to-and-from-uvec2.msl23.comp
+++ b/reference/shaders-msl/comp/buffer_device_address-packed-vec-and-cast-to-and-from-uvec2.msl23.comp
@@ -18,9 +18,9 @@
 
 kernel void main0(constant UBO& _10 [[buffer(0)]])
 {
-    ((device SSBO*)as_type<uint64_t>(_10.b))->a1 = float3(1.0, 2.0, 3.0);
-    uint2 v2 = as_type<uint2>((uint64_t)((device SSBO*)as_type<uint64_t>(_10.b + uint2(32u))));
-    float3 v3 = float3(((device SSBO*)as_type<uint64_t>(v2))->a1);
-    ((device SSBO*)as_type<uint64_t>(v2))->a1 = v3 + float3(1.0);
+    (reinterpret_cast<device SSBO*>(as_type<ulong>(_10.b)))->a1 = float3(1.0, 2.0, 3.0);
+    uint2 v2 = as_type<uint2>(reinterpret_cast<ulong>(reinterpret_cast<device SSBO*>(as_type<ulong>(_10.b + uint2(32u)))));
+    float3 v3 = float3((reinterpret_cast<device SSBO*>(as_type<ulong>(v2)))->a1);
+    (reinterpret_cast<device SSBO*>(as_type<ulong>(v2)))->a1 = v3 + float3(1.0);
 }
 
diff --git a/reference/shaders-no-opt/asm/comp/buffer-device-address-ptr-casting.vk.nocompat.asm.comp.vk b/reference/shaders-no-opt/asm/comp/buffer-device-address-ptr-casting.vk.nocompat.asm.comp.vk
new file mode 100644
index 0000000..f082267
--- /dev/null
+++ b/reference/shaders-no-opt/asm/comp/buffer-device-address-ptr-casting.vk.nocompat.asm.comp.vk
@@ -0,0 +1,37 @@
+#version 450
+#if defined(GL_ARB_gpu_shader_int64)
+#extension GL_ARB_gpu_shader_int64 : require
+#else
+#error No extension available for 64-bit integers.
+#endif
+#extension GL_EXT_buffer_reference : require
+#extension GL_EXT_buffer_reference_uvec2 : require
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+
+layout(buffer_reference) buffer SomeBuffer;
+layout(buffer_reference, buffer_reference_align = 16, std430) buffer SomeBuffer
+{
+    vec4 v;
+    uint64_t a;
+    uvec2 b;
+};
+
+layout(push_constant, std430) uniform Registers
+{
+    uint64_t address;
+    uvec2 address2;
+} registers;
+
+void main()
+{
+    SomeBuffer _44 = SomeBuffer(registers.address);
+    SomeBuffer _45 = SomeBuffer(registers.address);
+    SomeBuffer _46 = SomeBuffer(registers.address2);
+    _44.v = vec4(1.0, 2.0, 3.0, 4.0);
+    _45.v = vec4(1.0, 2.0, 3.0, 4.0);
+    _46.v = vec4(1.0, 2.0, 3.0, 4.0);
+    _44.a = uint64_t(_44);
+    _45.a = uint64_t(_45);
+    _46.b = uvec2(_46);
+}
+
diff --git a/shaders-msl-no-opt/asm/comp/buffer-device-address-ptr-casting.msl24.asm.comp b/shaders-msl-no-opt/asm/comp/buffer-device-address-ptr-casting.msl24.asm.comp
new file mode 100644
index 0000000..ed8d0ba
--- /dev/null
+++ b/shaders-msl-no-opt/asm/comp/buffer-device-address-ptr-casting.msl24.asm.comp
@@ -0,0 +1,106 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 62
+; Schema: 0
+               OpCapability Shader
+               OpCapability Int64
+               OpCapability PhysicalStorageBufferAddresses
+               OpExtension "SPV_KHR_physical_storage_buffer"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel PhysicalStorageBuffer64 GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpSource GLSL 450
+               OpSourceExtension "GL_ARB_gpu_shader_int64"
+               OpSourceExtension "GL_EXT_buffer_reference"
+               OpSourceExtension "GL_EXT_buffer_reference_uvec2"
+               OpName %main "main"
+               OpName %SomeBuffer "SomeBuffer"
+               OpMemberName %SomeBuffer 0 "v"
+               OpMemberName %SomeBuffer 1 "a"
+               OpMemberName %SomeBuffer 2 "b"
+               OpName %Registers "Registers"
+               OpMemberName %Registers 0 "address"
+               OpMemberName %Registers 1 "address2"
+               OpName %registers "registers"
+               OpName %a "a"
+               OpName %b "b"
+               OpMemberDecorate %SomeBuffer 0 Offset 0
+               OpMemberDecorate %SomeBuffer 1 Offset 16
+               OpMemberDecorate %SomeBuffer 2 Offset 24
+               OpDecorate %SomeBuffer Block
+               OpMemberDecorate %Registers 0 Offset 0
+               OpMemberDecorate %Registers 1 Offset 8
+               OpDecorate %Registers Block
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+               OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_SomeBuffer PhysicalStorageBuffer
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+      %ulong = OpTypeInt 64 0
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+ %SomeBuffer = OpTypeStruct %v4float %ulong %v2uint
+%_ptr_PhysicalStorageBuffer_SomeBuffer = OpTypePointer PhysicalStorageBuffer %SomeBuffer
+%_ptr_Function__ptr_PhysicalStorageBuffer_SomeBuffer = OpTypePointer Function %_ptr_PhysicalStorageBuffer_SomeBuffer
+  %Registers = OpTypeStruct %ulong %v2uint
+%_ptr_PushConstant_Registers = OpTypePointer PushConstant %Registers
+  %registers = OpVariable %_ptr_PushConstant_Registers PushConstant
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+%_ptr_PushConstant_ulong = OpTypePointer PushConstant %ulong
+      %int_1 = OpConstant %int 1
+%_ptr_PushConstant_v2uint = OpTypePointer PushConstant %v2uint
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+         %35 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
+%_ptr_PhysicalStorageBuffer_v4float = OpTypePointer PhysicalStorageBuffer %v4float
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+         %43 = OpConstantComposite %v4float %float_5 %float_6 %float_7 %float_8
+%_ptr_Function_ulong = OpTypePointer Function %ulong
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+%_ptr_PhysicalStorageBuffer_ulong = OpTypePointer PhysicalStorageBuffer %ulong
+      %int_2 = OpConstant %int 2
+%_ptr_PhysicalStorageBuffer_v2uint = OpTypePointer PhysicalStorageBuffer %v2uint
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+          %a = OpVariable %_ptr_Function_ulong Function
+          %b = OpVariable %_ptr_Function_v2uint Function
+         %21 = OpAccessChain %_ptr_PushConstant_ulong %registers %int_0
+         %27 = OpAccessChain %_ptr_PushConstant_v2uint %registers %int_1
+         %uint_ptr0 = OpLoad %ulong %21
+         %uint_ptr1 = OpLoad %v2uint %27
+
+		 ; ConvertUToPtr and vice versa do not accept vectors.
+         %ulong_ptr0 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_SomeBuffer %uint_ptr0
+         %ulong_ptr1 = OpBitcast %_ptr_PhysicalStorageBuffer_SomeBuffer %uint_ptr0
+         %uvec2_ptr0 = OpBitcast %_ptr_PhysicalStorageBuffer_SomeBuffer %uint_ptr1
+
+         %vec4_write0 = OpAccessChain %_ptr_PhysicalStorageBuffer_v4float %ulong_ptr0 %int_0
+         %vec4_write1 = OpAccessChain %_ptr_PhysicalStorageBuffer_v4float %ulong_ptr1 %int_0
+         %vec4_write2 = OpAccessChain %_ptr_PhysicalStorageBuffer_v4float %uvec2_ptr0 %int_0
+
+		   OpStore %vec4_write0 %35 Aligned 16
+		   OpStore %vec4_write1 %35 Aligned 16
+		   OpStore %vec4_write2 %35 Aligned 16
+
+         %ulong_from_ptr0 = OpConvertPtrToU %ulong %ulong_ptr0
+         %ulong_from_ptr1 = OpBitcast %ulong %ulong_ptr1
+         %uvec2_from_ptr0 = OpBitcast %v2uint %uvec2_ptr0
+
+         %ptr0 = OpAccessChain %_ptr_PhysicalStorageBuffer_ulong %ulong_ptr0 %int_1
+         %ptr1 = OpAccessChain %_ptr_PhysicalStorageBuffer_ulong %ulong_ptr1 %int_1
+         %ptr2 = OpAccessChain %_ptr_PhysicalStorageBuffer_v2uint %uvec2_ptr0 %int_2
+
+		   OpStore %ptr0 %ulong_from_ptr0 Aligned 8
+		   OpStore %ptr1 %ulong_from_ptr1 Aligned 8
+		   OpStore %ptr2 %uvec2_from_ptr0 Aligned 8
+
+               OpReturn
+               OpFunctionEnd
diff --git a/shaders-no-opt/asm/comp/buffer-device-address-ptr-casting.vk.nocompat.asm.comp b/shaders-no-opt/asm/comp/buffer-device-address-ptr-casting.vk.nocompat.asm.comp
new file mode 100644
index 0000000..ed8d0ba
--- /dev/null
+++ b/shaders-no-opt/asm/comp/buffer-device-address-ptr-casting.vk.nocompat.asm.comp
@@ -0,0 +1,106 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 62
+; Schema: 0
+               OpCapability Shader
+               OpCapability Int64
+               OpCapability PhysicalStorageBufferAddresses
+               OpExtension "SPV_KHR_physical_storage_buffer"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel PhysicalStorageBuffer64 GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpSource GLSL 450
+               OpSourceExtension "GL_ARB_gpu_shader_int64"
+               OpSourceExtension "GL_EXT_buffer_reference"
+               OpSourceExtension "GL_EXT_buffer_reference_uvec2"
+               OpName %main "main"
+               OpName %SomeBuffer "SomeBuffer"
+               OpMemberName %SomeBuffer 0 "v"
+               OpMemberName %SomeBuffer 1 "a"
+               OpMemberName %SomeBuffer 2 "b"
+               OpName %Registers "Registers"
+               OpMemberName %Registers 0 "address"
+               OpMemberName %Registers 1 "address2"
+               OpName %registers "registers"
+               OpName %a "a"
+               OpName %b "b"
+               OpMemberDecorate %SomeBuffer 0 Offset 0
+               OpMemberDecorate %SomeBuffer 1 Offset 16
+               OpMemberDecorate %SomeBuffer 2 Offset 24
+               OpDecorate %SomeBuffer Block
+               OpMemberDecorate %Registers 0 Offset 0
+               OpMemberDecorate %Registers 1 Offset 8
+               OpDecorate %Registers Block
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+               OpTypeForwardPointer %_ptr_PhysicalStorageBuffer_SomeBuffer PhysicalStorageBuffer
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+      %ulong = OpTypeInt 64 0
+       %uint = OpTypeInt 32 0
+     %v2uint = OpTypeVector %uint 2
+ %SomeBuffer = OpTypeStruct %v4float %ulong %v2uint
+%_ptr_PhysicalStorageBuffer_SomeBuffer = OpTypePointer PhysicalStorageBuffer %SomeBuffer
+%_ptr_Function__ptr_PhysicalStorageBuffer_SomeBuffer = OpTypePointer Function %_ptr_PhysicalStorageBuffer_SomeBuffer
+  %Registers = OpTypeStruct %ulong %v2uint
+%_ptr_PushConstant_Registers = OpTypePointer PushConstant %Registers
+  %registers = OpVariable %_ptr_PushConstant_Registers PushConstant
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+%_ptr_PushConstant_ulong = OpTypePointer PushConstant %ulong
+      %int_1 = OpConstant %int 1
+%_ptr_PushConstant_v2uint = OpTypePointer PushConstant %v2uint
+    %float_1 = OpConstant %float 1
+    %float_2 = OpConstant %float 2
+    %float_3 = OpConstant %float 3
+    %float_4 = OpConstant %float 4
+         %35 = OpConstantComposite %v4float %float_1 %float_2 %float_3 %float_4
+%_ptr_PhysicalStorageBuffer_v4float = OpTypePointer PhysicalStorageBuffer %v4float
+    %float_5 = OpConstant %float 5
+    %float_6 = OpConstant %float 6
+    %float_7 = OpConstant %float 7
+    %float_8 = OpConstant %float 8
+         %43 = OpConstantComposite %v4float %float_5 %float_6 %float_7 %float_8
+%_ptr_Function_ulong = OpTypePointer Function %ulong
+%_ptr_Function_v2uint = OpTypePointer Function %v2uint
+%_ptr_PhysicalStorageBuffer_ulong = OpTypePointer PhysicalStorageBuffer %ulong
+      %int_2 = OpConstant %int 2
+%_ptr_PhysicalStorageBuffer_v2uint = OpTypePointer PhysicalStorageBuffer %v2uint
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+          %a = OpVariable %_ptr_Function_ulong Function
+          %b = OpVariable %_ptr_Function_v2uint Function
+         %21 = OpAccessChain %_ptr_PushConstant_ulong %registers %int_0
+         %27 = OpAccessChain %_ptr_PushConstant_v2uint %registers %int_1
+         %uint_ptr0 = OpLoad %ulong %21
+         %uint_ptr1 = OpLoad %v2uint %27
+
+		 ; ConvertUToPtr and vice versa do not accept vectors.
+         %ulong_ptr0 = OpConvertUToPtr %_ptr_PhysicalStorageBuffer_SomeBuffer %uint_ptr0
+         %ulong_ptr1 = OpBitcast %_ptr_PhysicalStorageBuffer_SomeBuffer %uint_ptr0
+         %uvec2_ptr0 = OpBitcast %_ptr_PhysicalStorageBuffer_SomeBuffer %uint_ptr1
+
+         %vec4_write0 = OpAccessChain %_ptr_PhysicalStorageBuffer_v4float %ulong_ptr0 %int_0
+         %vec4_write1 = OpAccessChain %_ptr_PhysicalStorageBuffer_v4float %ulong_ptr1 %int_0
+         %vec4_write2 = OpAccessChain %_ptr_PhysicalStorageBuffer_v4float %uvec2_ptr0 %int_0
+
+		   OpStore %vec4_write0 %35 Aligned 16
+		   OpStore %vec4_write1 %35 Aligned 16
+		   OpStore %vec4_write2 %35 Aligned 16
+
+         %ulong_from_ptr0 = OpConvertPtrToU %ulong %ulong_ptr0
+         %ulong_from_ptr1 = OpBitcast %ulong %ulong_ptr1
+         %uvec2_from_ptr0 = OpBitcast %v2uint %uvec2_ptr0
+
+         %ptr0 = OpAccessChain %_ptr_PhysicalStorageBuffer_ulong %ulong_ptr0 %int_1
+         %ptr1 = OpAccessChain %_ptr_PhysicalStorageBuffer_ulong %ulong_ptr1 %int_1
+         %ptr2 = OpAccessChain %_ptr_PhysicalStorageBuffer_v2uint %uvec2_ptr0 %int_2
+
+		   OpStore %ptr0 %ulong_from_ptr0 Aligned 8
+		   OpStore %ptr1 %ulong_from_ptr1 Aligned 8
+		   OpStore %ptr2 %uvec2_from_ptr0 Aligned 8
+
+               OpReturn
+               OpFunctionEnd
diff --git a/spirv_msl.cpp b/spirv_msl.cpp
index 09a063b..583a923 100644
--- a/spirv_msl.cpp
+++ b/spirv_msl.cpp
@@ -8851,6 +8851,34 @@
 #undef MSL_RAY_QUERY_IS_OP2
 #undef MSL_RAY_QUERY_GET_OP2
 #undef MSL_RAY_QUERY_OP_INNER2
+
+	case OpConvertPtrToU:
+	case OpConvertUToPtr:
+	case OpBitcast:
+	{
+		auto &type = get<SPIRType>(ops[0]);
+		auto &input_type = expression_type(ops[2]);
+
+		if (opcode != OpBitcast || type.pointer || input_type.pointer)
+		{
+			string op;
+
+			if (type.vecsize == 1 && input_type.vecsize == 1)
+				op = join("reinterpret_cast<", type_to_glsl(type), ">(", to_unpacked_expression(ops[2]), ")");
+			else if (input_type.vecsize == 2)
+				op = join("reinterpret_cast<", type_to_glsl(type), ">(as_type<ulong>(", to_unpacked_expression(ops[2]), "))");
+			else
+				op = join("as_type<", type_to_glsl(type), ">(reinterpret_cast<ulong>(", to_unpacked_expression(ops[2]), "))");
+
+			emit_op(ops[0], ops[1], op, should_forward(ops[2]));
+			inherit_expression_dependencies(ops[1], ops[2]);
+		}
+		else
+			CompilerGLSL::emit_instruction(instruction);
+
+		break;
+	}
+
 	default:
 		CompilerGLSL::emit_instruction(instruction);
 		break;
@@ -14590,26 +14618,10 @@
 		return type_to_glsl(out_type);
 }
 
-bool CompilerMSL::emit_complex_bitcast(uint32_t result_type, uint32_t id, uint32_t op0)
+bool CompilerMSL::emit_complex_bitcast(uint32_t, uint32_t, uint32_t)
 {
-	auto &out_type = get<SPIRType>(result_type);
-	auto &in_type = expression_type(op0);
-	bool uvec2_to_ptr = (in_type.basetype == SPIRType::UInt && in_type.vecsize == 2 &&
-						 out_type.pointer && out_type.storage == StorageClassPhysicalStorageBuffer);
-	bool ptr_to_uvec2 = (in_type.pointer && in_type.storage == StorageClassPhysicalStorageBuffer &&
-						 out_type.basetype == SPIRType::UInt && out_type.vecsize == 2);
-	string expr;
-
-	// Casting between uvec2 and buffer storage pointer per GL_EXT_buffer_reference_uvec2
-	if (uvec2_to_ptr)
-		expr = join("((", type_to_glsl(out_type), ")as_type<uint64_t>(", to_unpacked_expression(op0), "))");
-	else if (ptr_to_uvec2)
-		expr = join("as_type<", type_to_glsl(out_type), ">((uint64_t)", to_unpacked_expression(op0), ")");
-	else
-		return false;
-
-	emit_op(result_type, id, expr, should_forward(op0));
-	return true;
+	// This is handled from the outside where we deal with PtrToU/UToPtr and friends.
+	return false;
 }
 
 // Returns an MSL string identifying the name of a SPIR-V builtin.