1 // Copyright (c) 2022 The Khronos Group Inc.
2 // Copyright (c) 2022 LunarG Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include <unordered_set>
17 
18 #include "test/opt/pass_fixture.h"
19 #include "test/opt/pass_utils.h"
20 
21 namespace spvtools {
22 namespace opt {
23 namespace {
24 
25 using ElimDeadOutputStoresTest = PassTest<::testing::Test>;
26 
TEST_F(ElimDeadOutputStoresTest, VertMultipleLocations)27 TEST_F(ElimDeadOutputStoresTest, VertMultipleLocations) {
28   // #version 450
29   //
30   // layout(location = 2) out Vertex
31   // {
32   //         vec4 color0;
33   //         vec4 color1;
34   //         vec4 color2[3];
35   // } oVert;
36   //
37   // void main()
38   // {
39   //     oVert.color0 = vec4(0.0,0.0,0.0,0.0);
40   //     oVert.color1 = vec4(0.1,0.0,0.0,0.0);
41   //     oVert.color2[0] = vec4(0.2,0.0,0.0,0.0);
42   //     oVert.color2[1] = vec4(0.3,0.0,0.0,0.0);
43   //     oVert.color2[2] = vec4(0.4,0.0,0.0,0.0);
44   // }
45   const std::string text = R"(
46                OpCapability Shader
47           %1 = OpExtInstImport "GLSL.std.450"
48                OpMemoryModel Logical GLSL450
49                OpEntryPoint Vertex %main "main" %oVert
50                OpSource GLSL 450
51                OpName %main "main"
52                OpName %Vertex "Vertex"
53                OpMemberName %Vertex 0 "color0"
54                OpMemberName %Vertex 1 "color1"
55                OpMemberName %Vertex 2 "color2"
56                OpName %oVert "oVert"
57                OpDecorate %Vertex Block
58                OpDecorate %oVert Location 2
59        %void = OpTypeVoid
60           %3 = OpTypeFunction %void
61       %float = OpTypeFloat 32
62     %v4float = OpTypeVector %float 4
63        %uint = OpTypeInt 32 0
64      %uint_3 = OpConstant %uint 3
65 %_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3
66      %Vertex = OpTypeStruct %v4float %v4float %_arr_v4float_uint_3
67 %_ptr_Output_Vertex = OpTypePointer Output %Vertex
68       %oVert = OpVariable %_ptr_Output_Vertex Output
69         %int = OpTypeInt 32 1
70       %int_0 = OpConstant %int 0
71     %float_0 = OpConstant %float 0
72          %17 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
73 %_ptr_Output_v4float = OpTypePointer Output %v4float
74       %int_1 = OpConstant %int 1
75 %float_0_100000001 = OpConstant %float 0.100000001
76          %22 = OpConstantComposite %v4float %float_0_100000001 %float_0 %float_0 %float_0
77       %int_2 = OpConstant %int 2
78 %float_0_200000003 = OpConstant %float 0.200000003
79          %26 = OpConstantComposite %v4float %float_0_200000003 %float_0 %float_0 %float_0
80 %float_0_300000012 = OpConstant %float 0.300000012
81          %29 = OpConstantComposite %v4float %float_0_300000012 %float_0 %float_0 %float_0
82 %float_0_400000006 = OpConstant %float 0.400000006
83          %32 = OpConstantComposite %v4float %float_0_400000006 %float_0 %float_0 %float_0
84        %main = OpFunction %void None %3
85           %5 = OpLabel
86          %19 = OpAccessChain %_ptr_Output_v4float %oVert %int_0
87                OpStore %19 %17
88 ;CHECK:            OpStore %19 %17
89          %23 = OpAccessChain %_ptr_Output_v4float %oVert %int_1
90                OpStore %23 %22
91 ;CHECK-NOT:        OpStore %23 %22
92          %27 = OpAccessChain %_ptr_Output_v4float %oVert %int_2 %int_0
93                OpStore %27 %26
94 ;CHECK-NOT:        OpStore %27 %26
95          %30 = OpAccessChain %_ptr_Output_v4float %oVert %int_2 %int_1
96                OpStore %30 %29
97 ;CHECK:            OpStore %30 %29
98          %33 = OpAccessChain %_ptr_Output_v4float %oVert %int_2 %int_2
99                OpStore %33 %32
100 ;CHECK-NOT:        OpStore %33 %32
101                OpReturn
102                OpFunctionEnd
103 )";
104 
105   SetTargetEnv(SPV_ENV_VULKAN_1_3);
106   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
107 
108   std::unordered_set<uint32_t> live_inputs;
109   std::unordered_set<uint32_t> live_builtins;
110   live_inputs.insert(2);
111   live_inputs.insert(5);
112   SinglePassRunAndMatch<EliminateDeadOutputStoresPass>(text, true, &live_inputs,
113                                                        &live_builtins);
114 }
115 
TEST_F(ElimDeadOutputStoresTest, VertMatrix)116 TEST_F(ElimDeadOutputStoresTest, VertMatrix) {
117   // #version 450
118   //
119   // layout(location = 2) out Vertex
120   // {
121   //         vec4 color0;
122   //         vec4 color1;
123   //         mat4 color2;
124   //         mat4 color3;
125   //         mat4 color4;
126   // } oVert;
127   //
128   // void main()
129   // {
130   //     oVert.color0 = vec4(0.0,0.0,0.0,0.0);
131   //     oVert.color1 = vec4(0.1,0.0,0.0,0.0);
132   //     oVert.color2[2] = vec4(0.2,0.0,0.0,0.0);
133   //     oVert.color3[1] = vec4(0.3,0.0,0.0,0.0);
134   //     oVert.color4[0] = vec4(0.4,0.0,0.0,0.0);
135   // }
136   const std::string text = R"(
137                OpCapability Shader
138           %1 = OpExtInstImport "GLSL.std.450"
139                OpMemoryModel Logical GLSL450
140                OpEntryPoint Vertex %main "main" %oVert
141                OpSource GLSL 450
142                OpName %main "main"
143                OpName %Vertex "Vertex"
144                OpMemberName %Vertex 0 "color0"
145                OpMemberName %Vertex 1 "color1"
146                OpMemberName %Vertex 2 "color2"
147                OpMemberName %Vertex 3 "color3"
148                OpMemberName %Vertex 4 "color4"
149                OpName %oVert "oVert"
150                OpDecorate %Vertex Block
151                OpDecorate %oVert Location 2
152        %void = OpTypeVoid
153           %3 = OpTypeFunction %void
154       %float = OpTypeFloat 32
155     %v4float = OpTypeVector %float 4
156 %mat4v4float = OpTypeMatrix %v4float 4
157      %Vertex = OpTypeStruct %v4float %v4float %mat4v4float %mat4v4float %mat4v4float
158 %_ptr_Output_Vertex = OpTypePointer Output %Vertex
159       %oVert = OpVariable %_ptr_Output_Vertex Output
160         %int = OpTypeInt 32 1
161       %int_0 = OpConstant %int 0
162     %float_0 = OpConstant %float 0
163          %15 = OpConstantComposite %v4float %float_0 %float_0 %float_0 %float_0
164 %_ptr_Output_v4float = OpTypePointer Output %v4float
165       %int_1 = OpConstant %int 1
166 %float_0_100000001 = OpConstant %float 0.100000001
167          %20 = OpConstantComposite %v4float %float_0_100000001 %float_0 %float_0 %float_0
168       %int_2 = OpConstant %int 2
169 %float_0_200000003 = OpConstant %float 0.200000003
170          %24 = OpConstantComposite %v4float %float_0_200000003 %float_0 %float_0 %float_0
171       %int_3 = OpConstant %int 3
172 %float_0_300000012 = OpConstant %float 0.300000012
173          %28 = OpConstantComposite %v4float %float_0_300000012 %float_0 %float_0 %float_0
174       %int_4 = OpConstant %int 4
175 %float_0_400000006 = OpConstant %float 0.400000006
176          %32 = OpConstantComposite %v4float %float_0_400000006 %float_0 %float_0 %float_0
177        %main = OpFunction %void None %3
178           %5 = OpLabel
179          %17 = OpAccessChain %_ptr_Output_v4float %oVert %int_0
180                OpStore %17 %15
181 ; CHECK:           OpStore %17 %15
182          %21 = OpAccessChain %_ptr_Output_v4float %oVert %int_1
183                OpStore %21 %20
184 ; CHECK-NOT:       OpStore %21 %20
185          %25 = OpAccessChain %_ptr_Output_v4float %oVert %int_2 %int_2
186                OpStore %25 %24
187 ; CHECK-NOT:       OpStore %25 %24
188          %29 = OpAccessChain %_ptr_Output_v4float %oVert %int_3 %int_1
189                OpStore %29 %28
190 ; CHECK:           OpStore %29 %28
191          %33 = OpAccessChain %_ptr_Output_v4float %oVert %int_4 %int_0
192                OpStore %33 %32
193 ; CHECK-NOT:       OpStore %33 %32
194                OpReturn
195                OpFunctionEnd
196 )";
197 
198   SetTargetEnv(SPV_ENV_VULKAN_1_3);
199   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
200 
201   std::unordered_set<uint32_t> live_inputs;
202   std::unordered_set<uint32_t> live_builtins;
203   live_inputs.insert(2);
204   live_inputs.insert(8);
205   live_inputs.insert(9);
206   live_inputs.insert(10);
207   live_inputs.insert(11);
208   SinglePassRunAndMatch<EliminateDeadOutputStoresPass>(text, true, &live_inputs,
209                                                        &live_builtins);
210 }
211 
TEST_F(ElimDeadOutputStoresTest, VertMemberLocs)212 TEST_F(ElimDeadOutputStoresTest, VertMemberLocs) {
213   // #version 450
214   //
215   // out Vertex
216   // {
217   //     layout (location = 1) vec4 Cd;
218   //     layout (location = 0) vec2 uv;
219   // } oVert;
220   //
221   // layout (location  = 0) in vec3 P;
222   //
223   // void main()
224   // {
225   //     oVert.uv = vec2(0.1, 0.7);
226   //     oVert.Cd = vec4(1, 0.5, 0, 1);
227   //     gl_Position = vec4(P, 1);
228   // }
229   const std::string text = R"(
230                OpCapability Shader
231           %1 = OpExtInstImport "GLSL.std.450"
232                OpMemoryModel Logical GLSL450
233                OpEntryPoint Vertex %main "main" %oVert %_ %P
234                OpSource GLSL 450
235                OpName %main "main"
236                OpName %Vertex "Vertex"
237                OpMemberName %Vertex 0 "Cd"
238                OpMemberName %Vertex 1 "uv"
239                OpName %oVert "oVert"
240                OpName %gl_PerVertex "gl_PerVertex"
241                OpMemberName %gl_PerVertex 0 "gl_Position"
242                OpMemberName %gl_PerVertex 1 "gl_PointSize"
243                OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
244                OpMemberName %gl_PerVertex 3 "gl_CullDistance"
245                OpName %_ ""
246                OpName %P "P"
247                OpMemberDecorate %Vertex 0 Location 1
248                OpMemberDecorate %Vertex 1 Location 0
249                OpDecorate %Vertex Block
250                OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
251                OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
252                OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
253                OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
254                OpDecorate %gl_PerVertex Block
255                OpDecorate %P Location 0
256        %void = OpTypeVoid
257           %3 = OpTypeFunction %void
258       %float = OpTypeFloat 32
259     %v4float = OpTypeVector %float 4
260     %v2float = OpTypeVector %float 2
261      %Vertex = OpTypeStruct %v4float %v2float
262 %_ptr_Output_Vertex = OpTypePointer Output %Vertex
263       %oVert = OpVariable %_ptr_Output_Vertex Output
264         %int = OpTypeInt 32 1
265       %int_1 = OpConstant %int 1
266 %float_0_100000001 = OpConstant %float 0.100000001
267 %float_0_699999988 = OpConstant %float 0.699999988
268          %16 = OpConstantComposite %v2float %float_0_100000001 %float_0_699999988
269 %_ptr_Output_v2float = OpTypePointer Output %v2float
270       %int_0 = OpConstant %int 0
271     %float_1 = OpConstant %float 1
272   %float_0_5 = OpConstant %float 0.5
273     %float_0 = OpConstant %float 0
274          %23 = OpConstantComposite %v4float %float_1 %float_0_5 %float_0 %float_1
275 %_ptr_Output_v4float = OpTypePointer Output %v4float
276        %uint = OpTypeInt 32 0
277      %uint_1 = OpConstant %uint 1
278 %_arr_float_uint_1 = OpTypeArray %float %uint_1
279 %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
280 %_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
281           %_ = OpVariable %_ptr_Output_gl_PerVertex Output
282     %v3float = OpTypeVector %float 3
283 %_ptr_Input_v3float = OpTypePointer Input %v3float
284           %P = OpVariable %_ptr_Input_v3float Input
285        %main = OpFunction %void None %3
286           %5 = OpLabel
287          %18 = OpAccessChain %_ptr_Output_v2float %oVert %int_1
288                OpStore %18 %16
289 ; CHECK-NOT:       OpStore %18 %16
290          %25 = OpAccessChain %_ptr_Output_v4float %oVert %int_0
291                OpStore %25 %23
292 ; CHECK:           OpStore %25 %23
293          %35 = OpLoad %v3float %P
294          %36 = OpCompositeExtract %float %35 0
295          %37 = OpCompositeExtract %float %35 1
296          %38 = OpCompositeExtract %float %35 2
297          %39 = OpCompositeConstruct %v4float %36 %37 %38 %float_1
298          %40 = OpAccessChain %_ptr_Output_v4float %_ %int_0
299                OpStore %40 %39
300                OpReturn
301                OpFunctionEnd
302 )";
303 
304   SetTargetEnv(SPV_ENV_VULKAN_1_3);
305   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
306 
307   std::unordered_set<uint32_t> live_inputs;
308   std::unordered_set<uint32_t> live_builtins;
309   live_inputs.insert(1);
310   SinglePassRunAndMatch<EliminateDeadOutputStoresPass>(text, true, &live_inputs,
311                                                        &live_builtins);
312 }
313 
TEST_F(ElimDeadOutputStoresTest, ArrayedOutput)314 TEST_F(ElimDeadOutputStoresTest, ArrayedOutput) {
315   // Tests elimination of arrayed output as seen in Tesc shaders.
316   //
317   // #version 450
318   //
319   // layout (vertices = 4) out;
320   //
321   // layout (location = 0) in vec3 N[];
322   // layout (location = 1) in vec3 P[];
323   //
324   // layout (location = 5) out Vertex
325   // {
326   //                 vec4 c;
327   //                 vec3 n;
328   //                 vec3 f[10];
329   // } oVert[];
330   //
331   // void main()
332   // {
333   //                 oVert[gl_InvocationID].c = vec4(1, 0, 0, 1);
334   //                 oVert[gl_InvocationID].n = N[gl_InvocationID];
335   //                 oVert[gl_InvocationID].f[3] = vec3(0, 1, 0);
336   //                 vec4 worldSpacePos = vec4(P[gl_InvocationID], 1);
337   //                 gl_out[gl_InvocationID].gl_Position = worldSpacePos;
338   // }
339   const std::string text = R"(
340                OpCapability Tessellation
341           %1 = OpExtInstImport "GLSL.std.450"
342                OpMemoryModel Logical GLSL450
343                OpEntryPoint TessellationControl %main "main" %oVert %gl_InvocationID %N %P %gl_out
344                OpExecutionMode %main OutputVertices 4
345                OpSource GLSL 450
346                OpName %main "main"
347                OpName %Vertex "Vertex"
348                OpMemberName %Vertex 0 "c"
349                OpMemberName %Vertex 1 "n"
350                OpMemberName %Vertex 2 "f"
351                OpName %oVert "oVert"
352                OpName %gl_InvocationID "gl_InvocationID"
353                OpName %N "N"
354                OpName %P "P"
355                OpName %gl_PerVertex "gl_PerVertex"
356                OpMemberName %gl_PerVertex 0 "gl_Position"
357                OpMemberName %gl_PerVertex 1 "gl_PointSize"
358                OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
359                OpMemberName %gl_PerVertex 3 "gl_CullDistance"
360                OpName %gl_out "gl_out"
361                OpDecorate %Vertex Block
362                OpDecorate %oVert Location 5
363                OpDecorate %gl_InvocationID BuiltIn InvocationId
364                OpDecorate %N Location 0
365                OpDecorate %P Location 1
366                OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
367                OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
368                OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
369                OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
370                OpDecorate %gl_PerVertex Block
371        %void = OpTypeVoid
372           %3 = OpTypeFunction %void
373       %float = OpTypeFloat 32
374     %v4float = OpTypeVector %float 4
375     %v3float = OpTypeVector %float 3
376        %uint = OpTypeInt 32 0
377     %uint_10 = OpConstant %uint 10
378 %_arr_v3float_uint_10 = OpTypeArray %v3float %uint_10
379      %Vertex = OpTypeStruct %v4float %v3float %_arr_v3float_uint_10
380      %uint_4 = OpConstant %uint 4
381 %_arr_Vertex_uint_4 = OpTypeArray %Vertex %uint_4
382 %_ptr_Output__arr_Vertex_uint_4 = OpTypePointer Output %_arr_Vertex_uint_4
383       %oVert = OpVariable %_ptr_Output__arr_Vertex_uint_4 Output
384         %int = OpTypeInt 32 1
385 %_ptr_Input_int = OpTypePointer Input %int
386 %gl_InvocationID = OpVariable %_ptr_Input_int Input
387       %int_0 = OpConstant %int 0
388     %float_1 = OpConstant %float 1
389     %float_0 = OpConstant %float 0
390          %24 = OpConstantComposite %v4float %float_1 %float_0 %float_0 %float_1
391 %_ptr_Output_v4float = OpTypePointer Output %v4float
392       %int_1 = OpConstant %int 1
393     %uint_32 = OpConstant %uint 32
394 %_arr_v3float_uint_32 = OpTypeArray %v3float %uint_32
395 %_ptr_Input__arr_v3float_uint_32 = OpTypePointer Input %_arr_v3float_uint_32
396           %N = OpVariable %_ptr_Input__arr_v3float_uint_32 Input
397 %_ptr_Input_v3float = OpTypePointer Input %v3float
398 %_ptr_Output_v3float = OpTypePointer Output %v3float
399       %int_2 = OpConstant %int 2
400       %int_3 = OpConstant %int 3
401          %42 = OpConstantComposite %v3float %float_0 %float_1 %float_0
402           %P = OpVariable %_ptr_Input__arr_v3float_uint_32 Input
403      %uint_1 = OpConstant %uint 1
404 %_arr_float_uint_1 = OpTypeArray %float %uint_1
405 %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
406 %_arr_gl_PerVertex_uint_4 = OpTypeArray %gl_PerVertex %uint_4
407 %_ptr_Output__arr_gl_PerVertex_uint_4 = OpTypePointer Output %_arr_gl_PerVertex_uint_4
408      %gl_out = OpVariable %_ptr_Output__arr_gl_PerVertex_uint_4 Output
409        %main = OpFunction %void None %3
410           %5 = OpLabel
411          %20 = OpLoad %int %gl_InvocationID
412          %26 = OpAccessChain %_ptr_Output_v4float %oVert %20 %int_0
413                OpStore %26 %24
414 ; CHECK:           OpStore %26 %24
415          %35 = OpAccessChain %_ptr_Input_v3float %N %20
416          %36 = OpLoad %v3float %35
417          %38 = OpAccessChain %_ptr_Output_v3float %oVert %20 %int_1
418                OpStore %38 %36
419 ; CHECK-NOT:       OpStore %38 %36
420          %43 = OpAccessChain %_ptr_Output_v3float %oVert %20 %int_2 %int_3
421                OpStore %43 %42
422 ; CHECK:           OpStore %43 %42
423          %48 = OpAccessChain %_ptr_Input_v3float %P %20
424          %49 = OpLoad %v3float %48
425          %50 = OpCompositeExtract %float %49 0
426          %51 = OpCompositeExtract %float %49 1
427          %52 = OpCompositeExtract %float %49 2
428          %53 = OpCompositeConstruct %v4float %50 %51 %52 %float_1
429          %62 = OpAccessChain %_ptr_Output_v4float %gl_out %20 %int_0
430                OpStore %62 %53
431                OpReturn
432                OpFunctionEnd
433 )";
434 
435   SetTargetEnv(SPV_ENV_VULKAN_1_3);
436   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
437 
438   std::unordered_set<uint32_t> live_inputs;
439   std::unordered_set<uint32_t> live_builtins;
440   live_inputs.insert(5);
441   live_inputs.insert(10);
442   SinglePassRunAndMatch<EliminateDeadOutputStoresPass>(text, true, &live_inputs,
443                                                        &live_builtins);
444 }
445 
TEST_F(ElimDeadOutputStoresTest, ArrayedOutputMemberLocs)446 TEST_F(ElimDeadOutputStoresTest, ArrayedOutputMemberLocs) {
447   // Tests elimination of member location with arrayed output as seen in
448   // Tesc shaders.
449   //
450   // #version 450
451   //
452   // layout (vertices = 4) out;
453   //
454   // layout (location = 0) in vec3 N[];
455   // layout (location = 1) in vec3 P[];
456   //
457   // out Vertex
458   // {
459   //                 layout (location = 1) vec4 c;
460   //                 layout (location = 3) vec3 n;
461   //                 layout (location = 5) vec3 f[10];
462   // } oVert[];
463   //
464   // void main()
465   // {
466   //                 oVert[gl_InvocationID].c = vec4(1, 0, 0, 1);
467   //                 oVert[gl_InvocationID].n = N[gl_InvocationID];
468   //                 oVert[gl_InvocationID].f[3] = vec3(0, 1, 0);
469   //                 vec4 worldSpacePos = vec4(P[gl_InvocationID], 1);
470   //                 gl_out[gl_InvocationID].gl_Position = worldSpacePos;
471   // }
472   const std::string text = R"(
473                OpCapability Tessellation
474           %1 = OpExtInstImport "GLSL.std.450"
475                OpMemoryModel Logical GLSL450
476                OpEntryPoint TessellationControl %main "main" %oVert %gl_InvocationID %N %P %gl_out
477                OpExecutionMode %main OutputVertices 4
478                OpSource GLSL 450
479                OpName %main "main"
480                OpName %Vertex "Vertex"
481                OpMemberName %Vertex 0 "c"
482                OpMemberName %Vertex 1 "n"
483                OpMemberName %Vertex 2 "f"
484                OpName %oVert "oVert"
485                OpName %gl_InvocationID "gl_InvocationID"
486                OpName %N "N"
487                OpName %P "P"
488                OpName %gl_PerVertex "gl_PerVertex"
489                OpMemberName %gl_PerVertex 0 "gl_Position"
490                OpMemberName %gl_PerVertex 1 "gl_PointSize"
491                OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
492                OpMemberName %gl_PerVertex 3 "gl_CullDistance"
493                OpName %gl_out "gl_out"
494                OpMemberDecorate %Vertex 0 Location 1
495                OpMemberDecorate %Vertex 1 Location 3
496                OpMemberDecorate %Vertex 2 Location 5
497                OpDecorate %Vertex Block
498                OpDecorate %gl_InvocationID BuiltIn InvocationId
499                OpDecorate %N Location 0
500                OpDecorate %P Location 1
501                OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
502                OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
503                OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
504                OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
505                OpDecorate %gl_PerVertex Block
506        %void = OpTypeVoid
507           %3 = OpTypeFunction %void
508       %float = OpTypeFloat 32
509     %v4float = OpTypeVector %float 4
510     %v3float = OpTypeVector %float 3
511        %uint = OpTypeInt 32 0
512     %uint_10 = OpConstant %uint 10
513 %_arr_v3float_uint_10 = OpTypeArray %v3float %uint_10
514      %Vertex = OpTypeStruct %v4float %v3float %_arr_v3float_uint_10
515      %uint_4 = OpConstant %uint 4
516 %_arr_Vertex_uint_4 = OpTypeArray %Vertex %uint_4
517 %_ptr_Output__arr_Vertex_uint_4 = OpTypePointer Output %_arr_Vertex_uint_4
518       %oVert = OpVariable %_ptr_Output__arr_Vertex_uint_4 Output
519         %int = OpTypeInt 32 1
520 %_ptr_Input_int = OpTypePointer Input %int
521 %gl_InvocationID = OpVariable %_ptr_Input_int Input
522       %int_0 = OpConstant %int 0
523     %float_1 = OpConstant %float 1
524     %float_0 = OpConstant %float 0
525          %24 = OpConstantComposite %v4float %float_1 %float_0 %float_0 %float_1
526 %_ptr_Output_v4float = OpTypePointer Output %v4float
527       %int_1 = OpConstant %int 1
528     %uint_32 = OpConstant %uint 32
529 %_arr_v3float_uint_32 = OpTypeArray %v3float %uint_32
530 %_ptr_Input__arr_v3float_uint_32 = OpTypePointer Input %_arr_v3float_uint_32
531           %N = OpVariable %_ptr_Input__arr_v3float_uint_32 Input
532 %_ptr_Input_v3float = OpTypePointer Input %v3float
533 %_ptr_Output_v3float = OpTypePointer Output %v3float
534       %int_2 = OpConstant %int 2
535       %int_3 = OpConstant %int 3
536          %42 = OpConstantComposite %v3float %float_0 %float_1 %float_0
537           %P = OpVariable %_ptr_Input__arr_v3float_uint_32 Input
538      %uint_1 = OpConstant %uint 1
539 %_arr_float_uint_1 = OpTypeArray %float %uint_1
540 %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
541 %_arr_gl_PerVertex_uint_4 = OpTypeArray %gl_PerVertex %uint_4
542 %_ptr_Output__arr_gl_PerVertex_uint_4 = OpTypePointer Output %_arr_gl_PerVertex_uint_4
543      %gl_out = OpVariable %_ptr_Output__arr_gl_PerVertex_uint_4 Output
544        %main = OpFunction %void None %3
545           %5 = OpLabel
546          %20 = OpLoad %int %gl_InvocationID
547          %26 = OpAccessChain %_ptr_Output_v4float %oVert %20 %int_0
548                OpStore %26 %24
549 ;CHECK:            OpStore %26 %24
550          %35 = OpAccessChain %_ptr_Input_v3float %N %20
551          %36 = OpLoad %v3float %35
552          %38 = OpAccessChain %_ptr_Output_v3float %oVert %20 %int_1
553                OpStore %38 %36
554 ;CHECK-NOT:        OpStore %38 %36
555          %43 = OpAccessChain %_ptr_Output_v3float %oVert %20 %int_2 %int_3
556                OpStore %43 %42
557 ;CHECK:            OpStore %43 %42
558          %48 = OpAccessChain %_ptr_Input_v3float %P %20
559          %49 = OpLoad %v3float %48
560          %50 = OpCompositeExtract %float %49 0
561          %51 = OpCompositeExtract %float %49 1
562          %52 = OpCompositeExtract %float %49 2
563          %53 = OpCompositeConstruct %v4float %50 %51 %52 %float_1
564          %62 = OpAccessChain %_ptr_Output_v4float %gl_out %20 %int_0
565                OpStore %62 %53
566                OpReturn
567                OpFunctionEnd
568 )";
569 
570   SetTargetEnv(SPV_ENV_VULKAN_1_3);
571   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
572 
573   std::unordered_set<uint32_t> live_inputs;
574   std::unordered_set<uint32_t> live_builtins;
575   live_inputs.insert(1);
576   live_inputs.insert(8);
577   SinglePassRunAndMatch<EliminateDeadOutputStoresPass>(text, true, &live_inputs,
578                                                        &live_builtins);
579 }
580 
TEST_F(ElimDeadOutputStoresTest, ScalarBuiltins)581 TEST_F(ElimDeadOutputStoresTest, ScalarBuiltins) {
582   // Tests elimination of scalar builtins as seen in vert shaders.
583   //
584   // #version 460
585   //
586   // layout (location = 0) in vec3 P;
587   //
588   // void main()
589   // {
590   //         gl_Position = vec4(P, 1.0);
591   //         gl_PointSize = 1.0;
592   // }
593   const std::string text = R"(
594                OpCapability Shader
595           %1 = OpExtInstImport "GLSL.std.450"
596                OpMemoryModel Logical GLSL450
597                OpEntryPoint Vertex %main "main" %_ %P
598                OpSource GLSL 460
599                OpName %main "main"
600                OpName %gl_PerVertex "gl_PerVertex"
601                OpMemberName %gl_PerVertex 0 "gl_Position"
602                OpMemberName %gl_PerVertex 1 "gl_PointSize"
603                OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
604                OpMemberName %gl_PerVertex 3 "gl_CullDistance"
605                OpName %_ ""
606                OpName %P "P"
607                OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
608                OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
609                OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
610                OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
611                OpDecorate %gl_PerVertex Block
612                OpDecorate %P Location 0
613        %void = OpTypeVoid
614           %3 = OpTypeFunction %void
615       %float = OpTypeFloat 32
616     %v4float = OpTypeVector %float 4
617        %uint = OpTypeInt 32 0
618      %uint_1 = OpConstant %uint 1
619 %_arr_float_uint_1 = OpTypeArray %float %uint_1
620 %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
621 %_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
622           %_ = OpVariable %_ptr_Output_gl_PerVertex Output
623         %int = OpTypeInt 32 1
624       %int_0 = OpConstant %int 0
625     %v3float = OpTypeVector %float 3
626 %_ptr_Input_v3float = OpTypePointer Input %v3float
627           %P = OpVariable %_ptr_Input_v3float Input
628     %float_1 = OpConstant %float 1
629 %_ptr_Output_v4float = OpTypePointer Output %v4float
630       %int_1 = OpConstant %int 1
631 %_ptr_Output_float = OpTypePointer Output %float
632        %main = OpFunction %void None %3
633           %5 = OpLabel
634          %19 = OpLoad %v3float %P
635          %21 = OpCompositeExtract %float %19 0
636          %22 = OpCompositeExtract %float %19 1
637          %23 = OpCompositeExtract %float %19 2
638          %24 = OpCompositeConstruct %v4float %21 %22 %23 %float_1
639          %26 = OpAccessChain %_ptr_Output_v4float %_ %int_0
640                OpStore %26 %24
641 ;CHECK:                   OpStore %26 %24
642          %29 = OpAccessChain %_ptr_Output_float %_ %int_1
643                OpStore %29 %float_1
644 ;CHECK-NOT:               OpStore %29 %float_1
645                OpReturn
646                OpFunctionEnd
647 )";
648 
649   SetTargetEnv(SPV_ENV_VULKAN_1_3);
650   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
651 
652   std::unordered_set<uint32_t> live_inputs;
653   std::unordered_set<uint32_t> live_builtins;
654   // Omit spv::BuiltIn::PointSize
655   live_builtins.insert((uint32_t)spv::BuiltIn::ClipDistance);
656   live_builtins.insert((uint32_t)spv::BuiltIn::CullDistance);
657   SinglePassRunAndMatch<EliminateDeadOutputStoresPass>(text, true, &live_inputs,
658                                                        &live_builtins);
659 }
660 
TEST_F(ElimDeadOutputStoresTest, ArrayedBuiltins)661 TEST_F(ElimDeadOutputStoresTest, ArrayedBuiltins) {
662   // Tests elimination of arrayed builtins as seen in geom, tesc, and tese
663   // shaders.
664   //
665   // #version 460
666   //
667   // layout(triangle_strip, max_vertices = 3) out;
668   // layout(triangles) in;
669   //
670   // void main()
671   // {
672   //         for (int i = 0; i < 3; i++)
673   //         {
674   //                 gl_Position = gl_in[i].gl_Position;
675   //                 gl_PointSize = gl_in[i].gl_PointSize;
676   //
677   //                 EmitVertex();
678   //         }
679   //
680   //         EndPrimitive();
681   // }
682   const std::string text = R"(
683                OpCapability Geometry
684                OpCapability GeometryPointSize
685           %1 = OpExtInstImport "GLSL.std.450"
686                OpMemoryModel Logical GLSL450
687                OpEntryPoint Geometry %main "main" %_ %gl_in
688                OpExecutionMode %main Triangles
689                OpExecutionMode %main Invocations 1
690                OpExecutionMode %main OutputTriangleStrip
691                OpExecutionMode %main OutputVertices 3
692                OpSource GLSL 460
693                OpName %main "main"
694                OpName %i "i"
695                OpName %gl_PerVertex "gl_PerVertex"
696                OpMemberName %gl_PerVertex 0 "gl_Position"
697                OpMemberName %gl_PerVertex 1 "gl_PointSize"
698                OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
699                OpMemberName %gl_PerVertex 3 "gl_CullDistance"
700                OpName %_ ""
701                OpName %gl_PerVertex_0 "gl_PerVertex"
702                OpMemberName %gl_PerVertex_0 0 "gl_Position"
703                OpMemberName %gl_PerVertex_0 1 "gl_PointSize"
704                OpMemberName %gl_PerVertex_0 2 "gl_ClipDistance"
705                OpMemberName %gl_PerVertex_0 3 "gl_CullDistance"
706                OpName %gl_in "gl_in"
707                OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
708                OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
709                OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
710                OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
711                OpDecorate %gl_PerVertex Block
712                OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
713                OpMemberDecorate %gl_PerVertex_0 1 BuiltIn PointSize
714                OpMemberDecorate %gl_PerVertex_0 2 BuiltIn ClipDistance
715                OpMemberDecorate %gl_PerVertex_0 3 BuiltIn CullDistance
716                OpDecorate %gl_PerVertex_0 Block
717        %void = OpTypeVoid
718           %3 = OpTypeFunction %void
719         %int = OpTypeInt 32 1
720 %_ptr_Function_int = OpTypePointer Function %int
721       %int_0 = OpConstant %int 0
722       %int_3 = OpConstant %int 3
723        %bool = OpTypeBool
724       %float = OpTypeFloat 32
725     %v4float = OpTypeVector %float 4
726        %uint = OpTypeInt 32 0
727      %uint_1 = OpConstant %uint 1
728 %_arr_float_uint_1 = OpTypeArray %float %uint_1
729 %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
730 %_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
731           %_ = OpVariable %_ptr_Output_gl_PerVertex Output
732 %gl_PerVertex_0 = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
733      %uint_3 = OpConstant %uint 3
734 %_arr_gl_PerVertex_0_uint_3 = OpTypeArray %gl_PerVertex_0 %uint_3
735 %_ptr_Input__arr_gl_PerVertex_0_uint_3 = OpTypePointer Input %_arr_gl_PerVertex_0_uint_3
736       %gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_0_uint_3 Input
737 %_ptr_Input_v4float = OpTypePointer Input %v4float
738 %_ptr_Output_v4float = OpTypePointer Output %v4float
739       %int_1 = OpConstant %int 1
740 %_ptr_Input_float = OpTypePointer Input %float
741 %_ptr_Output_float = OpTypePointer Output %float
742        %main = OpFunction %void None %3
743           %5 = OpLabel
744           %i = OpVariable %_ptr_Function_int Function
745                OpStore %i %int_0
746                OpBranch %10
747          %10 = OpLabel
748                OpLoopMerge %12 %13 None
749                OpBranch %14
750          %14 = OpLabel
751          %15 = OpLoad %int %i
752          %18 = OpSLessThan %bool %15 %int_3
753                OpBranchConditional %18 %11 %12
754          %11 = OpLabel
755          %32 = OpLoad %int %i
756          %34 = OpAccessChain %_ptr_Input_v4float %gl_in %32 %int_0
757          %35 = OpLoad %v4float %34
758          %37 = OpAccessChain %_ptr_Output_v4float %_ %int_0
759                OpStore %37 %35
760 ;CHECK:                   OpStore %37 %35
761          %39 = OpLoad %int %i
762          %41 = OpAccessChain %_ptr_Input_float %gl_in %39 %int_1
763          %42 = OpLoad %float %41
764          %44 = OpAccessChain %_ptr_Output_float %_ %int_1
765                OpStore %44 %42
766 ;CHECK-NOT:               OpStore %44 %42
767                OpEmitVertex
768                OpBranch %13
769          %13 = OpLabel
770          %45 = OpLoad %int %i
771          %46 = OpIAdd %int %45 %int_1
772                OpStore %i %46
773                OpBranch %10
774          %12 = OpLabel
775                OpEndPrimitive
776                OpReturn
777                OpFunctionEnd
778 )";
779 
780   SetTargetEnv(SPV_ENV_VULKAN_1_3);
781   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
782 
783   std::unordered_set<uint32_t> live_inputs;
784   std::unordered_set<uint32_t> live_builtins;
785   // Omit spv::BuiltIn::PointSize
786   live_builtins.insert((uint32_t)spv::BuiltIn::ClipDistance);
787   live_builtins.insert((uint32_t)spv::BuiltIn::CullDistance);
788   SinglePassRunAndMatch<EliminateDeadOutputStoresPass>(text, true, &live_inputs,
789                                                        &live_builtins);
790 }
791 
TEST_F(ElimDeadOutputStoresTest, ArrayedOutputPatchLocs)792 TEST_F(ElimDeadOutputStoresTest, ArrayedOutputPatchLocs) {
793   // Tests elimination of location with arrayed patch output as seen in
794   // Tesc shaders.
795   //
796   // #version 450 core
797   //
798   // layout(vertices = 4) out;
799   //
800   // layout(location=0) patch out float patchOut0[2];
801   // layout(location=2) patch out float patchOut1[2];
802   //
803   // void main()
804   // {
805   //     patchOut0[1] = 0.0;  // Dead loc 1
806   //     patchOut1[1] = 1.0;  // Live loc 3
807   // }
808   const std::string text = R"(
809                OpCapability Tessellation
810           %1 = OpExtInstImport "GLSL.std.450"
811                OpMemoryModel Logical GLSL450
812                OpEntryPoint TessellationControl %main "main" %patchOut0 %patchOut1
813                OpExecutionMode %main OutputVertices 4
814                OpSource GLSL 450
815                OpName %main "main"
816                OpName %patchOut0 "patchOut0"
817                OpName %patchOut1 "patchOut1"
818                OpDecorate %patchOut0 Patch
819                OpDecorate %patchOut0 Location 0
820                OpDecorate %patchOut1 Patch
821                OpDecorate %patchOut1 Location 2
822        %void = OpTypeVoid
823           %3 = OpTypeFunction %void
824       %float = OpTypeFloat 32
825        %uint = OpTypeInt 32 0
826      %uint_2 = OpConstant %uint 2
827 %_arr_float_uint_2 = OpTypeArray %float %uint_2
828 %_ptr_Output__arr_float_uint_2 = OpTypePointer Output %_arr_float_uint_2
829   %patchOut0 = OpVariable %_ptr_Output__arr_float_uint_2 Output
830         %int = OpTypeInt 32 1
831       %int_1 = OpConstant %int 1
832     %float_0 = OpConstant %float 0
833 %_ptr_Output_float = OpTypePointer Output %float
834   %patchOut1 = OpVariable %_ptr_Output__arr_float_uint_2 Output
835     %float_1 = OpConstant %float 1
836        %main = OpFunction %void None %3
837           %5 = OpLabel
838          %16 = OpAccessChain %_ptr_Output_float %patchOut0 %int_1
839                OpStore %16 %float_0
840 ;CHECK-NOT:               OpStore %16 %float_0
841          %19 = OpAccessChain %_ptr_Output_float %patchOut1 %int_1
842                OpStore %19 %float_1
843 ;CHECK:                   OpStore %19 %float_1
844                OpReturn
845                OpFunctionEnd
846 )";
847 
848   SetTargetEnv(SPV_ENV_VULKAN_1_3);
849   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
850 
851   std::unordered_set<uint32_t> live_inputs;
852   std::unordered_set<uint32_t> live_builtins;
853   live_inputs.insert(3);
854   SinglePassRunAndMatch<EliminateDeadOutputStoresPass>(text, true, &live_inputs,
855                                                        &live_builtins);
856 }
857 
TEST_F(ElimDeadOutputStoresTest, VertMultipleLocationsF16)858 TEST_F(ElimDeadOutputStoresTest, VertMultipleLocationsF16) {
859   // #version 450
860   //
861   // layout(location = 2) out Vertex
862   // {
863   //         f16vec4 color0;
864   //         f16vec4 color1;
865   //         f16vec4 color2[3];
866   // } oVert;
867   //
868   // void main()
869   // {
870   //     oVert.color0 = f16vec4(0.0,0.0,0.0,0.0);
871   //     oVert.color1 = f16vec4(0.1,0.0,0.0,0.0);
872   //     oVert.color2[0] = f16vec4(0.2,0.0,0.0,0.0);
873   //     oVert.color2[1] = f16vec4(0.3,0.0,0.0,0.0);
874   //     oVert.color2[2] = f16vec4(0.4,0.0,0.0,0.0);
875   // }
876   const std::string text = R"(
877                OpCapability Shader
878                OpCapability Float16
879                OpCapability StorageInputOutput16
880           %1 = OpExtInstImport "GLSL.std.450"
881                OpMemoryModel Logical GLSL450
882                OpEntryPoint Vertex %main "main" %oVert
883                OpSource GLSL 450
884                OpName %main "main"
885                OpName %Vertex "Vertex"
886                OpMemberName %Vertex 0 "color0"
887                OpMemberName %Vertex 1 "color1"
888                OpMemberName %Vertex 2 "color2"
889                OpName %oVert "oVert"
890                OpDecorate %Vertex Block
891                OpDecorate %oVert Location 2
892        %void = OpTypeVoid
893           %3 = OpTypeFunction %void
894       %half = OpTypeFloat 32
895     %v4half = OpTypeVector %half 4
896        %uint = OpTypeInt 32 0
897      %uint_3 = OpConstant %uint 3
898 %_arr_v4half_uint_3 = OpTypeArray %v4half %uint_3
899      %Vertex = OpTypeStruct %v4half %v4half %_arr_v4half_uint_3
900 %_ptr_Output_Vertex = OpTypePointer Output %Vertex
901       %oVert = OpVariable %_ptr_Output_Vertex Output
902         %int = OpTypeInt 32 1
903       %int_0 = OpConstant %int 0
904     %half_0 = OpConstant %half 0
905          %17 = OpConstantComposite %v4half %half_0 %half_0 %half_0 %half_0
906 %_ptr_Output_v4half = OpTypePointer Output %v4half
907       %int_1 = OpConstant %int 1
908 %half_0_100000001 = OpConstant %half 0.100000001
909          %22 = OpConstantComposite %v4half %half_0_100000001 %half_0 %half_0 %half_0
910       %int_2 = OpConstant %int 2
911 %half_0_200000003 = OpConstant %half 0.200000003
912          %26 = OpConstantComposite %v4half %half_0_200000003 %half_0 %half_0 %half_0
913 %half_0_300000012 = OpConstant %half 0.300000012
914          %29 = OpConstantComposite %v4half %half_0_300000012 %half_0 %half_0 %half_0
915 %half_0_400000006 = OpConstant %half 0.400000006
916          %32 = OpConstantComposite %v4half %half_0_400000006 %half_0 %half_0 %half_0
917        %main = OpFunction %void None %3
918           %5 = OpLabel
919          %19 = OpAccessChain %_ptr_Output_v4half %oVert %int_0
920                OpStore %19 %17
921 ;CHECK:            OpStore %19 %17
922          %23 = OpAccessChain %_ptr_Output_v4half %oVert %int_1
923                OpStore %23 %22
924 ;CHECK-NOT:        OpStore %23 %22
925          %27 = OpAccessChain %_ptr_Output_v4half %oVert %int_2 %int_0
926                OpStore %27 %26
927 ;CHECK-NOT:        OpStore %27 %26
928          %30 = OpAccessChain %_ptr_Output_v4half %oVert %int_2 %int_1
929                OpStore %30 %29
930 ;CHECK:            OpStore %30 %29
931          %33 = OpAccessChain %_ptr_Output_v4half %oVert %int_2 %int_2
932                OpStore %33 %32
933 ;CHECK-NOT:        OpStore %33 %32
934                OpReturn
935                OpFunctionEnd
936 )";
937 
938   SetTargetEnv(SPV_ENV_VULKAN_1_3);
939   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
940 
941   std::unordered_set<uint32_t> live_inputs;
942   std::unordered_set<uint32_t> live_builtins;
943   live_inputs.insert(2);
944   live_inputs.insert(5);
945   SinglePassRunAndMatch<EliminateDeadOutputStoresPass>(text, true, &live_inputs,
946                                                        &live_builtins);
947 }
948 
949 }  // namespace
950 }  // namespace opt
951 }  // namespace spvtools
952