• 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          %11 = OpLoad %type__Globals %_Globals
580          %12 = OpArrayLength %uint %_Globals 2
581                OpReturn
582                OpFunctionEnd
583 )";
584 
585   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
586 }
587 
TEST_F(EliminateDeadMemberTest,KeepMembersOpStore)588 TEST_F(EliminateDeadMemberTest, KeepMembersOpStore) {
589   // Test that all members are kept because of an OpStore.
590   // No change expected.
591   const std::string text = R"(
592                OpCapability Shader
593                OpMemoryModel Logical GLSL450
594                OpEntryPoint Vertex %main "main"
595                OpSource HLSL 600
596                OpName %type__Globals "type.$Globals"
597                OpMemberName %type__Globals 0 "x"
598                OpMemberName %type__Globals 1 "y"
599                OpMemberName %type__Globals 2 "z"
600                OpName %_Globals "$Globals"
601                OpName %_Globals "$Globals2"
602                OpName %main "main"
603                OpDecorate %_Globals DescriptorSet 0
604                OpDecorate %_Globals Binding 0
605                OpMemberDecorate %type__Globals 0 Offset 0
606                OpMemberDecorate %type__Globals 1 Offset 4
607                OpMemberDecorate %type__Globals 2 Offset 16
608                OpDecorate %type__Globals Block
609        %uint = OpTypeInt 32 0
610       %float = OpTypeFloat 32
611 %type__Globals = OpTypeStruct %float %float %float
612 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
613        %void = OpTypeVoid
614           %9 = OpTypeFunction %void
615    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
616    %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
617        %main = OpFunction %void None %9
618          %10 = OpLabel
619          %11 = OpLoad %type__Globals %_Globals
620                OpStore %_Globals2 %11
621                OpReturn
622                OpFunctionEnd
623 )";
624 
625   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
626       text, /* skip_nop = */ true, /* do_validation = */ true);
627   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
628 }
629 
TEST_F(EliminateDeadMemberTest,KeepMembersOpCopyMemory)630 TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemory) {
631   // Test that all members are kept because of an OpCopyMemory.
632   // No change expected.
633   const std::string text = R"(
634                OpCapability Shader
635                OpMemoryModel Logical GLSL450
636                OpEntryPoint Vertex %main "main"
637                OpSource HLSL 600
638                OpName %type__Globals "type.$Globals"
639                OpMemberName %type__Globals 0 "x"
640                OpMemberName %type__Globals 1 "y"
641                OpMemberName %type__Globals 2 "z"
642                OpName %_Globals "$Globals"
643                OpName %_Globals "$Globals2"
644                OpName %main "main"
645                OpDecorate %_Globals DescriptorSet 0
646                OpDecorate %_Globals Binding 0
647                OpMemberDecorate %type__Globals 0 Offset 0
648                OpMemberDecorate %type__Globals 1 Offset 4
649                OpMemberDecorate %type__Globals 2 Offset 16
650                OpDecorate %type__Globals Block
651        %uint = OpTypeInt 32 0
652       %float = OpTypeFloat 32
653 %type__Globals = OpTypeStruct %float %float %float
654 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
655        %void = OpTypeVoid
656           %9 = OpTypeFunction %void
657    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
658    %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
659        %main = OpFunction %void None %9
660          %10 = OpLabel
661                OpCopyMemory %_Globals2 %_Globals
662                OpReturn
663                OpFunctionEnd
664 )";
665 
666   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
667       text, /* skip_nop = */ true, /* do_validation = */ true);
668   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
669 }
670 
TEST_F(EliminateDeadMemberTest,KeepMembersOpCopyMemorySized)671 TEST_F(EliminateDeadMemberTest, KeepMembersOpCopyMemorySized) {
672   // Test that all members are kept because of an OpCopyMemorySized.
673   // No change expected.
674   const std::string text = R"(
675                OpCapability Shader
676                OpCapability Addresses
677                OpMemoryModel Logical GLSL450
678                OpEntryPoint Vertex %main "main"
679                OpSource HLSL 600
680                OpName %type__Globals "type.$Globals"
681                OpMemberName %type__Globals 0 "x"
682                OpMemberName %type__Globals 1 "y"
683                OpMemberName %type__Globals 2 "z"
684                OpName %_Globals "$Globals"
685                OpName %_Globals "$Globals2"
686                OpName %main "main"
687                OpDecorate %_Globals DescriptorSet 0
688                OpDecorate %_Globals Binding 0
689                OpMemberDecorate %type__Globals 0 Offset 0
690                OpMemberDecorate %type__Globals 1 Offset 4
691                OpMemberDecorate %type__Globals 2 Offset 16
692                OpDecorate %type__Globals Block
693        %uint = OpTypeInt 32 0
694     %uint_20 = OpConstant %uint 20
695       %float = OpTypeFloat 32
696 %type__Globals = OpTypeStruct %float %float %float
697 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
698        %void = OpTypeVoid
699           %9 = OpTypeFunction %void
700    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
701    %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
702        %main = OpFunction %void None %9
703          %10 = OpLabel
704                OpCopyMemorySized %_Globals2 %_Globals %uint_20
705                OpReturn
706                OpFunctionEnd
707 )";
708 
709   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
710       text, /* skip_nop = */ true, /* do_validation = */ true);
711   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
712 }
713 
TEST_F(EliminateDeadMemberTest,KeepMembersOpReturnValue)714 TEST_F(EliminateDeadMemberTest, KeepMembersOpReturnValue) {
715   // Test that all members are kept because of an OpCopyMemorySized.
716   // No change expected.
717   const std::string text = R"(
718                OpCapability Shader
719                OpCapability Linkage
720                OpMemoryModel Logical GLSL450
721                OpSource HLSL 600
722                OpName %type__Globals "type.$Globals"
723                OpMemberName %type__Globals 0 "x"
724                OpMemberName %type__Globals 1 "y"
725                OpMemberName %type__Globals 2 "z"
726                OpName %_Globals "$Globals"
727                OpName %_Globals "$Globals2"
728                OpName %main "main"
729                OpDecorate %_Globals DescriptorSet 0
730                OpDecorate %_Globals Binding 0
731                OpMemberDecorate %type__Globals 0 Offset 0
732                OpMemberDecorate %type__Globals 1 Offset 4
733                OpMemberDecorate %type__Globals 2 Offset 16
734                OpDecorate %type__Globals Block
735        %uint = OpTypeInt 32 0
736     %uint_20 = OpConstant %uint 20
737       %float = OpTypeFloat 32
738 %type__Globals = OpTypeStruct %float %float %float
739 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
740        %void = OpTypeVoid
741           %9 = OpTypeFunction %type__Globals
742    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
743    %_Globals2 = OpVariable %_ptr_Uniform_type__Globals Uniform
744        %main = OpFunction %type__Globals None %9
745          %10 = OpLabel
746          %11 = OpLoad %type__Globals %_Globals
747                OpReturnValue %11
748                OpFunctionEnd
749 )";
750 
751   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
752       text, /* skip_nop = */ true, /* do_validation = */ true);
753   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
754 }
755 
TEST_F(EliminateDeadMemberTest,RemoveMemberAccessChainWithArrays)756 TEST_F(EliminateDeadMemberTest, RemoveMemberAccessChainWithArrays) {
757   // Leave only 1 member in each of the structs.
758   // Update OpMemberName, OpMemberDecorate, and OpAccessChain.
759   const std::string text = R"(
760 ; CHECK: OpName
761 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
762 ; CHECK-NOT: OpMemberName
763 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 16
764 ; CHECK: OpMemberDecorate [[struct:%\w+]] 0 Offset 4
765 ; CHECK: [[struct]] = OpTypeStruct %float
766 ; CHECK: [[array:%\w+]] = OpTypeArray [[struct]]
767 ; CHECK: %type__Globals = OpTypeStruct [[array]]
768 ; CHECK: [[undef:%\w+]] = OpUndef %uint
769 ; CHECK: OpAccessChain %_ptr_Uniform_float %_Globals [[undef]] %uint_0 [[undef]] %uint_0
770                OpCapability Shader
771                OpCapability VariablePointersStorageBuffer
772                OpMemoryModel Logical GLSL450
773                OpEntryPoint Vertex %main "main"
774                OpSource HLSL 600
775                OpName %type__Globals "type.$Globals"
776                OpMemberName %type__Globals 0 "x"
777                OpMemberName %type__Globals 1 "y"
778                OpMemberName %type__Globals 2 "z"
779                OpName %_Globals "$Globals"
780                OpName %main "main"
781                OpDecorate %_Globals DescriptorSet 0
782                OpDecorate %_Globals Binding 0
783                OpMemberDecorate %type__Globals 0 Offset 0
784                OpMemberDecorate %type__Globals 1 Offset 16
785                OpMemberDecorate %type__Globals 2 Offset 48
786                OpMemberDecorate %_struct_4 0 Offset 0
787                OpMemberDecorate %_struct_4 1 Offset 4
788                OpDecorate %_arr__struct_4_uint_2 ArrayStride 16
789                OpDecorate %type__Globals Block
790        %uint = OpTypeInt 32 0
791      %uint_0 = OpConstant %uint 0
792      %uint_1 = OpConstant %uint 1
793      %uint_2 = OpConstant %uint 2
794      %uint_3 = OpConstant %uint 3
795       %float = OpTypeFloat 32
796   %_struct_4 = OpTypeStruct %float %float
797 %_arr__struct_4_uint_2 = OpTypeArray %_struct_4 %uint_2
798 %type__Globals = OpTypeStruct %float %_arr__struct_4_uint_2 %float
799 %_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3
800 %_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3
801        %void = OpTypeVoid
802          %15 = OpTypeFunction %void
803 %_ptr_Uniform_float = OpTypePointer Uniform %float
804    %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform
805        %main = OpFunction %void None %15
806          %17 = OpLabel
807          %18 = OpUndef %uint
808          %19 = OpAccessChain %_ptr_Uniform_float %_Globals %18 %uint_1 %18 %uint_1
809                OpReturn
810                OpFunctionEnd
811 )";
812 
813   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
814 }
815 
TEST_F(EliminateDeadMemberTest,RemoveMemberInboundsAccessChain)816 TEST_F(EliminateDeadMemberTest, RemoveMemberInboundsAccessChain) {
817   // Test that the member "y" is removed.
818   // Update OpMemberName for |y| and |z|.
819   // Update OpMemberDecorate for |y| and |z|.
820   // Update OpInboundsAccessChain for access to |z|.
821   const std::string text = R"(
822 ; CHECK: OpName
823 ; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
824 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
825 ; CHECK-NOT: OpMemberName
826 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
827 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 8
828 ; CHECK: %type__Globals = OpTypeStruct %float %float
829 ; CHECK: OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_0
830 ; CHECK: OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %uint_1
831                OpCapability Shader
832                OpMemoryModel Logical GLSL450
833                OpEntryPoint Vertex %main "main" %in_var_Position %gl_Position
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 %in_var_Position "in.var.Position"
841                OpName %main "main"
842                OpDecorate %gl_Position BuiltIn Position
843                OpDecorate %in_var_Position Location 0
844                OpDecorate %_Globals DescriptorSet 0
845                OpDecorate %_Globals Binding 0
846                OpMemberDecorate %type__Globals 0 Offset 0
847                OpMemberDecorate %type__Globals 1 Offset 4
848                OpMemberDecorate %type__Globals 2 Offset 8
849                OpDecorate %type__Globals Block
850         %int = OpTypeInt 32 1
851       %int_0 = OpConstant %int 0
852       %float = OpTypeFloat 32
853       %int_2 = OpConstant %int 2
854 %type__Globals = OpTypeStruct %float %float %float
855 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
856     %v4float = OpTypeVector %float 4
857 %_ptr_Input_v4float = OpTypePointer Input %v4float
858 %_ptr_Output_v4float = OpTypePointer Output %v4float
859        %void = OpTypeVoid
860          %15 = OpTypeFunction %void
861 %_ptr_Uniform_float = OpTypePointer Uniform %float
862    %_Globals = OpVariable %_ptr_Uniform_type__Globals Uniform
863 %in_var_Position = OpVariable %_ptr_Input_v4float Input
864 %gl_Position = OpVariable %_ptr_Output_v4float Output
865        %main = OpFunction %void None %15
866          %17 = OpLabel
867          %18 = OpLoad %v4float %in_var_Position
868          %19 = OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_0
869          %20 = OpLoad %float %19
870          %21 = OpCompositeExtract %float %18 0
871          %22 = OpFAdd %float %21 %20
872          %23 = OpCompositeInsert %v4float %22 %18 0
873          %24 = OpCompositeExtract %float %18 1
874          %25 = OpCompositeInsert %v4float %24 %23 1
875          %26 = OpInBoundsAccessChain %_ptr_Uniform_float %_Globals %int_2
876          %27 = OpLoad %float %26
877          %28 = OpCompositeExtract %float %18 2
878          %29 = OpFAdd %float %28 %27
879          %30 = OpCompositeInsert %v4float %29 %25 2
880                OpStore %gl_Position %30
881                OpReturn
882                OpFunctionEnd
883 )";
884 
885   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
886 }
887 
TEST_F(EliminateDeadMemberTest,RemoveMemberPtrAccessChain)888 TEST_F(EliminateDeadMemberTest, RemoveMemberPtrAccessChain) {
889   // Test that the member "y" is removed.
890   // Update OpMemberName for |y| and |z|.
891   // Update OpMemberDecorate for |y| and |z|.
892   // Update OpInboundsAccessChain for access to |z|.
893   const std::string text = R"(
894 ; CHECK: OpName
895 ; CHECK-NEXT: OpMemberName %type__Globals 0 "x"
896 ; CHECK-NEXT: OpMemberName %type__Globals 1 "z"
897 ; CHECK-NOT: OpMemberName
898 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 0
899 ; CHECK: OpMemberDecorate %type__Globals 1 Offset 16
900 ; CHECK: %type__Globals = OpTypeStruct %float %float
901 ; CHECK: [[ac:%\w+]] = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0
902 ; CHECK: OpPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_1 %uint_0
903 ; CHECK: OpPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_0 %uint_1
904                OpCapability Shader
905                OpCapability VariablePointersStorageBuffer
906                OpMemoryModel Logical GLSL450
907                OpEntryPoint Vertex %main "main"
908                OpSource HLSL 600
909                OpName %type__Globals "type.$Globals"
910                OpMemberName %type__Globals 0 "x"
911                OpMemberName %type__Globals 1 "y"
912                OpMemberName %type__Globals 2 "z"
913                OpName %_Globals "$Globals"
914                OpName %main "main"
915                OpDecorate %_Globals DescriptorSet 0
916                OpDecorate %_Globals Binding 0
917                OpMemberDecorate %type__Globals 0 Offset 0
918                OpMemberDecorate %type__Globals 1 Offset 4
919                OpMemberDecorate %type__Globals 2 Offset 16
920                OpDecorate %type__Globals Block
921        %uint = OpTypeInt 32 0
922      %uint_0 = OpConstant %uint 0
923      %uint_1 = OpConstant %uint 1
924      %uint_2 = OpConstant %uint 2
925      %uint_3 = OpConstant %uint 3
926       %float = OpTypeFloat 32
927 %type__Globals = OpTypeStruct %float %float %float
928 %_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3
929 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
930 %_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3
931        %void = OpTypeVoid
932          %14 = OpTypeFunction %void
933 %_ptr_Uniform_float = OpTypePointer Uniform %float
934    %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform
935        %main = OpFunction %void None %14
936          %16 = OpLabel
937          %17 = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0
938          %18 = OpPtrAccessChain %_ptr_Uniform_float %17 %uint_1 %uint_0
939          %19 = OpPtrAccessChain %_ptr_Uniform_float %17 %uint_0 %uint_2
940                OpReturn
941                OpFunctionEnd
942 )";
943 
944   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
945 }
946 
TEST_F(EliminateDeadMemberTest,RemoveMemberInBoundsPtrAccessChain)947 TEST_F(EliminateDeadMemberTest, RemoveMemberInBoundsPtrAccessChain) {
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: OpInBoundsPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_1 %uint_0
962 ; CHECK: OpInBoundsPtrAccessChain %_ptr_Uniform_float [[ac]] %uint_0 %uint_1
963                OpCapability Shader
964                OpCapability Addresses
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        %uint = OpTypeInt 32 0
981      %uint_0 = OpConstant %uint 0
982      %uint_1 = OpConstant %uint 1
983      %uint_2 = OpConstant %uint 2
984      %uint_3 = OpConstant %uint 3
985       %float = OpTypeFloat 32
986 %type__Globals = OpTypeStruct %float %float %float
987 %_arr_type__Globals_uint_3 = OpTypeArray %type__Globals %uint_3
988 %_ptr_Uniform_type__Globals = OpTypePointer Uniform %type__Globals
989 %_ptr_Uniform__arr_type__Globals_uint_3 = OpTypePointer Uniform %_arr_type__Globals_uint_3
990        %void = OpTypeVoid
991          %14 = OpTypeFunction %void
992 %_ptr_Uniform_float = OpTypePointer Uniform %float
993    %_Globals = OpVariable %_ptr_Uniform__arr_type__Globals_uint_3 Uniform
994        %main = OpFunction %void None %14
995          %16 = OpLabel
996          %17 = OpAccessChain %_ptr_Uniform_type__Globals %_Globals %uint_0
997          %18 = OpInBoundsPtrAccessChain %_ptr_Uniform_float %17 %uint_1 %uint_0
998          %19 = OpInBoundsPtrAccessChain %_ptr_Uniform_float %17 %uint_0 %uint_2
999                OpReturn
1000                OpFunctionEnd
1001 )";
1002 
1003   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
1004 }
1005 
TEST_F(EliminateDeadMemberTest,DontRemoveModfStructResultTypeMembers)1006 TEST_F(EliminateDeadMemberTest, DontRemoveModfStructResultTypeMembers) {
1007   const std::string text = R"(
1008                OpCapability Shader
1009           %1 = OpExtInstImport "GLSL.std.450"
1010                OpMemoryModel Logical GLSL450
1011                OpEntryPoint Fragment %main "main"
1012                OpExecutionMode %main OriginUpperLeft
1013                OpSource HLSL 600
1014       %float = OpTypeFloat 32
1015        %void = OpTypeVoid
1016          %21 = OpTypeFunction %void
1017 %ModfStructType = OpTypeStruct %float %float
1018 %main = OpFunction %void None %21
1019          %22 = OpLabel
1020          %23 = OpUndef %float
1021          %24 = OpExtInst %ModfStructType %1 ModfStruct %23
1022          %25 = OpCompositeExtract %float %24 1
1023                OpReturn
1024                OpFunctionEnd
1025 )";
1026 
1027   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
1028       text, /* skip_nop = */ true, /* do_validation = */ true);
1029   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
1030 }
1031 
TEST_F(EliminateDeadMemberTest,DontChangeInputStructs)1032 TEST_F(EliminateDeadMemberTest, DontChangeInputStructs) {
1033   // The input for a shader has to match the type of the output from the
1034   // previous shader in the pipeline.  Because of that, we cannot change the
1035   // types of input variables.
1036   const std::string text = R"(
1037                OpCapability Shader
1038           %1 = OpExtInstImport "GLSL.std.450"
1039                OpMemoryModel Logical GLSL450
1040                OpEntryPoint Fragment %main "main" %input_var
1041                OpExecutionMode %main OriginUpperLeft
1042                OpSource HLSL 600
1043       %float = OpTypeFloat 32
1044        %void = OpTypeVoid
1045          %21 = OpTypeFunction %void
1046 %in_var_type = OpTypeStruct %float %float
1047 %in_ptr_type = OpTypePointer Input %in_var_type
1048 %input_var = OpVariable %in_ptr_type Input
1049 %main = OpFunction %void None %21
1050          %22 = OpLabel
1051                OpReturn
1052                OpFunctionEnd
1053 )";
1054 
1055   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
1056       text, /* skip_nop = */ true, /* do_validation = */ true);
1057   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
1058 }
1059 
TEST_F(EliminateDeadMemberTest,DontChangeOutputStructs)1060 TEST_F(EliminateDeadMemberTest, DontChangeOutputStructs) {
1061   // The output for a shader has to match the type of the output from the
1062   // previous shader in the pipeline.  Because of that, we cannot change the
1063   // types of output variables.
1064   const std::string text = R"(
1065                OpCapability Shader
1066           %1 = OpExtInstImport "GLSL.std.450"
1067                OpMemoryModel Logical GLSL450
1068                OpEntryPoint Fragment %main "main" %output_var
1069                OpExecutionMode %main OriginUpperLeft
1070                OpSource HLSL 600
1071       %float = OpTypeFloat 32
1072        %void = OpTypeVoid
1073          %21 = OpTypeFunction %void
1074 %out_var_type = OpTypeStruct %float %float
1075 %out_ptr_type = OpTypePointer Output %out_var_type
1076 %output_var = OpVariable %out_ptr_type Output
1077 %main = OpFunction %void None %21
1078          %22 = OpLabel
1079                OpReturn
1080                OpFunctionEnd
1081 )";
1082 
1083   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
1084       text, /* skip_nop = */ true, /* do_validation = */ true);
1085   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
1086 }
1087 
TEST_F(EliminateDeadMemberTest,UpdateSpecConstOpExtract)1088 TEST_F(EliminateDeadMemberTest, UpdateSpecConstOpExtract) {
1089   // Test that an extract in an OpSpecConstantOp is correctly updated.
1090   const std::string text = R"(
1091 ; CHECK: OpName
1092 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
1093 ; CHECK-NOT: OpMemberName
1094 ; CHECK: OpDecorate [[spec_const:%\w+]] SpecId 1
1095 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
1096 ; CHECK: %type__Globals = OpTypeStruct %uint
1097 ; CHECK: [[struct:%\w+]] = OpSpecConstantComposite %type__Globals [[spec_const]]
1098 ; CHECK: OpSpecConstantOp %uint CompositeExtract [[struct]] 0
1099                OpCapability Shader
1100                OpCapability Addresses
1101                OpMemoryModel Logical GLSL450
1102                OpEntryPoint Vertex %main "main"
1103                OpSource HLSL 600
1104                OpName %type__Globals "type.$Globals"
1105                OpMemberName %type__Globals 0 "x"
1106                OpMemberName %type__Globals 1 "y"
1107                OpMemberName %type__Globals 2 "z"
1108                OpName %main "main"
1109                OpDecorate %c_0 SpecId 0
1110                OpDecorate %c_1 SpecId 1
1111                OpDecorate %c_2 SpecId 2
1112                OpMemberDecorate %type__Globals 0 Offset 0
1113                OpMemberDecorate %type__Globals 1 Offset 4
1114                OpMemberDecorate %type__Globals 2 Offset 16
1115        %uint = OpTypeInt 32 0
1116         %c_0 = OpSpecConstant %uint 0
1117         %c_1 = OpSpecConstant %uint 1
1118         %c_2 = OpSpecConstant %uint 2
1119      %uint_0 = OpConstant %uint 0
1120      %uint_1 = OpConstant %uint 1
1121      %uint_2 = OpConstant %uint 2
1122      %uint_3 = OpConstant %uint 3
1123 %type__Globals = OpTypeStruct %uint %uint %uint
1124 %spec_const_global = OpSpecConstantComposite %type__Globals %c_0 %c_1 %c_2
1125 %extract = OpSpecConstantOp %uint CompositeExtract %spec_const_global 1
1126        %void = OpTypeVoid
1127          %14 = OpTypeFunction %void
1128        %main = OpFunction %void None %14
1129          %16 = OpLabel
1130                OpReturn
1131                OpFunctionEnd
1132 )";
1133 
1134   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
1135 }
1136 
TEST_F(EliminateDeadMemberTest,UpdateSpecConstOpInsert)1137 TEST_F(EliminateDeadMemberTest, UpdateSpecConstOpInsert) {
1138   // Test that an insert in an OpSpecConstantOp is correctly updated.
1139   const std::string text = R"(
1140 ; CHECK: OpName
1141 ; CHECK-NEXT: OpMemberName %type__Globals 0 "y"
1142 ; CHECK-NOT: OpMemberName
1143 ; CHECK: OpDecorate [[spec_const:%\w+]] SpecId 1
1144 ; CHECK: OpMemberDecorate %type__Globals 0 Offset 4
1145 ; CHECK: %type__Globals = OpTypeStruct %uint
1146 ; CHECK: [[struct:%\w+]] = OpSpecConstantComposite %type__Globals [[spec_const]]
1147 ; CHECK: OpSpecConstantOp %type__Globals CompositeInsert %uint_3 [[struct]] 0
1148                OpCapability Shader
1149                OpCapability Addresses
1150                OpMemoryModel Logical GLSL450
1151                OpEntryPoint Vertex %main "main"
1152                OpSource HLSL 600
1153                OpName %type__Globals "type.$Globals"
1154                OpMemberName %type__Globals 0 "x"
1155                OpMemberName %type__Globals 1 "y"
1156                OpMemberName %type__Globals 2 "z"
1157                OpName %main "main"
1158                OpDecorate %c_0 SpecId 0
1159                OpDecorate %c_1 SpecId 1
1160                OpDecorate %c_2 SpecId 2
1161                OpMemberDecorate %type__Globals 0 Offset 0
1162                OpMemberDecorate %type__Globals 1 Offset 4
1163                OpMemberDecorate %type__Globals 2 Offset 16
1164        %uint = OpTypeInt 32 0
1165         %c_0 = OpSpecConstant %uint 0
1166         %c_1 = OpSpecConstant %uint 1
1167         %c_2 = OpSpecConstant %uint 2
1168      %uint_0 = OpConstant %uint 0
1169      %uint_1 = OpConstant %uint 1
1170      %uint_2 = OpConstant %uint 2
1171      %uint_3 = OpConstant %uint 3
1172 %type__Globals = OpTypeStruct %uint %uint %uint
1173 %spec_const_global = OpSpecConstantComposite %type__Globals %c_0 %c_1 %c_2
1174 %insert = OpSpecConstantOp %type__Globals CompositeInsert %uint_3 %spec_const_global 1
1175 %extract = OpSpecConstantOp %uint CompositeExtract %insert 1
1176        %void = OpTypeVoid
1177          %14 = OpTypeFunction %void
1178        %main = OpFunction %void None %14
1179          %16 = OpLabel
1180                OpReturn
1181                OpFunctionEnd
1182 )";
1183 
1184   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
1185 }
1186 
1187 TEST_F(EliminateDeadMemberTest, 8BitIndexNoChange) {
1188   // Test that the pass does not crash when an 8 bit index is used in an
1189   // OpAccessChain. No change is expected.
1190   const std::string text = R"(
1191                OpCapability ImageQuery
1192                OpCapability Int8
1193                OpMemoryModel Logical GLSL450
1194                OpEntryPoint Fragment %1 "OpnSeman/" %2
1195                OpExecutionMode %1 OriginUpperLeft
1196        %void = OpTypeVoid
1197           %4 = OpTypeFunction %void
1198       %float = OpTypeFloat 32
1199     %v4float = OpTypeVector %float 4
1200   %_struct_7 = OpTypeStruct %v4float
1201 %_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
1202 %_ptr_Output_v4float = OpTypePointer Output %v4float
1203          %10 = OpTypeFunction %v4float %_ptr_Function__struct_7
1204        %char = OpTypeInt 8 1
1205      %char_0 = OpConstant %char 0
1206 %_ptr_Function_v4float = OpTypePointer Function %v4float
1207           %2 = OpVariable %_ptr_Output_v4float Output
1208           %1 = OpFunction %void None %4
1209          %14 = OpLabel
1210          %15 = OpVariable %_ptr_Function__struct_7 Function
1211          %16 = OpFunctionCall %v4float %17 %15
1212                OpReturn
1213                OpFunctionEnd
1214          %17 = OpFunction %v4float DontInline %10
1215          %18 = OpFunctionParameter %_ptr_Function__struct_7
1216          %19 = OpLabel
1217          %20 = OpAccessChain %_ptr_Function_v4float %18 %char_0
1218          %21 = OpLoad %v4float %20
1219                OpReturnValue %21
1220                OpFunctionEnd
1221 )";
1222 
1223   auto result = SinglePassRunAndDisassemble<opt::EliminateDeadMembersPass>(
1224       text, /* skip_nop = */ true, /* do_validation = */ true);
1225   EXPECT_EQ(opt::Pass::Status::SuccessWithoutChange, std::get<1>(result));
1226 }
1227 
1228 TEST_F(EliminateDeadMemberTest, 8BitIndexWithChange) {
1229   // Test that the pass does not crash when an 8 bit index is used in an
1230   // OpAccessChain. The index in the access change should be changed to 0.
1231   const std::string text = R"(
1232                OpCapability ImageQuery
1233                OpCapability Int8
1234                OpMemoryModel Logical GLSL450
1235                OpEntryPoint Fragment %1 "OpnSeman/" %2
1236                OpExecutionMode %1 OriginUpperLeft
1237        %void = OpTypeVoid
1238           %4 = OpTypeFunction %void
1239       %float = OpTypeFloat 32
1240     %v4float = OpTypeVector %float 4
1241   %_struct_7 = OpTypeStruct %v4float %v4float
1242 %_ptr_Function__struct_7 = OpTypePointer Function %_struct_7
1243 %_ptr_Output_v4float = OpTypePointer Output %v4float
1244          %10 = OpTypeFunction %v4float %_ptr_Function__struct_7
1245        %char = OpTypeInt 8 1
1246      %char_1 = OpConstant %char 1
1247 %_ptr_Function_v4float = OpTypePointer Function %v4float
1248           %2 = OpVariable %_ptr_Output_v4float Output
1249           %1 = OpFunction %void None %4
1250          %14 = OpLabel
1251          %15 = OpVariable %_ptr_Function__struct_7 Function
1252          %16 = OpFunctionCall %v4float %17 %15
1253                OpReturn
1254                OpFunctionEnd
1255          %17 = OpFunction %v4float DontInline %10
1256 ; CHECK: [[param:%\w+]] = OpFunctionParameter
1257          %18 = OpFunctionParameter %_ptr_Function__struct_7
1258          %19 = OpLabel
1259 ; CHECK: OpAccessChain %_ptr_Function_v4float [[param]] %uint_0
1260          %20 = OpAccessChain %_ptr_Function_v4float %18 %char_1
1261          %21 = OpLoad %v4float %20
1262                OpReturnValue %21
1263                OpFunctionEnd
1264 )";
1265 
1266   SinglePassRunAndMatch<opt::EliminateDeadMembersPass>(text, true);
1267 }
1268 
1269 }  // namespace
1270