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