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 "reduce_test_util.h"
16
17 #include "source/reduce/operand_to_const_reduction_pass.h"
18 #include "source/reduce/reducer.h"
19 #include "source/reduce/remove_opname_instruction_reduction_pass.h"
20 #include "source/reduce/remove_unreferenced_instruction_reduction_pass.h"
21
22 namespace spvtools {
23 namespace reduce {
24 namespace {
25
26 // This changes its mind each time IsInteresting is invoked as to whether the
27 // binary is interesting, until some limit is reached after which the binary is
28 // always deemed interesting. This is useful to test that reduction passes
29 // interleave in interesting ways for a while, and then always succeed after
30 // some point; the latter is important to end up with a predictable final
31 // reduced binary for tests.
32 class PingPongInteresting {
33 public:
PingPongInteresting(uint32_t always_interesting_after)34 explicit PingPongInteresting(uint32_t always_interesting_after)
35 : is_interesting_(true),
36 always_interesting_after_(always_interesting_after),
37 count_(0) {}
38
IsInteresting(const std::vector<uint32_t> &)39 bool IsInteresting(const std::vector<uint32_t>&) {
40 bool result;
41 if (count_ > always_interesting_after_) {
42 result = true;
43 } else {
44 result = is_interesting_;
45 is_interesting_ = !is_interesting_;
46 }
47 count_++;
48 return result;
49 }
50
51 private:
52 bool is_interesting_;
53 const uint32_t always_interesting_after_;
54 uint32_t count_;
55 };
56
TEST(ReducerTest,ExprToConstantAndRemoveUnreferenced)57 TEST(ReducerTest, ExprToConstantAndRemoveUnreferenced) {
58 std::string original = R"(
59 OpCapability Shader
60 %1 = OpExtInstImport "GLSL.std.450"
61 OpMemoryModel Logical GLSL450
62 OpEntryPoint Fragment %4 "main" %60
63 OpExecutionMode %4 OriginUpperLeft
64 OpSource ESSL 310
65 OpName %4 "main"
66 OpName %16 "buf2"
67 OpMemberName %16 0 "i"
68 OpName %18 ""
69 OpName %25 "buf1"
70 OpMemberName %25 0 "f"
71 OpName %27 ""
72 OpName %60 "_GLF_color"
73 OpMemberDecorate %16 0 Offset 0
74 OpDecorate %16 Block
75 OpDecorate %18 DescriptorSet 0
76 OpDecorate %18 Binding 2
77 OpMemberDecorate %25 0 Offset 0
78 OpDecorate %25 Block
79 OpDecorate %27 DescriptorSet 0
80 OpDecorate %27 Binding 1
81 OpDecorate %60 Location 0
82 %2 = OpTypeVoid
83 %3 = OpTypeFunction %2
84 %6 = OpTypeInt 32 1
85 %9 = OpConstant %6 0
86 %16 = OpTypeStruct %6
87 %17 = OpTypePointer Uniform %16
88 %18 = OpVariable %17 Uniform
89 %19 = OpTypePointer Uniform %6
90 %22 = OpTypeBool
91 %100 = OpConstantTrue %22
92 %24 = OpTypeFloat 32
93 %25 = OpTypeStruct %24
94 %26 = OpTypePointer Uniform %25
95 %27 = OpVariable %26 Uniform
96 %28 = OpTypePointer Uniform %24
97 %31 = OpConstant %24 2
98 %56 = OpConstant %6 1
99 %58 = OpTypeVector %24 4
100 %59 = OpTypePointer Output %58
101 %60 = OpVariable %59 Output
102 %72 = OpUndef %24
103 %74 = OpUndef %6
104 %4 = OpFunction %2 None %3
105 %5 = OpLabel
106 OpBranch %10
107 %10 = OpLabel
108 %73 = OpPhi %6 %74 %5 %77 %34
109 %71 = OpPhi %24 %72 %5 %76 %34
110 %70 = OpPhi %6 %9 %5 %57 %34
111 %20 = OpAccessChain %19 %18 %9
112 %21 = OpLoad %6 %20
113 %23 = OpSLessThan %22 %70 %21
114 OpLoopMerge %12 %34 None
115 OpBranchConditional %23 %11 %12
116 %11 = OpLabel
117 %29 = OpAccessChain %28 %27 %9
118 %30 = OpLoad %24 %29
119 %32 = OpFOrdGreaterThan %22 %30 %31
120 OpSelectionMerge %34 None
121 OpBranchConditional %32 %33 %46
122 %33 = OpLabel
123 %40 = OpFAdd %24 %71 %30
124 %45 = OpISub %6 %73 %21
125 OpBranch %34
126 %46 = OpLabel
127 %50 = OpFMul %24 %71 %30
128 %54 = OpSDiv %6 %73 %21
129 OpBranch %34
130 %34 = OpLabel
131 %77 = OpPhi %6 %45 %33 %54 %46
132 %76 = OpPhi %24 %40 %33 %50 %46
133 %57 = OpIAdd %6 %70 %56
134 OpBranch %10
135 %12 = OpLabel
136 %61 = OpAccessChain %28 %27 %9
137 %62 = OpLoad %24 %61
138 %66 = OpConvertSToF %24 %21
139 %68 = OpConvertSToF %24 %73
140 %69 = OpCompositeConstruct %58 %62 %71 %66 %68
141 OpStore %60 %69
142 OpReturn
143 OpFunctionEnd
144 )";
145
146 std::string expected = R"(
147 OpCapability Shader
148 %1 = OpExtInstImport "GLSL.std.450"
149 OpMemoryModel Logical GLSL450
150 OpEntryPoint Fragment %4 "main" %60
151 OpExecutionMode %4 OriginUpperLeft
152 OpSource ESSL 310
153 OpName %4 "main"
154 OpName %16 "buf2"
155 OpMemberName %16 0 "i"
156 OpName %18 ""
157 OpName %25 "buf1"
158 OpMemberName %25 0 "f"
159 OpName %27 ""
160 OpName %60 "_GLF_color"
161 OpMemberDecorate %16 0 Offset 0
162 OpDecorate %16 Block
163 OpDecorate %18 DescriptorSet 0
164 OpDecorate %18 Binding 2
165 OpMemberDecorate %25 0 Offset 0
166 OpDecorate %25 Block
167 OpDecorate %27 DescriptorSet 0
168 OpDecorate %27 Binding 1
169 OpDecorate %60 Location 0
170 %2 = OpTypeVoid
171 %3 = OpTypeFunction %2
172 %6 = OpTypeInt 32 1
173 %9 = OpConstant %6 0
174 %16 = OpTypeStruct %6
175 %17 = OpTypePointer Uniform %16
176 %18 = OpVariable %17 Uniform
177 %19 = OpTypePointer Uniform %6
178 %22 = OpTypeBool
179 %100 = OpConstantTrue %22
180 %24 = OpTypeFloat 32
181 %25 = OpTypeStruct %24
182 %26 = OpTypePointer Uniform %25
183 %27 = OpVariable %26 Uniform
184 %28 = OpTypePointer Uniform %24
185 %31 = OpConstant %24 2
186 %56 = OpConstant %6 1
187 %58 = OpTypeVector %24 4
188 %59 = OpTypePointer Output %58
189 %60 = OpVariable %59 Output
190 %72 = OpUndef %24
191 %74 = OpUndef %6
192 %4 = OpFunction %2 None %3
193 %5 = OpLabel
194 OpBranch %10
195 %10 = OpLabel
196 OpLoopMerge %12 %34 None
197 OpBranchConditional %100 %11 %12
198 %11 = OpLabel
199 OpSelectionMerge %34 None
200 OpBranchConditional %100 %33 %46
201 %33 = OpLabel
202 OpBranch %34
203 %46 = OpLabel
204 OpBranch %34
205 %34 = OpLabel
206 OpBranch %10
207 %12 = OpLabel
208 OpReturn
209 OpFunctionEnd
210 )";
211
212 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
213 Reducer reducer(env);
214 PingPongInteresting ping_pong_interesting(10);
215 reducer.SetMessageConsumer(NopDiagnostic);
216 reducer.SetInterestingnessFunction(
217 [&](const std::vector<uint32_t>& binary, uint32_t) -> bool {
218 return ping_pong_interesting.IsInteresting(binary);
219 });
220 reducer.AddReductionPass(MakeUnique<OperandToConstReductionPass>(env));
221 reducer.AddReductionPass(
222 MakeUnique<RemoveUnreferencedInstructionReductionPass>(env));
223
224 std::vector<uint32_t> binary_in;
225 SpirvTools t(env);
226
227 ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption));
228 std::vector<uint32_t> binary_out;
229 spvtools::ReducerOptions reducer_options;
230 reducer_options.set_step_limit(500);
231
232 reducer.Run(std::move(binary_in), &binary_out, reducer_options);
233
234 CheckEqual(env, expected, binary_out);
235 }
236
TEST(ReducerTest,RemoveOpnameAndRemoveUnreferenced)237 TEST(ReducerTest, RemoveOpnameAndRemoveUnreferenced) {
238 const std::string original = R"(
239 OpCapability Shader
240 %1 = OpExtInstImport "GLSL.std.450"
241 OpMemoryModel Logical GLSL450
242 OpEntryPoint Fragment %2 "main"
243 OpExecutionMode %2 OriginUpperLeft
244 OpSource ESSL 310
245 OpName %2 "main"
246 OpName %3 "a"
247 OpName %4 "this-name-counts-as-usage-for-load-instruction"
248 %5 = OpTypeVoid
249 %6 = OpTypeFunction %5
250 %7 = OpTypeFloat 32
251 %8 = OpTypePointer Function %7
252 %9 = OpConstant %7 1
253 %2 = OpFunction %5 None %6
254 %10 = OpLabel
255 %3 = OpVariable %8 Function
256 %4 = OpLoad %7 %3
257 OpStore %3 %7
258 OpReturn
259 OpFunctionEnd
260 )";
261
262 const std::string expected = R"(
263 OpCapability Shader
264 %1 = OpExtInstImport "GLSL.std.450"
265 OpMemoryModel Logical GLSL450
266 OpEntryPoint Fragment %2 "main"
267 OpExecutionMode %2 OriginUpperLeft
268 OpSource ESSL 310
269 %5 = OpTypeVoid
270 %6 = OpTypeFunction %5
271 %7 = OpTypeFloat 32
272 %8 = OpTypePointer Function %7
273 %9 = OpConstant %7 1
274 %2 = OpFunction %5 None %6
275 %10 = OpLabel
276 OpReturn
277 OpFunctionEnd
278 )";
279
280 spv_target_env env = SPV_ENV_UNIVERSAL_1_3;
281 Reducer reducer(env);
282 // Make ping-pong interesting very quickly, as there are not much
283 // opportunities.
284 PingPongInteresting ping_pong_interesting(1);
285 reducer.SetMessageConsumer(NopDiagnostic);
286 reducer.SetInterestingnessFunction(
287 [&](const std::vector<uint32_t>& binary, uint32_t) -> bool {
288 return ping_pong_interesting.IsInteresting(binary);
289 });
290 reducer.AddReductionPass(
291 MakeUnique<RemoveOpNameInstructionReductionPass>(env));
292 reducer.AddReductionPass(
293 MakeUnique<RemoveUnreferencedInstructionReductionPass>(env));
294
295 std::vector<uint32_t> binary_in;
296 SpirvTools t(env);
297
298 ASSERT_TRUE(t.Assemble(original, &binary_in, kReduceAssembleOption));
299 std::vector<uint32_t> binary_out;
300 spvtools::ReducerOptions reducer_options;
301 reducer_options.set_step_limit(500);
302
303 reducer.Run(std::move(binary_in), &binary_out, reducer_options);
304
305 CheckEqual(env, expected, binary_out);
306 }
307
308 } // namespace
309 } // namespace reduce
310 } // namespace spvtools