• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2019 Google LLC
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 "source/reduce/remove_block_reduction_opportunity_finder.h"
16 
17 #include "source/opt/build_module.h"
18 #include "source/reduce/reduction_opportunity.h"
19 #include "test/reduce/reduce_test_util.h"
20 
21 namespace spvtools {
22 namespace reduce {
23 namespace {
24 
TEST(RemoveBlockReductionPassTest,BasicCheck)25 TEST(RemoveBlockReductionPassTest, BasicCheck) {
26   std::string shader = R"(
27                OpCapability Shader
28           %1 = OpExtInstImport "GLSL.std.450"
29                OpMemoryModel Logical GLSL450
30                OpEntryPoint Fragment %4 "main"
31                OpExecutionMode %4 OriginUpperLeft
32                OpSource ESSL 310
33                OpName %4 "main"
34                OpName %8 "x"
35           %2 = OpTypeVoid
36           %3 = OpTypeFunction %2
37           %6 = OpTypeInt 32 1
38           %7 = OpTypePointer Function %6
39           %9 = OpConstant %6 1
40          %10 = OpConstant %6 2
41          %11 = OpConstant %6 3
42          %12 = OpConstant %6 4
43           %4 = OpFunction %2 None %3
44           %5 = OpLabel
45           %8 = OpVariable %7 Function
46                OpBranch %14
47          %13 = OpLabel ; unreachable
48                OpStore %8 %9
49                OpBranch %14
50          %14 = OpLabel
51                OpStore %8 %10
52                OpBranch %16
53          %15 = OpLabel ; unreachable
54                OpStore %8 %11
55                OpBranch %16
56          %16 = OpLabel
57                OpStore %8 %12
58                OpBranch %17
59          %17 = OpLabel
60                OpReturn
61                OpFunctionEnd
62   )";
63   const auto env = SPV_ENV_UNIVERSAL_1_3;
64   const auto consumer = nullptr;
65   const auto context =
66       BuildModule(env, consumer, shader, kReduceAssembleOption);
67   const auto ops =
68       RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
69           context.get(), 0);
70   ASSERT_EQ(2, ops.size());
71 
72   ASSERT_TRUE(ops[0]->PreconditionHolds());
73   ops[0]->TryToApply();
74 
75   std::string after_op_0 = R"(
76                OpCapability Shader
77           %1 = OpExtInstImport "GLSL.std.450"
78                OpMemoryModel Logical GLSL450
79                OpEntryPoint Fragment %4 "main"
80                OpExecutionMode %4 OriginUpperLeft
81                OpSource ESSL 310
82                OpName %4 "main"
83                OpName %8 "x"
84           %2 = OpTypeVoid
85           %3 = OpTypeFunction %2
86           %6 = OpTypeInt 32 1
87           %7 = OpTypePointer Function %6
88           %9 = OpConstant %6 1
89          %10 = OpConstant %6 2
90          %11 = OpConstant %6 3
91          %12 = OpConstant %6 4
92           %4 = OpFunction %2 None %3
93           %5 = OpLabel
94           %8 = OpVariable %7 Function
95                OpBranch %14
96          %14 = OpLabel
97                OpStore %8 %10
98                OpBranch %16
99          %15 = OpLabel
100                OpStore %8 %11
101                OpBranch %16
102          %16 = OpLabel
103                OpStore %8 %12
104                OpBranch %17
105          %17 = OpLabel
106                OpReturn
107                OpFunctionEnd
108   )";
109 
110   CheckEqual(env, after_op_0, context.get());
111 
112   ASSERT_TRUE(ops[1]->PreconditionHolds());
113   ops[1]->TryToApply();
114 
115   std::string after_op_1 = R"(
116                OpCapability Shader
117           %1 = OpExtInstImport "GLSL.std.450"
118                OpMemoryModel Logical GLSL450
119                OpEntryPoint Fragment %4 "main"
120                OpExecutionMode %4 OriginUpperLeft
121                OpSource ESSL 310
122                OpName %4 "main"
123                OpName %8 "x"
124           %2 = OpTypeVoid
125           %3 = OpTypeFunction %2
126           %6 = OpTypeInt 32 1
127           %7 = OpTypePointer Function %6
128           %9 = OpConstant %6 1
129          %10 = OpConstant %6 2
130          %11 = OpConstant %6 3
131          %12 = OpConstant %6 4
132           %4 = OpFunction %2 None %3
133           %5 = OpLabel
134           %8 = OpVariable %7 Function
135                OpBranch %14
136          %14 = OpLabel
137                OpStore %8 %10
138                OpBranch %16
139          %16 = OpLabel
140                OpStore %8 %12
141                OpBranch %17
142          %17 = OpLabel
143                OpReturn
144                OpFunctionEnd
145   )";
146 
147   CheckEqual(env, after_op_1, context.get());
148 }
149 
TEST(RemoveBlockReductionPassTest,UnreachableContinueAndMerge)150 TEST(RemoveBlockReductionPassTest, UnreachableContinueAndMerge) {
151   // Loop with unreachable merge and continue target. There should be no
152   // opportunities.
153 
154   std::string shader = R"(
155                OpCapability Shader
156           %1 = OpExtInstImport "GLSL.std.450"
157                OpMemoryModel Logical GLSL450
158                OpEntryPoint Fragment %4 "main"
159                OpExecutionMode %4 OriginUpperLeft
160                OpSource ESSL 310
161                OpName %4 "main"
162           %2 = OpTypeVoid
163           %3 = OpTypeFunction %2
164           %4 = OpFunction %2 None %3
165           %5 = OpLabel
166                OpBranch %13
167          %13 = OpLabel
168                OpLoopMerge %16 %15 None
169                OpBranch %14
170          %14 = OpLabel
171                OpReturn
172          %15 = OpLabel
173                OpBranch %13
174          %16 = OpLabel
175                OpReturn
176                OpFunctionEnd
177   )";
178   const auto env = SPV_ENV_UNIVERSAL_1_3;
179   const auto consumer = nullptr;
180   const auto context =
181       BuildModule(env, consumer, shader, kReduceAssembleOption);
182   const auto ops =
183       RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
184           context.get(), 0);
185   ASSERT_EQ(0, ops.size());
186 }
187 
TEST(RemoveBlockReductionPassTest,OneBlock)188 TEST(RemoveBlockReductionPassTest, OneBlock) {
189   // Function with just one block. There should be no opportunities.
190 
191   std::string shader = R"(
192                OpCapability Shader
193           %1 = OpExtInstImport "GLSL.std.450"
194                OpMemoryModel Logical GLSL450
195                OpEntryPoint Fragment %4 "main"
196                OpExecutionMode %4 OriginUpperLeft
197                OpSource ESSL 310
198                OpName %4 "main"
199           %2 = OpTypeVoid
200           %3 = OpTypeFunction %2
201           %4 = OpFunction %2 None %3
202           %5 = OpLabel
203                OpReturn
204                OpFunctionEnd
205   )";
206   const auto env = SPV_ENV_UNIVERSAL_1_3;
207   const auto consumer = nullptr;
208   const auto context =
209       BuildModule(env, consumer, shader, kReduceAssembleOption);
210   const auto ops =
211       RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
212           context.get(), 0);
213   ASSERT_EQ(0, ops.size());
214 }
215 
TEST(RemoveBlockReductionPassTest,UnreachableBlocksWithOutsideIdUses)216 TEST(RemoveBlockReductionPassTest, UnreachableBlocksWithOutsideIdUses) {
217   // A function with two unreachable blocks A -> B. A defines ID %9 and B uses
218   // %9. There are no references to A, but removing A would be invalid because
219   // of B's use of %9, so there should be no opportunities.
220 
221   std::string shader = R"(
222                OpCapability Shader
223           %1 = OpExtInstImport "GLSL.std.450"
224                OpMemoryModel Logical GLSL450
225                OpEntryPoint Fragment %2 "main"
226                OpExecutionMode %2 OriginUpperLeft
227                OpSource ESSL 310
228                OpName %2 "main"
229           %3 = OpTypeVoid
230           %4 = OpTypeInt 32 1
231           %5 = OpTypeFunction %3
232           %6 = OpConstant %4 1
233           %2 = OpFunction %3 None %5
234           %7 = OpLabel
235                OpReturn
236           %8 = OpLabel          ; A
237           %9 = OpUndef %4
238                OpBranch %10
239          %10 = OpLabel          ; B
240          %11 = OpIAdd %4 %6 %9  ; uses %9 from A, so A cannot be removed
241                OpReturn
242                OpFunctionEnd
243   )";
244   const auto env = SPV_ENV_UNIVERSAL_1_3;
245   const auto consumer = nullptr;
246   const auto context =
247       BuildModule(env, consumer, shader, kReduceAssembleOption);
248   const auto ops =
249       RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
250           context.get(), 0);
251   ASSERT_EQ(0, ops.size());
252 }
253 
TEST(RemoveBlockReductionPassTest,UnreachableBlocksWithInsideIdUses)254 TEST(RemoveBlockReductionPassTest, UnreachableBlocksWithInsideIdUses) {
255   // Similar to the above test.
256 
257   // A function with two unreachable blocks A -> B. Both blocks create and use
258   // IDs, but the uses are contained within each block, so A should be removed.
259 
260   std::string shader = R"(
261                OpCapability Shader
262           %1 = OpExtInstImport "GLSL.std.450"
263                OpMemoryModel Logical GLSL450
264                OpEntryPoint Fragment %2 "main"
265                OpExecutionMode %2 OriginUpperLeft
266                OpSource ESSL 310
267                OpName %2 "main"
268           %3 = OpTypeVoid
269           %4 = OpTypeInt 32 1
270           %5 = OpTypeFunction %3
271           %6 = OpConstant %4 1
272           %2 = OpFunction %3 None %5
273           %7 = OpLabel
274                OpReturn
275           %8 = OpLabel                     ; A
276           %9 = OpUndef %4                  ; define %9
277          %10 = OpIAdd %4 %6 %9             ; use %9
278                OpBranch %11
279          %11 = OpLabel                     ; B
280          %12 = OpUndef %4                  ; define %12
281          %13 = OpIAdd %4 %6 %12            ; use %12
282                OpReturn
283                OpFunctionEnd
284   )";
285   const auto env = SPV_ENV_UNIVERSAL_1_3;
286   const auto consumer = nullptr;
287   const auto context =
288       BuildModule(env, consumer, shader, kReduceAssembleOption);
289   auto ops = RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
290       context.get(), 0);
291   ASSERT_EQ(1, ops.size());
292 
293   ASSERT_TRUE(ops[0]->PreconditionHolds());
294 
295   ops[0]->TryToApply();
296 
297   // Same as above, but block A is removed.
298   std::string after_op_0 = R"(
299                OpCapability Shader
300           %1 = OpExtInstImport "GLSL.std.450"
301                OpMemoryModel Logical GLSL450
302                OpEntryPoint Fragment %2 "main"
303                OpExecutionMode %2 OriginUpperLeft
304                OpSource ESSL 310
305                OpName %2 "main"
306           %3 = OpTypeVoid
307           %4 = OpTypeInt 32 1
308           %5 = OpTypeFunction %3
309           %6 = OpConstant %4 1
310           %2 = OpFunction %3 None %5
311           %7 = OpLabel
312                OpReturn
313          %11 = OpLabel
314          %12 = OpUndef %4
315          %13 = OpIAdd %4 %6 %12
316                OpReturn
317                OpFunctionEnd
318   )";
319 
320   CheckEqual(env, after_op_0, context.get());
321 
322   // Find opportunities again. There are no reference to B. B should now be
323   // removed.
324 
325   ops = RemoveBlockReductionOpportunityFinder().GetAvailableOpportunities(
326       context.get(), 0);
327 
328   ASSERT_EQ(1, ops.size());
329 
330   ASSERT_TRUE(ops[0]->PreconditionHolds());
331 
332   ops[0]->TryToApply();
333 
334   // Same as above, but block B is removed.
335   std::string after_op_0_again = R"(
336                OpCapability Shader
337           %1 = OpExtInstImport "GLSL.std.450"
338                OpMemoryModel Logical GLSL450
339                OpEntryPoint Fragment %2 "main"
340                OpExecutionMode %2 OriginUpperLeft
341                OpSource ESSL 310
342                OpName %2 "main"
343           %3 = OpTypeVoid
344           %4 = OpTypeInt 32 1
345           %5 = OpTypeFunction %3
346           %6 = OpConstant %4 1
347           %2 = OpFunction %3 None %5
348           %7 = OpLabel
349                OpReturn
350                OpFunctionEnd
351   )";
352 
353   CheckEqual(env, after_op_0_again, context.get());
354 }
355 
356 }  // namespace
357 }  // namespace reduce
358 }  // namespace spvtools
359