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
TEST_F(EliminateDeadFunctionsBasicTest,BasicDeleteDeadFunction)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
TEST_F(EliminateDeadFunctionsBasicTest,BasicKeepLiveFunction)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
TEST_F(EliminateDeadFunctionsBasicTest,BasicKeepExportFunctions)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
TEST_F(EliminateDeadFunctionsBasicTest,BasicRemoveDecorationsAndNames)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