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 AnalyzeLiveInputTest = PassTest<::testing::Test>;
26 
TEST_F(AnalyzeLiveInputTest,FragMultipleLocations)27 TEST_F(AnalyzeLiveInputTest, FragMultipleLocations) {
28   // Should report locations {2, 5}
29   //
30   // #version 450
31   //
32   // layout(location = 2) in Vertex
33   // {
34   //         vec4 color0;
35   //         vec4 color1;
36   //         vec4 color2[3];
37   // } iVert;
38   //
39   // layout(location = 0) out vec4 oFragColor;
40   //
41   // void main()
42   // {
43   //     oFragColor = iVert.color0 + iVert.color2[1];
44   // }
45   const std::string text = R"(
46                OpCapability Shader
47           %1 = OpExtInstImport "GLSL.std.450"
48                OpMemoryModel Logical GLSL450
49                OpEntryPoint Fragment %main "main" %oFragColor %iVert
50                OpExecutionMode %main OriginUpperLeft
51                OpSource GLSL 450
52                OpName %main "main"
53                OpName %oFragColor "oFragColor"
54                OpName %Vertex "Vertex"
55                OpMemberName %Vertex 0 "color0"
56                OpMemberName %Vertex 1 "color1"
57                OpMemberName %Vertex 2 "color2"
58                OpName %iVert "iVert"
59                OpDecorate %oFragColor Location 0
60                OpDecorate %Vertex Block
61                OpDecorate %iVert Location 2
62        %void = OpTypeVoid
63           %3 = OpTypeFunction %void
64       %float = OpTypeFloat 32
65     %v4float = OpTypeVector %float 4
66 %_ptr_Output_v4float = OpTypePointer Output %v4float
67  %oFragColor = OpVariable %_ptr_Output_v4float Output
68        %uint = OpTypeInt 32 0
69      %uint_3 = OpConstant %uint 3
70 %_arr_v4float_uint_3 = OpTypeArray %v4float %uint_3
71      %Vertex = OpTypeStruct %v4float %v4float %_arr_v4float_uint_3
72 %_ptr_Input_Vertex = OpTypePointer Input %Vertex
73       %iVert = OpVariable %_ptr_Input_Vertex Input
74         %int = OpTypeInt 32 1
75       %int_0 = OpConstant %int 0
76 %_ptr_Input_v4float = OpTypePointer Input %v4float
77       %int_2 = OpConstant %int 2
78       %int_1 = OpConstant %int 1
79        %main = OpFunction %void None %3
80           %5 = OpLabel
81          %19 = OpAccessChain %_ptr_Input_v4float %iVert %int_0
82          %20 = OpLoad %v4float %19
83          %23 = OpAccessChain %_ptr_Input_v4float %iVert %int_2 %int_1
84          %24 = OpLoad %v4float %23
85          %25 = OpFAdd %v4float %20 %24
86                OpStore %oFragColor %25
87                OpReturn
88                OpFunctionEnd
89 )";
90 
91   SetTargetEnv(SPV_ENV_VULKAN_1_3);
92   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
93 
94   std::unordered_set<uint32_t> live_inputs;
95   std::unordered_set<uint32_t> live_builtins;
96   auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
97       text, true, &live_inputs, &live_builtins);
98 
99   auto itr0 = live_inputs.find(0);
100   auto itr1 = live_inputs.find(1);
101   auto itr2 = live_inputs.find(2);
102   auto itr3 = live_inputs.find(3);
103   auto itr4 = live_inputs.find(4);
104   auto itr5 = live_inputs.find(5);
105   auto itr6 = live_inputs.find(6);
106 
107   // Expect live_inputs == {2, 5}
108   EXPECT_TRUE(itr0 == live_inputs.end());
109   EXPECT_TRUE(itr1 == live_inputs.end());
110   EXPECT_TRUE(itr2 != live_inputs.end());
111   EXPECT_TRUE(itr3 == live_inputs.end());
112   EXPECT_TRUE(itr4 == live_inputs.end());
113   EXPECT_TRUE(itr5 != live_inputs.end());
114   EXPECT_TRUE(itr6 == live_inputs.end());
115 }
116 
TEST_F(AnalyzeLiveInputTest,FragMatrix)117 TEST_F(AnalyzeLiveInputTest, FragMatrix) {
118   // Should report locations {2, 8, 9, 10, 11}
119   //
120   // #version 450
121   //
122   // uniform ui_name {
123   //     int i;
124   // } ui_inst;
125   //
126   // layout(location = 2) in Vertex
127   // {
128   //         vec4 color0;
129   //         vec4 color1;
130   //         mat4 color2;
131   //         mat4 color3;
132   //         mat4 color4;
133   // } iVert;
134   //
135   // // Output variable for the color
136   // layout(location = 0) out vec4 oFragColor;
137   //
138   // void main()
139   // {
140   //     oFragColor = iVert.color0 + iVert.color3[ui_inst.i];
141   // }
142   const std::string text = R"(
143                OpCapability Shader
144           %1 = OpExtInstImport "GLSL.std.450"
145                OpMemoryModel Logical GLSL450
146                OpEntryPoint Fragment %main "main" %oFragColor %iVert %ui_inst
147                OpExecutionMode %main OriginUpperLeft
148                OpSource GLSL 450
149                OpName %main "main"
150                OpName %oFragColor "oFragColor"
151                OpName %Vertex "Vertex"
152                OpMemberName %Vertex 0 "color0"
153                OpMemberName %Vertex 1 "color1"
154                OpMemberName %Vertex 2 "color2"
155                OpMemberName %Vertex 3 "color3"
156                OpMemberName %Vertex 4 "color4"
157                OpName %iVert "iVert"
158                OpName %ui_name "ui_name"
159                OpMemberName %ui_name 0 "i"
160                OpName %ui_inst "ui_inst"
161                OpDecorate %oFragColor Location 0
162                OpDecorate %Vertex Block
163                OpDecorate %iVert Location 2
164                OpMemberDecorate %ui_name 0 Offset 0
165                OpDecorate %ui_name Block
166                OpDecorate %ui_inst DescriptorSet 0
167                OpDecorate %ui_inst Binding 0
168        %void = OpTypeVoid
169           %3 = OpTypeFunction %void
170       %float = OpTypeFloat 32
171     %v4float = OpTypeVector %float 4
172 %_ptr_Output_v4float = OpTypePointer Output %v4float
173  %oFragColor = OpVariable %_ptr_Output_v4float Output
174 %mat4v4float = OpTypeMatrix %v4float 4
175      %Vertex = OpTypeStruct %v4float %v4float %mat4v4float %mat4v4float %mat4v4float
176 %_ptr_Input_Vertex = OpTypePointer Input %Vertex
177       %iVert = OpVariable %_ptr_Input_Vertex Input
178         %int = OpTypeInt 32 1
179       %int_0 = OpConstant %int 0
180 %_ptr_Input_v4float = OpTypePointer Input %v4float
181       %int_3 = OpConstant %int 3
182     %ui_name = OpTypeStruct %int
183 %_ptr_Uniform_ui_name = OpTypePointer Uniform %ui_name
184     %ui_inst = OpVariable %_ptr_Uniform_ui_name Uniform
185 %_ptr_Uniform_int = OpTypePointer Uniform %int
186        %main = OpFunction %void None %3
187           %5 = OpLabel
188          %17 = OpAccessChain %_ptr_Input_v4float %iVert %int_0
189          %18 = OpLoad %v4float %17
190          %24 = OpAccessChain %_ptr_Uniform_int %ui_inst %int_0
191          %25 = OpLoad %int %24
192          %26 = OpAccessChain %_ptr_Input_v4float %iVert %int_3 %25
193          %27 = OpLoad %v4float %26
194          %28 = OpFAdd %v4float %18 %27
195                OpStore %oFragColor %28
196                OpReturn
197                OpFunctionEnd
198 )";
199 
200   SetTargetEnv(SPV_ENV_VULKAN_1_3);
201   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
202 
203   std::unordered_set<uint32_t> live_inputs;
204   std::unordered_set<uint32_t> live_builtins;
205   auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
206       text, true, &live_inputs, &live_builtins);
207 
208   auto itr0 = live_inputs.find(0);
209   auto itr1 = live_inputs.find(1);
210   auto itr2 = live_inputs.find(2);
211   auto itr3 = live_inputs.find(3);
212   auto itr4 = live_inputs.find(4);
213   auto itr5 = live_inputs.find(5);
214   auto itr6 = live_inputs.find(6);
215   auto itr7 = live_inputs.find(7);
216   auto itr8 = live_inputs.find(8);
217   auto itr9 = live_inputs.find(9);
218   auto itr10 = live_inputs.find(10);
219   auto itr11 = live_inputs.find(11);
220   auto itr12 = live_inputs.find(12);
221   auto itr13 = live_inputs.find(13);
222   auto itr14 = live_inputs.find(14);
223   auto itr15 = live_inputs.find(15);
224 
225   // Expect live_inputs == {2, 8, 9, 10, 11}
226   EXPECT_TRUE(itr0 == live_inputs.end());
227   EXPECT_TRUE(itr1 == live_inputs.end());
228   EXPECT_TRUE(itr2 != live_inputs.end());
229   EXPECT_TRUE(itr3 == live_inputs.end());
230   EXPECT_TRUE(itr4 == live_inputs.end());
231   EXPECT_TRUE(itr5 == live_inputs.end());
232   EXPECT_TRUE(itr6 == live_inputs.end());
233   EXPECT_TRUE(itr7 == live_inputs.end());
234   EXPECT_TRUE(itr8 != live_inputs.end());
235   EXPECT_TRUE(itr9 != live_inputs.end());
236   EXPECT_TRUE(itr10 != live_inputs.end());
237   EXPECT_TRUE(itr11 != live_inputs.end());
238   EXPECT_TRUE(itr12 == live_inputs.end());
239   EXPECT_TRUE(itr13 == live_inputs.end());
240   EXPECT_TRUE(itr14 == live_inputs.end());
241   EXPECT_TRUE(itr15 == live_inputs.end());
242 }
243 
TEST_F(AnalyzeLiveInputTest,FragMemberLocs)244 TEST_F(AnalyzeLiveInputTest, FragMemberLocs) {
245   // Should report location {1}
246   //
247   // #version 450
248   //
249   // in Vertex
250   // {
251   //     layout (location = 1) vec4 Cd;
252   //     layout (location = 0) vec2 uv;
253   // } iVert;
254   //
255   // layout (location = 0) out vec4 fragColor;
256   //
257   // void main()
258   // {
259   //     vec4 color = vec4(iVert.Cd);
260   //     fragColor = color;
261   // }
262   const std::string text = R"(
263                OpCapability Shader
264           %1 = OpExtInstImport "GLSL.std.450"
265                OpMemoryModel Logical GLSL450
266                OpEntryPoint Fragment %main "main" %iVert %fragColor
267                OpExecutionMode %main OriginUpperLeft
268                OpSource GLSL 450
269                OpName %main "main"
270                OpName %color "color"
271                OpName %Vertex "Vertex"
272                OpMemberName %Vertex 0 "Cd"
273                OpMemberName %Vertex 1 "uv"
274                OpName %iVert "iVert"
275                OpName %fragColor "fragColor"
276                OpMemberDecorate %Vertex 0 Location 1
277                OpMemberDecorate %Vertex 1 Location 0
278                OpDecorate %Vertex Block
279                OpDecorate %fragColor Location 0
280                OpDecorate %_struct_27 Block
281                OpMemberDecorate %_struct_27 0 Location 1
282        %void = OpTypeVoid
283           %3 = OpTypeFunction %void
284       %float = OpTypeFloat 32
285     %v4float = OpTypeVector %float 4
286 %_ptr_Function_v4float = OpTypePointer Function %v4float
287     %v2float = OpTypeVector %float 2
288      %Vertex = OpTypeStruct %v4float %v2float
289 %_ptr_Input_Vertex = OpTypePointer Input %Vertex
290         %int = OpTypeInt 32 1
291       %int_0 = OpConstant %int 0
292 %_ptr_Input_v4float = OpTypePointer Input %v4float
293 %_ptr_Output_v4float = OpTypePointer Output %v4float
294   %fragColor = OpVariable %_ptr_Output_v4float Output
295  %_struct_27 = OpTypeStruct %v4float
296 %_ptr_Input__struct_27 = OpTypePointer Input %_struct_27
297       %iVert = OpVariable %_ptr_Input__struct_27 Input
298        %main = OpFunction %void None %3
299           %5 = OpLabel
300       %color = OpVariable %_ptr_Function_v4float Function
301          %17 = OpAccessChain %_ptr_Input_v4float %iVert %int_0
302          %18 = OpLoad %v4float %17
303          %19 = OpCompositeExtract %float %18 0
304          %20 = OpCompositeExtract %float %18 1
305          %21 = OpCompositeExtract %float %18 2
306          %22 = OpCompositeExtract %float %18 3
307          %23 = OpCompositeConstruct %v4float %19 %20 %21 %22
308                OpStore %color %23
309          %26 = OpLoad %v4float %color
310                OpStore %fragColor %26
311                OpReturn
312                OpFunctionEnd
313 )";
314 
315   SetTargetEnv(SPV_ENV_VULKAN_1_3);
316   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
317 
318   std::unordered_set<uint32_t> live_inputs;
319   std::unordered_set<uint32_t> live_builtins;
320   auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
321       text, true, &live_inputs, &live_builtins);
322 
323   auto itr0 = live_inputs.find(0);
324   auto itr1 = live_inputs.find(1);
325 
326   // Expect live_inputs == {2, 5}
327   EXPECT_TRUE(itr0 == live_inputs.end());
328   EXPECT_TRUE(itr1 != live_inputs.end());
329 }
330 
TEST_F(AnalyzeLiveInputTest,ArrayedInput)331 TEST_F(AnalyzeLiveInputTest, ArrayedInput) {
332   // Tests handling of arrayed input seen in Tesc, Tese and Geom shaders.
333   //
334   // Should report location {1, 10}.
335   //
336   // #version 450
337   //
338   // layout (vertices = 4) out;
339   //
340   // layout (location = 1) in Vertex
341   // {
342   //                 vec4 p;
343   //                 vec3 n;
344   //                 vec4 f[100];
345   // } iVert[];
346   //
347   // layout (location = 0) out vec4 position[4];
348   //
349   // void main()
350   // {
351   //                 vec4 pos = iVert[gl_InvocationID].p *
352   //                            iVert[gl_InvocationID].f[7];
353   //                 position[gl_InvocationID] = pos;
354   // }
355   const std::string text = R"(
356                OpCapability Tessellation
357           %1 = OpExtInstImport "GLSL.std.450"
358                OpMemoryModel Logical GLSL450
359                OpEntryPoint TessellationControl %main "main" %iVert %gl_InvocationID %position
360                OpExecutionMode %main OutputVertices 4
361                OpSource GLSL 450
362                OpName %main "main"
363                OpName %Vertex "Vertex"
364                OpMemberName %Vertex 0 "p"
365                OpMemberName %Vertex 1 "n"
366                OpMemberName %Vertex 2 "f"
367                OpName %iVert "iVert"
368                OpName %gl_InvocationID "gl_InvocationID"
369                OpName %position "position"
370                OpDecorate %Vertex Block
371                OpDecorate %iVert Location 1
372                OpDecorate %gl_InvocationID BuiltIn InvocationId
373                OpDecorate %position Location 0
374        %void = OpTypeVoid
375           %3 = OpTypeFunction %void
376       %float = OpTypeFloat 32
377     %v4float = OpTypeVector %float 4
378     %v3float = OpTypeVector %float 3
379        %uint = OpTypeInt 32 0
380    %uint_100 = OpConstant %uint 100
381 %_arr_v4float_uint_100 = OpTypeArray %v4float %uint_100
382      %Vertex = OpTypeStruct %v4float %v3float %_arr_v4float_uint_100
383     %uint_32 = OpConstant %uint 32
384 %_arr_Vertex_uint_32 = OpTypeArray %Vertex %uint_32
385 %_ptr_Input__arr_Vertex_uint_32 = OpTypePointer Input %_arr_Vertex_uint_32
386       %iVert = OpVariable %_ptr_Input__arr_Vertex_uint_32 Input
387         %int = OpTypeInt 32 1
388 %_ptr_Input_int = OpTypePointer Input %int
389 %gl_InvocationID = OpVariable %_ptr_Input_int Input
390       %int_0 = OpConstant %int 0
391 %_ptr_Input_v4float = OpTypePointer Input %v4float
392       %int_2 = OpConstant %int 2
393       %int_7 = OpConstant %int 7
394      %uint_4 = OpConstant %uint 4
395 %_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4
396 %_ptr_Output__arr_v4float_uint_4 = OpTypePointer Output %_arr_v4float_uint_4
397    %position = OpVariable %_ptr_Output__arr_v4float_uint_4 Output
398 %_ptr_Output_v4float = OpTypePointer Output %v4float
399        %main = OpFunction %void None %3
400           %5 = OpLabel
401          %22 = OpLoad %int %gl_InvocationID
402          %25 = OpAccessChain %_ptr_Input_v4float %iVert %22 %int_0
403          %26 = OpLoad %v4float %25
404          %30 = OpAccessChain %_ptr_Input_v4float %iVert %22 %int_2 %int_7
405          %31 = OpLoad %v4float %30
406          %32 = OpFMul %v4float %26 %31
407          %40 = OpAccessChain %_ptr_Output_v4float %position %22
408                OpStore %40 %32
409                OpReturn
410                OpFunctionEnd
411 )";
412 
413   SetTargetEnv(SPV_ENV_VULKAN_1_3);
414   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
415 
416   std::unordered_set<uint32_t> live_inputs;
417   std::unordered_set<uint32_t> live_builtins;
418   auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
419       text, true, &live_inputs, &live_builtins);
420 
421   auto itr0 = live_inputs.find(0);
422   auto itr1 = live_inputs.find(1);
423   auto itr2 = live_inputs.find(2);
424   auto itr3 = live_inputs.find(3);
425   auto itr4 = live_inputs.find(4);
426   auto itr5 = live_inputs.find(5);
427   auto itr6 = live_inputs.find(6);
428   auto itr7 = live_inputs.find(7);
429   auto itr8 = live_inputs.find(8);
430   auto itr9 = live_inputs.find(9);
431   auto itr10 = live_inputs.find(10);
432   auto itr11 = live_inputs.find(11);
433 
434   // Expect live_inputs == {1, 10}
435   EXPECT_TRUE(itr0 == live_inputs.end());
436   EXPECT_TRUE(itr1 != live_inputs.end());
437   EXPECT_TRUE(itr2 == live_inputs.end());
438   EXPECT_TRUE(itr3 == live_inputs.end());
439   EXPECT_TRUE(itr4 == live_inputs.end());
440   EXPECT_TRUE(itr5 == live_inputs.end());
441   EXPECT_TRUE(itr6 == live_inputs.end());
442   EXPECT_TRUE(itr7 == live_inputs.end());
443   EXPECT_TRUE(itr8 == live_inputs.end());
444   EXPECT_TRUE(itr9 == live_inputs.end());
445   EXPECT_TRUE(itr10 != live_inputs.end());
446   EXPECT_TRUE(itr11 == live_inputs.end());
447 }
448 
TEST_F(AnalyzeLiveInputTest,ArrayedInputMemberLocs)449 TEST_F(AnalyzeLiveInputTest, ArrayedInputMemberLocs) {
450   // Tests handling of member locs with arrayed input seen in Tesc, Tese
451   // and Geom shaders.
452   //
453   // Should report location {1, 12}.
454   //
455   // #version 450
456   //
457   // layout (vertices = 4) out;
458   //
459   // in Vertex
460   // {
461   //     layout (location = 1) vec4 p;
462   //     layout (location = 3) vec3 n;
463   //     layout (location = 5) vec4 f[100];
464   // } iVert[];
465   //
466   // layout (location = 0) out vec4 position[4];
467   //
468   // void main()
469   // {
470   //                 vec4 pos = iVert[gl_InvocationID].p *
471   //                            iVert[gl_InvocationID].f[7];
472   //                 position[gl_InvocationID] = pos;
473   // }
474   const std::string text = R"(
475                OpCapability Tessellation
476           %1 = OpExtInstImport "GLSL.std.450"
477                OpMemoryModel Logical GLSL450
478                OpEntryPoint TessellationControl %main "main" %iVert %gl_InvocationID %position
479                OpExecutionMode %main OutputVertices 4
480                OpSource GLSL 450
481                OpName %main "main"
482                OpName %Vertex "Vertex"
483                OpMemberName %Vertex 0 "p"
484                OpMemberName %Vertex 1 "n"
485                OpMemberName %Vertex 2 "f"
486                OpName %iVert "iVert"
487                OpName %gl_InvocationID "gl_InvocationID"
488                OpName %position "position"
489                OpMemberDecorate %Vertex 0 Location 1
490                OpMemberDecorate %Vertex 1 Location 3
491                OpMemberDecorate %Vertex 2 Location 5
492                OpDecorate %Vertex Block
493                OpDecorate %gl_InvocationID BuiltIn InvocationId
494                OpDecorate %position Location 0
495        %void = OpTypeVoid
496           %3 = OpTypeFunction %void
497       %float = OpTypeFloat 32
498     %v4float = OpTypeVector %float 4
499     %v3float = OpTypeVector %float 3
500        %uint = OpTypeInt 32 0
501    %uint_100 = OpConstant %uint 100
502 %_arr_v4float_uint_100 = OpTypeArray %v4float %uint_100
503      %Vertex = OpTypeStruct %v4float %v3float %_arr_v4float_uint_100
504     %uint_32 = OpConstant %uint 32
505 %_arr_Vertex_uint_32 = OpTypeArray %Vertex %uint_32
506 %_ptr_Input__arr_Vertex_uint_32 = OpTypePointer Input %_arr_Vertex_uint_32
507       %iVert = OpVariable %_ptr_Input__arr_Vertex_uint_32 Input
508         %int = OpTypeInt 32 1
509 %_ptr_Input_int = OpTypePointer Input %int
510 %gl_InvocationID = OpVariable %_ptr_Input_int Input
511       %int_0 = OpConstant %int 0
512 %_ptr_Input_v4float = OpTypePointer Input %v4float
513       %int_2 = OpConstant %int 2
514       %int_7 = OpConstant %int 7
515      %uint_4 = OpConstant %uint 4
516 %_arr_v4float_uint_4 = OpTypeArray %v4float %uint_4
517 %_ptr_Output__arr_v4float_uint_4 = OpTypePointer Output %_arr_v4float_uint_4
518    %position = OpVariable %_ptr_Output__arr_v4float_uint_4 Output
519 %_ptr_Output_v4float = OpTypePointer Output %v4float
520        %main = OpFunction %void None %3
521           %5 = OpLabel
522          %22 = OpLoad %int %gl_InvocationID
523          %25 = OpAccessChain %_ptr_Input_v4float %iVert %22 %int_0
524          %26 = OpLoad %v4float %25
525          %30 = OpAccessChain %_ptr_Input_v4float %iVert %22 %int_2 %int_7
526          %31 = OpLoad %v4float %30
527          %32 = OpFMul %v4float %26 %31
528          %40 = OpAccessChain %_ptr_Output_v4float %position %22
529                OpStore %40 %32
530                OpReturn
531                OpFunctionEnd
532 )";
533 
534   SetTargetEnv(SPV_ENV_VULKAN_1_3);
535   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
536 
537   std::unordered_set<uint32_t> live_inputs;
538   std::unordered_set<uint32_t> live_builtins;
539   auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
540       text, true, &live_inputs, &live_builtins);
541 
542   auto itr0 = live_inputs.find(0);
543   auto itr1 = live_inputs.find(1);
544   auto itr2 = live_inputs.find(2);
545   auto itr3 = live_inputs.find(3);
546   auto itr4 = live_inputs.find(4);
547   auto itr5 = live_inputs.find(5);
548   auto itr6 = live_inputs.find(6);
549   auto itr7 = live_inputs.find(7);
550   auto itr8 = live_inputs.find(8);
551   auto itr9 = live_inputs.find(9);
552   auto itr10 = live_inputs.find(10);
553   auto itr11 = live_inputs.find(11);
554   auto itr12 = live_inputs.find(12);
555   auto itr13 = live_inputs.find(13);
556 
557   // Expect live_inputs == {1, 12}
558   EXPECT_TRUE(itr0 == live_inputs.end());
559   EXPECT_TRUE(itr1 != live_inputs.end());
560   EXPECT_TRUE(itr2 == live_inputs.end());
561   EXPECT_TRUE(itr3 == live_inputs.end());
562   EXPECT_TRUE(itr4 == live_inputs.end());
563   EXPECT_TRUE(itr5 == live_inputs.end());
564   EXPECT_TRUE(itr6 == live_inputs.end());
565   EXPECT_TRUE(itr7 == live_inputs.end());
566   EXPECT_TRUE(itr8 == live_inputs.end());
567   EXPECT_TRUE(itr9 == live_inputs.end());
568   EXPECT_TRUE(itr10 == live_inputs.end());
569   EXPECT_TRUE(itr11 == live_inputs.end());
570   EXPECT_TRUE(itr12 != live_inputs.end());
571   EXPECT_TRUE(itr13 == live_inputs.end());
572 }
573 
TEST_F(AnalyzeLiveInputTest,Builtins)574 TEST_F(AnalyzeLiveInputTest, Builtins) {
575   // Tests handling of builtin input seen in Tesc, Tese and Geom shaders.
576   //
577   // Should report builtin gl_PointSize only.
578   //
579   // #version 460
580   //
581   // layout(triangle_strip, max_vertices = 3) out;
582   // layout(triangles) in;
583   //
584   // void main()
585   // {
586   //         for (int i = 0; i < 3; i++)
587   //         {
588   //                 gl_Position = gl_in[i].gl_Position;
589   //                 gl_PointSize = gl_in[i].gl_PointSize;
590   //
591   //                 EmitVertex();
592   //         }
593   //
594   //         EndPrimitive();
595   // }
596   const std::string text = R"(
597                OpCapability Geometry
598                OpCapability GeometryPointSize
599           %1 = OpExtInstImport "GLSL.std.450"
600                OpMemoryModel Logical GLSL450
601                OpEntryPoint Geometry %main "main" %_ %gl_in
602                OpExecutionMode %main Triangles
603                OpExecutionMode %main Invocations 1
604                OpExecutionMode %main OutputTriangleStrip
605                OpExecutionMode %main OutputVertices 3
606                OpSource GLSL 460
607                OpName %main "main"
608                OpName %i "i"
609                OpName %gl_PerVertex "gl_PerVertex"
610                OpMemberName %gl_PerVertex 0 "gl_Position"
611                OpMemberName %gl_PerVertex 1 "gl_PointSize"
612                OpMemberName %gl_PerVertex 2 "gl_ClipDistance"
613                OpMemberName %gl_PerVertex 3 "gl_CullDistance"
614                OpName %_ ""
615                OpName %gl_PerVertex_0 "gl_PerVertex"
616                OpMemberName %gl_PerVertex_0 0 "gl_Position"
617                OpMemberName %gl_PerVertex_0 1 "gl_PointSize"
618                OpMemberName %gl_PerVertex_0 2 "gl_ClipDistance"
619                OpMemberName %gl_PerVertex_0 3 "gl_CullDistance"
620                OpName %gl_in "gl_in"
621                OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
622                OpMemberDecorate %gl_PerVertex 1 BuiltIn PointSize
623                OpMemberDecorate %gl_PerVertex 2 BuiltIn ClipDistance
624                OpMemberDecorate %gl_PerVertex 3 BuiltIn CullDistance
625                OpDecorate %gl_PerVertex Block
626                OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
627                OpMemberDecorate %gl_PerVertex_0 1 BuiltIn PointSize
628                OpDecorate %gl_PerVertex_0 Block
629        %void = OpTypeVoid
630           %3 = OpTypeFunction %void
631         %int = OpTypeInt 32 1
632 %_ptr_Function_int = OpTypePointer Function %int
633       %int_0 = OpConstant %int 0
634       %int_3 = OpConstant %int 3
635        %bool = OpTypeBool
636       %float = OpTypeFloat 32
637     %v4float = OpTypeVector %float 4
638        %uint = OpTypeInt 32 0
639      %uint_1 = OpConstant %uint 1
640 %_arr_float_uint_1 = OpTypeArray %float %uint_1
641 %gl_PerVertex = OpTypeStruct %v4float %float %_arr_float_uint_1 %_arr_float_uint_1
642 %_ptr_Output_gl_PerVertex = OpTypePointer Output %gl_PerVertex
643           %_ = OpVariable %_ptr_Output_gl_PerVertex Output
644 %gl_PerVertex_0 = OpTypeStruct %v4float %float
645      %uint_3 = OpConstant %uint 3
646 %_arr_gl_PerVertex_0_uint_3 = OpTypeArray %gl_PerVertex_0 %uint_3
647 %_ptr_Input__arr_gl_PerVertex_0_uint_3 = OpTypePointer Input %_arr_gl_PerVertex_0_uint_3
648       %gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_0_uint_3 Input
649 %_ptr_Input_v4float = OpTypePointer Input %v4float
650 %_ptr_Output_v4float = OpTypePointer Output %v4float
651       %int_1 = OpConstant %int 1
652 %_ptr_Input_float = OpTypePointer Input %float
653 %_ptr_Output_float = OpTypePointer Output %float
654        %main = OpFunction %void None %3
655           %5 = OpLabel
656           %i = OpVariable %_ptr_Function_int Function
657                OpStore %i %int_0
658                OpBranch %10
659          %10 = OpLabel
660                OpLoopMerge %12 %13 None
661                OpBranch %14
662          %14 = OpLabel
663          %15 = OpLoad %int %i
664          %18 = OpSLessThan %bool %15 %int_3
665                OpBranchConditional %18 %11 %12
666          %11 = OpLabel
667          %32 = OpLoad %int %i
668          %34 = OpAccessChain %_ptr_Input_v4float %gl_in %32 %int_0
669          %35 = OpLoad %v4float %34
670          %37 = OpAccessChain %_ptr_Output_v4float %_ %int_0
671                OpStore %37 %35
672          %39 = OpLoad %int %i
673          %41 = OpAccessChain %_ptr_Input_float %gl_in %39 %int_1
674          %42 = OpLoad %float %41
675          %44 = OpAccessChain %_ptr_Output_float %_ %int_1
676                OpStore %44 %42
677                OpEmitVertex
678                OpBranch %13
679          %13 = OpLabel
680          %45 = OpLoad %int %i
681          %46 = OpIAdd %int %45 %int_1
682                OpStore %i %46
683                OpBranch %10
684          %12 = OpLabel
685                OpEndPrimitive
686                OpReturn
687                OpFunctionEnd
688 )";
689 
690   SetTargetEnv(SPV_ENV_VULKAN_1_3);
691   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
692 
693   std::unordered_set<uint32_t> live_inputs;
694   std::unordered_set<uint32_t> live_builtins;
695   auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
696       text, true, &live_inputs, &live_builtins);
697 
698   auto itr0 = live_builtins.find((uint32_t)spv::BuiltIn::PointSize);
699   auto itr1 = live_builtins.find((uint32_t)spv::BuiltIn::ClipDistance);
700   auto itr2 = live_builtins.find((uint32_t)spv::BuiltIn::CullDistance);
701 
702   // Expect live_builtins == { spv::BuiltIn::PointSize }
703   EXPECT_TRUE(itr0 != live_builtins.end());
704   EXPECT_TRUE(itr1 == live_builtins.end());
705   EXPECT_TRUE(itr2 == live_builtins.end());
706 }
707 
TEST_F(AnalyzeLiveInputTest,ArrayedInputPatchLocs)708 TEST_F(AnalyzeLiveInputTest, ArrayedInputPatchLocs) {
709   // Tests handling of locs with arrayed input patch seen in Tese
710   //
711   // Should report location {3}.
712   //
713   // #version 450 core
714   //
715   // layout(triangles, ccw) in;
716   //
717   // layout(fractional_odd_spacing) in;
718   //
719   // layout(point_mode) in;
720   //
721   // layout(location=2) patch in float patchIn1[2];
722   //
723   // void main()
724   // {
725   //     vec4 p = gl_in[1].gl_Position;
726   //     gl_Position = p * patchIn1[1];
727   // }
728   const std::string text = R"(
729                OpCapability Tessellation
730           %1 = OpExtInstImport "GLSL.std.450"
731                OpMemoryModel Logical GLSL450
732                OpEntryPoint TessellationEvaluation %main "main" %gl_in %_ %patchIn1
733                OpExecutionMode %main Triangles
734                OpExecutionMode %main SpacingFractionalOdd
735                OpExecutionMode %main VertexOrderCcw
736                OpExecutionMode %main PointMode
737                OpSource GLSL 450
738                OpName %main "main"
739                OpName %p "p"
740                OpName %gl_PerVertex "gl_PerVertex"
741                OpMemberName %gl_PerVertex 0 "gl_Position"
742                OpName %gl_in "gl_in"
743                OpName %gl_PerVertex_0 "gl_PerVertex"
744                OpMemberName %gl_PerVertex_0 0 "gl_Position"
745                OpName %_ ""
746                OpName %patchIn1 "patchIn1"
747                OpMemberDecorate %gl_PerVertex 0 BuiltIn Position
748                OpDecorate %gl_PerVertex Block
749                OpMemberDecorate %gl_PerVertex_0 0 BuiltIn Position
750                OpDecorate %gl_PerVertex_0 Block
751                OpDecorate %patchIn1 Patch
752                OpDecorate %patchIn1 Location 2
753        %void = OpTypeVoid
754           %3 = OpTypeFunction %void
755       %float = OpTypeFloat 32
756     %v4float = OpTypeVector %float 4
757 %_ptr_Function_v4float = OpTypePointer Function %v4float
758        %uint = OpTypeInt 32 0
759      %uint_1 = OpConstant %uint 1
760 %_arr_float_uint_1 = OpTypeArray %float %uint_1
761 %gl_PerVertex = OpTypeStruct %v4float
762     %uint_32 = OpConstant %uint 32
763 %_arr_gl_PerVertex_uint_32 = OpTypeArray %gl_PerVertex %uint_32
764 %_ptr_Input__arr_gl_PerVertex_uint_32 = OpTypePointer Input %_arr_gl_PerVertex_uint_32
765       %gl_in = OpVariable %_ptr_Input__arr_gl_PerVertex_uint_32 Input
766         %int = OpTypeInt 32 1
767       %int_1 = OpConstant %int 1
768       %int_0 = OpConstant %int 0
769 %_ptr_Input_v4float = OpTypePointer Input %v4float
770 %gl_PerVertex_0 = OpTypeStruct %v4float
771 %_ptr_Output_gl_PerVertex_0 = OpTypePointer Output %gl_PerVertex_0
772           %_ = OpVariable %_ptr_Output_gl_PerVertex_0 Output
773      %uint_2 = OpConstant %uint 2
774 %_arr_float_uint_2 = OpTypeArray %float %uint_2
775 %_ptr_Input__arr_float_uint_2 = OpTypePointer Input %_arr_float_uint_2
776    %patchIn1 = OpVariable %_ptr_Input__arr_float_uint_2 Input
777 %_ptr_Input_float = OpTypePointer Input %float
778 %_ptr_Output_v4float = OpTypePointer Output %v4float
779        %main = OpFunction %void None %3
780           %5 = OpLabel
781           %p = OpVariable %_ptr_Function_v4float Function
782          %22 = OpAccessChain %_ptr_Input_v4float %gl_in %int_1 %int_0
783          %23 = OpLoad %v4float %22
784                OpStore %p %23
785          %27 = OpLoad %v4float %p
786          %33 = OpAccessChain %_ptr_Input_float %patchIn1 %int_1
787          %34 = OpLoad %float %33
788          %35 = OpVectorTimesScalar %v4float %27 %34
789          %37 = OpAccessChain %_ptr_Output_v4float %_ %int_0
790                OpStore %37 %35
791                OpReturn
792                OpFunctionEnd
793 )";
794 
795   SetTargetEnv(SPV_ENV_VULKAN_1_3);
796   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
797 
798   std::unordered_set<uint32_t> live_inputs;
799   std::unordered_set<uint32_t> live_builtins;
800   auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
801       text, true, &live_inputs, &live_builtins);
802 
803   auto itr0 = live_inputs.find(0);
804   auto itr1 = live_inputs.find(1);
805   auto itr2 = live_inputs.find(2);
806   auto itr3 = live_inputs.find(3);
807 
808   // Expect live_inputs == {3}
809   EXPECT_TRUE(itr0 == live_inputs.end());
810   EXPECT_TRUE(itr1 == live_inputs.end());
811   EXPECT_TRUE(itr2 == live_inputs.end());
812   EXPECT_TRUE(itr3 != live_inputs.end());
813 }
814 
TEST_F(AnalyzeLiveInputTest,FragMultipleLocationsF16)815 TEST_F(AnalyzeLiveInputTest, FragMultipleLocationsF16) {
816   // Should report locations {2, 5}
817   //
818   // #version 450
819   //
820   // layout(location = 2) in Vertex
821   // {
822   //         f16vec4 color0;
823   //         f16vec4 color1;
824   //         f16vec4 color2[3];
825   // } iVert;
826   //
827   // layout(location = 0) out f16vec4 oFragColor;
828   //
829   // void main()
830   // {
831   //     oFragColor = iVert.color0 + iVert.color2[1];
832   // }
833   const std::string text = R"(
834                OpCapability Shader
835                OpCapability Float16
836                OpCapability StorageInputOutput16
837           %1 = OpExtInstImport "GLSL.std.450"
838                OpMemoryModel Logical GLSL450
839                OpEntryPoint Fragment %main "main" %oFragColor %iVert
840                OpExecutionMode %main OriginUpperLeft
841                OpSource GLSL 450
842                OpName %main "main"
843                OpName %oFragColor "oFragColor"
844                OpName %Vertex "Vertex"
845                OpMemberName %Vertex 0 "color0"
846                OpMemberName %Vertex 1 "color1"
847                OpMemberName %Vertex 2 "color2"
848                OpName %iVert "iVert"
849                OpDecorate %oFragColor Location 0
850                OpDecorate %Vertex Block
851                OpDecorate %iVert Location 2
852        %void = OpTypeVoid
853           %3 = OpTypeFunction %void
854        %half = OpTypeFloat 16
855      %v4half = OpTypeVector %half 4
856 %_ptr_Output_v4half = OpTypePointer Output %v4half
857  %oFragColor = OpVariable %_ptr_Output_v4half Output
858        %uint = OpTypeInt 32 0
859      %uint_3 = OpConstant %uint 3
860 %_arr_v4half_uint_3 = OpTypeArray %v4half %uint_3
861      %Vertex = OpTypeStruct %v4half %v4half %_arr_v4half_uint_3
862 %_ptr_Input_Vertex = OpTypePointer Input %Vertex
863       %iVert = OpVariable %_ptr_Input_Vertex Input
864         %int = OpTypeInt 32 1
865       %int_0 = OpConstant %int 0
866 %_ptr_Input_v4half = OpTypePointer Input %v4half
867       %int_2 = OpConstant %int 2
868       %int_1 = OpConstant %int 1
869        %main = OpFunction %void None %3
870           %5 = OpLabel
871          %19 = OpAccessChain %_ptr_Input_v4half %iVert %int_0
872          %20 = OpLoad %v4half %19
873          %23 = OpAccessChain %_ptr_Input_v4half %iVert %int_2 %int_1
874          %24 = OpLoad %v4half %23
875          %25 = OpFAdd %v4half %20 %24
876                OpStore %oFragColor %25
877                OpReturn
878                OpFunctionEnd
879 )";
880 
881   SetTargetEnv(SPV_ENV_VULKAN_1_3);
882   SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
883 
884   std::unordered_set<uint32_t> live_inputs;
885   std::unordered_set<uint32_t> live_builtins;
886   auto result = SinglePassRunToBinary<AnalyzeLiveInputPass>(
887       text, true, &live_inputs, &live_builtins);
888 
889   auto itr0 = live_inputs.find(0);
890   auto itr1 = live_inputs.find(1);
891   auto itr2 = live_inputs.find(2);
892   auto itr3 = live_inputs.find(3);
893   auto itr4 = live_inputs.find(4);
894   auto itr5 = live_inputs.find(5);
895   auto itr6 = live_inputs.find(6);
896 
897   // Expect live_inputs == {2, 5}
898   EXPECT_TRUE(itr0 == live_inputs.end());
899   EXPECT_TRUE(itr1 == live_inputs.end());
900   EXPECT_TRUE(itr2 != live_inputs.end());
901   EXPECT_TRUE(itr3 == live_inputs.end());
902   EXPECT_TRUE(itr4 == live_inputs.end());
903   EXPECT_TRUE(itr5 != live_inputs.end());
904   EXPECT_TRUE(itr6 == live_inputs.end());
905 }
906 
907 }  // namespace
908 }  // namespace opt
909 }  // namespace spvtools
910