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 23 namespace spvtools { 24 namespace opt { 25 namespace { 26 27 using ::testing::HasSubstr; 28 using EliminateDeadFunctionsBasicTest = PassTest<::testing::Test>; 29 30 TEST_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 69 TEST_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 107 TEST_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 146 TEST_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 188 OpMemoryModel Logical GLSL450 189 OpEntryPoint Vertex %main "main" 190 OpName %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 198 OpReturn 199 OpFunctionEnd 200 )"; 201 202 SetAssembleOptions(SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS); 203 SinglePassRunAndCheck<EliminateDeadFunctionsPass>(text, expected_output, 204 /* skip_nop = */ true); 205 } 206 207 } // namespace 208 } // namespace opt 209 } // namespace spvtools 210