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