Merge pull request #1587 from KhronosGroup/refactor-active-variable-consideration

Refactor active variable consideration
diff --git a/reference/opt/shaders-msl/asm/vert/fake-builtin-input.asm.vert b/reference/opt/shaders-msl/asm/vert/fake-builtin-input.asm.vert
index f9fcbc8..3079ae9 100644
--- a/reference/opt/shaders-msl/asm/vert/fake-builtin-input.asm.vert
+++ b/reference/opt/shaders-msl/asm/vert/fake-builtin-input.asm.vert
@@ -5,6 +5,7 @@
 
 struct main0_out
 {
+    half4 out_var_SV_Target [[user(locn0)]];
     float4 gl_Position [[position]];
 };
 
diff --git a/reference/opt/shaders/asm/vert/empty-io.asm.vert b/reference/opt/shaders/asm/vert/empty-io.asm.vert
index 3819a71..52fd706 100644
--- a/reference/opt/shaders/asm/vert/empty-io.asm.vert
+++ b/reference/opt/shaders/asm/vert/empty-io.asm.vert
@@ -6,6 +6,7 @@
 };
 
 layout(location = 0) in vec4 position;
+layout(location = 0) out VSOutput _entryPointOutput;
 
 void main()
 {
diff --git a/reference/shaders-hlsl-no-opt/asm/frag/only-initializer-frag-depth.asm.frag b/reference/shaders-hlsl-no-opt/asm/frag/only-initializer-frag-depth.asm.frag
new file mode 100644
index 0000000..dcbe5d1
--- /dev/null
+++ b/reference/shaders-hlsl-no-opt/asm/frag/only-initializer-frag-depth.asm.frag
@@ -0,0 +1,17 @@
+static float gl_FragDepth = 0.5f;
+struct SPIRV_Cross_Output
+{
+    float gl_FragDepth : SV_Depth;
+};
+
+void frag_main()
+{
+}
+
+SPIRV_Cross_Output main()
+{
+    frag_main();
+    SPIRV_Cross_Output stage_output;
+    stage_output.gl_FragDepth = gl_FragDepth;
+    return stage_output;
+}
diff --git a/reference/shaders-hlsl-no-opt/asm/vert/builtin-output-initializer.asm.vert b/reference/shaders-hlsl-no-opt/asm/vert/builtin-output-initializer.asm.vert
index cf3e916..ee30c17 100644
--- a/reference/shaders-hlsl-no-opt/asm/vert/builtin-output-initializer.asm.vert
+++ b/reference/shaders-hlsl-no-opt/asm/vert/builtin-output-initializer.asm.vert
@@ -2,9 +2,14 @@
 static const float _24[1] = { 0.0f };
 
 static float4 gl_Position = 0.0f.xxxx;
+static float gl_PointSize = 0.0f;
+static float gl_ClipDistance[1] = _23;
+static float gl_CullDistance[1] = _24;
 struct SPIRV_Cross_Output
 {
     float4 gl_Position : SV_Position;
+    float gl_ClipDistance0 : SV_ClipDistance0;
+    float gl_CullDistance0 : SV_CullDistance0;
 };
 
 void vert_main()
@@ -17,5 +22,7 @@
     vert_main();
     SPIRV_Cross_Output stage_output;
     stage_output.gl_Position = gl_Position;
+    stage_output.gl_ClipDistance0.x = gl_ClipDistance[0];
+    stage_output.gl_CullDistance0.x = gl_CullDistance[0];
     return stage_output;
 }
diff --git a/reference/shaders-msl-no-opt/asm/frag/only-initializer-frag-depth.asm.frag b/reference/shaders-msl-no-opt/asm/frag/only-initializer-frag-depth.asm.frag
new file mode 100644
index 0000000..3f552eb
--- /dev/null
+++ b/reference/shaders-msl-no-opt/asm/frag/only-initializer-frag-depth.asm.frag
@@ -0,0 +1,17 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct main0_out
+{
+    float gl_FragDepth [[depth(any)]];
+};
+
+fragment main0_out main0()
+{
+    main0_out out = {};
+    out.gl_FragDepth = 0.5;
+    return out;
+}
+
diff --git a/reference/shaders-msl-no-opt/asm/tesc/builtin-control-point-initializer.asm.tesc b/reference/shaders-msl-no-opt/asm/tesc/builtin-control-point-initializer.asm.tesc
index 4d6e757..8777212 100644
--- a/reference/shaders-msl-no-opt/asm/tesc/builtin-control-point-initializer.asm.tesc
+++ b/reference/shaders-msl-no-opt/asm/tesc/builtin-control-point-initializer.asm.tesc
@@ -48,8 +48,6 @@
 {
     float4 _RESERVED_IDENTIFIER_FIXUP_gl_Position;
     float _RESERVED_IDENTIFIER_FIXUP_gl_PointSize;
-    spvUnsafeArray<float, 1> _RESERVED_IDENTIFIER_FIXUP_gl_ClipDistance;
-    spvUnsafeArray<float, 1> _RESERVED_IDENTIFIER_FIXUP_gl_CullDistance;
 };
 
 struct Verts
@@ -58,25 +56,24 @@
     float2 b;
 };
 
-constant spvUnsafeArray<float, 1> _40 = spvUnsafeArray<float, 1>({ 0.0 });
-constant spvUnsafeArray<float, 1> _41 = spvUnsafeArray<float, 1>({ 0.0 });
-
 struct main0_out
 {
     float Verts_a;
     float2 Verts_b;
     float4 gl_Position;
+    float gl_PointSize;
 };
 
 kernel void main0(uint gl_InvocationID [[thread_index_in_threadgroup]], uint gl_PrimitiveID [[threadgroup_position_in_grid]], device main0_out* spvOut [[buffer(28)]], constant uint* spvIndirectParams [[buffer(29)]], device MTLQuadTessellationFactorsHalf* spvTessLevel [[buffer(26)]])
 {
-    spvUnsafeArray<_RESERVED_IDENTIFIER_FIXUP_gl_PerVertex, 4> _18 = spvUnsafeArray<_RESERVED_IDENTIFIER_FIXUP_gl_PerVertex, 4>({ _RESERVED_IDENTIFIER_FIXUP_gl_PerVertex{ float4(0.0), 0.0, spvUnsafeArray<float, 1>({ 0.0 }), spvUnsafeArray<float, 1>({ 0.0 }) }, _RESERVED_IDENTIFIER_FIXUP_gl_PerVertex{ float4(0.0), 0.0, spvUnsafeArray<float, 1>({ 0.0 }), spvUnsafeArray<float, 1>({ 0.0 }) }, _RESERVED_IDENTIFIER_FIXUP_gl_PerVertex{ float4(0.0), 0.0, spvUnsafeArray<float, 1>({ 0.0 }), spvUnsafeArray<float, 1>({ 0.0 }) }, _RESERVED_IDENTIFIER_FIXUP_gl_PerVertex{ float4(0.0), 0.0, spvUnsafeArray<float, 1>({ 0.0 }), spvUnsafeArray<float, 1>({ 0.0 }) } });
-    spvUnsafeArray<Verts, 4> _28 = spvUnsafeArray<Verts, 4>({ Verts{ 0.0, float2(0.0) }, Verts{ 0.0, float2(0.0) }, Verts{ 0.0, float2(0.0) }, Verts{ 0.0, float2(0.0) } });
+    spvUnsafeArray<_RESERVED_IDENTIFIER_FIXUP_gl_PerVertex, 4> _17 = spvUnsafeArray<_RESERVED_IDENTIFIER_FIXUP_gl_PerVertex, 4>({ _RESERVED_IDENTIFIER_FIXUP_gl_PerVertex{ float4(0.0), 0.0 }, _RESERVED_IDENTIFIER_FIXUP_gl_PerVertex{ float4(0.0), 0.0 }, _RESERVED_IDENTIFIER_FIXUP_gl_PerVertex{ float4(0.0), 0.0 }, _RESERVED_IDENTIFIER_FIXUP_gl_PerVertex{ float4(0.0), 0.0 } });
+    spvUnsafeArray<Verts, 4> _27 = spvUnsafeArray<Verts, 4>({ Verts{ 0.0, float2(0.0) }, Verts{ 0.0, float2(0.0) }, Verts{ 0.0, float2(0.0) }, Verts{ 0.0, float2(0.0) } });
     
     device main0_out* gl_out = &spvOut[gl_PrimitiveID * 4];
-    gl_out[gl_InvocationID].gl_Position = _18[gl_InvocationID]._RESERVED_IDENTIFIER_FIXUP_gl_Position;
-    gl_out[gl_InvocationID].Verts_a = _28[gl_InvocationID].a;
-    gl_out[gl_InvocationID].Verts_b = _28[gl_InvocationID].b;
+    gl_out[gl_InvocationID].gl_Position = _17[gl_InvocationID]._RESERVED_IDENTIFIER_FIXUP_gl_Position;
+    gl_out[gl_InvocationID].gl_PointSize = _17[gl_InvocationID]._RESERVED_IDENTIFIER_FIXUP_gl_PointSize;
+    gl_out[gl_InvocationID].Verts_a = _27[gl_InvocationID].a;
+    gl_out[gl_InvocationID].Verts_b = _27[gl_InvocationID].b;
     gl_out[gl_InvocationID].gl_Position = float4(1.0);
     gl_out[gl_InvocationID].Verts_a = float(gl_InvocationID);
 }
diff --git a/reference/shaders-msl-no-opt/asm/vert/builtin-output-initializer.asm.vert b/reference/shaders-msl-no-opt/asm/vert/builtin-output-initializer.asm.vert
index 3736533..54b88ba 100644
--- a/reference/shaders-msl-no-opt/asm/vert/builtin-output-initializer.asm.vert
+++ b/reference/shaders-msl-no-opt/asm/vert/builtin-output-initializer.asm.vert
@@ -1,61 +1,19 @@
-#pragma clang diagnostic ignored "-Wmissing-prototypes"
-#pragma clang diagnostic ignored "-Wmissing-braces"
-
 #include <metal_stdlib>
 #include <simd/simd.h>
 
 using namespace metal;
 
-template<typename T, size_t Num>
-struct spvUnsafeArray
-{
-    T elements[Num ? Num : 1];
-    
-    thread T& operator [] (size_t pos) thread
-    {
-        return elements[pos];
-    }
-    constexpr const thread T& operator [] (size_t pos) const thread
-    {
-        return elements[pos];
-    }
-    
-    device T& operator [] (size_t pos) device
-    {
-        return elements[pos];
-    }
-    constexpr const device T& operator [] (size_t pos) const device
-    {
-        return elements[pos];
-    }
-    
-    constexpr const constant T& operator [] (size_t pos) const constant
-    {
-        return elements[pos];
-    }
-    
-    threadgroup T& operator [] (size_t pos) threadgroup
-    {
-        return elements[pos];
-    }
-    constexpr const threadgroup T& operator [] (size_t pos) const threadgroup
-    {
-        return elements[pos];
-    }
-};
-
-constant spvUnsafeArray<float, 1> _23 = spvUnsafeArray<float, 1>({ 0.0 });
-constant spvUnsafeArray<float, 1> _24 = spvUnsafeArray<float, 1>({ 0.0 });
-
 struct main0_out
 {
     float4 gl_Position [[position]];
+    float gl_PointSize [[point_size]];
 };
 
 vertex main0_out main0()
 {
     main0_out out = {};
     out.gl_Position = float4(0.0);
+    out.gl_PointSize = 0.0;
     out.gl_Position = float4(1.0);
     return out;
 }
diff --git a/reference/shaders-msl-no-opt/asm/vert/duplicate-view-index.asm.vert b/reference/shaders-msl-no-opt/asm/vert/duplicate-view-index.asm.vert
new file mode 100644
index 0000000..f007a67
--- /dev/null
+++ b/reference/shaders-msl-no-opt/asm/vert/duplicate-view-index.asm.vert
@@ -0,0 +1,19 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct main0_out
+{
+    float4 gl_Position [[position]];
+    uint gl_Layer [[render_target_array_index]];
+};
+
+vertex main0_out main0(uint gl_InstanceIndex [[instance_id]], uint gl_BaseInstance [[base_instance]])
+{
+    main0_out out = {};
+    const uint gl_ViewIndex = 0;
+    out.gl_Position = float4(float(int(gl_ViewIndex)));
+    return out;
+}
+
diff --git a/reference/shaders-msl-no-opt/vert/uninitialized-vertex-output.vert b/reference/shaders-msl-no-opt/vert/uninitialized-vertex-output.vert
new file mode 100644
index 0000000..f8209ae
--- /dev/null
+++ b/reference/shaders-msl-no-opt/vert/uninitialized-vertex-output.vert
@@ -0,0 +1,18 @@
+#include <metal_stdlib>
+#include <simd/simd.h>
+
+using namespace metal;
+
+struct main0_out
+{
+    float4 Pos [[user(locn0)]];
+    float4 gl_Position [[position]];
+};
+
+vertex main0_out main0()
+{
+    main0_out out = {};
+    out.gl_Position = float4(1.0);
+    return out;
+}
+
diff --git a/reference/shaders-msl/asm/vert/fake-builtin-input.asm.vert b/reference/shaders-msl/asm/vert/fake-builtin-input.asm.vert
index f9fcbc8..3079ae9 100644
--- a/reference/shaders-msl/asm/vert/fake-builtin-input.asm.vert
+++ b/reference/shaders-msl/asm/vert/fake-builtin-input.asm.vert
@@ -5,6 +5,7 @@
 
 struct main0_out
 {
+    half4 out_var_SV_Target [[user(locn0)]];
     float4 gl_Position [[position]];
 };
 
diff --git a/reference/shaders-no-opt/asm/frag/only-initializer-frag-depth.asm.frag b/reference/shaders-no-opt/asm/frag/only-initializer-frag-depth.asm.frag
new file mode 100644
index 0000000..1041f71
--- /dev/null
+++ b/reference/shaders-no-opt/asm/frag/only-initializer-frag-depth.asm.frag
@@ -0,0 +1,8 @@
+#version 450
+
+const float _3_init = 0.5;
+void main()
+{
+    gl_FragDepth = _3_init;
+}
+
diff --git a/reference/shaders-no-opt/asm/tesc/array-of-block-output-initializer.asm.tesc b/reference/shaders-no-opt/asm/tesc/array-of-block-output-initializer.asm.tesc
index 83e2651..13e1d32 100644
--- a/reference/shaders-no-opt/asm/tesc/array-of-block-output-initializer.asm.tesc
+++ b/reference/shaders-no-opt/asm/tesc/array-of-block-output-initializer.asm.tesc
@@ -1,6 +1,14 @@
 #version 450
 layout(vertices = 4) out;
 
+out gl_PerVertex
+{
+    vec4 gl_Position;
+    float gl_PointSize;
+    float gl_ClipDistance[1];
+    float gl_CullDistance[1];
+} gl_out[4];
+
 layout(location = 0) patch out vert
 {
     float v0;
@@ -23,6 +31,8 @@
 
 const vec4 _3_0_init[4] = vec4[](vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0));
 const float _3_1_init[4] = float[](0.0, 0.0, 0.0, 0.0);
+const float _3_2_init[4][1] = float[][](float[](0.0), float[](0.0), float[](0.0), float[](0.0));
+const float _3_3_init[4][1] = float[][](float[](0.0), float[](0.0), float[](0.0), float[](0.0));
 const float _6_0_init[2] = float[](0.0, 0.0);
 const float _6_1_init[2] = float[](0.0, 0.0);
 const float _7_init = 0.0;
@@ -34,6 +44,8 @@
 {
     gl_out[gl_InvocationID].gl_Position = _3_0_init[gl_InvocationID];
     gl_out[gl_InvocationID].gl_PointSize = _3_1_init[gl_InvocationID];
+    gl_out[gl_InvocationID].gl_ClipDistance = _3_2_init[gl_InvocationID];
+    gl_out[gl_InvocationID].gl_CullDistance = _3_3_init[gl_InvocationID];
     if (gl_InvocationID == 0)
     {
         _5.v0 = 0.0;
diff --git a/reference/shaders-no-opt/asm/vert/builtin-output-initializer.asm.vert b/reference/shaders-no-opt/asm/vert/builtin-output-initializer.asm.vert
index 4b77870..b449f08 100644
--- a/reference/shaders-no-opt/asm/vert/builtin-output-initializer.asm.vert
+++ b/reference/shaders-no-opt/asm/vert/builtin-output-initializer.asm.vert
@@ -1,9 +1,14 @@
 #version 450
 
+out float gl_ClipDistance[1];
+out float gl_CullDistance[1];
+
 void main()
 {
     gl_Position = vec4(0.0);
     gl_PointSize = 0.0;
+    gl_ClipDistance = float[](0.0);
+    gl_CullDistance = float[](0.0);
     gl_Position = vec4(1.0);
 }
 
diff --git a/reference/shaders/asm/vert/empty-io.asm.vert b/reference/shaders/asm/vert/empty-io.asm.vert
index cc432cb..91e65d6 100644
--- a/reference/shaders/asm/vert/empty-io.asm.vert
+++ b/reference/shaders/asm/vert/empty-io.asm.vert
@@ -16,6 +16,7 @@
 };
 
 layout(location = 0) in vec4 position;
+layout(location = 0) out VSOutput_1 _entryPointOutput;
 
 VSOutput _main(VSInput _input)
 {
diff --git a/shaders-hlsl-no-opt/asm/frag/only-initializer-frag-depth.asm.frag b/shaders-hlsl-no-opt/asm/frag/only-initializer-frag-depth.asm.frag
new file mode 100644
index 0000000..17aab1d
--- /dev/null
+++ b/shaders-hlsl-no-opt/asm/frag/only-initializer-frag-depth.asm.frag
@@ -0,0 +1,25 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 10
+; Schema: 0
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %gl_FragDepth
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main DepthReplacing
+               OpSource GLSL 450
+               OpName %main "main"
+               OpName %gl_FragDepth "gl_FragDepth"
+               OpDecorate %gl_FragDepth BuiltIn FragDepth
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+%_ptr_Output_float = OpTypePointer Output %float
+  %float_0_5 = OpConstant %float 0.5
+%gl_FragDepth = OpVariable %_ptr_Output_float Output %float_0_5
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/shaders-msl-no-opt/asm/frag/only-initializer-frag-depth.asm.frag b/shaders-msl-no-opt/asm/frag/only-initializer-frag-depth.asm.frag
new file mode 100644
index 0000000..17aab1d
--- /dev/null
+++ b/shaders-msl-no-opt/asm/frag/only-initializer-frag-depth.asm.frag
@@ -0,0 +1,25 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 10
+; Schema: 0
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %gl_FragDepth
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main DepthReplacing
+               OpSource GLSL 450
+               OpName %main "main"
+               OpName %gl_FragDepth "gl_FragDepth"
+               OpDecorate %gl_FragDepth BuiltIn FragDepth
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+%_ptr_Output_float = OpTypePointer Output %float
+  %float_0_5 = OpConstant %float 0.5
+%gl_FragDepth = OpVariable %_ptr_Output_float Output %float_0_5
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/shaders-msl-no-opt/asm/tesc/builtin-control-point-initializer.asm.tesc b/shaders-msl-no-opt/asm/tesc/builtin-control-point-initializer.asm.tesc
index a04e0dd..1219183 100644
--- a/shaders-msl-no-opt/asm/tesc/builtin-control-point-initializer.asm.tesc
+++ b/shaders-msl-no-opt/asm/tesc/builtin-control-point-initializer.asm.tesc
@@ -13,8 +13,6 @@
                OpName %gl_PerVertex "gl_PerVertex"
                OpMemberName %gl_PerVertex 0 "gl_Position"
                OpMemberName %gl_PerVertex 1 "gl_PointSize"
-               OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
-               OpMemberName %gl_PerVertex 3 "gl_CullDistance"
                OpName %gl_out "gl_out"
                OpName %gl_InvocationID "gl_InvocationID"
                OpName %Verts "Verts"
@@ -23,8 +21,6 @@
                OpName %verts "verts"
                OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
                OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
-               OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
-               OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
                OpDecorate %gl_PerVertex Block
                OpDecorate %gl_InvocationID BuiltIn InvocationId
                OpDecorate %Verts Block
@@ -35,8 +31,7 @@
     %v4float = OpTypeVector %float 4
        %uint = OpTypeInt 32 0
      %uint_1 = OpConstant %uint 1
-%_arr_float_uint_1 = OpTypeArray %float %uint_1
-%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
+%gl_PerVertex = OpTypeStruct %v4float %float
      %uint_4 = OpConstant %uint 4
 %_arr_gl_PerVertex_uint_4 = OpTypeArray %gl_PerVertex %uint_4
 %_ptr_Output__arr_gl_PerVertex_uint_4 = OpTypePointer Output %_arr_gl_PerVertex_uint_4
diff --git a/shaders-msl-no-opt/asm/vert/builtin-output-initializer.asm.vert b/shaders-msl-no-opt/asm/vert/builtin-output-initializer.asm.vert
index aaa6866..a00d4b7 100644
--- a/shaders-msl-no-opt/asm/vert/builtin-output-initializer.asm.vert
+++ b/shaders-msl-no-opt/asm/vert/builtin-output-initializer.asm.vert
@@ -12,13 +12,9 @@
                OpName %gl_PerVertex "gl_PerVertex"
                OpMemberName %gl_PerVertex 0 "gl_Position"
                OpMemberName %gl_PerVertex 1 "gl_PointSize"
-               OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
-               OpMemberName %gl_PerVertex 3 "gl_CullDistance"
                OpName %_ ""
                OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
                OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
-               OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
-               OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
                OpDecorate %gl_PerVertex Block
        %void = OpTypeVoid
           %3 = OpTypeFunction %void
@@ -26,8 +22,7 @@
     %v4float = OpTypeVector %float 4
        %uint = OpTypeInt 32 0
      %uint_1 = OpConstant %uint 1
-%_arr_float_uint_1 = OpTypeArray %float %uint_1
-%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
+%gl_PerVertex = OpTypeStruct %v4float %float
 %_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
 	%zero = OpConstantNull %gl_PerVertex
           %_ = OpVariable %_ptr_Output_gl_PerVertex Output %zero
diff --git a/shaders-msl-no-opt/asm/vert/duplicate-view-index.asm.vert b/shaders-msl-no-opt/asm/vert/duplicate-view-index.asm.vert
new file mode 100644
index 0000000..00ad1ee
--- /dev/null
+++ b/shaders-msl-no-opt/asm/vert/duplicate-view-index.asm.vert
@@ -0,0 +1,66 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 23
+; Schema: 0
+               OpCapability Shader
+               OpCapability MultiView
+               OpExtension "SPV_KHR_multiview"
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Vertex %main "main" %_ %gl_ViewIndex
+               OpEntryPoint Vertex %main2 "main2" %_ %gl_ViewIndex2
+               OpSource GLSL 450
+               OpSourceExtension "GL_EXT_multiview"
+               OpName %main "main"
+               OpName %gl_PerVertex "gl_PerVertex"
+               OpMemberName %gl_PerVertex 0 "gl_Position"
+               OpMemberName %gl_PerVertex 1 "gl_PointSize"
+               OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
+               OpMemberName %gl_PerVertex 3 "gl_CullDistance"
+               OpName %_ ""
+               OpName %gl_ViewIndex "gl_ViewIndex"
+               OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
+               OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
+               OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
+               OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
+               OpDecorate %gl_PerVertex Block
+               OpDecorate %gl_ViewIndex BuiltIn ViewIndex
+               OpDecorate %gl_ViewIndex2 BuiltIn ViewIndex
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+    %v4float = OpTypeVector %float 4
+       %uint = OpTypeInt 32 0
+     %uint_1 = OpConstant %uint 1
+%_arr_float_uint_1 = OpTypeArray %float %uint_1
+%gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
+%_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
+          %_ = OpVariable %_ptr_Output_gl_PerVertex Output
+        %int = OpTypeInt 32 1
+      %int_0 = OpConstant %int 0
+%_ptr_Input_int = OpTypePointer Input %int
+%gl_ViewIndex = OpVariable %_ptr_Input_int Input
+%gl_ViewIndex2 = OpVariable %_ptr_Input_int Input
+%_ptr_Output_v4float = OpTypePointer Output %v4float
+
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+         %18 = OpLoad %int %gl_ViewIndex
+         %19 = OpConvertSToF %float %18
+         %20 = OpCompositeConstruct %v4float %19 %19 %19 %19
+         %22 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+               OpStore %22 %20
+               OpReturn
+               OpFunctionEnd
+
+       %main2 = OpFunction %void None %3
+          %100 = OpLabel
+         %101 = OpLoad %int %gl_ViewIndex2
+         %102 = OpConvertSToF %float %101
+         %103 = OpCompositeConstruct %v4float %102 %102 %102 %102
+         %104 = OpAccessChain %_ptr_Output_v4float %_ %int_0
+               OpStore %104 %103
+
+               OpReturn
+               OpFunctionEnd
diff --git a/shaders-msl-no-opt/vert/uninitialized-vertex-output.vert b/shaders-msl-no-opt/vert/uninitialized-vertex-output.vert
new file mode 100644
index 0000000..54c7afd
--- /dev/null
+++ b/shaders-msl-no-opt/vert/uninitialized-vertex-output.vert
@@ -0,0 +1,8 @@
+#version 450
+
+layout(location = 0) out vec4 Pos;
+
+void main()
+{
+	gl_Position = vec4(1.0);
+}
diff --git a/shaders-no-opt/asm/frag/only-initializer-frag-depth.asm.frag b/shaders-no-opt/asm/frag/only-initializer-frag-depth.asm.frag
new file mode 100644
index 0000000..17aab1d
--- /dev/null
+++ b/shaders-no-opt/asm/frag/only-initializer-frag-depth.asm.frag
@@ -0,0 +1,25 @@
+; SPIR-V
+; Version: 1.0
+; Generator: Khronos Glslang Reference Front End; 10
+; Bound: 10
+; Schema: 0
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %main "main" %gl_FragDepth
+               OpExecutionMode %main OriginUpperLeft
+               OpExecutionMode %main DepthReplacing
+               OpSource GLSL 450
+               OpName %main "main"
+               OpName %gl_FragDepth "gl_FragDepth"
+               OpDecorate %gl_FragDepth BuiltIn FragDepth
+       %void = OpTypeVoid
+          %3 = OpTypeFunction %void
+      %float = OpTypeFloat 32
+%_ptr_Output_float = OpTypePointer Output %float
+  %float_0_5 = OpConstant %float 0.5
+%gl_FragDepth = OpVariable %_ptr_Output_float Output %float_0_5
+       %main = OpFunction %void None %3
+          %5 = OpLabel
+               OpReturn
+               OpFunctionEnd
diff --git a/spirv_cross.cpp b/spirv_cross.cpp
index 5c1b3eb..5fd7876 100644
--- a/spirv_cross.cpp
+++ b/spirv_cross.cpp
@@ -805,9 +805,17 @@
 	InterfaceVariableAccessHandler handler(*this, variables);
 	traverse_all_reachable_opcodes(get<SPIRFunction>(ir.default_entry_point), handler);
 
-	// Make sure we preserve output variables which are only initialized, but never accessed by any code.
 	ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
-		if (var.storage == StorageClassOutput && var.initializer != ID(0))
+		if (var.storage != StorageClassOutput)
+			return;
+		if (!interface_variable_exists_in_entry_point(var.self))
+			return;
+
+		// An output variable which is just declared (but uninitialized) might be read by subsequent stages
+		// so we should force-enable these outputs,
+		// since compilation will fail if a subsequent stage attempts to read from the variable in question.
+		// Also, make sure we preserve output variables which are only initialized, but never accessed by any code.
+		if (var.initializer != ID(0) || get_execution_model() != ExecutionModelFragment)
 			variables.insert(var.self);
 	});
 
@@ -3839,23 +3847,55 @@
 	}
 }
 
-bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t length)
+void Compiler::ActiveBuiltinHandler::add_if_builtin(uint32_t id, bool allow_blocks)
 {
-	const auto add_if_builtin = [&](uint32_t id) {
-		// Only handles variables here.
-		// Builtins which are part of a block are handled in AccessChain.
-		auto *var = compiler.maybe_get<SPIRVariable>(id);
-		auto &decorations = compiler.ir.meta[id].decoration;
-		if (var && decorations.builtin)
+	// Only handle plain variables here.
+	// Builtins which are part of a block are handled in AccessChain.
+	// If allow_blocks is used however, this is to handle initializers of blocks,
+	// which implies that all members are written to.
+
+	auto *var = compiler.maybe_get<SPIRVariable>(id);
+	auto *m = compiler.ir.find_meta(id);
+	if (var && m)
+	{
+		auto &type = compiler.get<SPIRType>(var->basetype);
+		auto &decorations = m->decoration;
+		auto &flags = type.storage == StorageClassInput ?
+		              compiler.active_input_builtins : compiler.active_output_builtins;
+		if (decorations.builtin)
 		{
-			auto &type = compiler.get<SPIRType>(var->basetype);
-			auto &flags =
-			    type.storage == StorageClassInput ? compiler.active_input_builtins : compiler.active_output_builtins;
 			flags.set(decorations.builtin_type);
 			handle_builtin(type, decorations.builtin_type, decorations.decoration_flags);
 		}
-	};
+		else if (allow_blocks && compiler.has_decoration(type.self, DecorationBlock))
+		{
+			uint32_t member_count = uint32_t(type.member_types.size());
+			for (uint32_t i = 0; i < member_count; i++)
+			{
+				if (compiler.has_member_decoration(type.self, i, DecorationBuiltIn))
+				{
+					auto &member_type = compiler.get<SPIRType>(type.member_types[i]);
+					BuiltIn builtin = BuiltIn(compiler.get_member_decoration(type.self, i, DecorationBuiltIn));
+					flags.set(builtin);
+					handle_builtin(member_type, builtin, compiler.get_member_decoration_bitset(type.self, i));
+				}
+			}
+		}
+	}
+}
 
+void Compiler::ActiveBuiltinHandler::add_if_builtin(uint32_t id)
+{
+	add_if_builtin(id, false);
+}
+
+void Compiler::ActiveBuiltinHandler::add_if_builtin_or_block(uint32_t id)
+{
+	add_if_builtin(id, true);
+}
+
+bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t length)
+{
 	switch (opcode)
 	{
 	case OpStore:
@@ -3993,6 +4033,17 @@
 	clip_distance_count = 0;
 	ActiveBuiltinHandler handler(*this);
 	traverse_all_reachable_opcodes(get<SPIRFunction>(ir.default_entry_point), handler);
+
+	ir.for_each_typed_id<SPIRVariable>([&](uint32_t, const SPIRVariable &var) {
+		if (var.storage != StorageClassOutput)
+			return;
+		if (!interface_variable_exists_in_entry_point(var.self))
+			return;
+
+		// Also, make sure we preserve output variables which are only initialized, but never accessed by any code.
+		if (var.initializer != ID(0))
+			handler.add_if_builtin_or_block(var.self);
+	});
 }
 
 // Returns whether this shader uses a builtin of the storage class
diff --git a/spirv_cross.hpp b/spirv_cross.hpp
index 47f1d79..016d13e 100644
--- a/spirv_cross.hpp
+++ b/spirv_cross.hpp
@@ -833,6 +833,9 @@
 		Compiler &compiler;
 
 		void handle_builtin(const SPIRType &type, spv::BuiltIn builtin, const Bitset &decoration_flags);
+		void add_if_builtin(uint32_t id);
+		void add_if_builtin_or_block(uint32_t id);
+		void add_if_builtin(uint32_t id, bool allow_blocks);
 	};
 
 	bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp
index 3b5bd8e..ab47941 100644
--- a/spirv_glsl.cpp
+++ b/spirv_glsl.cpp
@@ -2801,6 +2801,13 @@
 		}
 	});
 
+	// If we're declaring clip/cull planes with control points we need to force block declaration.
+	if (get_execution_model() == ExecutionModelTessellationControl &&
+	    (clip_distance_count || cull_distance_count))
+	{
+		should_force = true;
+	}
+
 	return should_force;
 }
 
diff --git a/spirv_msl.cpp b/spirv_msl.cpp
index 688da23..daca7c7 100644
--- a/spirv_msl.cpp
+++ b/spirv_msl.cpp
@@ -198,9 +198,12 @@
 		bool has_workgroup_size = false;
 		uint32_t workgroup_id_type = 0;
 
-		// FIXME: Investigate the fact that there are no checks for the entry point interface variables.
 		ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
-			if (!ir.meta[var.self].decoration.builtin)
+			if (var.storage != StorageClassInput && var.storage != StorageClassOutput)
+				return;
+			if (!interface_variable_exists_in_entry_point(var.self))
+				return;
+			if (!has_decoration(var.self, DecorationBuiltIn))
 				return;
 
 			BuiltIn builtin = ir.meta[var.self].decoration.builtin_type;
@@ -10586,11 +10589,14 @@
 	// Builtin variables
 	SmallVector<pair<SPIRVariable *, BuiltIn>, 8> active_builtins;
 	ir.for_each_typed_id<SPIRVariable>([&](uint32_t var_id, SPIRVariable &var) {
+		if (var.storage != StorageClassInput)
+			return;
+
 		auto bi_type = BuiltIn(get_decoration(var_id, DecorationBuiltIn));
 
 		// Don't emit SamplePosition as a separate parameter. In the entry
 		// point, we get that by calling get_sample_position() on the sample ID.
-		if (var.storage == StorageClassInput && is_builtin_variable(var) &&
+		if (is_builtin_variable(var) &&
 		    get_variable_data_type(var).basetype != SPIRType::Struct &&
 		    get_variable_data_type(var).basetype != SPIRType::ControlPointArray)
 		{
@@ -10624,8 +10630,7 @@
 			}
 		}
 
-		if (var.storage == StorageClassInput &&
-		    has_extended_decoration(var_id, SPIRVCrossDecorationBuiltInDispatchBase))
+		if (has_extended_decoration(var_id, SPIRVCrossDecorationBuiltInDispatchBase))
 		{
 			// This is a special implicit builtin, not corresponding to any SPIR-V builtin,
 			// which holds the base that was passed to vkCmdDispatchBase() or vkCmdDrawIndexed(). If it's present,
@@ -10637,8 +10642,7 @@
 			ep_args += type_to_glsl(get_variable_data_type(var)) + " " + to_expression(var_id) + " [[grid_origin]]";
 		}
 
-		if (var.storage == StorageClassInput &&
-		    has_extended_decoration(var_id, SPIRVCrossDecorationBuiltInStageInputSize))
+		if (has_extended_decoration(var_id, SPIRVCrossDecorationBuiltInStageInputSize))
 		{
 			// This is another special implicit builtin, not corresponding to any SPIR-V builtin,
 			// which holds the number of vertices and instances to draw. If it's present,
@@ -11175,6 +11179,11 @@
 		uint32_t var_id = var.self;
 		BuiltIn bi_type = ir.meta[var_id].decoration.builtin_type;
 
+		if (var.storage != StorageClassInput && var.storage != StorageClassOutput)
+			return;
+		if (!interface_variable_exists_in_entry_point(var.self))
+			return;
+
 		if (var.storage == StorageClassInput && is_builtin_variable(var) && active_input_builtins.get(bi_type))
 		{
 			switch (bi_type)