1// Copyright (c) 2017 Google Inc.
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 <string>
16#include <vector>
17
18#include "gmock/gmock.h"
19#include "test/opt/assembly_builder.h"
20#include "test/opt/pass_fixture.h"
21#include "test/opt/pass_utils.h"
22
23namespace spvtools {
24namespace opt {
25namespace {
26
27using ::testing::HasSubstr;
28using EliminateDeadFunctionsBasicTest = PassTest<::testing::Test>;
29
30TEST_F(EliminateDeadFunctionsBasicTest, BasicDeleteDeadFunction) {
31  // The function Dead should be removed because it is never called.
32  const std::vector<const char*> common_code = {
33      // clang-format off
34               "OpCapability Shader",
35               "OpMemoryModel Logical GLSL450",
36               "OpEntryPoint Fragment %main \"main\"",
37               "OpName %main \"main\"",
38               "OpName %Live \"Live\"",
39       "%void = OpTypeVoid",
40          "%7 = OpTypeFunction %void",
41       "%main = OpFunction %void None %7",
42         "%15 = OpLabel",
43         "%16 = OpFunctionCall %void %Live",
44         "%17 = OpFunctionCall %void %Live",
45               "OpReturn",
46               "OpFunctionEnd",
47  "%Live = OpFunction %void None %7",
48         "%20 = OpLabel",
49               "OpReturn",
50               "OpFunctionEnd"
51      // clang-format on
52  };
53
54  const std::vector<const char*> dead_function = {
55      // clang-format off
56      "%Dead = OpFunction %void None %7",
57         "%19 = OpLabel",
58               "OpReturn",
59               "OpFunctionEnd",
60      // clang-format on
61  };
62
63  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
64  SinglePassRunAndCheck<EliminateDeadFunctionsPass>(
65      JoinAllInsts(Concat(common_code, dead_function)),
66      JoinAllInsts(common_code), /* skip_nop = */ true);
67}
68
69TEST_F(EliminateDeadFunctionsBasicTest, BasicKeepLiveFunction) {
70  // Everything is reachable from an entry point, so no functions should be
71  // deleted.
72  const std::vector<const char*> text = {
73      // clang-format off
74               "OpCapability Shader",
75               "OpMemoryModel Logical GLSL450",
76               "OpEntryPoint Fragment %main \"main\"",
77               "OpName %main \"main\"",
78               "OpName %Live1 \"Live1\"",
79               "OpName %Live2 \"Live2\"",
80       "%void = OpTypeVoid",
81          "%7 = OpTypeFunction %void",
82       "%main = OpFunction %void None %7",
83         "%15 = OpLabel",
84         "%16 = OpFunctionCall %void %Live2",
85         "%17 = OpFunctionCall %void %Live1",
86               "OpReturn",
87               "OpFunctionEnd",
88      "%Live1 = OpFunction %void None %7",
89         "%19 = OpLabel",
90               "OpReturn",
91               "OpFunctionEnd",
92      "%Live2 = OpFunction %void None %7",
93         "%20 = OpLabel",
94               "OpReturn",
95               "OpFunctionEnd"
96      // clang-format on
97  };
98
99  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
100  std::string assembly = JoinAllInsts(text);
101  auto result = SinglePassRunAndDisassemble<EliminateDeadFunctionsPass>(
102      assembly, /* skip_nop = */ true, /* do_validation = */ false);
103  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
104  EXPECT_EQ(assembly, std::get<0>(result));
105}
106
107TEST_F(EliminateDeadFunctionsBasicTest, BasicKeepExportFunctions) {
108  // All functions are reachable.  In particular, ExportedFunc and Constant are
109  // reachable because ExportedFunc is exported.  Nothing should be removed.
110  const std::vector<const char*> text = {
111      // clang-format off
112               "OpCapability Shader",
113               "OpCapability Linkage",
114               "OpMemoryModel Logical GLSL450",
115               "OpEntryPoint Fragment %main \"main\"",
116               "OpName %main \"main\"",
117               "OpName %ExportedFunc \"ExportedFunc\"",
118               "OpName %Live \"Live\"",
119               "OpDecorate %ExportedFunc LinkageAttributes \"ExportedFunc\" Export",
120       "%void = OpTypeVoid",
121          "%7 = OpTypeFunction %void",
122       "%main = OpFunction %void None %7",
123         "%15 = OpLabel",
124               "OpReturn",
125               "OpFunctionEnd",
126"%ExportedFunc = OpFunction %void None %7",
127         "%19 = OpLabel",
128         "%16 = OpFunctionCall %void %Live",
129               "OpReturn",
130               "OpFunctionEnd",
131  "%Live = OpFunction %void None %7",
132         "%20 = OpLabel",
133               "OpReturn",
134               "OpFunctionEnd"
135      // clang-format on
136  };
137
138  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
139  std::string assembly = JoinAllInsts(text);
140  auto result = SinglePassRunAndDisassemble<EliminateDeadFunctionsPass>(
141      assembly, /* skip_nop = */ true, /* do_validation = */ false);
142  EXPECT_EQ(Pass::Status::SuccessWithoutChange, std::get<1>(result));
143  EXPECT_EQ(assembly, std::get<0>(result));
144}
145
146TEST_F(EliminateDeadFunctionsBasicTest, BasicRemoveDecorationsAndNames) {
147  // We want to remove the names and decorations associated with results that
148  // are removed.  This test will check for that.
149  const std::string text = R"(
150               OpCapability Shader
151               OpMemoryModel Logical GLSL450
152               OpEntryPoint Vertex %main "main"
153               OpName %main "main"
154               OpName %Dead "Dead"
155               OpName %x "x"
156               OpName %y "y"
157               OpName %z "z"
158               OpDecorate %x RelaxedPrecision
159               OpDecorate %y RelaxedPrecision
160               OpDecorate %z RelaxedPrecision
161               OpDecorate %6 RelaxedPrecision
162               OpDecorate %7 RelaxedPrecision
163               OpDecorate %8 RelaxedPrecision
164       %void = OpTypeVoid
165         %10 = OpTypeFunction %void
166      %float = OpTypeFloat 32
167%_ptr_Function_float = OpTypePointer Function %float
168    %float_1 = OpConstant %float 1
169       %main = OpFunction %void None %10
170         %14 = OpLabel
171               OpReturn
172               OpFunctionEnd
173       %Dead = OpFunction %void None %10
174         %15 = OpLabel
175          %x = OpVariable %_ptr_Function_float Function
176          %y = OpVariable %_ptr_Function_float Function
177          %z = OpVariable %_ptr_Function_float Function
178               OpStore %x %float_1
179               OpStore %y %float_1
180          %6 = OpLoad %float %x
181          %7 = OpLoad %float %y
182          %8 = OpFAdd %float %6 %7
183               OpStore %z %8
184               OpReturn
185               OpFunctionEnd)";
186
187  const std::string expected_output = R"(OpCapability Shader
188OpMemoryModel Logical GLSL450
189OpEntryPoint Vertex %main "main"
190OpName %main "main"
191%void = OpTypeVoid
192%10 = OpTypeFunction %void
193%float = OpTypeFloat 32
194%_ptr_Function_float = OpTypePointer Function %float
195%float_1 = OpConstant %float 1
196%main = OpFunction %void None %10
197%14 = OpLabel
198OpReturn
199OpFunctionEnd
200)";
201
202  SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
203  SinglePassRunAndCheck<EliminateDeadFunctionsPass>(text, expected_output,
204                                                    /* skip_nop = */ true);
205}
206
207TEST_F(EliminateDeadFunctionsBasicTest, DebugRemoveFunctionFromDebugFunction) {
208  // We want to remove id of OpFunction from DebugFunction.
209  const std::string text = R"(OpCapability Shader
210%1 = OpExtInstImport "OpenCL.DebugInfo.100"
211OpMemoryModel Logical GLSL450
212OpEntryPoint Fragment %2 "main" %3 %4
213OpExecutionMode %2 OriginUpperLeft
214%5 = OpString "ps.hlsl"
215OpSource HLSL 600 %5 "float4 foo() {
216  return 1;
217}
218float4 main(float4 color : COLOR) : SV_TARGET {
219  return foo() + color;
220}
221"
222%6 = OpString "float"
223%7 = OpString "main"
224%8 = OpString "foo"
225; CHECK: [[foo:%\d+]] = OpString "foo"
226OpDecorate %3 Location 0
227OpDecorate %4 Location 0
228%uint = OpTypeInt 32 0
229%uint_32 = OpConstant %uint 32
230%float = OpTypeFloat 32
231%float_1 = OpConstant %float 1
232%v4float = OpTypeVector %float 4
233%14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
234%_ptr_Input_v4float = OpTypePointer Input %v4float
235%_ptr_Output_v4float = OpTypePointer Output %v4float
236%void = OpTypeVoid
237%18 = OpTypeFunction %void
238%19 = OpTypeFunction %v4float
239%3 = OpVariable %_ptr_Input_v4float Input
240%4 = OpVariable %_ptr_Output_v4float Output
241%_ptr_Function_v4float = OpTypePointer Function %v4float
242; CHECK: [[info_none:%\d+]] = OpExtInst %void %1 DebugInfoNone
243%20 = OpExtInst %void %1 DebugSource %5
244%21 = OpExtInst %void %1 DebugCompilationUnit 1 4 %20 HLSL
245%22 = OpExtInst %void %1 DebugTypeBasic %6 %uint_32 Float
246%23 = OpExtInst %void %1 DebugTypeVector %22 4
247%24 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %23 %23
248%25 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %23
249%26 = OpExtInst %void %1 DebugFunction %7 %24 %20 4 1 %21 %7 FlagIsProtected|FlagIsPrivate 4 %2
250%27 = OpExtInst %void %1 DebugFunction %8 %25 %20 1 1 %21 %8 FlagIsProtected|FlagIsPrivate 1 %28
251; CHECK: {{%\d+}} = OpExtInst %void %1 DebugFunction [[foo]] {{%\d+}} {{%\d+}} 1 1 {{%\d+}} {{%\d+}} FlagIsProtected|FlagIsPrivate 1 [[info_none]]
252%29 = OpExtInst %void %1 DebugLexicalBlock %20 1 14 %27
253%40 = OpExtInst %void %1 DebugInlinedAt 4 %26
254%2 = OpFunction %void None %18
255%30 = OpLabel
256%39 = OpVariable %_ptr_Function_v4float Function
257%41 = OpExtInst %void %1 DebugScope %27 %40
258OpStore %39 %14
259%32 = OpLoad %v4float %39
260%42 = OpExtInst %void %1 DebugScope %26
261%33 = OpLoad %v4float %3
262%34 = OpFAdd %v4float %32 %33
263OpStore %4 %34
264%43 = OpExtInst %void %1 DebugNoScope
265OpReturn
266OpFunctionEnd
267%28 = OpFunction %v4float None %19
268%36 = OpLabel
269OpReturnValue %14
270OpFunctionEnd
271)";
272
273  SinglePassRunAndMatch<EliminateDeadFunctionsPass>(text, false);
274}
275
276TEST_F(EliminateDeadFunctionsBasicTest,
277       DebugRemoveFunctionUsingExistingDebugInfoNone) {
278  // We want to remove id of OpFunction from DebugFunction.
279  const std::string text = R"(OpCapability Shader
280%1 = OpExtInstImport "OpenCL.DebugInfo.100"
281OpMemoryModel Logical GLSL450
282OpEntryPoint Fragment %2 "main" %3 %4
283OpExecutionMode %2 OriginUpperLeft
284%5 = OpString "ps.hlsl"
285OpSource HLSL 600 %5 "float4 foo() {
286  return 1;
287}
288float4 main(float4 color : COLOR) : SV_TARGET {
289  return foo() + color;
290}
291"
292%6 = OpString "float"
293%7 = OpString "main"
294%8 = OpString "foo"
295; CHECK: [[foo:%\d+]] = OpString "foo"
296OpDecorate %3 Location 0
297OpDecorate %4 Location 0
298%uint = OpTypeInt 32 0
299%uint_32 = OpConstant %uint 32
300%float = OpTypeFloat 32
301%float_1 = OpConstant %float 1
302%v4float = OpTypeVector %float 4
303%14 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
304%_ptr_Input_v4float = OpTypePointer Input %v4float
305%_ptr_Output_v4float = OpTypePointer Output %v4float
306%void = OpTypeVoid
307%18 = OpTypeFunction %void
308%19 = OpTypeFunction %v4float
309%3 = OpVariable %_ptr_Input_v4float Input
310%4 = OpVariable %_ptr_Output_v4float Output
311%_ptr_Function_v4float = OpTypePointer Function %v4float
312; CHECK: [[info_none:%\d+]] = OpExtInst %void %1 DebugInfoNone
313%20 = OpExtInst %void %1 DebugSource %5
314%21 = OpExtInst %void %1 DebugCompilationUnit 1 4 %20 HLSL
315%22 = OpExtInst %void %1 DebugTypeBasic %6 %uint_32 Float
316%23 = OpExtInst %void %1 DebugTypeVector %22 4
317%24 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %23 %23
318%25 = OpExtInst %void %1 DebugTypeFunction FlagIsProtected|FlagIsPrivate %23
319%26 = OpExtInst %void %1 DebugFunction %7 %24 %20 4 1 %21 %7 FlagIsProtected|FlagIsPrivate 4 %2
320%27 = OpExtInst %void %1 DebugFunction %8 %25 %20 1 1 %21 %8 FlagIsProtected|FlagIsPrivate 1 %28
321; CHECK: {{%\d+}} = OpExtInst %void %1 DebugFunction [[foo]] {{%\d+}} {{%\d+}} 1 1 {{%\d+}} {{%\d+}} FlagIsProtected|FlagIsPrivate 1 [[info_none]]
322%29 = OpExtInst %void %1 DebugLexicalBlock %20 1 14 %27
323%35 = OpExtInst %void %1 DebugInfoNone
324%40 = OpExtInst %void %1 DebugInlinedAt 4 %26
325%2 = OpFunction %void None %18
326%30 = OpLabel
327%39 = OpVariable %_ptr_Function_v4float Function
328%41 = OpExtInst %void %1 DebugScope %27 %40
329OpStore %39 %14
330%32 = OpLoad %v4float %39
331%42 = OpExtInst %void %1 DebugScope %26
332%33 = OpLoad %v4float %3
333%34 = OpFAdd %v4float %32 %33
334OpStore %4 %34
335%43 = OpExtInst %void %1 DebugNoScope
336OpReturn
337OpFunctionEnd
338%28 = OpFunction %v4float None %19
339%36 = OpLabel
340OpReturnValue %14
341OpFunctionEnd
342)";
343
344  SinglePassRunAndMatch<EliminateDeadFunctionsPass>(text, false);
345}
346
347TEST_F(EliminateDeadFunctionsBasicTest, NonSemanticInfoPersists) {
348  const std::string text = R"(
349; CHECK: [[import:%\w+]] = OpExtInstImport
350; CHECK: [[void:%\w+]] = OpTypeVoid
351; CHECK-NOT: OpExtInst [[void]] [[import]] 1
352; CHECK: OpExtInst [[void]] [[import]] 2
353OpCapability Shader
354OpExtension "SPV_KHR_non_semantic_info"
355%ext = OpExtInstImport "NonSemantic.Test"
356OpMemoryModel Logical GLSL450
357OpEntryPoint GLCompute %main "main"
358OpExecutionMode %main LocalSize 1 1 1
359%void = OpTypeVoid
360%void_fn = OpTypeFunction %void
361%main = OpFunction %void None %void_fn
362%entry = OpLabel
363OpReturn
364OpFunctionEnd
365%foo = OpFunction %void None %void_fn
366%foo_entry = OpLabel
367%non_semantic1 = OpExtInst %void %ext 1
368OpReturn
369OpFunctionEnd
370%non_semantic2 = OpExtInst %void %ext 2
371)";
372
373  SinglePassRunAndMatch<EliminateDeadFunctionsPass>(text, true);
374}
375
376TEST_F(EliminateDeadFunctionsBasicTest, NonSemanticInfoRemoveDependent) {
377  const std::string text = R"(
378; CHECK: [[import:%\w+]] = OpExtInstImport
379; CHECK: [[void:%\w+]] = OpTypeVoid
380; CHECK-NOT: OpExtInst [[void]] [[import]] 1
381; CHECK-NOT: OpExtInst [[void]] [[import]] 2
382; CHECK: OpExtInst [[void]] [[import]] 3
383OpCapability Shader
384OpExtension "SPV_KHR_non_semantic_info"
385%ext = OpExtInstImport "NonSemantic.Test"
386OpMemoryModel Logical GLSL450
387OpEntryPoint GLCompute %main "main"
388OpExecutionMode %main LocalSize 1 1 1
389%void = OpTypeVoid
390%void_fn = OpTypeFunction %void
391%main = OpFunction %void None %void_fn
392%entry = OpLabel
393OpReturn
394OpFunctionEnd
395%foo = OpFunction %void None %void_fn
396%foo_entry = OpLabel
397%non_semantic1 = OpExtInst %void %ext 1
398OpReturn
399OpFunctionEnd
400%non_semantic2 = OpExtInst %void %ext 2 %foo
401%non_semantic3 = OpExtInst %void %ext 3
402)";
403
404  SinglePassRunAndMatch<EliminateDeadFunctionsPass>(text, true);
405}
406
407TEST_F(EliminateDeadFunctionsBasicTest, NonSemanticInfoRemoveDependentTree) {
408  const std::string text = R"(
409; CHECK: [[import:%\w+]] = OpExtInstImport
410; CHECK: [[void:%\w+]] = OpTypeVoid
411; CHECK-NOT: OpExtInst [[void]] [[import]] 1
412; CHECK-NOT: OpExtInst [[void]] [[import]] 2
413; CHECK: OpExtInst [[void]] [[import]] 3
414; CHECK-NOT: OpExtInst [[void]] [[import]] 4
415; CHECK-NOT: OpExtInst [[void]] [[import]] 5
416OpCapability Shader
417OpExtension "SPV_KHR_non_semantic_info"
418%ext = OpExtInstImport "NonSemantic.Test"
419OpMemoryModel Logical GLSL450
420OpEntryPoint GLCompute %main "main"
421OpExecutionMode %main LocalSize 1 1 1
422%void = OpTypeVoid
423%void_fn = OpTypeFunction %void
424%main = OpFunction %void None %void_fn
425%entry = OpLabel
426OpReturn
427OpFunctionEnd
428%foo = OpFunction %void None %void_fn
429%foo_entry = OpLabel
430%non_semantic1 = OpExtInst %void %ext 1
431OpReturn
432OpFunctionEnd
433%non_semantic2 = OpExtInst %void %ext 2 %foo
434%non_semantic3 = OpExtInst %void %ext 3
435%non_semantic4 = OpExtInst %void %ext 4 %non_semantic2
436%non_semantic5 = OpExtInst %void %ext 5 %non_semantic4
437)";
438
439  SinglePassRunAndMatch<EliminateDeadFunctionsPass>(text, true);
440}
441
442TEST_F(EliminateDeadFunctionsBasicTest, NonSemanticInfoRemoveDebugPrintf) {
443  const std::string text = R"(
444; CHECK-NOT: %foo_ = OpFunction %void None % 3
445; CHECK-NOT: % 7 = OpLabel
446; CHECK-NOT: %c = OpVariable %_ptr_Function_v4float Function
447; CHECK-NOT: % 22 = OpAccessChain %_ptr_UniformConstant_13 %samplers %int_0
448; CHECK-NOT: % 23 = OpLoad % 13 % 22
449; CHECK-NOT: % 27 = OpImageSampleExplicitLod %v4float % 23 % 26 Lod %float_0
450; CHECK-NOT: OpStore %c % 27
451; CHECK-NOT: % 31 = OpAccessChain %_ptr_Function_float %c %uint_0
452; CHECK-NOT: % 32 = OpLoad %float %31
453; CHECK-NOT: % 34 = OpExtInst %void %33 1 % 28 % 32
454OpCapability RayTracingKHR
455OpExtension "SPV_KHR_non_semantic_info"
456OpExtension "SPV_KHR_ray_tracing"
457%1 = OpExtInstImport "GLSL.std.450"
458%33 = OpExtInstImport "NonSemantic.DebugPrintf"
459OpMemoryModel Logical GLSL450
460OpEntryPoint ClosestHitNV %main "main" %samplers
461%28 = OpString "%f"
462OpSource GLSL 460
463OpSourceExtension "GL_EXT_debug_printf"
464OpName %main "main"
465OpName %foo_ "foo("
466OpName %c "c"
467OpName %samplers "samplers"
468OpDecorate %samplers DescriptorSet 0
469OpDecorate %samplers Binding 0
470%void = OpTypeVoid
471%3 = OpTypeFunction %void
472%float = OpTypeFloat 32
473%v4float = OpTypeVector %float 4
474%_ptr_Function_v4float = OpTypePointer Function %v4float
475%12 = OpTypeImage %float 3D 0 0 0 1 Unknown
476%13 = OpTypeSampledImage %12
477%uint = OpTypeInt 32 0
478%uint_1 = OpConstant %uint 1
479%_arr_13_uint_1 = OpTypeArray %13 %uint_1
480%_ptr_UniformConstant__arr_13_uint_1 = OpTypePointer UniformConstant %_arr_13_uint_1
481%samplers = OpVariable %_ptr_UniformConstant__arr_13_uint_1 UniformConstant
482%int = OpTypeInt 32 1
483%int_0 = OpConstant %int 0
484%_ptr_UniformConstant_13 = OpTypePointer UniformConstant %13
485%v3float = OpTypeVector %float 3
486%float_0 = OpConstant %float 0
487%26 = OpConstantComposite %v3float %float_0 %float_0 %float_0
488%uint_0 = OpConstant %uint 0
489%_ptr_Function_float = OpTypePointer Function %float
490%main = OpFunction %void None %3
491%5 = OpLabel
492%36 = OpVariable %_ptr_Function_v4float Function
493%38 = OpAccessChain %_ptr_UniformConstant_13 %samplers %int_0
494%39 = OpLoad %13 %38
495%40 = OpImageSampleExplicitLod %v4float %39 %26 Lod %float_0
496OpStore %36 %40
497%41 = OpAccessChain %_ptr_Function_float %36 %uint_0
498%42 = OpLoad %float %41
499%43 = OpExtInst %void %33 1 %28 %42
500OpReturn
501OpFunctionEnd
502%foo_ = OpFunction %void None %3
503%7 = OpLabel
504%c = OpVariable %_ptr_Function_v4float Function
505%22 = OpAccessChain %_ptr_UniformConstant_13 %samplers %int_0
506%23 = OpLoad %13 %22
507%27 = OpImageSampleExplicitLod %v4float %23 %26 Lod %float_0
508OpStore %c %27
509%31 = OpAccessChain %_ptr_Function_float %c %uint_0
510%32 = OpLoad %float %31
511%34 = OpExtInst %void %33 1 %28 %32
512OpReturn
513OpFunctionEnd
514)";
515
516  SetTargetEnv(SPV_ENV_VULKAN_1_2);
517  SinglePassRunAndMatch<EliminateDeadFunctionsPass>(text, true);
518}
519
520TEST_F(EliminateDeadFunctionsBasicTest, DependentNonSemanticChain) {
521  const std::string text = R"(
522; CHECK: OpEntryPoint GLCompute [[main:%\w+]]
523; CHECK: [[main]] = OpFunction
524; CHECK-NOT: = OpFunction
525; CHECK: [[ext1:%\w+]] = OpExtInst %void {{%\w+}} 1 [[main]]
526; CHECK: [[ext2:%\w+]] = OpExtInst %void {{%\w+}} 2 [[ext1]]
527; CHECK: [[ext3:%\w+]] = OpExtInst %void {{%\w+}} 3 [[ext1]] [[ext2]]
528OpCapability Shader
529OpExtension "SPV_KHR_non_semantic_info"
530%1 = OpExtInstImport "NonSemantic.Test"
531OpMemoryModel Logical GLSL450
532OpEntryPoint GLCompute %main "main"
533OpExecutionMode %main LocalSize 1 1 1
534%void = OpTypeVoid
535%void_fn = OpTypeFunction %void
536%main = OpFunction %void None %void_fn
537%main_entry = OpLabel
538OpReturn
539OpFunctionEnd
540%dead = OpFunction %void None %void_fn
541%dead_entry = OpLabel
542OpReturn
543OpFunctionEnd
544%2 = OpExtInst %void %1 1 %main
545%3 = OpExtInst %void %1 2 %2
546%4 = OpExtInst %void %1 3 %2 %3
547)";
548
549  SetTargetEnv(SPV_ENV_VULKAN_1_0);
550  SinglePassRunAndMatch<EliminateDeadFunctionsPass>(text, true);
551}
552
553}  // namespace
554}  // namespace opt
555}  // namespace spvtools
556