1 // Copyright (c) 2018 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/operand_to_const_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(OperandToConstantReductionPassTest,BasicCheck)25 TEST(OperandToConstantReductionPassTest, BasicCheck) {
26 std::string prologue = R"(
27 OpCapability Shader
28 %1 = OpExtInstImport "GLSL.std.450"
29 OpMemoryModel Logical GLSL450
30 OpEntryPoint Fragment %4 "main" %37
31 OpExecutionMode %4 OriginUpperLeft
32 OpSource ESSL 310
33 OpName %4 "main"
34 OpName %9 "buf1"
35 OpMemberName %9 0 "f"
36 OpName %11 ""
37 OpName %24 "buf2"
38 OpMemberName %24 0 "i"
39 OpName %26 ""
40 OpName %37 "_GLF_color"
41 OpMemberDecorate %9 0 Offset 0
42 OpDecorate %9 Block
43 OpDecorate %11 DescriptorSet 0
44 OpDecorate %11 Binding 1
45 OpMemberDecorate %24 0 Offset 0
46 OpDecorate %24 Block
47 OpDecorate %26 DescriptorSet 0
48 OpDecorate %26 Binding 2
49 OpDecorate %37 Location 0
50 %2 = OpTypeVoid
51 %3 = OpTypeFunction %2
52 %6 = OpTypeFloat 32
53 %9 = OpTypeStruct %6
54 %10 = OpTypePointer Uniform %9
55 %11 = OpVariable %10 Uniform
56 %12 = OpTypeInt 32 1
57 %13 = OpConstant %12 0
58 %14 = OpTypePointer Uniform %6
59 %20 = OpConstant %6 2
60 %24 = OpTypeStruct %12
61 %25 = OpTypePointer Uniform %24
62 %26 = OpVariable %25 Uniform
63 %27 = OpTypePointer Uniform %12
64 %33 = OpConstant %12 3
65 %35 = OpTypeVector %6 4
66 %36 = OpTypePointer Output %35
67 %37 = OpVariable %36 Output
68 %4 = OpFunction %2 None %3
69 %5 = OpLabel
70 %15 = OpAccessChain %14 %11 %13
71 %16 = OpLoad %6 %15
72 %19 = OpFAdd %6 %16 %16
73 %21 = OpFAdd %6 %19 %20
74 %28 = OpAccessChain %27 %26 %13
75 %29 = OpLoad %12 %28
76 )";
77
78 std::string epilogue = R"(
79 %45 = OpConvertSToF %6 %34
80 %46 = OpCompositeConstruct %35 %16 %21 %43 %45
81 OpStore %37 %46
82 OpReturn
83 OpFunctionEnd
84 )";
85
86 std::string original = prologue + R"(
87 %32 = OpIAdd %12 %29 %29
88 %34 = OpIAdd %12 %32 %33
89 %43 = OpConvertSToF %6 %29
90 )" + epilogue;
91
92 std::string expected = prologue + R"(
93 %32 = OpIAdd %12 %13 %13 ; %29 -> %13 x 2
94 %34 = OpIAdd %12 %13 %33 ; %32 -> %13
95 %43 = OpConvertSToF %6 %13 ; %29 -> %13
96 )" + epilogue;
97
98 const auto env = SPV_ENV_UNIVERSAL_1_3;
99 const auto consumer = nullptr;
100 const auto context =
101 BuildModule(env, consumer, original, kReduceAssembleOption);
102 const auto ops =
103 OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
104 context.get(), 0);
105 ASSERT_EQ(17, ops.size());
106 ASSERT_TRUE(ops[0]->PreconditionHolds());
107 ops[0]->TryToApply();
108 ASSERT_TRUE(ops[1]->PreconditionHolds());
109 ops[1]->TryToApply();
110 ASSERT_TRUE(ops[2]->PreconditionHolds());
111 ops[2]->TryToApply();
112 ASSERT_TRUE(ops[3]->PreconditionHolds());
113 ops[3]->TryToApply();
114
115 CheckEqual(env, expected, context.get());
116 }
117
TEST(OperandToConstantReductionPassTest,WithCalledFunction)118 TEST(OperandToConstantReductionPassTest, WithCalledFunction) {
119 std::string shader = R"(
120 OpCapability Shader
121 %1 = OpExtInstImport "GLSL.std.450"
122 OpMemoryModel Logical GLSL450
123 OpEntryPoint Fragment %4 "main" %10 %12
124 OpExecutionMode %4 OriginUpperLeft
125 OpSource ESSL 310
126 %2 = OpTypeVoid
127 %3 = OpTypeFunction %2
128 %6 = OpTypeFloat 32
129 %7 = OpTypeVector %6 4
130 %8 = OpTypeFunction %7
131 %9 = OpTypePointer Output %7
132 %10 = OpVariable %9 Output
133 %11 = OpTypePointer Input %7
134 %12 = OpVariable %11 Input
135 %13 = OpConstant %6 0
136 %14 = OpConstantComposite %7 %13 %13 %13 %13
137 %4 = OpFunction %2 None %3
138 %5 = OpLabel
139 %15 = OpFunctionCall %7 %16
140 OpReturn
141 OpFunctionEnd
142 %16 = OpFunction %7 None %8
143 %17 = OpLabel
144 OpReturnValue %14
145 OpFunctionEnd
146 )";
147
148 const auto env = SPV_ENV_UNIVERSAL_1_3;
149 const auto consumer = nullptr;
150 const auto context =
151 BuildModule(env, consumer, shader, kReduceAssembleOption);
152 const auto ops =
153 OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
154 context.get(), 0);
155 ASSERT_EQ(0, ops.size());
156 }
157
TEST(OperandToConstantReductionPassTest,TargetSpecificFunction)158 TEST(OperandToConstantReductionPassTest, TargetSpecificFunction) {
159 std::string shader = R"(
160 OpCapability Shader
161 %1 = OpExtInstImport "GLSL.std.450"
162 OpMemoryModel Logical GLSL450
163 OpEntryPoint Fragment %4 "main"
164 OpExecutionMode %4 OriginUpperLeft
165 OpSource ESSL 320
166 %2 = OpTypeVoid
167 %3 = OpTypeFunction %2
168 %6 = OpTypeInt 32 1
169 %7 = OpTypePointer Function %6
170 %8 = OpTypeFunction %6 %7
171 %17 = OpConstant %6 1
172 %20 = OpConstant %6 2
173 %23 = OpConstant %6 0
174 %24 = OpTypeBool
175 %35 = OpConstant %6 3
176 %53 = OpConstant %6 10
177 %4 = OpFunction %2 None %3
178 %5 = OpLabel
179 %65 = OpVariable %7 Function
180 %68 = OpVariable %7 Function
181 %73 = OpVariable %7 Function
182 OpStore %65 %35
183 %66 = OpLoad %6 %65
184 %67 = OpIAdd %6 %66 %17
185 OpStore %65 %67
186 %69 = OpLoad %6 %65
187 OpStore %68 %69
188 %70 = OpFunctionCall %6 %13 %68
189 %71 = OpLoad %6 %65
190 %72 = OpIAdd %6 %71 %70
191 OpStore %65 %72
192 %74 = OpLoad %6 %65
193 OpStore %73 %74
194 %75 = OpFunctionCall %6 %10 %73
195 %76 = OpLoad %6 %65
196 %77 = OpIAdd %6 %76 %75
197 OpStore %65 %77
198 OpReturn
199 OpFunctionEnd
200 %10 = OpFunction %6 None %8
201 %9 = OpFunctionParameter %7
202 %11 = OpLabel
203 %15 = OpVariable %7 Function
204 %16 = OpLoad %6 %9
205 %18 = OpIAdd %6 %16 %17
206 OpStore %15 %18
207 %19 = OpLoad %6 %15
208 %21 = OpIAdd %6 %19 %20
209 OpStore %15 %21
210 %22 = OpLoad %6 %15
211 %25 = OpSGreaterThan %24 %22 %23
212 OpSelectionMerge %27 None
213 OpBranchConditional %25 %26 %27
214 %26 = OpLabel
215 %28 = OpLoad %6 %9
216 OpReturnValue %28
217 %27 = OpLabel
218 %30 = OpLoad %6 %9
219 %31 = OpIAdd %6 %30 %17
220 OpReturnValue %31
221 OpFunctionEnd
222 %13 = OpFunction %6 None %8
223 %12 = OpFunctionParameter %7
224 %14 = OpLabel
225 %41 = OpVariable %7 Function
226 %46 = OpVariable %7 Function
227 %55 = OpVariable %7 Function
228 %34 = OpLoad %6 %12
229 %36 = OpIEqual %24 %34 %35
230 OpSelectionMerge %38 None
231 OpBranchConditional %36 %37 %38
232 %37 = OpLabel
233 %39 = OpLoad %6 %12
234 %40 = OpIMul %6 %20 %39
235 OpStore %41 %40
236 %42 = OpFunctionCall %6 %10 %41
237 OpReturnValue %42
238 %38 = OpLabel
239 %44 = OpLoad %6 %12
240 %45 = OpIAdd %6 %44 %17
241 OpStore %12 %45
242 OpStore %46 %23
243 OpBranch %47
244 %47 = OpLabel
245 OpLoopMerge %49 %50 None
246 OpBranch %51
247 %51 = OpLabel
248 %52 = OpLoad %6 %46
249 %54 = OpSLessThan %24 %52 %53
250 OpBranchConditional %54 %48 %49
251 %48 = OpLabel
252 %56 = OpLoad %6 %12
253 OpStore %55 %56
254 %57 = OpFunctionCall %6 %10 %55
255 %58 = OpLoad %6 %12
256 %59 = OpIAdd %6 %58 %57
257 OpStore %12 %59
258 OpBranch %50
259 %50 = OpLabel
260 %60 = OpLoad %6 %46
261 %61 = OpIAdd %6 %60 %17
262 OpStore %46 %61
263 OpBranch %47
264 %49 = OpLabel
265 %62 = OpLoad %6 %12
266 OpReturnValue %62
267 OpFunctionEnd
268 )";
269
270 const auto env = SPV_ENV_UNIVERSAL_1_3;
271 const auto consumer = nullptr;
272 const auto context =
273 BuildModule(env, consumer, shader, kReduceAssembleOption);
274
275 // Targeting all functions, there are quite a few opportunities. To avoid
276 // making the test too sensitive, we check that there are more than a number
277 // somewhat lower than the real number.
278 const auto all_ops =
279 OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
280 context.get(), 0);
281 ASSERT_TRUE(all_ops.size() > 100);
282
283 // Targeting individual functions, there are fewer opportunities. Again, we
284 // avoid checking against an exact number so that the test is not too
285 // sensitive.
286 const auto ops_for_function_4 =
287 OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
288 context.get(), 4);
289 const auto ops_for_function_10 =
290 OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
291 context.get(), 10);
292 const auto ops_for_function_13 =
293 OperandToConstReductionOpportunityFinder().GetAvailableOpportunities(
294 context.get(), 13);
295 ASSERT_TRUE(ops_for_function_4.size() < 60);
296 ASSERT_TRUE(ops_for_function_10.size() < 50);
297 ASSERT_TRUE(ops_for_function_13.size() < 80);
298
299 // The total number of opportunities should be the sum of the per-function
300 // opportunities.
301 ASSERT_EQ(all_ops.size(), ops_for_function_4.size() +
302 ops_for_function_10.size() +
303 ops_for_function_13.size());
304 }
305
306 } // namespace
307 } // namespace reduce
308 } // namespace spvtools
309