1 // Copyright (c) 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "assembly_builder.h"
16 #include "pass_fixture.h"
17 #include "pass_utils.h"
18 
19 namespace {
20 
21 using namespace spvtools;
22 
23 using EliminateDeadMemberTest = opt::PassTest<::testing::Test>;
24 
TEST_F(EliminateDeadMemberTest,RemoveMember1)25 TEST_F(EliminateDeadMemberTest, RemoveMember1) {
26   // Test that the member "y" is removed.
27   // Update OpMemberName for |y| and |z|.
28   // Update OpMemberDecorate for |y| and |z|.
29   // Update OpAccessChain for access to |z|.
30   const std::string text = R"(
31 ; CHECK: OpName
32 ; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
33 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
34 ; CHECK-NOT: OpMemberName
35 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
36 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
37 ; CHECK: %type__Globals = OpTypeStruct %float %float
38 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %int_0
39 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1
40                OpCapability Shader
41                OpMemoryModel Logical GLSL450
42                OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
43                OpSource HLSL 600
44                OpName %type__Globals "type.$Globals"
45                OpMemberName %type__Globals 0 "x"
46                OpMemberName %type__Globals 1 "y"
47                OpMemberName %type__Globals 2 "z"
48                OpName %_Globals "$Globals"
49                OpName %in_var_Position "in.var.Position"
50                OpName %main "main"
51                OpDecorate %gl_Position BuiltIn Position
52                OpDecorate %in_var_Position Location 0
53                OpDecorate %_Globals DescriptorSet 0
54                OpDecorate %_Globals Binding 0
55                OpMemberDecorate %type__Globals 0 Offset 0
56                OpMemberDecorate %type__Globals 1 Offset 4
57                OpMemberDecorate %type__Globals 2 Offset 8
58                OpDecorate %type__Globals Block
59         %int = OpTypeInt 32 1
60       %int_0 = OpConstant %int 0
61       %float = OpTypeFloat 32
62       %int_2 = OpConstant %int 2
63 %type__Globals = OpTypeStruct %float %float %float
64 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
65     %v4float = OpTypeVector %float 4
66 %_ptr_Input_v4float = OpTypePointer Input %v4float
67 %_ptr_Output_v4float = OpTypePointer Output %v4float
68        %void = OpTypeVoid
69          %15 = OpTypeFunction %void
70 %_ptr_Uniform_float = OpTypePointer Uniform %float
71    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
72 %in_var_Position = OpVariable %_ptr_Input_v4float Input
73 %gl_Position = OpVariable %_ptr_Output_v4float Output
74        %main = OpFunction %void None %15
75          %17 = OpLabel
76          %18 = OpLoad %v4float %in_var_Position
77          %19 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0
78          %20 = OpLoad %float %19
79          %21 = OpCompositeExtract %float %18 0
80          %22 = OpFAdd %float %21 %20
81          %23 = OpCompositeInsert %v4float %22 %18 0
82          %24 = OpCompositeExtract %float %18 1
83          %25 = OpCompositeInsert %v4float %24 %23 1
84          %26 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2
85          %27 = OpLoad %float %26
86          %28 = OpCompositeExtract %float %18 2
87          %29 = OpFAdd %float %28 %27
88          %30 = OpCompositeInsert %v4float %29 %25 2
89                OpStore %gl_Position %30
90                OpReturn
91                OpFunctionEnd
92 )";
93 
94   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
95 }
96 
TEST_F(EliminateDeadMemberTest,RemoveMemberWithGroupDecorations)97 TEST_F(EliminateDeadMemberTest, RemoveMemberWithGroupDecorations) {
98   // Test that the member "y" is removed.
99   // Update OpGroupMemberDecorate for %type__Globals member 1 and 2.
100   // Update OpAccessChain for access to %type__Globals member 2.
101   const std::string text = R"(
102 ; CHECK: OpDecorate [[gr1:%\w+]] Offset 0
103 ; CHECK: OpDecorate [[gr2:%\w+]] Offset 4
104 ; CHECK: OpDecorate [[gr3:%\w+]] Offset 8
105 ; CHECK: [[gr1]] = OpDecorationGroup
106 ; CHECK: [[gr2]] = OpDecorationGroup
107 ; CHECK: [[gr3]] = OpDecorationGroup
108 ; CHECK: OpGroupMemberDecorate [[gr1]] %type__Globals 0
109 ; CHECK-NOT: OpGroupMemberDecorate [[gr2]]
110 ; CHECK: OpGroupMemberDecorate [[gr3]] %type__Globals 1
111 ; CHECK: %type__Globals = OpTypeStruct %float %float
112 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %int_0
113 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1
114                OpCapability Shader
115                OpMemoryModel Logical GLSL450
116                OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
117                OpSource HLSL 600
118                OpName %type__Globals "type.$Globals"
119                OpName %_Globals "$Globals"
120                OpDecorate %gl_Position BuiltIn Position
121                OpDecorate %in_var_Position Location 0
122                OpDecorate %_Globals DescriptorSet 0
123                OpDecorate %_Globals Binding 0
124                OpDecorate %gr1 Offset 0
125                OpDecorate %gr2 Offset 4
126                OpDecorate %gr3 Offset 8
127                OpDecorate %type__Globals Block
128         %gr1 = OpDecorationGroup
129         %gr2 = OpDecorationGroup
130         %gr3 = OpDecorationGroup
131                OpGroupMemberDecorate %gr1 %type__Globals 0
132                OpGroupMemberDecorate %gr2 %type__Globals 1
133                OpGroupMemberDecorate %gr3 %type__Globals 2
134         %int = OpTypeInt 32 1
135       %int_0 = OpConstant %int 0
136       %float = OpTypeFloat 32
137       %int_2 = OpConstant %int 2
138 %type__Globals = OpTypeStruct %float %float %float
139 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
140     %v4float = OpTypeVector %float 4
141 %_ptr_Input_v4float = OpTypePointer Input %v4float
142 %_ptr_Output_v4float = OpTypePointer Output %v4float
143        %void = OpTypeVoid
144          %15 = OpTypeFunction %void
145 %_ptr_Uniform_float = OpTypePointer Uniform %float
146    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
147 %in_var_Position = OpVariable %_ptr_Input_v4float Input
148 %gl_Position = OpVariable %_ptr_Output_v4float Output
149        %main = OpFunction %void None %15
150          %17 = OpLabel
151          %18 = OpLoad %v4float %in_var_Position
152          %19 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0
153          %20 = OpLoad %float %19
154          %21 = OpCompositeExtract %float %18 0
155          %22 = OpFAdd %float %21 %20
156          %23 = OpCompositeInsert %v4float %22 %18 0
157          %24 = OpCompositeExtract %float %18 1
158          %25 = OpCompositeInsert %v4float %24 %23 1
159          %26 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2
160          %27 = OpLoad %float %26
161          %28 = OpCompositeExtract %float %18 2
162          %29 = OpFAdd %float %28 %27
163          %30 = OpCompositeInsert %v4float %29 %25 2
164                OpStore %gl_Position %30
165                OpReturn
166                OpFunctionEnd
167 )";
168 
169   // Skipping validation because of a bug in the validator.  See issue #2376.
170   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, false);
171 }
172 
TEST_F(EliminateDeadMemberTest,RemoveMemberUpdateConstant)173 TEST_F(EliminateDeadMemberTest, RemoveMemberUpdateConstant) {
174   // Test that the member "x" is removed.
175   // Update the OpConstantComposite instruction.
176   const std::string text = R"(
177 ; CHECK: OpName
178 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
179 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
180 ; CHECK-NOT: OpMemberName
181 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
182 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
183 ; CHECK: %type__Globals = OpTypeStruct %float %float
184 ; CHECK: OpConstantComposite %type__Globals %float_1 %float_2
185 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_0
186 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1
187                OpCapability Shader
188                OpMemoryModel Logical GLSL450
189                OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
190                OpSource HLSL 600
191                OpName %type__Globals "type.$Globals"
192                OpMemberName %type__Globals 0 "x"
193                OpMemberName %type__Globals 1 "y"
194                OpMemberName %type__Globals 2 "z"
195                OpName %_Globals "$Globals"
196                OpName %in_var_Position "in.var.Position"
197                OpName %main "main"
198                OpDecorate %gl_Position BuiltIn Position
199                OpDecorate %in_var_Position Location 0
200                OpDecorate %_Globals DescriptorSet 0
201                OpDecorate %_Globals Binding 0
202                OpMemberDecorate %type__Globals 0 Offset 0
203                OpMemberDecorate %type__Globals 1 Offset 4
204                OpMemberDecorate %type__Globals 2 Offset 8
205                OpDecorate %type__Globals Block
206         %int = OpTypeInt 32 1
207       %int_1 = OpConstant %int 1
208       %float = OpTypeFloat 32
209     %float_0 = OpConstant %float 0
210     %float_1 = OpConstant %float 1
211     %float_2 = OpConstant %float 2
212       %int_2 = OpConstant %int 2
213 %type__Globals = OpTypeStruct %float %float %float
214          %13 = OpConstantComposite %type__Globals %float_0 %float_1 %float_2
215 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
216     %v4float = OpTypeVector %float 4
217 %_ptr_Input_v4float = OpTypePointer Input %v4float
218 %_ptr_Output_v4float = OpTypePointer Output %v4float
219        %void = OpTypeVoid
220          %19 = OpTypeFunction %void
221 %_ptr_Uniform_float = OpTypePointer Uniform %float
222    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
223 %in_var_Position = OpVariable %_ptr_Input_v4float Input
224 %gl_Position = OpVariable %_ptr_Output_v4float Output
225        %main = OpFunction %void None %19
226          %21 = OpLabel
227          %22 = OpLoad %v4float %in_var_Position
228          %23 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1
229          %24 = OpLoad %float %23
230          %25 = OpCompositeExtract %float %22 0
231          %26 = OpFAdd %float %25 %24
232          %27 = OpCompositeInsert %v4float %26 %22 0
233          %28 = OpCompositeExtract %float %22 1
234          %29 = OpCompositeInsert %v4float %28 %27 1
235          %30 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2
236          %31 = OpLoad %float %30
237          %32 = OpCompositeExtract %float %22 2
238          %33 = OpFAdd %float %32 %31
239          %34 = OpCompositeInsert %v4float %33 %29 2
240                OpStore %gl_Position %34
241                OpReturn
242                OpFunctionEnd
243 )";
244 
245   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
246 }
247 
TEST_F(EliminateDeadMemberTest,RemoveMemberUpdateCompositeConstruct)248 TEST_F(EliminateDeadMemberTest, RemoveMemberUpdateCompositeConstruct) {
249   // Test that the member "x" is removed.
250   // Update the OpConstantComposite instruction.
251   const std::string text = R"(
252 ; CHECK: OpName
253 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
254 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
255 ; CHECK-NOT: OpMemberName
256 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
257 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
258 ; CHECK: %type__Globals = OpTypeStruct %float %float
259 ; CHECK: OpCompositeConstruct %type__Globals %float_1 %float_2
260 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_0
261 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1
262                OpCapability Shader
263                OpMemoryModel Logical GLSL450
264                OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
265                OpSource HLSL 600
266                OpName %type__Globals "type.$Globals"
267                OpMemberName %type__Globals 0 "x"
268                OpMemberName %type__Globals 1 "y"
269                OpMemberName %type__Globals 2 "z"
270                OpName %_Globals "$Globals"
271                OpName %in_var_Position "in.var.Position"
272                OpName %main "main"
273                OpDecorate %gl_Position BuiltIn Position
274                OpDecorate %in_var_Position Location 0
275                OpDecorate %_Globals DescriptorSet 0
276                OpDecorate %_Globals Binding 0
277                OpMemberDecorate %type__Globals 0 Offset 0
278                OpMemberDecorate %type__Globals 1 Offset 4
279                OpMemberDecorate %type__Globals 2 Offset 8
280                OpDecorate %type__Globals Block
281         %int = OpTypeInt 32 1
282       %int_1 = OpConstant %int 1
283       %float = OpTypeFloat 32
284     %float_0 = OpConstant %float 0
285     %float_1 = OpConstant %float 1
286     %float_2 = OpConstant %float 2
287       %int_2 = OpConstant %int 2
288 %type__Globals = OpTypeStruct %float %float %float
289 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
290     %v4float = OpTypeVector %float 4
291 %_ptr_Input_v4float = OpTypePointer Input %v4float
292 %_ptr_Output_v4float = OpTypePointer Output %v4float
293        %void = OpTypeVoid
294          %19 = OpTypeFunction %void
295 %_ptr_Uniform_float = OpTypePointer Uniform %float
296    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
297 %in_var_Position = OpVariable %_ptr_Input_v4float Input
298 %gl_Position = OpVariable %_ptr_Output_v4float Output
299        %main = OpFunction %void None %19
300          %21 = OpLabel
301          %13 = OpCompositeConstruct %type__Globals %float_0 %float_1 %float_2
302          %22 = OpLoad %v4float %in_var_Position
303          %23 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1
304          %24 = OpLoad %float %23
305          %25 = OpCompositeExtract %float %22 0
306          %26 = OpFAdd %float %25 %24
307          %27 = OpCompositeInsert %v4float %26 %22 0
308          %28 = OpCompositeExtract %float %22 1
309          %29 = OpCompositeInsert %v4float %28 %27 1
310          %30 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2
311          %31 = OpLoad %float %30
312          %32 = OpCompositeExtract %float %22 2
313          %33 = OpFAdd %float %32 %31
314          %34 = OpCompositeInsert %v4float %33 %29 2
315                OpStore %gl_Position %34
316                OpReturn
317                OpFunctionEnd
318 )";
319 
320   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
321 }
322 
TEST_F(EliminateDeadMemberTest,RemoveMembersUpdateInserExtract1)323 TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract1) {
324   // Test that the members "x" and "z" are removed.
325   // Update the OpCompositeExtract instruction.
326   // Remove the OpCompositeInsert instruction since the member being inserted is
327   // dead.
328   const std::string text = R"(
329 ; CHECK: OpName
330 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
331 ; CHECK-NOT: OpMemberName
332 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
333 ; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
334 ; CHECK: %type__Globals = OpTypeStruct %float
335 ; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals
336 ; CHECK: OpCompositeExtract %float [[ld]] 0
337 ; CHECK-NOT: OpCompositeInsert
338 ; CHECK: OpReturn
339                OpCapability Shader
340                OpMemoryModel Logical GLSL450
341                OpEntryPoint Vertex %main "main"
342                OpSource HLSL 600
343                OpName %type__Globals "type.$Globals"
344                OpMemberName %type__Globals 0 "x"
345                OpMemberName %type__Globals 1 "y"
346                OpMemberName %type__Globals 2 "z"
347                OpName %_Globals "$Globals"
348                OpName %main "main"
349                OpDecorate %_Globals DescriptorSet 0
350                OpDecorate %_Globals Binding 0
351                OpMemberDecorate %type__Globals 0 Offset 0
352                OpMemberDecorate %type__Globals 1 Offset 4
353                OpMemberDecorate %type__Globals 2 Offset 8
354                OpDecorate %type__Globals Block
355       %float = OpTypeFloat 32
356 %type__Globals = OpTypeStruct %float %float %float
357 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
358        %void = OpTypeVoid
359           %7 = OpTypeFunction %void
360    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
361        %main = OpFunction %void None %7
362           %8 = OpLabel
363           %9 = OpLoad %type__Globals %_Globals
364          %10 = OpCompositeExtract %float %9 1
365          %11 = OpCompositeInsert %type__Globals %10 %9 2
366                OpReturn
367                OpFunctionEnd
368 
369 )";
370 
371   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
372 }
373 
TEST_F(EliminateDeadMemberTest,RemoveMembersUpdateInserExtract2)374 TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract2) {
375   // Test that the members "x" and "z" are removed.
376   // Update the OpCompositeExtract instruction.
377   // Update the OpCompositeInsert instruction.
378   const std::string text = R"(
379 ; CHECK: OpName
380 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
381 ; CHECK-NOT: OpMemberName
382 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
383 ; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
384 ; CHECK: %type__Globals = OpTypeStruct %float
385 ; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals
386 ; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0
387 ; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0
388 ; CHECK: OpReturn
389                OpCapability Shader
390                OpMemoryModel Logical GLSL450
391                OpEntryPoint Vertex %main "main"
392                OpSource HLSL 600
393                OpName %type__Globals "type.$Globals"
394                OpMemberName %type__Globals 0 "x"
395                OpMemberName %type__Globals 1 "y"
396                OpMemberName %type__Globals 2 "z"
397                OpName %_Globals "$Globals"
398                OpName %main "main"
399                OpDecorate %_Globals DescriptorSet 0
400                OpDecorate %_Globals Binding 0
401                OpMemberDecorate %type__Globals 0 Offset 0
402                OpMemberDecorate %type__Globals 1 Offset 4
403                OpMemberDecorate %type__Globals 2 Offset 8
404                OpDecorate %type__Globals Block
405       %float = OpTypeFloat 32
406 %type__Globals = OpTypeStruct %float %float %float
407 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
408        %void = OpTypeVoid
409           %7 = OpTypeFunction %void
410    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
411        %main = OpFunction %void None %7
412           %8 = OpLabel
413           %9 = OpLoad %type__Globals %_Globals
414          %10 = OpCompositeExtract %float %9 1
415          %11 = OpCompositeInsert %type__Globals %10 %9 1
416                OpReturn
417                OpFunctionEnd
418 
419 )";
420 
421   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
422 }
423 
TEST_F(EliminateDeadMemberTest,RemoveMembersUpdateInserExtract3)424 TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract3) {
425   // Test that the members "x" and "z" are removed, and one member from the
426   // substruct. Update the OpCompositeExtract instruction. Update the
427   // OpCompositeInsert instruction.
428   const std::string text = R"(
429 ; CHECK: OpName
430 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
431 ; CHECK-NOT: OpMemberName
432 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
433 ; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
434 ; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4
435 ; CHECK: [[struct:%\w+]] = OpTypeStruct %float
436 ; CHECK: %type__Globals = OpTypeStruct [[struct]]
437 ; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals
438 ; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 0
439 ; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0 0
440 ; CHECK: OpReturn
441                OpCapability Shader
442                OpMemoryModel Logical GLSL450
443                OpEntryPoint Vertex %main "main"
444                OpSource HLSL 600
445                OpName %type__Globals "type.$Globals"
446                OpMemberName %type__Globals 0 "x"
447                OpMemberName %type__Globals 1 "y"
448                OpMemberName %type__Globals 2 "z"
449                OpName %_Globals "$Globals"
450                OpName %main "main"
451                OpDecorate %_Globals DescriptorSet 0
452                OpDecorate %_Globals Binding 0
453                OpMemberDecorate %type__Globals 0 Offset 0
454                OpMemberDecorate %type__Globals 1 Offset 16
455                OpMemberDecorate %type__Globals 2 Offset 24
456                OpMemberDecorate %_struct_6 0 Offset 0
457                OpMemberDecorate %_struct_6 1 Offset 4
458                OpDecorate %type__Globals Block
459       %float = OpTypeFloat 32
460   %_struct_6 = OpTypeStruct %float %float
461 %type__Globals = OpTypeStruct %float %_struct_6 %float
462 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
463        %void = OpTypeVoid
464           %7 = OpTypeFunction %void
465    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
466        %main = OpFunction %void None %7
467           %8 = OpLabel
468           %9 = OpLoad %type__Globals %_Globals
469          %10 = OpCompositeExtract %float %9 1 1
470          %11 = OpCompositeInsert %type__Globals %10 %9 1 1
471                OpReturn
472                OpFunctionEnd
473 
474 )";
475 
476   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
477 }
478 
TEST_F(EliminateDeadMemberTest,RemoveMembersUpdateInserExtract4)479 TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract4) {
480   // Test that the members "x" and "z" are removed, and one member from the
481   // substruct. Update the OpCompositeExtract instruction. Update the
482   // OpCompositeInsert instruction.
483   const std::string text = R"(
484 ; CHECK: OpName
485 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
486 ; CHECK-NOT: OpMemberName
487 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
488 ; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
489 ; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4
490 ; CHECK: [[struct:%\w+]] = OpTypeStruct %float
491 ; CHECK: [[array:%\w+]] = OpTypeArray [[struct]]
492 ; CHECK: %type__Globals = OpTypeStruct [[array]]
493 ; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals
494 ; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 1 0
495 ; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0 1 0
496 ; CHECK: OpReturn
497                OpCapability Shader
498                OpMemoryModel Logical GLSL450
499                OpEntryPoint Vertex %main "main"
500                OpSource HLSL 600
501                OpName %type__Globals "type.$Globals"
502                OpMemberName %type__Globals 0 "x"
503                OpMemberName %type__Globals 1 "y"
504                OpMemberName %type__Globals 2 "z"
505                OpName %_Globals "$Globals"
506                OpName %main "main"
507                OpDecorate %_Globals DescriptorSet 0
508                OpDecorate %_Globals Binding 0
509                OpMemberDecorate %type__Globals 0 Offset 0
510                OpMemberDecorate %type__Globals 1 Offset 16
511                OpMemberDecorate %type__Globals 2 Offset 80
512                OpMemberDecorate %_struct_6 0 Offset 0
513                OpMemberDecorate %_struct_6 1 Offset 4
514                OpDecorate %array ArrayStride 16
515                OpDecorate %type__Globals Block
516        %uint = OpTypeInt 32 0                         ; 32-bit int, sign-less
517      %uint_4 = OpConstant %uint 4
518       %float = OpTypeFloat 32
519   %_struct_6 = OpTypeStruct %float %float
520   %array = OpTypeArray %_struct_6 %uint_4
521 %type__Globals = OpTypeStruct %float %array %float
522 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
523        %void = OpTypeVoid
524           %7 = OpTypeFunction %void
525    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
526        %main = OpFunction %void None %7
527           %8 = OpLabel
528           %9 = OpLoad %type__Globals %_Globals
529          %10 = OpCompositeExtract %float %9 1 1 1
530          %11 = OpCompositeInsert %type__Globals %10 %9 1 1 1
531                OpReturn
532                OpFunctionEnd
533 
534 )";
535 
536   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
537 }
538 
TEST_F(EliminateDeadMemberTest,RemoveMembersUpdateArrayLength)539 TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateArrayLength) {
540   // Test that the members "x" and "y" are removed.
541   // Member "z" is live because of the OpArrayLength instruction.
542   // Update the OpArrayLength instruction.
543   const std::string text = R"(
544 ; CHECK: OpName
545 ; CHECK-NEXT: OpMemberName %type__Globals 0 "z"
546 ; CHECK-NOT: OpMemberName
547 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
548 ; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
549 ; CHECK: %type__Globals = OpTypeStruct %_runtimearr_float
550 ; CHECK: OpArrayLength %uint %_Globals 0
551                OpCapability Shader
552                OpMemoryModel Logical GLSL450
553                OpEntryPoint Vertex %main "main"
554                OpSource HLSL 600
555                OpName %type__Globals "type.$Globals"
556                OpMemberName %type__Globals 0 "x"
557                OpMemberName %type__Globals 1 "y"
558                OpMemberName %type__Globals 2 "z"
559                OpName %_Globals "$Globals"
560                OpName %main "main"
561                OpDecorate %_Globals DescriptorSet 0
562                OpDecorate %_Globals Binding 0
563                OpDecorate %_runtimearr_float ArrayStride 16
564                OpMemberDecorate %type__Globals 0 Offset 0
565                OpMemberDecorate %type__Globals 1 Offset 4
566                OpMemberDecorate %type__Globals 2 Offset 16
567                OpDecorate %type__Globals Block
568        %uint = OpTypeInt 32 0
569       %float = OpTypeFloat 32
570 %_runtimearr_float = OpTypeRuntimeArray %float
571 %type__Globals = OpTypeStruct %float %float %_runtimearr_float
572 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
573        %void = OpTypeVoid
574           %9 = OpTypeFunction %void
575    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
576        %main = OpFunction %void None %9
577          %10 = OpLabel
578          %12 = OpArrayLength %uint %_Globals 2
579                OpReturn
580                OpFunctionEnd
581 )";
582 
583   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
584 }
585 
TEST_F(EliminateDeadMemberTest,KeepMembersOpStore)586 TEST_F(EliminateDeadMemberTest, KeepMembersOpStore) {
587   // Test that all members are kept because of an OpStore.
588   // No change expected.
589   const std::string text = R"(
590                OpCapability Shader
591                OpMemoryModel Logical GLSL450
592                OpEntryPoint Vertex %main "main"
593                OpSource HLSL 600
594                OpName %type__Globals "type.$Globals"
595                OpMemberName %type__Globals 0 "x"
596                OpMemberName %type__Globals 1 "y"
597                OpMemberName %type__Globals 2 "z"
598                OpName %_Globals "$Globals"
599                OpName %_Globals "$Globals2"
600                OpName %main "main"
601                OpDecorate %_Globals DescriptorSet 0
602                OpDecorate %_Globals Binding 0
603                OpMemberDecorate %type__Globals 0 Offset 0
604                OpMemberDecorate %type__Globals 1 Offset 4
605                OpMemberDecorate %type__Globals 2 Offset 16
606                OpDecorate %type__Globals Block
607        %uint = OpTypeInt 32 0
608       %float = OpTypeFloat 32
609 %type__Globals = OpTypeStruct %float %float %float
610 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
611        %void = OpTypeVoid
612           %9 = OpTypeFunction %void
613    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
614    %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
615        %main = OpFunction %void None %9
616          %10 = OpLabel
617          %11 = OpLoad %type__Globals %_Globals
618                OpStore %_Globals2 %11
619                OpReturn
620                OpFunctionEnd
621 )";
622 
623   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
624       text, /* skip_nop = */ true, /* do_validation = */ true);
625   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
626 }
627 
TEST_F(EliminateDeadMemberTest,KeepStorageBufferMembers)628 TEST_F(EliminateDeadMemberTest, KeepStorageBufferMembers) {
629   // Test that all members of the storage buffer struct %S are kept.
630   // No change expected.
631   const std::string text = R"(
632                OpCapability Shader
633                OpExtension "SPV_GOOGLE_hlsl_functionality1"
634                OpExtension "SPV_GOOGLE_user_type"
635           %1 = OpExtInstImport "GLSL.std.450"
636                OpMemoryModel Logical GLSL450
637                OpEntryPoint Fragment %PSMain "PSMain" %out_var_SV_TARGET
638                OpExecutionMode %PSMain OriginUpperLeft
639                OpSource HLSL 600
640                OpName %type_StructuredBuffer_S "type.StructuredBuffer.S"
641                OpName %S "S"
642                OpMemberName %S 0 "A"
643                OpMemberName %S 1 "B"
644                OpName %Buf "Buf"
645                OpName %out_var_SV_TARGET "out.var.SV_TARGET"
646                OpName %PSMain "PSMain"
647                OpDecorateString %out_var_SV_TARGET UserSemantic "SV_TARGET"
648                OpDecorate %out_var_SV_TARGET Location 0
649                OpDecorate %Buf DescriptorSet 0
650                OpDecorate %Buf Binding 0
651                OpMemberDecorate %S 0 Offset 0
652                OpMemberDecorate %S 1 Offset 16
653                OpDecorate %_runtimearr_S ArrayStride 32
654                OpMemberDecorate %type_StructuredBuffer_S 0 Offset 0
655                OpMemberDecorate %type_StructuredBuffer_S 0 NonWritable
656                OpDecorate %type_StructuredBuffer_S BufferBlock
657                OpDecorateString %Buf UserTypeGOOGLE "structuredbuffer"
658         %int = OpTypeInt 32 1
659       %int_0 = OpConstant %int 0
660        %uint = OpTypeInt 32 0
661      %uint_0 = OpConstant %uint 0
662       %int_1 = OpConstant %int 1
663       %float = OpTypeFloat 32
664     %v4float = OpTypeVector %float 4
665           %S = OpTypeStruct %v4float %v4float
666 %_runtimearr_S = OpTypeRuntimeArray %S
667 %type_StructuredBuffer_S = OpTypeStruct %_runtimearr_S
668 %_ptr_Uniform_type_StructuredBuffer_S = OpTypePointer Uniform %type_StructuredBuffer_S
669 %_ptr_Output_v4float = OpTypePointer Output %v4float
670        %void = OpTypeVoid
671          %18 = OpTypeFunction %void
672 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
673         %Buf = OpVariable %_ptr_Uniform_type_StructuredBuffer_S Uniform
674 %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
675      %PSMain = OpFunction %void None %18
676          %20 = OpLabel
677          %21 = OpAccessChain %_ptr_Uniform_v4float %Buf %int_0 %uint_0 %int_1
678          %22 = OpLoad %v4float %21
679                OpStore %out_var_SV_TARGET %22
680                OpReturn
681                OpFunctionEnd
682 )";
683 
684   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
685       text, /* skip_nop = */ true, /* do_validation = */ true);
686   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
687 }
688 
TEST_F(EliminateDeadMemberTest,KeepMembersOpCopyMemory)689 TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemory) {
690   // Test that all members are kept because of an OpCopyMemory.
691   // No change expected.
692   const std::string text = R"(
693                OpCapability Shader
694                OpMemoryModel Logical GLSL450
695                OpEntryPoint Vertex %main "main"
696                OpSource HLSL 600
697                OpName %type__Globals "type.$Globals"
698                OpMemberName %type__Globals 0 "x"
699                OpMemberName %type__Globals 1 "y"
700                OpMemberName %type__Globals 2 "z"
701                OpName %_Globals "$Globals"
702                OpName %_Globals "$Globals2"
703                OpName %main "main"
704                OpDecorate %_Globals DescriptorSet 0
705                OpDecorate %_Globals Binding 0
706                OpMemberDecorate %type__Globals 0 Offset 0
707                OpMemberDecorate %type__Globals 1 Offset 4
708                OpMemberDecorate %type__Globals 2 Offset 16
709                OpDecorate %type__Globals Block
710        %uint = OpTypeInt 32 0
711       %float = OpTypeFloat 32
712 %type__Globals = OpTypeStruct %float %float %float
713 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
714        %void = OpTypeVoid
715           %9 = OpTypeFunction %void
716    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
717    %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
718        %main = OpFunction %void None %9
719          %10 = OpLabel
720                OpCopyMemory %_Globals2 %_Globals
721                OpReturn
722                OpFunctionEnd
723 )";
724 
725   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
726       text, /* skip_nop = */ true, /* do_validation = */ true);
727   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
728 }
729 
TEST_F(EliminateDeadMemberTest,KeepMembersOpCopyMemorySized)730 TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemorySized) {
731   // Test that all members are kept because of an OpCopyMemorySized.
732   // No change expected.
733   const std::string text = R"(
734                OpCapability Shader
735                OpCapability Addresses
736                OpMemoryModel Logical GLSL450
737                OpEntryPoint Vertex %main "main"
738                OpSource HLSL 600
739                OpName %type__Globals "type.$Globals"
740                OpMemberName %type__Globals 0 "x"
741                OpMemberName %type__Globals 1 "y"
742                OpMemberName %type__Globals 2 "z"
743                OpName %_Globals "$Globals"
744                OpName %_Globals "$Globals2"
745                OpName %main "main"
746                OpDecorate %_Globals DescriptorSet 0
747                OpDecorate %_Globals Binding 0
748                OpMemberDecorate %type__Globals 0 Offset 0
749                OpMemberDecorate %type__Globals 1 Offset 4
750                OpMemberDecorate %type__Globals 2 Offset 16
751                OpDecorate %type__Globals Block
752        %uint = OpTypeInt 32 0
753     %uint_20 = OpConstant %uint 20
754       %float = OpTypeFloat 32
755 %type__Globals = OpTypeStruct %float %float %float
756 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
757        %void = OpTypeVoid
758           %9 = OpTypeFunction %void
759    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
760    %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
761        %main = OpFunction %void None %9
762          %10 = OpLabel
763                OpCopyMemorySized %_Globals2 %_Globals %uint_20
764                OpReturn
765                OpFunctionEnd
766 )";
767 
768   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
769       text, /* skip_nop = */ true, /* do_validation = */ true);
770   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
771 }
772 
TEST_F(EliminateDeadMemberTest,KeepMembersOpReturnValue)773 TEST_F(EliminateDeadMemberTest, KeepMembersOpReturnValue) {
774   // Test that all members are kept because of an OpCopyMemorySized.
775   // No change expected.
776   const std::string text = R"(
777                OpCapability Shader
778                OpCapability Linkage
779                OpMemoryModel Logical GLSL450
780                OpSource HLSL 600
781                OpName %type__Globals "type.$Globals"
782                OpMemberName %type__Globals 0 "x"
783                OpMemberName %type__Globals 1 "y"
784                OpMemberName %type__Globals 2 "z"
785                OpName %_Globals "$Globals"
786                OpName %_Globals "$Globals2"
787                OpName %main "main"
788                OpDecorate %_Globals DescriptorSet 0
789                OpDecorate %_Globals Binding 0
790                OpMemberDecorate %type__Globals 0 Offset 0
791                OpMemberDecorate %type__Globals 1 Offset 4
792                OpMemberDecorate %type__Globals 2 Offset 16
793                OpDecorate %type__Globals Block
794        %uint = OpTypeInt 32 0
795     %uint_20 = OpConstant %uint 20
796       %float = OpTypeFloat 32
797 %type__Globals = OpTypeStruct %float %float %float
798 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
799        %void = OpTypeVoid
800           %9 = OpTypeFunction %type__Globals
801    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
802    %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
803        %main = OpFunction %type__Globals None %9
804          %10 = OpLabel
805          %11 = OpLoad %type__Globals %_Globals
806                OpReturnValue %11
807                OpFunctionEnd
808 )";
809 
810   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
811       text, /* skip_nop = */ true, /* do_validation = */ true);
812   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
813 }
814 
TEST_F(EliminateDeadMemberTest,RemoveMemberAccessChainWithArrays)815 TEST_F(EliminateDeadMemberTest, RemoveMemberAccessChainWithArrays) {
816   // Leave only 1 member in each of the structs.
817   // Update OpMemberName, OpMemberDecorate, and OpAccessChain.
818   const std::string text = R"(
819 ; CHECK: OpName
820 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
821 ; CHECK-NOT: OpMemberName
822 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
823 ; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4
824 ; CHECK: [[struct]] = OpTypeStruct %float
825 ; CHECK: [[array:%\w+]] = OpTypeArray [[struct]]
826 ; CHECK: %type__Globals = OpTypeStruct [[array]]
827 ; CHECK: [[undef:%\w+]] = OpUndef %uint
828 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals [[undef]] %uint_0 [[undef]] %uint_0
829                OpCapability Shader
830                OpCapability VariablePointersStorageBuffer
831                OpMemoryModel Logical GLSL450
832                OpEntryPoint Vertex %main "main"
833                OpSource HLSL 600
834                OpName %type__Globals "type.$Globals"
835                OpMemberName %type__Globals 0 "x"
836                OpMemberName %type__Globals 1 "y"
837                OpMemberName %type__Globals 2 "z"
838                OpName %_Globals "$Globals"
839                OpName %main "main"
840                OpDecorate %_Globals DescriptorSet 0
841                OpDecorate %_Globals Binding 0
842                OpMemberDecorate %type__Globals 0 Offset 0
843                OpMemberDecorate %type__Globals 1 Offset 16
844                OpMemberDecorate %type__Globals 2 Offset 48
845                OpMemberDecorate %_struct_4 0 Offset 0
846                OpMemberDecorate %_struct_4 1 Offset 4
847                OpDecorate %_arr__struct_4_uint_2 ArrayStride 16
848                OpDecorate %type__Globals Block
849        %uint = OpTypeInt 32 0
850      %uint_0 = OpConstant %uint 0
851      %uint_1 = OpConstant %uint 1
852      %uint_2 = OpConstant %uint 2
853      %uint_3 = OpConstant %uint 3
854       %float = OpTypeFloat 32
855   %_struct_4 = OpTypeStruct %float %float
856 %_arr__struct_4_uint_2 = OpTypeArray %_struct_4 %uint_2
857 %type__Globals = OpTypeStruct %float %_arr__struct_4_uint_2 %float
858 %_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3
859 %_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3
860        %void = OpTypeVoid
861          %15 = OpTypeFunction %void
862 %_ptr_Uniform_float = OpTypePointer Uniform %float
863    %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform
864        %main = OpFunction %void None %15
865          %17 = OpLabel
866          %18 = OpUndef %uint
867          %19 = OpAccessChain %_ptr_Uniform_float %_Globals %18 %uint_1 %18 %uint_1
868                OpReturn
869                OpFunctionEnd
870 )";
871 
872   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
873 }
874 
TEST_F(EliminateDeadMemberTest,RemoveMemberInboundsAccessChain)875 TEST_F(EliminateDeadMemberTest, RemoveMemberInboundsAccessChain) {
876   // Test that the member "y" is removed.
877   // Update OpMemberName for |y| and |z|.
878   // Update OpMemberDecorate for |y| and |z|.
879   // Update OpInboundsAccessChain for access to |z|.
880   const std::string text = R"(
881 ; CHECK: OpName
882 ; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
883 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
884 ; CHECK-NOT: OpMemberName
885 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
886 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
887 ; CHECK: %type__Globals = OpTypeStruct %float %float
888 ; CHECK: OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_0
889 ; CHECK: OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %uint_1
890                OpCapability Shader
891                OpMemoryModel Logical GLSL450
892                OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
893                OpSource HLSL 600
894                OpName %type__Globals "type.$Globals"
895                OpMemberName %type__Globals 0 "x"
896                OpMemberName %type__Globals 1 "y"
897                OpMemberName %type__Globals 2 "z"
898                OpName %_Globals "$Globals"
899                OpName %in_var_Position "in.var.Position"
900                OpName %main "main"
901                OpDecorate %gl_Position BuiltIn Position
902                OpDecorate %in_var_Position Location 0
903                OpDecorate %_Globals DescriptorSet 0
904                OpDecorate %_Globals Binding 0
905                OpMemberDecorate %type__Globals 0 Offset 0
906                OpMemberDecorate %type__Globals 1 Offset 4
907                OpMemberDecorate %type__Globals 2 Offset 8
908                OpDecorate %type__Globals Block
909         %int = OpTypeInt 32 1
910       %int_0 = OpConstant %int 0
911       %float = OpTypeFloat 32
912       %int_2 = OpConstant %int 2
913 %type__Globals = OpTypeStruct %float %float %float
914 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
915     %v4float = OpTypeVector %float 4
916 %_ptr_Input_v4float = OpTypePointer Input %v4float
917 %_ptr_Output_v4float = OpTypePointer Output %v4float
918        %void = OpTypeVoid
919          %15 = OpTypeFunction %void
920 %_ptr_Uniform_float = OpTypePointer Uniform %float
921    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
922 %in_var_Position = OpVariable %_ptr_Input_v4float Input
923 %gl_Position = OpVariable %_ptr_Output_v4float Output
924        %main = OpFunction %void None %15
925          %17 = OpLabel
926          %18 = OpLoad %v4float %in_var_Position
927          %19 = OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_0
928          %20 = OpLoad %float %19
929          %21 = OpCompositeExtract %float %18 0
930          %22 = OpFAdd %float %21 %20
931          %23 = OpCompositeInsert %v4float %22 %18 0
932          %24 = OpCompositeExtract %float %18 1
933          %25 = OpCompositeInsert %v4float %24 %23 1
934          %26 = OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_2
935          %27 = OpLoad %float %26
936          %28 = OpCompositeExtract %float %18 2
937          %29 = OpFAdd %float %28 %27
938          %30 = OpCompositeInsert %v4float %29 %25 2
939                OpStore %gl_Position %30
940                OpReturn
941                OpFunctionEnd
942 )";
943 
944   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
945 }
946 
TEST_F(EliminateDeadMemberTest,RemoveMemberPtrAccessChain)947 TEST_F(EliminateDeadMemberTest, RemoveMemberPtrAccessChain) {
948   // Test that the member "y" is removed.
949   // Update OpMemberName for |y| and |z|.
950   // Update OpMemberDecorate for |y| and |z|.
951   // Update OpInboundsAccessChain for access to |z|.
952   const std::string text = R"(
953 ; CHECK: OpName
954 ; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
955 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
956 ; CHECK-NOT: OpMemberName
957 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
958 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 16
959 ; CHECK: %type__Globals = OpTypeStruct %float %float
960 ; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0
961 ; CHECK: OpPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_1 %uint_0
962 ; CHECK: OpPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_0 %uint_1
963                OpCapability Shader
964                OpCapability VariablePointersStorageBuffer
965                OpMemoryModel Logical GLSL450
966                OpEntryPoint Vertex %main "main"
967                OpSource HLSL 600
968                OpName %type__Globals "type.$Globals"
969                OpMemberName %type__Globals 0 "x"
970                OpMemberName %type__Globals 1 "y"
971                OpMemberName %type__Globals 2 "z"
972                OpName %_Globals "$Globals"
973                OpName %main "main"
974                OpDecorate %_Globals DescriptorSet 0
975                OpDecorate %_Globals Binding 0
976                OpMemberDecorate %type__Globals 0 Offset 0
977                OpMemberDecorate %type__Globals 1 Offset 4
978                OpMemberDecorate %type__Globals 2 Offset 16
979                OpDecorate %type__Globals Block
980                OpDecorate %_ptr_Uniform_type__Globals ArrayStride 8
981        %uint = OpTypeInt 32 0
982      %uint_0 = OpConstant %uint 0
983      %uint_1 = OpConstant %uint 1
984      %uint_2 = OpConstant %uint 2
985      %uint_3 = OpConstant %uint 3
986       %float = OpTypeFloat 32
987 %type__Globals = OpTypeStruct %float %float %float
988 %_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3
989 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
990 %_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3
991        %void = OpTypeVoid
992          %14 = OpTypeFunction %void
993 %_ptr_Uniform_float = OpTypePointer Uniform %float
994    %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform
995        %main = OpFunction %void None %14
996          %16 = OpLabel
997          %17 = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0
998          %18 = OpPtrAccessChain %_ptr_Uniform_float %17 %uint_1 %uint_0
999          %19 = OpPtrAccessChain %_ptr_Uniform_float %17 %uint_0 %uint_2
1000                OpReturn
1001                OpFunctionEnd
1002 )";
1003 
1004   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
1005 }
1006 
TEST_F(EliminateDeadMemberTest,RemoveMemberInBoundsPtrAccessChain)1007 TEST_F(EliminateDeadMemberTest, RemoveMemberInBoundsPtrAccessChain) {
1008   // Test that the member "y" is removed.
1009   // Update OpMemberName for |y| and |z|.
1010   // Update OpMemberDecorate for |y| and |z|.
1011   // Update OpInboundsAccessChain for access to |z|.
1012   const std::string text = R"(
1013 ; CHECK: OpName
1014 ; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
1015 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
1016 ; CHECK-NOT: OpMemberName
1017 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
1018 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 16
1019 ; CHECK: %type__Globals = OpTypeStruct %float %float
1020 ; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0
1021 ; CHECK: OpInBoundsPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_1 %uint_0
1022 ; CHECK: OpInBoundsPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_0 %uint_1
1023                OpCapability Shader
1024                OpCapability Addresses
1025                OpMemoryModel Logical GLSL450
1026                OpEntryPoint Vertex %main "main"
1027                OpSource HLSL 600
1028                OpName %type__Globals "type.$Globals"
1029                OpMemberName %type__Globals 0 "x"
1030                OpMemberName %type__Globals 1 "y"
1031                OpMemberName %type__Globals 2 "z"
1032                OpName %_Globals "$Globals"
1033                OpName %main "main"
1034                OpDecorate %_Globals DescriptorSet 0
1035                OpDecorate %_Globals Binding 0
1036                OpMemberDecorate %type__Globals 0 Offset 0
1037                OpMemberDecorate %type__Globals 1 Offset 4
1038                OpMemberDecorate %type__Globals 2 Offset 16
1039                OpDecorate %type__Globals Block
1040        %uint = OpTypeInt 32 0
1041      %uint_0 = OpConstant %uint 0
1042      %uint_1 = OpConstant %uint 1
1043      %uint_2 = OpConstant %uint 2
1044      %uint_3 = OpConstant %uint 3
1045       %float = OpTypeFloat 32
1046 %type__Globals = OpTypeStruct %float %float %float
1047 %_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3
1048 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
1049 %_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3
1050        %void = OpTypeVoid
1051          %14 = OpTypeFunction %void
1052 %_ptr_Uniform_float = OpTypePointer Uniform %float
1053    %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform
1054        %main = OpFunction %void None %14
1055          %16 = OpLabel
1056          %17 = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0
1057          %18 = OpInBoundsPtrAccessChain %_ptr_Uniform_float %17 %uint_1 %uint_0
1058          %19 = OpInBoundsPtrAccessChain %_ptr_Uniform_float %17 %uint_0 %uint_2
1059                OpReturn
1060                OpFunctionEnd
1061 )";
1062 
1063   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
1064 }
1065 
TEST_F(EliminateDeadMemberTest,DontRemoveModfStructResultTypeMembers)1066 TEST_F(EliminateDeadMemberTest, DontRemoveModfStructResultTypeMembers) {
1067   const std::string text = R"(
1068                OpCapability Shader
1069           %1 = OpExtInstImport "GLSL.std.450"
1070                OpMemoryModel Logical GLSL450
1071                OpEntryPoint Fragment %main "main"
1072                OpExecutionMode %main OriginUpperLeft
1073                OpSource HLSL 600
1074       %float = OpTypeFloat 32
1075        %void = OpTypeVoid
1076          %21 = OpTypeFunction %void
1077 %ModfStructType = OpTypeStruct %float %float
1078 %main = OpFunction %void None %21
1079          %22 = OpLabel
1080          %23 = OpUndef %float
1081          %24 = OpExtInst %ModfStructType %1 ModfStruct %23
1082          %25 = OpCompositeExtract %float %24 1
1083                OpReturn
1084                OpFunctionEnd
1085 )";
1086 
1087   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
1088       text, /* skip_nop = */ true, /* do_validation = */ true);
1089   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
1090 }
1091 
TEST_F(EliminateDeadMemberTest,DontChangeInputStructs)1092 TEST_F(EliminateDeadMemberTest, DontChangeInputStructs) {
1093   // The input for a shader has to match the type of the output from the
1094   // previous shader in the pipeline.  Because of that, we cannot change the
1095   // types of input variables.
1096   const std::string text = R"(
1097                OpCapability Shader
1098           %1 = OpExtInstImport "GLSL.std.450"
1099                OpMemoryModel Logical GLSL450
1100                OpEntryPoint Fragment %main "main" %input_var
1101                OpExecutionMode %main OriginUpperLeft
1102                OpSource HLSL 600
1103       %float = OpTypeFloat 32
1104        %void = OpTypeVoid
1105          %21 = OpTypeFunction %void
1106 %in_var_type = OpTypeStruct %float %float
1107 %in_ptr_type = OpTypePointer Input %in_var_type
1108 %input_var = OpVariable %in_ptr_type Input
1109 %main = OpFunction %void None %21
1110          %22 = OpLabel
1111                OpReturn
1112                OpFunctionEnd
1113 )";
1114 
1115   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
1116       text, /* skip_nop = */ true, /* do_validation = */ true);
1117   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
1118 }
1119 
TEST_F(EliminateDeadMemberTest,DontChangeOutputStructs)1120 TEST_F(EliminateDeadMemberTest, DontChangeOutputStructs) {
1121   // The output for a shader has to match the type of the output from the
1122   // previous shader in the pipeline.  Because of that, we cannot change the
1123   // types of output variables.
1124   const std::string text = R"(
1125                OpCapability Shader
1126           %1 = OpExtInstImport "GLSL.std.450"
1127                OpMemoryModel Logical GLSL450
1128                OpEntryPoint Fragment %main "main" %output_var
1129                OpExecutionMode %main OriginUpperLeft
1130                OpSource HLSL 600
1131       %float = OpTypeFloat 32
1132        %void = OpTypeVoid
1133          %21 = OpTypeFunction %void
1134 %out_var_type = OpTypeStruct %float %float
1135 %out_ptr_type = OpTypePointer Output %out_var_type
1136 %output_var = OpVariable %out_ptr_type Output
1137 %main = OpFunction %void None %21
1138          %22 = OpLabel
1139                OpReturn
1140                OpFunctionEnd
1141 )";
1142 
1143   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
1144       text, /* skip_nop = */ true, /* do_validation = */ true);
1145   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
1146 }
1147 
TEST_F(EliminateDeadMemberTest,UpdateSpecConstOpExtract)1148 TEST_F(EliminateDeadMemberTest, UpdateSpecConstOpExtract) {
1149   // Test that an extract in an OpSpecConstantOp is correctly updated.
1150   const std::string text = R"(
1151 ; CHECK: OpName
1152 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
1153 ; CHECK-NOT: OpMemberName
1154 ; CHECK: OpDecorate [[spec_const:%\w+]] SpecId 1
1155 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
1156 ; CHECK: %type__Globals = OpTypeStruct %uint
1157 ; CHECK: [[struct:%\w+]] = OpSpecConstantComposite %type__Globals [[spec_const]]
1158 ; CHECK: OpSpecConstantOp %uint CompositeExtract [[struct]] 0
1159                OpCapability Shader
1160                OpCapability Addresses
1161                OpMemoryModel Logical GLSL450
1162                OpEntryPoint Vertex %main "main"
1163                OpSource HLSL 600
1164                OpName %type__Globals "type.$Globals"
1165                OpMemberName %type__Globals 0 "x"
1166                OpMemberName %type__Globals 1 "y"
1167                OpMemberName %type__Globals 2 "z"
1168                OpName %main "main"
1169                OpDecorate %c_0 SpecId 0
1170                OpDecorate %c_1 SpecId 1
1171                OpDecorate %c_2 SpecId 2
1172                OpMemberDecorate %type__Globals 0 Offset 0
1173                OpMemberDecorate %type__Globals 1 Offset 4
1174                OpMemberDecorate %type__Globals 2 Offset 16
1175        %uint = OpTypeInt 32 0
1176         %c_0 = OpSpecConstant %uint 0
1177         %c_1 = OpSpecConstant %uint 1
1178         %c_2 = OpSpecConstant %uint 2
1179      %uint_0 = OpConstant %uint 0
1180      %uint_1 = OpConstant %uint 1
1181      %uint_2 = OpConstant %uint 2
1182      %uint_3 = OpConstant %uint 3
1183 %type__Globals = OpTypeStruct %uint %uint %uint
1184 %spec_const_global = OpSpecConstantComposite %type__Globals %c_0 %c_1 %c_2
1185 %extract = OpSpecConstantOp %uint CompositeExtract %spec_const_global 1
1186        %void = OpTypeVoid
1187          %14 = OpTypeFunction %void
1188        %main = OpFunction %void None %14
1189          %16 = OpLabel
1190                OpReturn
1191                OpFunctionEnd
1192 )";
1193 
1194   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
1195 }
1196 
TEST_F(EliminateDeadMemberTest,UpdateSpecConstOpInsert)1197 TEST_F(EliminateDeadMemberTest, UpdateSpecConstOpInsert) {
1198   // Test that an insert in an OpSpecConstantOp is correctly updated.
1199   const std::string text = R"(
1200 ; CHECK: OpName
1201 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
1202 ; CHECK-NOT: OpMemberName
1203 ; CHECK: OpDecorate [[spec_const:%\w+]] SpecId 1
1204 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
1205 ; CHECK: %type__Globals = OpTypeStruct %uint
1206 ; CHECK: [[struct:%\w+]] = OpSpecConstantComposite %type__Globals [[spec_const]]
1207 ; CHECK: OpSpecConstantOp %type__Globals CompositeInsert %uint_3 [[struct]] 0
1208                OpCapability Shader
1209                OpCapability Addresses
1210                OpMemoryModel Logical GLSL450
1211                OpEntryPoint Vertex %main "main"
1212                OpSource HLSL 600
1213                OpName %type__Globals "type.$Globals"
1214                OpMemberName %type__Globals 0 "x"
1215                OpMemberName %type__Globals 1 "y"
1216                OpMemberName %type__Globals 2 "z"
1217                OpName %main "main"
1218                OpDecorate %c_0 SpecId 0
1219                OpDecorate %c_1 SpecId 1
1220                OpDecorate %c_2 SpecId 2
1221                OpMemberDecorate %type__Globals 0 Offset 0
1222                OpMemberDecorate %type__Globals 1 Offset 4
1223                OpMemberDecorate %type__Globals 2 Offset 16
1224        %uint = OpTypeInt 32 0
1225         %c_0 = OpSpecConstant %uint 0
1226         %c_1 = OpSpecConstant %uint 1
1227         %c_2 = OpSpecConstant %uint 2
1228      %uint_0 = OpConstant %uint 0
1229      %uint_1 = OpConstant %uint 1
1230      %uint_2 = OpConstant %uint 2
1231      %uint_3 = OpConstant %uint 3
1232 %type__Globals = OpTypeStruct %uint %uint %uint
1233 %spec_const_global = OpSpecConstantComposite %type__Globals %c_0 %c_1 %c_2
1234 %insert = OpSpecConstantOp %type__Globals CompositeInsert %uint_3 %spec_const_global 1
1235 %extract = OpSpecConstantOp %uint CompositeExtract %insert 1
1236        %void = OpTypeVoid
1237          %14 = OpTypeFunction %void
1238        %main = OpFunction %void None %14
1239          %16 = OpLabel
1240                OpReturn
1241                OpFunctionEnd
1242 )";
1243 
1244   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
1245 }
1246 
1247 TEST_F(EliminateDeadMemberTest, 8BitIndexNoChange) {
1248   // Test that the pass does not crash when an 8 bit index is used in an
1249   // OpAccessChain. No change is expected.
1250   const std::string text = R"(
1251                OpCapability ImageQuery
1252                OpCapability Int8
1253                OpMemoryModel Logical GLSL450
1254                OpEntryPoint Fragment %1 "OpnSeman/" %2
1255                OpExecutionMode %1 OriginUpperLeft
1256        %void = OpTypeVoid
1257           %4 = OpTypeFunction %void
1258       %float = OpTypeFloat 32
1259     %v4float = OpTypeVector %float 4
1260   %_struct_7 = OpTypeStruct %v4float
1261 %_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
1262 %_ptr_Output_v4float = OpTypePointer Output %v4float
1263          %10 = OpTypeFunction %v4float %_ptr_Function__struct_7
1264        %char = OpTypeInt 8 1
1265      %char_0 = OpConstant %char 0
1266 %_ptr_Function_v4float = OpTypePointer Function %v4float
1267           %2 = OpVariable %_ptr_Output_v4float Output
1268           %1 = OpFunction %void None %4
1269          %14 = OpLabel
1270          %15 = OpVariable %_ptr_Function__struct_7 Function
1271          %16 = OpFunctionCall %v4float %17 %15
1272                OpReturn
1273                OpFunctionEnd
1274          %17 = OpFunction %v4float DontInline %10
1275          %18 = OpFunctionParameter %_ptr_Function__struct_7
1276          %19 = OpLabel
1277          %20 = OpAccessChain %_ptr_Function_v4float %18 %char_0
1278          %21 = OpLoad %v4float %20
1279                OpReturnValue %21
1280                OpFunctionEnd
1281 )";
1282 
1283   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
1284       text, /* skip_nop = */ true, /* do_validation = */ true);
1285   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
1286 }
1287 
1288 TEST_F(EliminateDeadMemberTest, 8BitIndexWithChange) {
1289   // Test that the pass does not crash when an 8 bit index is used in an
1290   // OpAccessChain. The index in the access change should be changed to 0.
1291   const std::string text = R"(
1292                OpCapability ImageQuery
1293                OpCapability Int8
1294                OpMemoryModel Logical GLSL450
1295                OpEntryPoint Fragment %1 "OpnSeman/" %2
1296                OpExecutionMode %1 OriginUpperLeft
1297        %void = OpTypeVoid
1298           %4 = OpTypeFunction %void
1299       %float = OpTypeFloat 32
1300     %v4float = OpTypeVector %float 4
1301   %_struct_7 = OpTypeStruct %v4float %v4float
1302 %_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
1303 %_ptr_Output_v4float = OpTypePointer Output %v4float
1304          %10 = OpTypeFunction %v4float %_ptr_Function__struct_7
1305        %char = OpTypeInt 8 1
1306      %char_1 = OpConstant %char 1
1307 %_ptr_Function_v4float = OpTypePointer Function %v4float
1308           %2 = OpVariable %_ptr_Output_v4float Output
1309           %1 = OpFunction %void None %4
1310          %14 = OpLabel
1311          %15 = OpVariable %_ptr_Function__struct_7 Function
1312          %16 = OpFunctionCall %v4float %17 %15
1313                OpReturn
1314                OpFunctionEnd
1315          %17 = OpFunction %v4float DontInline %10
1316 ; CHECK: [[param:%\w+]] = OpFunctionParameter
1317          %18 = OpFunctionParameter %_ptr_Function__struct_7
1318          %19 = OpLabel
1319 ; CHECK: OpAccessChain %_ptr_Function_v4float [[param]] %uint_0
1320          %20 = OpAccessChain %_ptr_Function_v4float %18 %char_1
1321          %21 = OpLoad %v4float %20
1322                OpReturnValue %21
1323                OpFunctionEnd
1324 )";
1325 
1326   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
1327 }
1328 
1329 }  // namespace
1330