--- /dev/null
+#!amber
+#
+# Copyright 2020 The Khronos Group Inc.
+# Copyright 2020 Valve Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+SHADER compute comp SPIRV-ASM TARGET_ENV spv1.0
+; SPIR-V
+; Version: 1.0
+ OpCapability Shader
+ OpMemoryModel Logical GLSL450
+ OpEntryPoint GLCompute %main "main"
+ OpExecutionMode %main LocalSize 1 1 1
+ OpMemberDecorate %InputBlock 0 Offset 0
+ OpDecorate %InputBlock BufferBlock
+ OpDecorate %inputBuffer DescriptorSet 0
+ OpDecorate %inputBuffer Binding 0
+ OpMemberDecorate %OutputBlock 0 Offset 0
+ OpDecorate %OutputBlock BufferBlock
+ OpDecorate %outputBuffer DescriptorSet 0
+ OpDecorate %outputBuffer Binding 1
+ %void = OpTypeVoid
+ %voidFunc = OpTypeFunction %void
+ %uint = OpTypeInt 32 0
+ %uint_4 = OpConstant %uint 4
+ %uint_5 = OpConstant %uint 5
+ %uint_6 = OpConstant %uint 6
+ %uint_7 = OpConstant %uint 7
+ %uint_8 = OpConstant %uint 8
+ %InputBlock = OpTypeStruct %uint
+ %InputBlock_ptr = OpTypePointer Uniform %InputBlock
+ %inputBuffer = OpVariable %InputBlock_ptr Uniform
+ %int = OpTypeInt 32 1
+ %int_0 = OpConstant %int 0
+ %uint_uniform_ptr = OpTypePointer Uniform %uint
+%uint_Function_ptr = OpTypePointer Function %uint
+ %OutputBlock = OpTypeStruct %uint
+ %OutputBlock_ptr = OpTypePointer Uniform %OutputBlock
+ %outputBuffer = OpVariable %OutputBlock_ptr Uniform
+ %main = OpFunction %void None %voidFunc
+ %mainLabel = OpLabel
+;
+; %aux will contain value 4 by default and it should not be modified.
+;
+ %aux = OpVariable %uint_Function_ptr Function
+ OpStore %aux %uint_4
+ %ptrIn = OpAccessChain %uint_uniform_ptr %inputBuffer %int_0
+ %inputVal = OpLoad %uint %ptrIn
+;
+; From fauly.asm in https://gitlab.freedesktop.org/mesa/mesa/-/issues/3460
+;
+; OpSelectionMerge %3153 None
+; OpSwitch %166 %3152 0 %3153 1 %3151 2 %3150 3 %3149
+; %3152 = OpLabel
+; OpBranch %3153
+; %3151 = OpLabel
+; OpBranch %3153
+; %3150 = OpLabel
+; %345 = OpAccessChain %_ptr_StorageBuffer_v4float %71 %uint_0 %uint_37
+; %346 = OpLoad %v4float %345
+; %347 = OpBitcast %v4uint %346
+; %348 = OpCompositeExtract %uint %347 0
+; %188 = OpShiftLeftLogical %uint %348 %uint_1
+; OpBranch %3153
+; %3149 = OpLabel
+; OpBranch %3153
+; %3153 = OpLabel
+;
+; Similar structure replicated below.
+; Value 0 jumps to the merge label while the others store unexpected values in %aux.
+;
+ OpSelectionMerge %mergeLabel None
+ OpSwitch %inputVal %defaultLabel 0 %mergeLabel 1 %val1Label 2 %val2Label 3 %val3Label
+ %defaultLabel = OpLabel
+ OpStore %aux %uint_5
+ OpBranch %mergeLabel
+ %val1Label = OpLabel
+ OpStore %aux %uint_6
+ OpBranch %mergeLabel
+ %val2Label = OpLabel
+ OpStore %aux %uint_7
+ OpBranch %mergeLabel
+ %val3Label = OpLabel
+ OpStore %aux %uint_8
+ OpBranch %mergeLabel
+ %mergeLabel = OpLabel
+ %ptrOut = OpAccessChain %uint_uniform_ptr %outputBuffer %int_0
+ %aux_val = OpLoad %uint %aux
+ OpStore %ptrOut %aux_val
+ OpReturn
+ OpFunctionEnd
+END
+
+BUFFER inputBuffer DATA_TYPE uint32 DATA 0 END
+BUFFER outputBuffer DATA_TYPE uint32 DATA 0 END
+
+# Store 0 as the input value to make the switch go directly to the merge label.
+PIPELINE compute compute_pipeline
+ ATTACH comp
+ BIND BUFFER inputBuffer AS storage DESCRIPTOR_SET 0 BINDING 0
+ BIND BUFFER outputBuffer AS storage DESCRIPTOR_SET 0 BINDING 1
+END
+
+RUN compute_pipeline 1 1 1
+# Expect 4, the initial value stored in %aux before the switch.
+EXPECT outputBuffer IDX 0 EQ 4
}
}
+void addOpSwitchAmberTests(tcu::TestCaseGroup& group, tcu::TestContext& testCtx)
+{
+ static const char dataDir[] = "spirv_assembly/instruction/compute/switch";
+
+ struct Case
+ {
+ string name;
+ string desc;
+ };
+
+ static const Case cases[] =
+ {
+ { "switch-case-to-merge-block", "Test switch containing a case that jumps directly to the merge block" },
+ };
+
+ for (int i = 0; i < DE_LENGTH_OF_ARRAY(cases); ++i)
+ {
+ const string fileName = cases[i].name + ".amber";
+ group.addChild(cts_amber::createAmberTestCase(testCtx, cases[i].name.c_str(), cases[i].desc.c_str(), dataDir, fileName));
+ }
+}
+
tcu::TestCaseGroup* createOpArrayLengthComputeGroup (tcu::TestContext& testCtx)
{
de::MovePtr<tcu::TestCaseGroup> group (new tcu::TestCaseGroup(testCtx, "oparraylength", "Test the OpArrayLength instruction"));
createTestsForAllStages("out_of_order", inputColors, outputColors, fragments, group.get());
+ addOpSwitchAmberTests(*group, testCtx);
+
return group.release();
}