• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "gmock/gmock.h"
17 #include "pass_fixture.h"
18 #include "pass_utils.h"
19 
20 namespace {
21 
22 using namespace spvtools;
23 
24 using EliminateDeadMemberTest = opt::PassTest<::testing::Test>;
25 
TEST_F(EliminateDeadMemberTest,RemoveMember1)26 TEST_F(EliminateDeadMemberTest, RemoveMember1) {
27   // Test that the member "y" is removed.
28   // Update OpMemberName for |y| and |z|.
29   // Update OpMemberDecorate for |y| and |z|.
30   // Update OpAccessChain for access to |z|.
31   const std::string text = R"(
32 ; CHECK: OpName
33 ; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
34 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
35 ; CHECK-NOT: OpMemberName
36 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
37 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
38 ; CHECK: %type__Globals = OpTypeStruct %float %float
39 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %int_0
40 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1
41                OpCapability Shader
42                OpMemoryModel Logical GLSL450
43                OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
44                OpSource HLSL 600
45                OpName %type__Globals "type.$Globals"
46                OpMemberName %type__Globals 0 "x"
47                OpMemberName %type__Globals 1 "y"
48                OpMemberName %type__Globals 2 "z"
49                OpName %_Globals "$Globals"
50                OpName %in_var_Position "in.var.Position"
51                OpName %main "main"
52                OpDecorate %gl_Position BuiltIn Position
53                OpDecorate %in_var_Position Location 0
54                OpDecorate %_Globals DescriptorSet 0
55                OpDecorate %_Globals Binding 0
56                OpMemberDecorate %type__Globals 0 Offset 0
57                OpMemberDecorate %type__Globals 1 Offset 4
58                OpMemberDecorate %type__Globals 2 Offset 8
59                OpDecorate %type__Globals Block
60         %int = OpTypeInt 32 1
61       %int_0 = OpConstant %int 0
62       %float = OpTypeFloat 32
63       %int_2 = OpConstant %int 2
64 %type__Globals = OpTypeStruct %float %float %float
65 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
66     %v4float = OpTypeVector %float 4
67 %_ptr_Input_v4float = OpTypePointer Input %v4float
68 %_ptr_Output_v4float = OpTypePointer Output %v4float
69        %void = OpTypeVoid
70          %15 = OpTypeFunction %void
71 %_ptr_Uniform_float = OpTypePointer Uniform %float
72    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
73 %in_var_Position = OpVariable %_ptr_Input_v4float Input
74 %gl_Position = OpVariable %_ptr_Output_v4float Output
75        %main = OpFunction %void None %15
76          %17 = OpLabel
77          %18 = OpLoad %v4float %in_var_Position
78          %19 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0
79          %20 = OpLoad %float %19
80          %21 = OpCompositeExtract %float %18 0
81          %22 = OpFAdd %float %21 %20
82          %23 = OpCompositeInsert %v4float %22 %18 0
83          %24 = OpCompositeExtract %float %18 1
84          %25 = OpCompositeInsert %v4float %24 %23 1
85          %26 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2
86          %27 = OpLoad %float %26
87          %28 = OpCompositeExtract %float %18 2
88          %29 = OpFAdd %float %28 %27
89          %30 = OpCompositeInsert %v4float %29 %25 2
90                OpStore %gl_Position %30
91                OpReturn
92                OpFunctionEnd
93 )";
94 
95   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
96 }
97 
TEST_F(EliminateDeadMemberTest,RemoveMemberWithGroupDecorations)98 TEST_F(EliminateDeadMemberTest, RemoveMemberWithGroupDecorations) {
99   // Test that the member "y" is removed.
100   // Update OpGroupMemberDecorate for %type__Globals member 1 and 2.
101   // Update OpAccessChain for access to %type__Globals member 2.
102   const std::string text = R"(
103 ; CHECK: OpDecorate [[gr1:%\w+]] Offset 0
104 ; CHECK: OpDecorate [[gr2:%\w+]] Offset 4
105 ; CHECK: OpDecorate [[gr3:%\w+]] Offset 8
106 ; CHECK: [[gr1]] = OpDecorationGroup
107 ; CHECK: [[gr2]] = OpDecorationGroup
108 ; CHECK: [[gr3]] = OpDecorationGroup
109 ; CHECK: OpGroupMemberDecorate [[gr1]] %type__Globals 0
110 ; CHECK-NOT: OpGroupMemberDecorate [[gr2]]
111 ; CHECK: OpGroupMemberDecorate [[gr3]] %type__Globals 1
112 ; CHECK: %type__Globals = OpTypeStruct %float %float
113 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %int_0
114 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1
115                OpCapability Shader
116                OpMemoryModel Logical GLSL450
117                OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
118                OpSource HLSL 600
119                OpName %type__Globals "type.$Globals"
120                OpName %_Globals "$Globals"
121                OpDecorate %gl_Position BuiltIn Position
122                OpDecorate %in_var_Position Location 0
123                OpDecorate %_Globals DescriptorSet 0
124                OpDecorate %_Globals Binding 0
125                OpDecorate %gr1 Offset 0
126                OpDecorate %gr2 Offset 4
127                OpDecorate %gr3 Offset 8
128                OpDecorate %type__Globals Block
129         %gr1 = OpDecorationGroup
130         %gr2 = OpDecorationGroup
131         %gr3 = OpDecorationGroup
132                OpGroupMemberDecorate %gr1 %type__Globals 0
133                OpGroupMemberDecorate %gr2 %type__Globals 1
134                OpGroupMemberDecorate %gr3 %type__Globals 2
135         %int = OpTypeInt 32 1
136       %int_0 = OpConstant %int 0
137       %float = OpTypeFloat 32
138       %int_2 = OpConstant %int 2
139 %type__Globals = OpTypeStruct %float %float %float
140 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
141     %v4float = OpTypeVector %float 4
142 %_ptr_Input_v4float = OpTypePointer Input %v4float
143 %_ptr_Output_v4float = OpTypePointer Output %v4float
144        %void = OpTypeVoid
145          %15 = OpTypeFunction %void
146 %_ptr_Uniform_float = OpTypePointer Uniform %float
147    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
148 %in_var_Position = OpVariable %_ptr_Input_v4float Input
149 %gl_Position = OpVariable %_ptr_Output_v4float Output
150        %main = OpFunction %void None %15
151          %17 = OpLabel
152          %18 = OpLoad %v4float %in_var_Position
153          %19 = OpAccessChain %_ptr_Uniform_float %_Globals %int_0
154          %20 = OpLoad %float %19
155          %21 = OpCompositeExtract %float %18 0
156          %22 = OpFAdd %float %21 %20
157          %23 = OpCompositeInsert %v4float %22 %18 0
158          %24 = OpCompositeExtract %float %18 1
159          %25 = OpCompositeInsert %v4float %24 %23 1
160          %26 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2
161          %27 = OpLoad %float %26
162          %28 = OpCompositeExtract %float %18 2
163          %29 = OpFAdd %float %28 %27
164          %30 = OpCompositeInsert %v4float %29 %25 2
165                OpStore %gl_Position %30
166                OpReturn
167                OpFunctionEnd
168 )";
169 
170   // Skipping validation because of a bug in the validator.  See issue #2376.
171   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, false);
172 }
173 
TEST_F(EliminateDeadMemberTest,RemoveMemberUpdateConstant)174 TEST_F(EliminateDeadMemberTest, RemoveMemberUpdateConstant) {
175   // Test that the member "x" is removed.
176   // Update the OpConstantComposite instruction.
177   const std::string text = R"(
178 ; CHECK: OpName
179 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
180 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
181 ; CHECK-NOT: OpMemberName
182 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
183 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
184 ; CHECK: %type__Globals = OpTypeStruct %float %float
185 ; CHECK: OpConstantComposite %type__Globals %float_1 %float_2
186 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_0
187 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1
188                OpCapability Shader
189                OpMemoryModel Logical GLSL450
190                OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
191                OpSource HLSL 600
192                OpName %type__Globals "type.$Globals"
193                OpMemberName %type__Globals 0 "x"
194                OpMemberName %type__Globals 1 "y"
195                OpMemberName %type__Globals 2 "z"
196                OpName %_Globals "$Globals"
197                OpName %in_var_Position "in.var.Position"
198                OpName %main "main"
199                OpDecorate %gl_Position BuiltIn Position
200                OpDecorate %in_var_Position Location 0
201                OpDecorate %_Globals DescriptorSet 0
202                OpDecorate %_Globals Binding 0
203                OpMemberDecorate %type__Globals 0 Offset 0
204                OpMemberDecorate %type__Globals 1 Offset 4
205                OpMemberDecorate %type__Globals 2 Offset 8
206                OpDecorate %type__Globals Block
207         %int = OpTypeInt 32 1
208       %int_1 = OpConstant %int 1
209       %float = OpTypeFloat 32
210     %float_0 = OpConstant %float 0
211     %float_1 = OpConstant %float 1
212     %float_2 = OpConstant %float 2
213       %int_2 = OpConstant %int 2
214 %type__Globals = OpTypeStruct %float %float %float
215          %13 = OpConstantComposite %type__Globals %float_0 %float_1 %float_2
216 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
217     %v4float = OpTypeVector %float 4
218 %_ptr_Input_v4float = OpTypePointer Input %v4float
219 %_ptr_Output_v4float = OpTypePointer Output %v4float
220        %void = OpTypeVoid
221          %19 = OpTypeFunction %void
222 %_ptr_Uniform_float = OpTypePointer Uniform %float
223    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
224 %in_var_Position = OpVariable %_ptr_Input_v4float Input
225 %gl_Position = OpVariable %_ptr_Output_v4float Output
226        %main = OpFunction %void None %19
227          %21 = OpLabel
228          %22 = OpLoad %v4float %in_var_Position
229          %23 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1
230          %24 = OpLoad %float %23
231          %25 = OpCompositeExtract %float %22 0
232          %26 = OpFAdd %float %25 %24
233          %27 = OpCompositeInsert %v4float %26 %22 0
234          %28 = OpCompositeExtract %float %22 1
235          %29 = OpCompositeInsert %v4float %28 %27 1
236          %30 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2
237          %31 = OpLoad %float %30
238          %32 = OpCompositeExtract %float %22 2
239          %33 = OpFAdd %float %32 %31
240          %34 = OpCompositeInsert %v4float %33 %29 2
241                OpStore %gl_Position %34
242                OpReturn
243                OpFunctionEnd
244 )";
245 
246   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
247 }
248 
TEST_F(EliminateDeadMemberTest,RemoveMemberUpdateCompositeConstruct)249 TEST_F(EliminateDeadMemberTest, RemoveMemberUpdateCompositeConstruct) {
250   // Test that the member "x" is removed.
251   // Update the OpConstantComposite instruction.
252   const std::string text = R"(
253 ; CHECK: OpName
254 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
255 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
256 ; CHECK-NOT: OpMemberName
257 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
258 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
259 ; CHECK: %type__Globals = OpTypeStruct %float %float
260 ; CHECK: OpCompositeConstruct %type__Globals %float_1 %float_2
261 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_0
262 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals %uint_1
263                OpCapability Shader
264                OpMemoryModel Logical GLSL450
265                OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
266                OpSource HLSL 600
267                OpName %type__Globals "type.$Globals"
268                OpMemberName %type__Globals 0 "x"
269                OpMemberName %type__Globals 1 "y"
270                OpMemberName %type__Globals 2 "z"
271                OpName %_Globals "$Globals"
272                OpName %in_var_Position "in.var.Position"
273                OpName %main "main"
274                OpDecorate %gl_Position BuiltIn Position
275                OpDecorate %in_var_Position Location 0
276                OpDecorate %_Globals DescriptorSet 0
277                OpDecorate %_Globals Binding 0
278                OpMemberDecorate %type__Globals 0 Offset 0
279                OpMemberDecorate %type__Globals 1 Offset 4
280                OpMemberDecorate %type__Globals 2 Offset 8
281                OpDecorate %type__Globals Block
282         %int = OpTypeInt 32 1
283       %int_1 = OpConstant %int 1
284       %float = OpTypeFloat 32
285     %float_0 = OpConstant %float 0
286     %float_1 = OpConstant %float 1
287     %float_2 = OpConstant %float 2
288       %int_2 = OpConstant %int 2
289 %type__Globals = OpTypeStruct %float %float %float
290 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
291     %v4float = OpTypeVector %float 4
292 %_ptr_Input_v4float = OpTypePointer Input %v4float
293 %_ptr_Output_v4float = OpTypePointer Output %v4float
294        %void = OpTypeVoid
295          %19 = OpTypeFunction %void
296 %_ptr_Uniform_float = OpTypePointer Uniform %float
297    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
298 %in_var_Position = OpVariable %_ptr_Input_v4float Input
299 %gl_Position = OpVariable %_ptr_Output_v4float Output
300        %main = OpFunction %void None %19
301          %21 = OpLabel
302          %13 = OpCompositeConstruct %type__Globals %float_0 %float_1 %float_2
303          %22 = OpLoad %v4float %in_var_Position
304          %23 = OpAccessChain %_ptr_Uniform_float %_Globals %int_1
305          %24 = OpLoad %float %23
306          %25 = OpCompositeExtract %float %22 0
307          %26 = OpFAdd %float %25 %24
308          %27 = OpCompositeInsert %v4float %26 %22 0
309          %28 = OpCompositeExtract %float %22 1
310          %29 = OpCompositeInsert %v4float %28 %27 1
311          %30 = OpAccessChain %_ptr_Uniform_float %_Globals %int_2
312          %31 = OpLoad %float %30
313          %32 = OpCompositeExtract %float %22 2
314          %33 = OpFAdd %float %32 %31
315          %34 = OpCompositeInsert %v4float %33 %29 2
316                OpStore %gl_Position %34
317                OpReturn
318                OpFunctionEnd
319 )";
320 
321   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
322 }
323 
TEST_F(EliminateDeadMemberTest,RemoveMembersUpdateInserExtract1)324 TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract1) {
325   // Test that the members "x" and "z" are removed.
326   // Update the OpCompositeExtract instruction.
327   // Remove the OpCompositeInsert instruction since the member being inserted is
328   // dead.
329   const std::string text = R"(
330 ; CHECK: OpName
331 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
332 ; CHECK-NOT: OpMemberName
333 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
334 ; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
335 ; CHECK: %type__Globals = OpTypeStruct %float
336 ; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals
337 ; CHECK: OpCompositeExtract %float [[ld]] 0
338 ; CHECK-NOT: OpCompositeInsert
339 ; CHECK: OpReturn
340                OpCapability Shader
341                OpMemoryModel Logical GLSL450
342                OpEntryPoint Vertex %main "main"
343                OpSource HLSL 600
344                OpName %type__Globals "type.$Globals"
345                OpMemberName %type__Globals 0 "x"
346                OpMemberName %type__Globals 1 "y"
347                OpMemberName %type__Globals 2 "z"
348                OpName %_Globals "$Globals"
349                OpName %main "main"
350                OpDecorate %_Globals DescriptorSet 0
351                OpDecorate %_Globals Binding 0
352                OpMemberDecorate %type__Globals 0 Offset 0
353                OpMemberDecorate %type__Globals 1 Offset 4
354                OpMemberDecorate %type__Globals 2 Offset 8
355                OpDecorate %type__Globals Block
356       %float = OpTypeFloat 32
357 %type__Globals = OpTypeStruct %float %float %float
358 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
359        %void = OpTypeVoid
360           %7 = OpTypeFunction %void
361    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
362        %main = OpFunction %void None %7
363           %8 = OpLabel
364           %9 = OpLoad %type__Globals %_Globals
365          %10 = OpCompositeExtract %float %9 1
366          %11 = OpCompositeInsert %type__Globals %10 %9 2
367                OpReturn
368                OpFunctionEnd
369 
370 )";
371 
372   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
373 }
374 
TEST_F(EliminateDeadMemberTest,RemoveMembersUpdateInserExtract2)375 TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract2) {
376   // Test that the members "x" and "z" are removed.
377   // Update the OpCompositeExtract instruction.
378   // Update the OpCompositeInsert instruction.
379   const std::string text = R"(
380 ; CHECK: OpName
381 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
382 ; CHECK-NOT: OpMemberName
383 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
384 ; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
385 ; CHECK: %type__Globals = OpTypeStruct %float
386 ; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals
387 ; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0
388 ; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0
389 ; CHECK: OpReturn
390                OpCapability Shader
391                OpMemoryModel Logical GLSL450
392                OpEntryPoint Vertex %main "main"
393                OpSource HLSL 600
394                OpName %type__Globals "type.$Globals"
395                OpMemberName %type__Globals 0 "x"
396                OpMemberName %type__Globals 1 "y"
397                OpMemberName %type__Globals 2 "z"
398                OpName %_Globals "$Globals"
399                OpName %main "main"
400                OpDecorate %_Globals DescriptorSet 0
401                OpDecorate %_Globals Binding 0
402                OpMemberDecorate %type__Globals 0 Offset 0
403                OpMemberDecorate %type__Globals 1 Offset 4
404                OpMemberDecorate %type__Globals 2 Offset 8
405                OpDecorate %type__Globals Block
406       %float = OpTypeFloat 32
407 %type__Globals = OpTypeStruct %float %float %float
408 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
409        %void = OpTypeVoid
410           %7 = OpTypeFunction %void
411    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
412        %main = OpFunction %void None %7
413           %8 = OpLabel
414           %9 = OpLoad %type__Globals %_Globals
415          %10 = OpCompositeExtract %float %9 1
416          %11 = OpCompositeInsert %type__Globals %10 %9 1
417                OpReturn
418                OpFunctionEnd
419 
420 )";
421 
422   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
423 }
424 
TEST_F(EliminateDeadMemberTest,RemoveMembersUpdateInserExtract3)425 TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract3) {
426   // Test that the members "x" and "z" are removed, and one member from the
427   // substruct. Update the OpCompositeExtract instruction. Update the
428   // OpCompositeInsert instruction.
429   const std::string text = R"(
430 ; CHECK: OpName
431 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
432 ; CHECK-NOT: OpMemberName
433 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
434 ; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
435 ; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4
436 ; CHECK: [[struct:%\w+]] = OpTypeStruct %float
437 ; CHECK: %type__Globals = OpTypeStruct [[struct]]
438 ; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals
439 ; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 0
440 ; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0 0
441 ; CHECK: OpReturn
442                OpCapability Shader
443                OpMemoryModel Logical GLSL450
444                OpEntryPoint Vertex %main "main"
445                OpSource HLSL 600
446                OpName %type__Globals "type.$Globals"
447                OpMemberName %type__Globals 0 "x"
448                OpMemberName %type__Globals 1 "y"
449                OpMemberName %type__Globals 2 "z"
450                OpName %_Globals "$Globals"
451                OpName %main "main"
452                OpDecorate %_Globals DescriptorSet 0
453                OpDecorate %_Globals Binding 0
454                OpMemberDecorate %type__Globals 0 Offset 0
455                OpMemberDecorate %type__Globals 1 Offset 16
456                OpMemberDecorate %type__Globals 2 Offset 24
457                OpMemberDecorate %_struct_6 0 Offset 0
458                OpMemberDecorate %_struct_6 1 Offset 4
459                OpDecorate %type__Globals Block
460       %float = OpTypeFloat 32
461   %_struct_6 = OpTypeStruct %float %float
462 %type__Globals = OpTypeStruct %float %_struct_6 %float
463 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
464        %void = OpTypeVoid
465           %7 = OpTypeFunction %void
466    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
467        %main = OpFunction %void None %7
468           %8 = OpLabel
469           %9 = OpLoad %type__Globals %_Globals
470          %10 = OpCompositeExtract %float %9 1 1
471          %11 = OpCompositeInsert %type__Globals %10 %9 1 1
472                OpReturn
473                OpFunctionEnd
474 
475 )";
476 
477   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
478 }
479 
TEST_F(EliminateDeadMemberTest,RemoveMembersUpdateInserExtract4)480 TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateInserExtract4) {
481   // Test that the members "x" and "z" are removed, and one member from the
482   // substruct. Update the OpCompositeExtract instruction. Update the
483   // OpCompositeInsert instruction.
484   const std::string text = R"(
485 ; CHECK: OpName
486 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
487 ; CHECK-NOT: OpMemberName
488 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
489 ; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
490 ; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4
491 ; CHECK: [[struct:%\w+]] = OpTypeStruct %float
492 ; CHECK: [[array:%\w+]] = OpTypeArray [[struct]]
493 ; CHECK: %type__Globals = OpTypeStruct [[array]]
494 ; CHECK: [[ld:%\w+]] = OpLoad %type__Globals %_Globals
495 ; CHECK: [[ex:%\w+]] = OpCompositeExtract %float [[ld]] 0 1 0
496 ; CHECK: OpCompositeInsert %type__Globals [[ex]] [[ld]] 0 1 0
497 ; CHECK: OpReturn
498                OpCapability Shader
499                OpMemoryModel Logical GLSL450
500                OpEntryPoint Vertex %main "main"
501                OpSource HLSL 600
502                OpName %type__Globals "type.$Globals"
503                OpMemberName %type__Globals 0 "x"
504                OpMemberName %type__Globals 1 "y"
505                OpMemberName %type__Globals 2 "z"
506                OpName %_Globals "$Globals"
507                OpName %main "main"
508                OpDecorate %_Globals DescriptorSet 0
509                OpDecorate %_Globals Binding 0
510                OpMemberDecorate %type__Globals 0 Offset 0
511                OpMemberDecorate %type__Globals 1 Offset 16
512                OpMemberDecorate %type__Globals 2 Offset 80
513                OpMemberDecorate %_struct_6 0 Offset 0
514                OpMemberDecorate %_struct_6 1 Offset 4
515                OpDecorate %array ArrayStride 16
516                OpDecorate %type__Globals Block
517        %uint = OpTypeInt 32 0                         ; 32-bit int, sign-less
518      %uint_4 = OpConstant %uint 4
519       %float = OpTypeFloat 32
520   %_struct_6 = OpTypeStruct %float %float
521   %array = OpTypeArray %_struct_6 %uint_4
522 %type__Globals = OpTypeStruct %float %array %float
523 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
524        %void = OpTypeVoid
525           %7 = OpTypeFunction %void
526    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
527        %main = OpFunction %void None %7
528           %8 = OpLabel
529           %9 = OpLoad %type__Globals %_Globals
530          %10 = OpCompositeExtract %float %9 1 1 1
531          %11 = OpCompositeInsert %type__Globals %10 %9 1 1 1
532                OpReturn
533                OpFunctionEnd
534 
535 )";
536 
537   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
538 }
539 
TEST_F(EliminateDeadMemberTest,RemoveMembersUpdateArrayLength)540 TEST_F(EliminateDeadMemberTest, RemoveMembersUpdateArrayLength) {
541   // Test that the members "x" and "y" are removed.
542   // Member "z" is live because of the OpArrayLength instruction.
543   // Update the OpArrayLength instruction.
544   const std::string text = R"(
545 ; CHECK: OpName
546 ; CHECK-NEXT: OpMemberName %type__Globals 0 "z"
547 ; CHECK-NOT: OpMemberName
548 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
549 ; CHECK-NOT: OpMemberDecorate %type__Globals 1 Offset
550 ; CHECK: %type__Globals = OpTypeStruct %_runtimearr_float
551 ; CHECK: OpArrayLength %uint %_Globals 0
552                OpCapability Shader
553                OpMemoryModel Logical GLSL450
554                OpEntryPoint Vertex %main "main"
555                OpSource HLSL 600
556                OpName %type__Globals "type.$Globals"
557                OpMemberName %type__Globals 0 "x"
558                OpMemberName %type__Globals 1 "y"
559                OpMemberName %type__Globals 2 "z"
560                OpName %_Globals "$Globals"
561                OpName %main "main"
562                OpDecorate %_Globals DescriptorSet 0
563                OpDecorate %_Globals Binding 0
564                OpDecorate %_runtimearr_float ArrayStride 16
565                OpMemberDecorate %type__Globals 0 Offset 0
566                OpMemberDecorate %type__Globals 1 Offset 4
567                OpMemberDecorate %type__Globals 2 Offset 16
568                OpDecorate %type__Globals Block
569        %uint = OpTypeInt 32 0
570       %float = OpTypeFloat 32
571 %_runtimearr_float = OpTypeRuntimeArray %float
572 %type__Globals = OpTypeStruct %float %float %_runtimearr_float
573 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
574        %void = OpTypeVoid
575           %9 = OpTypeFunction %void
576    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
577        %main = OpFunction %void None %9
578          %10 = OpLabel
579          %12 = OpArrayLength %uint %_Globals 2
580                OpReturn
581                OpFunctionEnd
582 )";
583 
584   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
585 }
586 
TEST_F(EliminateDeadMemberTest,KeepMembersOpStore)587 TEST_F(EliminateDeadMemberTest, KeepMembersOpStore) {
588   // Test that all members are kept because of an OpStore.
589   // No change expected.
590   const std::string text = R"(
591                OpCapability Shader
592                OpMemoryModel Logical GLSL450
593                OpEntryPoint Vertex %main "main"
594                OpSource HLSL 600
595                OpName %type__Globals "type.$Globals"
596                OpMemberName %type__Globals 0 "x"
597                OpMemberName %type__Globals 1 "y"
598                OpMemberName %type__Globals 2 "z"
599                OpName %_Globals "$Globals"
600                OpName %_Globals "$Globals2"
601                OpName %main "main"
602                OpDecorate %_Globals DescriptorSet 0
603                OpDecorate %_Globals Binding 0
604                OpMemberDecorate %type__Globals 0 Offset 0
605                OpMemberDecorate %type__Globals 1 Offset 4
606                OpMemberDecorate %type__Globals 2 Offset 16
607                OpDecorate %type__Globals Block
608        %uint = OpTypeInt 32 0
609       %float = OpTypeFloat 32
610 %type__Globals = OpTypeStruct %float %float %float
611 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
612        %void = OpTypeVoid
613           %9 = OpTypeFunction %void
614    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
615    %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
616        %main = OpFunction %void None %9
617          %10 = OpLabel
618          %11 = OpLoad %type__Globals %_Globals
619                OpStore %_Globals2 %11
620                OpReturn
621                OpFunctionEnd
622 )";
623 
624   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
625       text, /* skip_nop = */ true, /* do_validation = */ true);
626   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
627 }
628 
TEST_F(EliminateDeadMemberTest,KeepStorageBufferMembers)629 TEST_F(EliminateDeadMemberTest, KeepStorageBufferMembers) {
630   // Test that all members of the storage buffer struct %S are kept.
631   // No change expected.
632   const std::string text = R"(
633                OpCapability Shader
634                OpExtension "SPV_GOOGLE_hlsl_functionality1"
635                OpExtension "SPV_GOOGLE_user_type"
636           %1 = OpExtInstImport "GLSL.std.450"
637                OpMemoryModel Logical GLSL450
638                OpEntryPoint Fragment %PSMain "PSMain" %out_var_SV_TARGET
639                OpExecutionMode %PSMain OriginUpperLeft
640                OpSource HLSL 600
641                OpName %type_StructuredBuffer_S "type.StructuredBuffer.S"
642                OpName %S "S"
643                OpMemberName %S 0 "A"
644                OpMemberName %S 1 "B"
645                OpName %Buf "Buf"
646                OpName %out_var_SV_TARGET "out.var.SV_TARGET"
647                OpName %PSMain "PSMain"
648                OpDecorateString %out_var_SV_TARGET UserSemantic "SV_TARGET"
649                OpDecorate %out_var_SV_TARGET Location 0
650                OpDecorate %Buf DescriptorSet 0
651                OpDecorate %Buf Binding 0
652                OpMemberDecorate %S 0 Offset 0
653                OpMemberDecorate %S 1 Offset 16
654                OpDecorate %_runtimearr_S ArrayStride 32
655                OpMemberDecorate %type_StructuredBuffer_S 0 Offset 0
656                OpMemberDecorate %type_StructuredBuffer_S 0 NonWritable
657                OpDecorate %type_StructuredBuffer_S BufferBlock
658                OpDecorateString %Buf UserTypeGOOGLE "structuredbuffer"
659         %int = OpTypeInt 32 1
660       %int_0 = OpConstant %int 0
661        %uint = OpTypeInt 32 0
662      %uint_0 = OpConstant %uint 0
663       %int_1 = OpConstant %int 1
664       %float = OpTypeFloat 32
665     %v4float = OpTypeVector %float 4
666           %S = OpTypeStruct %v4float %v4float
667 %_runtimearr_S = OpTypeRuntimeArray %S
668 %type_StructuredBuffer_S = OpTypeStruct %_runtimearr_S
669 %_ptr_Uniform_type_StructuredBuffer_S = OpTypePointer Uniform %type_StructuredBuffer_S
670 %_ptr_Output_v4float = OpTypePointer Output %v4float
671        %void = OpTypeVoid
672          %18 = OpTypeFunction %void
673 %_ptr_Uniform_v4float = OpTypePointer Uniform %v4float
674         %Buf = OpVariable %_ptr_Uniform_type_StructuredBuffer_S Uniform
675 %out_var_SV_TARGET = OpVariable %_ptr_Output_v4float Output
676      %PSMain = OpFunction %void None %18
677          %20 = OpLabel
678          %21 = OpAccessChain %_ptr_Uniform_v4float %Buf %int_0 %uint_0 %int_1
679          %22 = OpLoad %v4float %21
680                OpStore %out_var_SV_TARGET %22
681                OpReturn
682                OpFunctionEnd
683 )";
684 
685   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
686       text, /* skip_nop = */ true, /* do_validation = */ true);
687   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
688 }
689 
TEST_F(EliminateDeadMemberTest,KeepMembersOpCopyMemory)690 TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemory) {
691   // Test that all members are kept because of an OpCopyMemory.
692   // No change expected.
693   const std::string text = R"(
694                OpCapability Shader
695                OpMemoryModel Logical GLSL450
696                OpEntryPoint Vertex %main "main"
697                OpSource HLSL 600
698                OpName %type__Globals "type.$Globals"
699                OpMemberName %type__Globals 0 "x"
700                OpMemberName %type__Globals 1 "y"
701                OpMemberName %type__Globals 2 "z"
702                OpName %_Globals "$Globals"
703                OpName %_Globals "$Globals2"
704                OpName %main "main"
705                OpDecorate %_Globals DescriptorSet 0
706                OpDecorate %_Globals Binding 0
707                OpMemberDecorate %type__Globals 0 Offset 0
708                OpMemberDecorate %type__Globals 1 Offset 4
709                OpMemberDecorate %type__Globals 2 Offset 16
710                OpDecorate %type__Globals Block
711        %uint = OpTypeInt 32 0
712       %float = OpTypeFloat 32
713 %type__Globals = OpTypeStruct %float %float %float
714 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
715        %void = OpTypeVoid
716           %9 = OpTypeFunction %void
717    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
718    %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
719        %main = OpFunction %void None %9
720          %10 = OpLabel
721                OpCopyMemory %_Globals2 %_Globals
722                OpReturn
723                OpFunctionEnd
724 )";
725 
726   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
727       text, /* skip_nop = */ true, /* do_validation = */ true);
728   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
729 }
730 
TEST_F(EliminateDeadMemberTest,KeepMembersOpCopyMemorySized)731 TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemorySized) {
732   // Test that all members are kept because of an OpCopyMemorySized.
733   // No change expected.
734   const std::string text = R"(
735                OpCapability Shader
736                OpCapability Addresses
737                OpMemoryModel Logical GLSL450
738                OpEntryPoint Vertex %main "main"
739                OpSource HLSL 600
740                OpName %type__Globals "type.$Globals"
741                OpMemberName %type__Globals 0 "x"
742                OpMemberName %type__Globals 1 "y"
743                OpMemberName %type__Globals 2 "z"
744                OpName %_Globals "$Globals"
745                OpName %_Globals "$Globals2"
746                OpName %main "main"
747                OpDecorate %_Globals DescriptorSet 0
748                OpDecorate %_Globals Binding 0
749                OpMemberDecorate %type__Globals 0 Offset 0
750                OpMemberDecorate %type__Globals 1 Offset 4
751                OpMemberDecorate %type__Globals 2 Offset 16
752                OpDecorate %type__Globals Block
753        %uint = OpTypeInt 32 0
754     %uint_20 = OpConstant %uint 20
755       %float = OpTypeFloat 32
756 %type__Globals = OpTypeStruct %float %float %float
757 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
758        %void = OpTypeVoid
759           %9 = OpTypeFunction %void
760    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
761    %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
762        %main = OpFunction %void None %9
763          %10 = OpLabel
764                OpCopyMemorySized %_Globals2 %_Globals %uint_20
765                OpReturn
766                OpFunctionEnd
767 )";
768 
769   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
770       text, /* skip_nop = */ true, /* do_validation = */ true);
771   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
772 }
773 
TEST_F(EliminateDeadMemberTest,KeepMembersOpReturnValue)774 TEST_F(EliminateDeadMemberTest, KeepMembersOpReturnValue) {
775   // Test that all members are kept because of an OpCopyMemorySized.
776   // No change expected.
777   const std::string text = R"(
778                OpCapability Shader
779                OpCapability Linkage
780                OpMemoryModel Logical GLSL450
781                OpSource HLSL 600
782                OpName %type__Globals "type.$Globals"
783                OpMemberName %type__Globals 0 "x"
784                OpMemberName %type__Globals 1 "y"
785                OpMemberName %type__Globals 2 "z"
786                OpName %_Globals "$Globals"
787                OpName %_Globals "$Globals2"
788                OpName %main "main"
789                OpDecorate %_Globals DescriptorSet 0
790                OpDecorate %_Globals Binding 0
791                OpMemberDecorate %type__Globals 0 Offset 0
792                OpMemberDecorate %type__Globals 1 Offset 4
793                OpMemberDecorate %type__Globals 2 Offset 16
794                OpDecorate %type__Globals Block
795        %uint = OpTypeInt 32 0
796     %uint_20 = OpConstant %uint 20
797       %float = OpTypeFloat 32
798 %type__Globals = OpTypeStruct %float %float %float
799 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
800        %void = OpTypeVoid
801           %9 = OpTypeFunction %type__Globals
802    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
803    %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
804        %main = OpFunction %type__Globals None %9
805          %10 = OpLabel
806          %11 = OpLoad %type__Globals %_Globals
807                OpReturnValue %11
808                OpFunctionEnd
809 )";
810 
811   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
812       text, /* skip_nop = */ true, /* do_validation = */ true);
813   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
814 }
815 
TEST_F(EliminateDeadMemberTest,RemoveMemberAccessChainWithArrays)816 TEST_F(EliminateDeadMemberTest, RemoveMemberAccessChainWithArrays) {
817   // Leave only 1 member in each of the structs.
818   // Update OpMemberName, OpMemberDecorate, and OpAccessChain.
819   const std::string text = R"(
820 ; CHECK: OpName
821 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
822 ; CHECK-NOT: OpMemberName
823 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
824 ; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4
825 ; CHECK: [[struct]] = OpTypeStruct %float
826 ; CHECK: [[array:%\w+]] = OpTypeArray [[struct]]
827 ; CHECK: %type__Globals = OpTypeStruct [[array]]
828 ; CHECK: [[undef:%\w+]] = OpUndef %uint
829 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals [[undef]] %uint_0 [[undef]] %uint_0
830                OpCapability Shader
831                OpCapability VariablePointersStorageBuffer
832                OpMemoryModel Logical GLSL450
833                OpEntryPoint Vertex %main "main"
834                OpSource HLSL 600
835                OpName %type__Globals "type.$Globals"
836                OpMemberName %type__Globals 0 "x"
837                OpMemberName %type__Globals 1 "y"
838                OpMemberName %type__Globals 2 "z"
839                OpName %_Globals "$Globals"
840                OpName %main "main"
841                OpDecorate %_Globals DescriptorSet 0
842                OpDecorate %_Globals Binding 0
843                OpMemberDecorate %type__Globals 0 Offset 0
844                OpMemberDecorate %type__Globals 1 Offset 16
845                OpMemberDecorate %type__Globals 2 Offset 48
846                OpMemberDecorate %_struct_4 0 Offset 0
847                OpMemberDecorate %_struct_4 1 Offset 4
848                OpDecorate %_arr__struct_4_uint_2 ArrayStride 16
849                OpDecorate %type__Globals Block
850        %uint = OpTypeInt 32 0
851      %uint_0 = OpConstant %uint 0
852      %uint_1 = OpConstant %uint 1
853      %uint_2 = OpConstant %uint 2
854      %uint_3 = OpConstant %uint 3
855       %float = OpTypeFloat 32
856   %_struct_4 = OpTypeStruct %float %float
857 %_arr__struct_4_uint_2 = OpTypeArray %_struct_4 %uint_2
858 %type__Globals = OpTypeStruct %float %_arr__struct_4_uint_2 %float
859 %_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3
860 %_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3
861        %void = OpTypeVoid
862          %15 = OpTypeFunction %void
863 %_ptr_Uniform_float = OpTypePointer Uniform %float
864    %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform
865        %main = OpFunction %void None %15
866          %17 = OpLabel
867          %18 = OpUndef %uint
868          %19 = OpAccessChain %_ptr_Uniform_float %_Globals %18 %uint_1 %18 %uint_1
869                OpReturn
870                OpFunctionEnd
871 )";
872 
873   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
874 }
875 
TEST_F(EliminateDeadMemberTest,RemoveMemberInboundsAccessChain)876 TEST_F(EliminateDeadMemberTest, RemoveMemberInboundsAccessChain) {
877   // Test that the member "y" is removed.
878   // Update OpMemberName for |y| and |z|.
879   // Update OpMemberDecorate for |y| and |z|.
880   // Update OpInboundsAccessChain for access to |z|.
881   const std::string text = R"(
882 ; CHECK: OpName
883 ; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
884 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
885 ; CHECK-NOT: OpMemberName
886 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
887 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
888 ; CHECK: %type__Globals = OpTypeStruct %float %float
889 ; CHECK: OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_0
890 ; CHECK: OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %uint_1
891                OpCapability Shader
892                OpMemoryModel Logical GLSL450
893                OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
894                OpSource HLSL 600
895                OpName %type__Globals "type.$Globals"
896                OpMemberName %type__Globals 0 "x"
897                OpMemberName %type__Globals 1 "y"
898                OpMemberName %type__Globals 2 "z"
899                OpName %_Globals "$Globals"
900                OpName %in_var_Position "in.var.Position"
901                OpName %main "main"
902                OpDecorate %gl_Position BuiltIn Position
903                OpDecorate %in_var_Position Location 0
904                OpDecorate %_Globals DescriptorSet 0
905                OpDecorate %_Globals Binding 0
906                OpMemberDecorate %type__Globals 0 Offset 0
907                OpMemberDecorate %type__Globals 1 Offset 4
908                OpMemberDecorate %type__Globals 2 Offset 8
909                OpDecorate %type__Globals Block
910         %int = OpTypeInt 32 1
911       %int_0 = OpConstant %int 0
912       %float = OpTypeFloat 32
913       %int_2 = OpConstant %int 2
914 %type__Globals = OpTypeStruct %float %float %float
915 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
916     %v4float = OpTypeVector %float 4
917 %_ptr_Input_v4float = OpTypePointer Input %v4float
918 %_ptr_Output_v4float = OpTypePointer Output %v4float
919        %void = OpTypeVoid
920          %15 = OpTypeFunction %void
921 %_ptr_Uniform_float = OpTypePointer Uniform %float
922    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
923 %in_var_Position = OpVariable %_ptr_Input_v4float Input
924 %gl_Position = OpVariable %_ptr_Output_v4float Output
925        %main = OpFunction %void None %15
926          %17 = OpLabel
927          %18 = OpLoad %v4float %in_var_Position
928          %19 = OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_0
929          %20 = OpLoad %float %19
930          %21 = OpCompositeExtract %float %18 0
931          %22 = OpFAdd %float %21 %20
932          %23 = OpCompositeInsert %v4float %22 %18 0
933          %24 = OpCompositeExtract %float %18 1
934          %25 = OpCompositeInsert %v4float %24 %23 1
935          %26 = OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_2
936          %27 = OpLoad %float %26
937          %28 = OpCompositeExtract %float %18 2
938          %29 = OpFAdd %float %28 %27
939          %30 = OpCompositeInsert %v4float %29 %25 2
940                OpStore %gl_Position %30
941                OpReturn
942                OpFunctionEnd
943 )";
944 
945   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
946 }
947 
TEST_F(EliminateDeadMemberTest,RemoveMemberPtrAccessChain)948 TEST_F(EliminateDeadMemberTest, RemoveMemberPtrAccessChain) {
949   // Test that the member "y" is removed.
950   // Update OpMemberName for |y| and |z|.
951   // Update OpMemberDecorate for |y| and |z|.
952   // Update OpInboundsAccessChain for access to |z|.
953   const std::string text = R"(
954 ; CHECK: OpName
955 ; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
956 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
957 ; CHECK-NOT: OpMemberName
958 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
959 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 16
960 ; CHECK: %type__Globals = OpTypeStruct %float %float
961 ; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0
962 ; CHECK: OpPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_1 %uint_0
963 ; CHECK: OpPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_0 %uint_1
964                OpCapability Shader
965                OpCapability VariablePointersStorageBuffer
966                OpMemoryModel Logical GLSL450
967                OpEntryPoint Vertex %main "main"
968                OpSource HLSL 600
969                OpName %type__Globals "type.$Globals"
970                OpMemberName %type__Globals 0 "x"
971                OpMemberName %type__Globals 1 "y"
972                OpMemberName %type__Globals 2 "z"
973                OpName %_Globals "$Globals"
974                OpName %main "main"
975                OpDecorate %_Globals DescriptorSet 0
976                OpDecorate %_Globals Binding 0
977                OpMemberDecorate %type__Globals 0 Offset 0
978                OpMemberDecorate %type__Globals 1 Offset 4
979                OpMemberDecorate %type__Globals 2 Offset 16
980                OpDecorate %type__Globals Block
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