1fd4e5da5Sopenharmony_ci// Copyright (c) 2019 Google LLC
2fd4e5da5Sopenharmony_ci//
3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License.
5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at
6fd4e5da5Sopenharmony_ci//
7fd4e5da5Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8fd4e5da5Sopenharmony_ci//
9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and
13fd4e5da5Sopenharmony_ci// limitations under the License.
14fd4e5da5Sopenharmony_ci
15fd4e5da5Sopenharmony_ci#include "source/reduce/remove_function_reduction_opportunity_finder.h"
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include "source/opt/build_module.h"
18fd4e5da5Sopenharmony_ci#include "source/reduce/reduction_opportunity.h"
19fd4e5da5Sopenharmony_ci#include "test/reduce/reduce_test_util.h"
20fd4e5da5Sopenharmony_ci
21fd4e5da5Sopenharmony_cinamespace spvtools {
22fd4e5da5Sopenharmony_cinamespace reduce {
23fd4e5da5Sopenharmony_cinamespace {
24fd4e5da5Sopenharmony_ci
25fd4e5da5Sopenharmony_ci// Helper to count the number of functions in the module.
26fd4e5da5Sopenharmony_ci// Remove if there turns out to be a more direct way to do this.
27fd4e5da5Sopenharmony_ciuint32_t count_functions(opt::IRContext* context) {
28fd4e5da5Sopenharmony_ci  uint32_t result = 0;
29fd4e5da5Sopenharmony_ci  for (auto& function : *context->module()) {
30fd4e5da5Sopenharmony_ci    (void)(function);
31fd4e5da5Sopenharmony_ci    ++result;
32fd4e5da5Sopenharmony_ci  }
33fd4e5da5Sopenharmony_ci  return result;
34fd4e5da5Sopenharmony_ci}
35fd4e5da5Sopenharmony_ci
36fd4e5da5Sopenharmony_ciTEST(RemoveFunctionTest, BasicCheck) {
37fd4e5da5Sopenharmony_ci  std::string shader = R"(
38fd4e5da5Sopenharmony_ci               OpCapability Shader
39fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
40fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
41fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
42fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
43fd4e5da5Sopenharmony_ci               OpSource ESSL 310
44fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
45fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
46fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
47fd4e5da5Sopenharmony_ci          %5 = OpLabel
48fd4e5da5Sopenharmony_ci               OpReturn
49fd4e5da5Sopenharmony_ci               OpFunctionEnd
50fd4e5da5Sopenharmony_ci          %6 = OpFunction %2 None %3
51fd4e5da5Sopenharmony_ci          %7 = OpLabel
52fd4e5da5Sopenharmony_ci               OpReturn
53fd4e5da5Sopenharmony_ci               OpFunctionEnd
54fd4e5da5Sopenharmony_ci          %8 = OpFunction %2 None %3
55fd4e5da5Sopenharmony_ci          %9 = OpLabel
56fd4e5da5Sopenharmony_ci         %10 = OpFunctionCall %2 %6
57fd4e5da5Sopenharmony_ci               OpReturn
58fd4e5da5Sopenharmony_ci               OpFunctionEnd
59fd4e5da5Sopenharmony_ci  )";
60fd4e5da5Sopenharmony_ci
61fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
62fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
63fd4e5da5Sopenharmony_ci  const auto context =
64fd4e5da5Sopenharmony_ci      BuildModule(env, consumer, shader, kReduceAssembleOption);
65fd4e5da5Sopenharmony_ci
66fd4e5da5Sopenharmony_ci  ASSERT_EQ(3, count_functions(context.get()));
67fd4e5da5Sopenharmony_ci
68fd4e5da5Sopenharmony_ci  auto ops =
69fd4e5da5Sopenharmony_ci      RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
70fd4e5da5Sopenharmony_ci          context.get(), 0);
71fd4e5da5Sopenharmony_ci  ASSERT_EQ(1, ops.size());
72fd4e5da5Sopenharmony_ci
73fd4e5da5Sopenharmony_ci  ASSERT_TRUE(ops[0]->PreconditionHolds());
74fd4e5da5Sopenharmony_ci  ops[0]->TryToApply();
75fd4e5da5Sopenharmony_ci
76fd4e5da5Sopenharmony_ci  ASSERT_EQ(2, count_functions(context.get()));
77fd4e5da5Sopenharmony_ci
78fd4e5da5Sopenharmony_ci  std::string after_first = R"(
79fd4e5da5Sopenharmony_ci               OpCapability Shader
80fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
81fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
82fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
83fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
84fd4e5da5Sopenharmony_ci               OpSource ESSL 310
85fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
86fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
87fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
88fd4e5da5Sopenharmony_ci          %5 = OpLabel
89fd4e5da5Sopenharmony_ci               OpReturn
90fd4e5da5Sopenharmony_ci               OpFunctionEnd
91fd4e5da5Sopenharmony_ci          %6 = OpFunction %2 None %3
92fd4e5da5Sopenharmony_ci          %7 = OpLabel
93fd4e5da5Sopenharmony_ci               OpReturn
94fd4e5da5Sopenharmony_ci               OpFunctionEnd
95fd4e5da5Sopenharmony_ci  )";
96fd4e5da5Sopenharmony_ci
97fd4e5da5Sopenharmony_ci  CheckEqual(env, after_first, context.get());
98fd4e5da5Sopenharmony_ci
99fd4e5da5Sopenharmony_ci  ops = RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
100fd4e5da5Sopenharmony_ci      context.get(), 0);
101fd4e5da5Sopenharmony_ci
102fd4e5da5Sopenharmony_ci  ASSERT_EQ(1, ops.size());
103fd4e5da5Sopenharmony_ci
104fd4e5da5Sopenharmony_ci  ASSERT_TRUE(ops[0]->PreconditionHolds());
105fd4e5da5Sopenharmony_ci  ops[0]->TryToApply();
106fd4e5da5Sopenharmony_ci
107fd4e5da5Sopenharmony_ci  ASSERT_EQ(1, count_functions(context.get()));
108fd4e5da5Sopenharmony_ci
109fd4e5da5Sopenharmony_ci  std::string after_second = R"(
110fd4e5da5Sopenharmony_ci               OpCapability Shader
111fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
112fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
113fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
114fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
115fd4e5da5Sopenharmony_ci               OpSource ESSL 310
116fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
117fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
118fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
119fd4e5da5Sopenharmony_ci          %5 = OpLabel
120fd4e5da5Sopenharmony_ci               OpReturn
121fd4e5da5Sopenharmony_ci               OpFunctionEnd
122fd4e5da5Sopenharmony_ci  )";
123fd4e5da5Sopenharmony_ci
124fd4e5da5Sopenharmony_ci  CheckEqual(env, after_second, context.get());
125fd4e5da5Sopenharmony_ci}
126fd4e5da5Sopenharmony_ci
127fd4e5da5Sopenharmony_ciTEST(RemoveFunctionTest, NothingToRemove) {
128fd4e5da5Sopenharmony_ci  std::string shader = R"(
129fd4e5da5Sopenharmony_ci               OpCapability Shader
130fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
131fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
132fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
133fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
134fd4e5da5Sopenharmony_ci               OpSource ESSL 310
135fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
136fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
137fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
138fd4e5da5Sopenharmony_ci          %5 = OpLabel
139fd4e5da5Sopenharmony_ci         %11 = OpFunctionCall %2 %8
140fd4e5da5Sopenharmony_ci               OpReturn
141fd4e5da5Sopenharmony_ci               OpFunctionEnd
142fd4e5da5Sopenharmony_ci          %6 = OpFunction %2 None %3
143fd4e5da5Sopenharmony_ci          %7 = OpLabel
144fd4e5da5Sopenharmony_ci               OpReturn
145fd4e5da5Sopenharmony_ci               OpFunctionEnd
146fd4e5da5Sopenharmony_ci          %8 = OpFunction %2 None %3
147fd4e5da5Sopenharmony_ci          %9 = OpLabel
148fd4e5da5Sopenharmony_ci         %10 = OpFunctionCall %2 %6
149fd4e5da5Sopenharmony_ci               OpReturn
150fd4e5da5Sopenharmony_ci               OpFunctionEnd
151fd4e5da5Sopenharmony_ci  )";
152fd4e5da5Sopenharmony_ci
153fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
154fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
155fd4e5da5Sopenharmony_ci  const auto context =
156fd4e5da5Sopenharmony_ci      BuildModule(env, consumer, shader, kReduceAssembleOption);
157fd4e5da5Sopenharmony_ci  auto ops =
158fd4e5da5Sopenharmony_ci      RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
159fd4e5da5Sopenharmony_ci          context.get(), 0);
160fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
161fd4e5da5Sopenharmony_ci}
162fd4e5da5Sopenharmony_ci
163fd4e5da5Sopenharmony_ciTEST(RemoveFunctionTest, TwoRemovableFunctions) {
164fd4e5da5Sopenharmony_ci  std::string shader = R"(
165fd4e5da5Sopenharmony_ci               OpCapability Shader
166fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
167fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
168fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
169fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
170fd4e5da5Sopenharmony_ci               OpSource ESSL 310
171fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
172fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
173fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
174fd4e5da5Sopenharmony_ci          %5 = OpLabel
175fd4e5da5Sopenharmony_ci               OpReturn
176fd4e5da5Sopenharmony_ci               OpFunctionEnd
177fd4e5da5Sopenharmony_ci          %6 = OpFunction %2 None %3
178fd4e5da5Sopenharmony_ci          %7 = OpLabel
179fd4e5da5Sopenharmony_ci               OpReturn
180fd4e5da5Sopenharmony_ci               OpFunctionEnd
181fd4e5da5Sopenharmony_ci          %8 = OpFunction %2 None %3
182fd4e5da5Sopenharmony_ci          %9 = OpLabel
183fd4e5da5Sopenharmony_ci               OpReturn
184fd4e5da5Sopenharmony_ci               OpFunctionEnd
185fd4e5da5Sopenharmony_ci  )";
186fd4e5da5Sopenharmony_ci
187fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
188fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
189fd4e5da5Sopenharmony_ci  const auto context =
190fd4e5da5Sopenharmony_ci      BuildModule(env, consumer, shader, kReduceAssembleOption);
191fd4e5da5Sopenharmony_ci
192fd4e5da5Sopenharmony_ci  ASSERT_EQ(3, count_functions(context.get()));
193fd4e5da5Sopenharmony_ci
194fd4e5da5Sopenharmony_ci  auto ops =
195fd4e5da5Sopenharmony_ci      RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
196fd4e5da5Sopenharmony_ci          context.get(), 0);
197fd4e5da5Sopenharmony_ci  ASSERT_EQ(2, ops.size());
198fd4e5da5Sopenharmony_ci
199fd4e5da5Sopenharmony_ci  ASSERT_TRUE(ops[0]->PreconditionHolds());
200fd4e5da5Sopenharmony_ci  ops[0]->TryToApply();
201fd4e5da5Sopenharmony_ci  ASSERT_EQ(2, count_functions(context.get()));
202fd4e5da5Sopenharmony_ci  ASSERT_TRUE(ops[1]->PreconditionHolds());
203fd4e5da5Sopenharmony_ci  ops[1]->TryToApply();
204fd4e5da5Sopenharmony_ci  ASSERT_EQ(1, count_functions(context.get()));
205fd4e5da5Sopenharmony_ci
206fd4e5da5Sopenharmony_ci  std::string after = R"(
207fd4e5da5Sopenharmony_ci               OpCapability Shader
208fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
209fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
210fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
211fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
212fd4e5da5Sopenharmony_ci               OpSource ESSL 310
213fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
214fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
215fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
216fd4e5da5Sopenharmony_ci          %5 = OpLabel
217fd4e5da5Sopenharmony_ci               OpReturn
218fd4e5da5Sopenharmony_ci               OpFunctionEnd
219fd4e5da5Sopenharmony_ci  )";
220fd4e5da5Sopenharmony_ci
221fd4e5da5Sopenharmony_ci  CheckEqual(env, after, context.get());
222fd4e5da5Sopenharmony_ci}
223fd4e5da5Sopenharmony_ci
224fd4e5da5Sopenharmony_ciTEST(RemoveFunctionTest, NoRemovalsDueToOpName) {
225fd4e5da5Sopenharmony_ci  std::string shader = R"(
226fd4e5da5Sopenharmony_ci               OpCapability Shader
227fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
228fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
229fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
230fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
231fd4e5da5Sopenharmony_ci               OpSource ESSL 310
232fd4e5da5Sopenharmony_ci               OpName %4 "main"
233fd4e5da5Sopenharmony_ci               OpName %6 "foo("
234fd4e5da5Sopenharmony_ci               OpName %8 "bar("
235fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
236fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
237fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
238fd4e5da5Sopenharmony_ci          %5 = OpLabel
239fd4e5da5Sopenharmony_ci               OpReturn
240fd4e5da5Sopenharmony_ci               OpFunctionEnd
241fd4e5da5Sopenharmony_ci          %6 = OpFunction %2 None %3
242fd4e5da5Sopenharmony_ci          %7 = OpLabel
243fd4e5da5Sopenharmony_ci               OpReturn
244fd4e5da5Sopenharmony_ci               OpFunctionEnd
245fd4e5da5Sopenharmony_ci          %8 = OpFunction %2 None %3
246fd4e5da5Sopenharmony_ci          %9 = OpLabel
247fd4e5da5Sopenharmony_ci               OpReturn
248fd4e5da5Sopenharmony_ci               OpFunctionEnd
249fd4e5da5Sopenharmony_ci  )";
250fd4e5da5Sopenharmony_ci
251fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
252fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
253fd4e5da5Sopenharmony_ci  const auto context =
254fd4e5da5Sopenharmony_ci      BuildModule(env, consumer, shader, kReduceAssembleOption);
255fd4e5da5Sopenharmony_ci  auto ops =
256fd4e5da5Sopenharmony_ci      RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
257fd4e5da5Sopenharmony_ci          context.get(), 0);
258fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
259fd4e5da5Sopenharmony_ci}
260fd4e5da5Sopenharmony_ci
261fd4e5da5Sopenharmony_ciTEST(RemoveFunctionTest, NoRemovalDueToLinkageDecoration) {
262fd4e5da5Sopenharmony_ci  // The non-entry point function is not removable because it is referenced by a
263fd4e5da5Sopenharmony_ci  // linkage decoration. Thus no function can be removed.
264fd4e5da5Sopenharmony_ci  std::string shader = R"(
265fd4e5da5Sopenharmony_ci               OpCapability Shader
266fd4e5da5Sopenharmony_ci               OpCapability Linkage
267fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
268fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %1 "main"
269fd4e5da5Sopenharmony_ci               OpName %1 "main"
270fd4e5da5Sopenharmony_ci               OpDecorate %2 LinkageAttributes "ExportedFunc" Export
271fd4e5da5Sopenharmony_ci          %4 = OpTypeVoid
272fd4e5da5Sopenharmony_ci          %5 = OpTypeFunction %4
273fd4e5da5Sopenharmony_ci          %1 = OpFunction %4 None %5
274fd4e5da5Sopenharmony_ci          %6 = OpLabel
275fd4e5da5Sopenharmony_ci               OpReturn
276fd4e5da5Sopenharmony_ci               OpFunctionEnd
277fd4e5da5Sopenharmony_ci          %2 = OpFunction %4 None %5
278fd4e5da5Sopenharmony_ci          %7 = OpLabel
279fd4e5da5Sopenharmony_ci               OpReturn
280fd4e5da5Sopenharmony_ci               OpFunctionEnd
281fd4e5da5Sopenharmony_ci  )";
282fd4e5da5Sopenharmony_ci
283fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_3;
284fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
285fd4e5da5Sopenharmony_ci  const auto context =
286fd4e5da5Sopenharmony_ci      BuildModule(env, consumer, shader, kReduceAssembleOption);
287fd4e5da5Sopenharmony_ci  auto ops =
288fd4e5da5Sopenharmony_ci      RemoveFunctionReductionOpportunityFinder().GetAvailableOpportunities(
289fd4e5da5Sopenharmony_ci          context.get(), 0);
290fd4e5da5Sopenharmony_ci  ASSERT_EQ(0, ops.size());
291fd4e5da5Sopenharmony_ci}
292fd4e5da5Sopenharmony_ci
293fd4e5da5Sopenharmony_ci}  // namespace
294fd4e5da5Sopenharmony_ci}  // namespace reduce
295fd4e5da5Sopenharmony_ci}  // namespace spvtools
296