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