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