Merge "Fix OpVariable position in OpInBoundsAccessChain tests." into vulkan-cts-1...
[platform/upstream/VK-GL-CTS.git] / external / vulkancts / modules / vulkan / spirv_assembly / vktSpvAsmInstructionTests.cpp
index 972b428..4a51a46 100644 (file)
@@ -256,7 +256,7 @@ struct OpFUnordCase
        const char*             opCode;
        compareFuncType compareFunc;
 
-                                       OpFUnordCase                    (const char* _name, const char* _opCode, compareFuncType _compareFunc)
+                                       OpFUnordCase                    (const char* _name, const char* _opCode, compareFuncType _compareFunc)
                                                : name                          (_name)
                                                , opCode                        (_opCode)
                                                , compareFunc           (_compareFunc) {}
@@ -384,7 +384,7 @@ struct OpAtomicCase
        void                    (*calculateExpected)(deInt32&, deInt32);
        deInt32                 numOutputElements;
 
-                                       OpAtomicCase                    (const char* _name, const char* _assembly, void (*_calculateExpected)(deInt32&, deInt32), deInt32 _numOutputElements)
+                                       OpAtomicCase                    (const char* _name, const char* _assembly, void (*_calculateExpected)(deInt32&, deInt32), deInt32 _numOutputElements)
                                                : name                          (_name)
                                                , assembly                      (_assembly)
                                                , calculateExpected     (_calculateExpected)
@@ -452,8 +452,8 @@ tcu::TestCaseGroup* createOpAtomicGroup (tcu::TestContext& testCtx)
 
        #define ADD_OPATOMIC_CASE(NAME, ASSEMBLY, CALCULATE_EXPECTED, NUM_OUTPUT_ELEMENTS) \
        do { \
-               DE_STATIC_ASSERT(NUM_OUTPUT_ELEMENTS == 1 || NUM_OUTPUT_ELEMENTS == numElements); \
-               struct calculateExpected_##NAME { static void calculateExpected(deInt32& expected, deInt32 input) CALCULATE_EXPECTED }; \
+               DE_STATIC_ASSERT((NUM_OUTPUT_ELEMENTS) == 1 || (NUM_OUTPUT_ELEMENTS) == numElements); \
+               struct calculateExpected_##NAME { static void calculateExpected(deInt32& expected, deInt32 input) CALCULATE_EXPECTED }; /* NOLINT(CALCULATE_EXPECTED) */ \
                cases.push_back(OpAtomicCase(#NAME, ASSEMBLY, calculateExpected_##NAME::calculateExpected, NUM_OUTPUT_ELEMENTS)); \
        } while (deGetFalse())
        #define ADD_OPATOMIC_CASE_1(NAME, ASSEMBLY, CALCULATE_EXPECTED) ADD_OPATOMIC_CASE(NAME, ASSEMBLY, CALCULATE_EXPECTED, 1)
@@ -1935,20 +1935,6 @@ tcu::TestCaseGroup* createBlockOrderGroup (tcu::TestContext& testCtx)
                "            OpSelectionMerge %if_merge None\n"
                "            OpBranchConditional %cmp %if_true %if_false\n"
 
-               // Merge block for switch-statement: placed at the beginning.
-               "%switch_merge = OpLabel\n"
-               "                OpBranch %if_merge\n"
-
-               // Case 1 for switch-statement.
-               "%case1    = OpLabel\n"
-               "%x_1      = OpLoad %u32 %xvar\n"
-               "%inloc_1  = OpAccessChain %f32ptr %indata %zero %x_1\n"
-               "%inval_1  = OpLoad %f32 %inloc_1\n"
-               "%addf42   = OpFAdd %f32 %inval_1 %constf42\n"
-               "%outloc_1 = OpAccessChain %f32ptr %outdata %zero %x_1\n"
-               "            OpStore %outloc_1 %addf42\n"
-               "            OpBranch %switch_merge\n"
-
                // False branch for if-statement: placed in the middle of switch cases and before true branch.
                "%if_false = OpLabel\n"
                "%x_f      = OpLoad %u32 %xvar\n"
@@ -1970,6 +1956,22 @@ tcu::TestCaseGroup* createBlockOrderGroup (tcu::TestContext& testCtx)
                "            OpSelectionMerge %switch_merge None\n"
                "            OpSwitch %mod %default 0 %case0 1 %case1 2 %case2\n"
 
+               // Merge block for switch-statement: placed before the case
+                // bodies.  But it must follow OpSwitch which dominates it.
+               "%switch_merge = OpLabel\n"
+               "                OpBranch %if_merge\n"
+
+               // Case 1 for switch-statement: placed before case 0.
+                // It must follow the OpSwitch that dominates it.
+               "%case1    = OpLabel\n"
+               "%x_1      = OpLoad %u32 %xvar\n"
+               "%inloc_1  = OpAccessChain %f32ptr %indata %zero %x_1\n"
+               "%inval_1  = OpLoad %f32 %inloc_1\n"
+               "%addf42   = OpFAdd %f32 %inval_1 %constf42\n"
+               "%outloc_1 = OpAccessChain %f32ptr %outdata %zero %x_1\n"
+               "            OpStore %outloc_1 %addf42\n"
+               "            OpBranch %switch_merge\n"
+
                // Case 2 for switch-statement.
                "%case2    = OpLabel\n"
                "%x_2      = OpLoad %u32 %xvar\n"
@@ -3097,7 +3099,7 @@ tcu::TestCaseGroup* createLoopControlGroup (tcu::TestContext& testCtx)
                "%loop_entry  = OpLabel\n"
                "%i_val       = OpLoad %u32 %i\n"
                "%cmp_lt      = OpULessThan %bool %i_val %four\n"
-               "               OpLoopMerge %loop_merge %loop_entry ${CONTROL}\n"
+               "               OpLoopMerge %loop_merge %loop_body ${CONTROL}\n"
                "               OpBranchConditional %cmp_lt %loop_body %loop_merge\n"
                "%loop_body   = OpLabel\n"
                "%outval      = OpLoad %f32 %outloc\n"
@@ -4269,6 +4271,8 @@ void createCombinedModule(vk::SourceCollections& dst, InstanceContext)
                "OpExecutionMode %tessc_main OutputVertices 3\n"
 
                "OpExecutionMode %tesse_main Triangles\n"
+               "OpExecutionMode %tesse_main SpacingEqual\n"
+               "OpExecutionMode %tesse_main VertexOrderCcw\n"
 
                "OpExecutionMode %frag_main OriginUpperLeft\n"
 
@@ -4480,9 +4484,9 @@ void createCombinedModule(vk::SourceCollections& dst, InstanceContext)
                "%tesse_in_pos_0 = OpLoad %v4f32 %tesse_in_pos_0_ptr\n"
                "%tesse_in_pos_1 = OpLoad %v4f32 %tesse_in_pos_1_ptr\n"
                "%tesse_in_pos_2 = OpLoad %v4f32 %tesse_in_pos_2_ptr\n"
-               "%tesse_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse_tc_0 %tesse_in_pos_0\n"
-               "%tesse_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse_tc_1 %tesse_in_pos_1\n"
-               "%tesse_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse_tc_2 %tesse_in_pos_2\n"
+               "%tesse_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_0 %tesse_tc_0\n"
+               "%tesse_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_1 %tesse_tc_1\n"
+               "%tesse_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse_in_pos_2 %tesse_tc_2\n"
                "%tesse_out_pos_ptr = OpAccessChain %op_v4f32 %tesse_stream %c_i32_0\n"
                "%tesse_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse_in_pos_0_weighted %tesse_in_pos_1_weighted\n"
                "%tesse_computed_out = OpFAdd %v4f32 %tesse_in_pos_0_plus_pos_1 %tesse_in_pos_2_weighted\n"
@@ -4493,9 +4497,9 @@ void createCombinedModule(vk::SourceCollections& dst, InstanceContext)
                "%tesse_in_clr_0 = OpLoad %v4f32 %tesse_in_clr_0_ptr\n"
                "%tesse_in_clr_1 = OpLoad %v4f32 %tesse_in_clr_1_ptr\n"
                "%tesse_in_clr_2 = OpLoad %v4f32 %tesse_in_clr_2_ptr\n"
-               "%tesse_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse_tc_0 %tesse_in_clr_0\n"
-               "%tesse_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse_tc_1 %tesse_in_clr_1\n"
-               "%tesse_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse_tc_2 %tesse_in_clr_2\n"
+               "%tesse_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_0 %tesse_tc_0\n"
+               "%tesse_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_1 %tesse_tc_1\n"
+               "%tesse_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse_in_clr_2 %tesse_tc_2\n"
                "%tesse_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse_in_clr_0_weighted %tesse_in_clr_1_weighted\n"
                "%tesse_computed_clr = OpFAdd %v4f32 %tesse_in_clr_0_plus_col_1 %tesse_in_clr_2_weighted\n"
                "OpStore %tesse_out_color %tesse_computed_clr\n"
@@ -4815,7 +4819,11 @@ void createMultipleEntries(vk::SourceCollections& dst, InstanceContext)
                "OpEntryPoint TessellationEvaluation %tesse1_main \"tesse1\" %stream %gl_tessCoord %in_position %out_color %in_color \n"
                "OpEntryPoint TessellationEvaluation %tesse2_main \"tesse2\" %stream %gl_tessCoord %in_position %out_color %in_color \n"
                "OpExecutionMode %tesse1_main Triangles\n"
+               "OpExecutionMode %tesse1_main SpacingEqual\n"
+               "OpExecutionMode %tesse1_main VertexOrderCcw\n"
                "OpExecutionMode %tesse2_main Triangles\n"
+               "OpExecutionMode %tesse2_main SpacingEqual\n"
+               "OpExecutionMode %tesse2_main VertexOrderCcw\n"
                "OpName %tesse1_main \"tesse1\"\n"
                "OpName %tesse2_main \"tesse2\"\n"
                "OpName %per_vertex_out \"gl_PerVertex\"\n"
@@ -4863,9 +4871,9 @@ void createMultipleEntries(vk::SourceCollections& dst, InstanceContext)
                "%tesse1_in_pos_0 = OpLoad %v4f32 %tesse1_in_pos_0_ptr\n"
                "%tesse1_in_pos_1 = OpLoad %v4f32 %tesse1_in_pos_1_ptr\n"
                "%tesse1_in_pos_2 = OpLoad %v4f32 %tesse1_in_pos_2_ptr\n"
-               "%tesse1_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_0 %tesse1_in_pos_0\n"
-               "%tesse1_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_1 %tesse1_in_pos_1\n"
-               "%tesse1_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_2 %tesse1_in_pos_2\n"
+               "%tesse1_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_0 %tesse1_tc_0\n"
+               "%tesse1_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_1 %tesse1_tc_1\n"
+               "%tesse1_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_pos_2 %tesse1_tc_2\n"
                "%tesse1_out_pos_ptr = OpAccessChain %op_v4f32 %stream %c_i32_0\n"
                "%tesse1_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse1_in_pos_0_weighted %tesse1_in_pos_1_weighted\n"
                "%tesse1_computed_out = OpFAdd %v4f32 %tesse1_in_pos_0_plus_pos_1 %tesse1_in_pos_2_weighted\n"
@@ -4876,9 +4884,9 @@ void createMultipleEntries(vk::SourceCollections& dst, InstanceContext)
                "%tesse1_in_clr_0 = OpLoad %v4f32 %tesse1_in_clr_0_ptr\n"
                "%tesse1_in_clr_1 = OpLoad %v4f32 %tesse1_in_clr_1_ptr\n"
                "%tesse1_in_clr_2 = OpLoad %v4f32 %tesse1_in_clr_2_ptr\n"
-               "%tesse1_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_0 %tesse1_in_clr_0\n"
-               "%tesse1_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_1 %tesse1_in_clr_1\n"
-               "%tesse1_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_tc_2 %tesse1_in_clr_2\n"
+               "%tesse1_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_0 %tesse1_tc_0\n"
+               "%tesse1_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_1 %tesse1_tc_1\n"
+               "%tesse1_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse1_in_clr_2 %tesse1_tc_2\n"
                "%tesse1_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse1_in_clr_0_weighted %tesse1_in_clr_1_weighted\n"
                "%tesse1_computed_clr = OpFAdd %v4f32 %tesse1_in_clr_0_plus_col_1 %tesse1_in_clr_2_weighted\n"
                "OpStore %out_color %tesse1_computed_clr\n"
@@ -4899,9 +4907,9 @@ void createMultipleEntries(vk::SourceCollections& dst, InstanceContext)
                "%tesse2_in_pos_0 = OpLoad %v4f32 %tesse2_in_pos_0_ptr\n"
                "%tesse2_in_pos_1 = OpLoad %v4f32 %tesse2_in_pos_1_ptr\n"
                "%tesse2_in_pos_2 = OpLoad %v4f32 %tesse2_in_pos_2_ptr\n"
-               "%tesse2_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_0 %tesse2_in_pos_0\n"
-               "%tesse2_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_1 %tesse2_in_pos_1\n"
-               "%tesse2_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_2 %tesse2_in_pos_2\n"
+               "%tesse2_in_pos_0_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_0 %tesse2_tc_0\n"
+               "%tesse2_in_pos_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_1 %tesse2_tc_1\n"
+               "%tesse2_in_pos_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_pos_2 %tesse2_tc_2\n"
                "%tesse2_out_pos_ptr = OpAccessChain %op_v4f32 %stream %c_i32_0\n"
                "%tesse2_in_pos_0_plus_pos_1 = OpFAdd %v4f32 %tesse2_in_pos_0_weighted %tesse2_in_pos_1_weighted\n"
                "%tesse2_computed_out = OpFAdd %v4f32 %tesse2_in_pos_0_plus_pos_1 %tesse2_in_pos_2_weighted\n"
@@ -4912,9 +4920,9 @@ void createMultipleEntries(vk::SourceCollections& dst, InstanceContext)
                "%tesse2_in_clr_0 = OpLoad %v4f32 %tesse2_in_clr_0_ptr\n"
                "%tesse2_in_clr_1 = OpLoad %v4f32 %tesse2_in_clr_1_ptr\n"
                "%tesse2_in_clr_2 = OpLoad %v4f32 %tesse2_in_clr_2_ptr\n"
-               "%tesse2_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_0 %tesse2_in_clr_0\n"
-               "%tesse2_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_1 %tesse2_in_clr_1\n"
-               "%tesse2_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_tc_2 %tesse2_in_clr_2\n"
+               "%tesse2_in_clr_0_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_0 %tesse2_tc_0\n"
+               "%tesse2_in_clr_1_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_1 %tesse2_tc_1\n"
+               "%tesse2_in_clr_2_weighted = OpVectorTimesScalar %v4f32 %tesse2_in_clr_2 %tesse2_tc_2\n"
                "%tesse2_in_clr_0_plus_col_1 = OpFAdd %v4f32 %tesse2_in_clr_0_weighted %tesse2_in_clr_1_weighted\n"
                "%tesse2_computed_clr = OpFAdd %v4f32 %tesse2_in_clr_0_plus_col_1 %tesse2_in_clr_2_weighted\n"
                "%tesse2_clr_transformed = OpFSub %v4f32 %cval %tesse2_computed_clr\n"
@@ -6125,7 +6133,7 @@ tcu::TestCaseGroup* createSelectionBlockOrderTests(tcu::TestContext& testCtx)
                "%loop      = OpLabel\n"
                "%ival      = OpLoad %i32 %iptr\n"
                "%lt_4      = OpSLessThan %bool %ival %c_i32_4\n"
-               "             OpLoopMerge %exit %loop None\n"
+               "             OpLoopMerge %exit %if_entry None\n"
                "             OpBranchConditional %lt_4 %if_entry %exit\n"
 
                // Merge block for loop.
@@ -6217,7 +6225,7 @@ tcu::TestCaseGroup* createSwitchBlockOrderTests(tcu::TestContext& testCtx)
                "%loop      = OpLabel\n"
                "%ival      = OpLoad %i32 %iptr\n"
                "%lt_4      = OpSLessThan %bool %ival %c_i32_4\n"
-               "             OpLoopMerge %exit %loop None\n"
+               "             OpLoopMerge %exit %switch_exit None\n"
                "             OpBranchConditional %lt_4 %switch_entry %exit\n"
 
                // Merge block for loop.
@@ -6647,7 +6655,7 @@ tcu::TestCaseGroup* createOpPhiTests(tcu::TestContext& testCtx)
                "%loop      = OpLabel\n"
                "%ival      = OpLoad %i32 %iptr\n"
                "%lt_4      = OpSLessThan %bool %ival %c_i32_4\n"
-               "             OpLoopMerge %exit %loop None\n"
+               "             OpLoopMerge %exit %phi None\n"
                "             OpBranchConditional %lt_4 %entry %exit\n"
 
                "%entry     = OpLabel\n"
@@ -8564,9 +8572,9 @@ struct AssemblyStructInfo
 const string specializeInBoundsShaderTemplate (const NumberType type, const AssemblyStructInfo& structInfo, const map<string, string>& params)
 {
        // Create the full index string
-       string                          fullIndex       = numberToString(structInfo.index) + " " + params.at("indexes");
+       string                          fullIndex       = numberToString(structInfo.index) + " " + params.at("indexes");
        // Convert it to list of indexes
-       vector<string>          indexes         = de::splitString(fullIndex, ' ');
+       vector<string>          indexes         = de::splitString(fullIndex, ' ');
 
        map<string, string>     parameters      (params);
        parameters["typeDeclaration"]   = getAssemblyTypeDeclaration(type);
@@ -8646,6 +8654,7 @@ const string specializeInBoundsShaderTemplate (const NumberType type, const Asse
                "%zero      = OpConstant %u32 0\n"
                "%main      = OpFunction %void None %voidf\n"
                "%label     = OpLabel\n"
+               "%struct_v  = OpVariable %struct_p Function\n"
                "%idval     = OpLoad %uvec3 %id\n"
                "%x         = OpCompositeExtract %u32 %idval 0\n"
                // Create the input/output type
@@ -8660,7 +8669,6 @@ const string specializeInBoundsShaderTemplate (const NumberType type, const Asse
                // Insert the value
                "%comp_obj  = OpCompositeInsert %struct_t %inval %struct ${insertIndexes}\n"
                // Store the object
-               "%struct_v  = OpVariable %struct_p Function\n"
                "             OpStore %struct_v %comp_obj\n"
                // Get deepest possible composite pointer
                "%inner_ptr = OpInBoundsAccessChain %composite_p %struct_v${accessChainIndexes}\n"
@@ -8733,6 +8741,195 @@ tcu::TestCaseGroup* createOpInBoundsAccessChainGroup (tcu::TestContext& testCtx)
        return group.release();
 }
 
+// If the params missing, uninitialized case
+const string specializeDefaultOutputShaderTemplate (const NumberType type, const map<string, string>& params = map<string, string>())
+{
+       map<string, string> parameters(params);
+
+       parameters["typeDeclaration"] = getAssemblyTypeDeclaration(type);
+
+       // Declare the const value, and use it in the initializer
+       if (params.find("constValue") != params.end())
+       {
+               parameters["constDeclaration"]          = "%const      = OpConstant %in_type " + params.at("constValue") + "\n";
+               parameters["variableInitializer"]       = "%const";
+       }
+       // Uninitialized case
+       else
+       {
+               parameters["constDeclaration"]          = "";
+               parameters["variableInitializer"]       = "";
+       }
+
+       return StringTemplate(
+               "OpCapability Shader\n"
+               "OpMemoryModel Logical GLSL450\n"
+               "OpEntryPoint GLCompute %main \"main\" %id\n"
+               "OpExecutionMode %main LocalSize 1 1 1\n"
+               "OpSource GLSL 430\n"
+               "OpName %main           \"main\"\n"
+               "OpName %id             \"gl_GlobalInvocationID\"\n"
+               // Decorators
+               "OpDecorate %id BuiltIn GlobalInvocationId\n"
+               "OpDecorate %indata DescriptorSet 0\n"
+               "OpDecorate %indata Binding 0\n"
+               "OpDecorate %outdata DescriptorSet 0\n"
+               "OpDecorate %outdata Binding 1\n"
+               "OpDecorate %in_arr ArrayStride 4\n"
+               "OpDecorate %in_buf BufferBlock\n"
+               "OpMemberDecorate %in_buf 0 Offset 0\n"
+               // Base types
+               "%void       = OpTypeVoid\n"
+               "%voidf      = OpTypeFunction %void\n"
+               "%u32        = OpTypeInt 32 0\n"
+               "%i32        = OpTypeInt 32 1\n"
+               "%uvec3      = OpTypeVector %u32 3\n"
+               "%uvec3ptr   = OpTypePointer Input %uvec3\n"
+               // Custom types
+               "%in_type    = ${typeDeclaration}\n"
+               // "%const      = OpConstant %in_type ${constValue}\n"
+               "${constDeclaration}\n"
+               // Derived types
+               "%in_ptr     = OpTypePointer Uniform %in_type\n"
+               "%in_arr     = OpTypeRuntimeArray %in_type\n"
+               "%in_buf     = OpTypeStruct %in_arr\n"
+               "%in_bufptr  = OpTypePointer Uniform %in_buf\n"
+               "%indata     = OpVariable %in_bufptr Uniform\n"
+               "%outdata    = OpVariable %in_bufptr Uniform\n"
+               "%id         = OpVariable %uvec3ptr Input\n"
+               "%var_ptr    = OpTypePointer Function %in_type\n"
+               // Constants
+               "%zero       = OpConstant %i32 0\n"
+               // Main function
+               "%main       = OpFunction %void None %voidf\n"
+               "%label      = OpLabel\n"
+               "%idval      = OpLoad %uvec3 %id\n"
+               "%x          = OpCompositeExtract %u32 %idval 0\n"
+               "%inloc      = OpAccessChain %in_ptr %indata %zero %x\n"
+               "%outloc     = OpAccessChain %in_ptr %outdata %zero %x\n"
+
+               "%out_var    = OpVariable %var_ptr Function ${variableInitializer}\n"
+               "%outval     = OpLoad %in_type %out_var\n"
+               "              OpStore %outloc %outval\n"
+               "              OpReturn\n"
+               "              OpFunctionEnd\n"
+       ).specialize(parameters);
+}
+
+bool compareFloats (const std::vector<BufferSp>&, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs, TestLog& log)
+{
+       DE_ASSERT(outputAllocs.size() != 0);
+       DE_ASSERT(outputAllocs.size() == expectedOutputs.size());
+
+       // Use custom epsilon because of the float->string conversion
+       const float     epsilon = 0.00001f;
+
+       for (size_t outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx)
+       {
+               float expected;
+               memcpy(&expected, expectedOutputs[outputNdx]->data(), expectedOutputs[outputNdx]->getNumBytes());
+
+               float actual;
+               memcpy(&actual, outputAllocs[outputNdx]->getHostPtr(), expectedOutputs[outputNdx]->getNumBytes());
+
+               // Test with epsilon
+               if (fabs(expected - actual) > epsilon)
+               {
+                       log << TestLog::Message << "Error: The actual and expected values not matching."
+                               << " Expected: " << expected << " Actual: " << actual << " Epsilon: " << epsilon << TestLog::EndMessage;
+                       return false;
+               }
+       }
+       return true;
+}
+
+// Checks if the driver crash with uninitialized cases
+bool passthruVerify (const std::vector<BufferSp>&, const vector<AllocationSp>& outputAllocs, const std::vector<BufferSp>& expectedOutputs, TestLog&)
+{
+       DE_ASSERT(outputAllocs.size() != 0);
+       DE_ASSERT(outputAllocs.size() == expectedOutputs.size());
+
+       // Copy and discard the result.
+       for (size_t outputNdx = 0; outputNdx < outputAllocs.size(); ++outputNdx)
+       {
+               size_t width = expectedOutputs[outputNdx]->getNumBytes();
+
+               vector<char> data(width);
+               memcpy(&data[0], outputAllocs[outputNdx]->getHostPtr(), width);
+       }
+       return true;
+}
+
+tcu::TestCaseGroup* createShaderDefaultOutputGroup (tcu::TestContext& testCtx)
+{
+       de::MovePtr<tcu::TestCaseGroup> group   (new tcu::TestCaseGroup(testCtx, "shader_default_output", "Test shader default output."));
+       de::Random                                              rnd             (deStringHash(group->getName()));
+
+       for (int type = TYPE_INT; type != TYPE_END; ++type)
+       {
+               NumberType                                              numberType      = NumberType(type);
+               const string                                    typeName        = getNumberTypeName(numberType);
+               const string                                    description     = "Test the OpVariable initializer with " + typeName + ".";
+               de::MovePtr<tcu::TestCaseGroup> subGroup        (new tcu::TestCaseGroup(testCtx, typeName.c_str(), description.c_str()));
+
+               // 2 similar subcases (initialized and uninitialized)
+               for (int subCase = 0; subCase < 2; ++subCase)
+               {
+                       ComputeShaderSpec spec;
+                       spec.numWorkGroups = IVec3(1, 1, 1);
+
+                       map<string, string>                             params;
+
+                       switch (numberType)
+                       {
+                               case TYPE_INT:
+                               {
+                                       deInt32 number = getInt(rnd);
+                                       spec.inputs.push_back(createCompositeBuffer<deInt32>(number));
+                                       spec.outputs.push_back(createCompositeBuffer<deInt32>(number));
+                                       params["constValue"] = numberToString(number);
+                                       break;
+                               }
+                               case TYPE_UINT:
+                               {
+                                       deUint32 number = rnd.getUint32();
+                                       spec.inputs.push_back(createCompositeBuffer<deUint32>(number));
+                                       spec.outputs.push_back(createCompositeBuffer<deUint32>(number));
+                                       params["constValue"] = numberToString(number);
+                                       break;
+                               }
+                               case TYPE_FLOAT:
+                               {
+                                       float number = rnd.getFloat();
+                                       spec.inputs.push_back(createCompositeBuffer<float>(number));
+                                       spec.outputs.push_back(createCompositeBuffer<float>(number));
+                                       spec.verifyIO = &compareFloats;
+                                       params["constValue"] = numberToString(number);
+                                       break;
+                               }
+                               default:
+                                       DE_ASSERT(false);
+                       }
+
+                       // Initialized subcase
+                       if (!subCase)
+                       {
+                               spec.assembly = specializeDefaultOutputShaderTemplate(numberType, params);
+                               subGroup->addChild(new SpvAsmComputeShaderCase(testCtx, "initialized", "OpVariable initializer tests.", spec));
+                       }
+                       // Uninitialized subcase
+                       else
+                       {
+                               spec.assembly = specializeDefaultOutputShaderTemplate(numberType);
+                               spec.verifyIO = &passthruVerify;
+                               subGroup->addChild(new SpvAsmComputeShaderCase(testCtx, "uninitialized", "OpVariable initializer tests.", spec));
+                       }
+               }
+               group->addChild(subGroup.release());
+       }
+       return group.release();
+}
+
 tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx)
 {
        de::MovePtr<tcu::TestCaseGroup> instructionTests        (new tcu::TestCaseGroup(testCtx, "instruction", "Instructions with special opcodes/operands"));
@@ -8769,6 +8966,7 @@ tcu::TestCaseGroup* createInstructionTests (tcu::TestContext& testCtx)
        computeTests->addChild(createUConvertTests(testCtx));
        computeTests->addChild(createOpCompositeInsertGroup(testCtx));
        computeTests->addChild(createOpInBoundsAccessChainGroup(testCtx));
+       computeTests->addChild(createShaderDefaultOutputGroup(testCtx));
 
        RGBA defaultColors[4];
        getDefaultColors(defaultColors);