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/fuzz/transformation_set_loop_control.h"
16
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "test/fuzz/fuzz_test_util.h"
20
21 namespace spvtools {
22 namespace fuzz {
23 namespace {
24
TEST(TransformationSetLoopControlTest,VariousScenarios)25 TEST(TransformationSetLoopControlTest, VariousScenarios) {
26 // This test features loops with various different controls, and goes through
27 // a number of acceptable and unacceptable transformations to those controls.
28
29 std::string shader = R"(
30 OpCapability Shader
31 %1 = OpExtInstImport "GLSL.std.450"
32 OpMemoryModel Logical GLSL450
33 OpEntryPoint Fragment %4 "main"
34 OpExecutionMode %4 OriginUpperLeft
35 OpSource ESSL 310
36 OpName %4 "main"
37 %2 = OpTypeVoid
38 %3 = OpTypeFunction %2
39 %6 = OpTypeInt 32 1
40 %7 = OpTypePointer Function %6
41 %9 = OpConstant %6 0
42 %16 = OpConstant %6 100
43 %17 = OpTypeBool
44 %20 = OpConstant %6 1
45 %4 = OpFunction %2 None %3
46 %5 = OpLabel
47 %8 = OpVariable %7 Function
48 %22 = OpVariable %7 Function
49 %32 = OpVariable %7 Function
50 %42 = OpVariable %7 Function
51 %52 = OpVariable %7 Function
52 %62 = OpVariable %7 Function
53 %72 = OpVariable %7 Function
54 %82 = OpVariable %7 Function
55 %92 = OpVariable %7 Function
56 %102 = OpVariable %7 Function
57 %112 = OpVariable %7 Function
58 %122 = OpVariable %7 Function
59 OpStore %8 %9
60 OpBranch %10
61 %10 = OpLabel
62 %132 = OpPhi %6 %9 %5 %21 %13
63 OpLoopMerge %12 %13 None
64 OpBranch %14
65 %14 = OpLabel
66 %18 = OpSLessThan %17 %132 %16
67 OpBranchConditional %18 %11 %12
68 %11 = OpLabel
69 OpBranch %13
70 %13 = OpLabel
71 %21 = OpIAdd %6 %132 %20
72 OpStore %8 %21
73 OpBranch %10
74 %12 = OpLabel
75 OpStore %22 %9
76 OpBranch %23
77 %23 = OpLabel
78 %133 = OpPhi %6 %9 %12 %31 %26
79 OpLoopMerge %25 %26 Unroll
80 OpBranch %27
81 %27 = OpLabel
82 %29 = OpSLessThan %17 %133 %16
83 OpBranchConditional %29 %24 %25
84 %24 = OpLabel
85 OpBranch %26
86 %26 = OpLabel
87 %31 = OpIAdd %6 %133 %20
88 OpStore %22 %31
89 OpBranch %23
90 %25 = OpLabel
91 OpStore %32 %9
92 OpBranch %33
93 %33 = OpLabel
94 %134 = OpPhi %6 %9 %25 %41 %36
95 OpLoopMerge %35 %36 DontUnroll
96 OpBranch %37
97 %37 = OpLabel
98 %39 = OpSLessThan %17 %134 %16
99 OpBranchConditional %39 %34 %35
100 %34 = OpLabel
101 OpBranch %36
102 %36 = OpLabel
103 %41 = OpIAdd %6 %134 %20
104 OpStore %32 %41
105 OpBranch %33
106 %35 = OpLabel
107 OpStore %42 %9
108 OpBranch %43
109 %43 = OpLabel
110 %135 = OpPhi %6 %9 %35 %51 %46
111 OpLoopMerge %45 %46 DependencyInfinite
112 OpBranch %47
113 %47 = OpLabel
114 %49 = OpSLessThan %17 %135 %16
115 OpBranchConditional %49 %44 %45
116 %44 = OpLabel
117 OpBranch %46
118 %46 = OpLabel
119 %51 = OpIAdd %6 %135 %20
120 OpStore %42 %51
121 OpBranch %43
122 %45 = OpLabel
123 OpStore %52 %9
124 OpBranch %53
125 %53 = OpLabel
126 %136 = OpPhi %6 %9 %45 %61 %56
127 OpLoopMerge %55 %56 DependencyLength 3
128 OpBranch %57
129 %57 = OpLabel
130 %59 = OpSLessThan %17 %136 %16
131 OpBranchConditional %59 %54 %55
132 %54 = OpLabel
133 OpBranch %56
134 %56 = OpLabel
135 %61 = OpIAdd %6 %136 %20
136 OpStore %52 %61
137 OpBranch %53
138 %55 = OpLabel
139 OpStore %62 %9
140 OpBranch %63
141 %63 = OpLabel
142 %137 = OpPhi %6 %9 %55 %71 %66
143 OpLoopMerge %65 %66 MinIterations 10
144 OpBranch %67
145 %67 = OpLabel
146 %69 = OpSLessThan %17 %137 %16
147 OpBranchConditional %69 %64 %65
148 %64 = OpLabel
149 OpBranch %66
150 %66 = OpLabel
151 %71 = OpIAdd %6 %137 %20
152 OpStore %62 %71
153 OpBranch %63
154 %65 = OpLabel
155 OpStore %72 %9
156 OpBranch %73
157 %73 = OpLabel
158 %138 = OpPhi %6 %9 %65 %81 %76
159 OpLoopMerge %75 %76 MaxIterations 50
160 OpBranch %77
161 %77 = OpLabel
162 %79 = OpSLessThan %17 %138 %16
163 OpBranchConditional %79 %74 %75
164 %74 = OpLabel
165 OpBranch %76
166 %76 = OpLabel
167 %81 = OpIAdd %6 %138 %20
168 OpStore %72 %81
169 OpBranch %73
170 %75 = OpLabel
171 OpStore %82 %9
172 OpBranch %83
173 %83 = OpLabel
174 %139 = OpPhi %6 %9 %75 %91 %86
175 OpLoopMerge %85 %86 IterationMultiple 4
176 OpBranch %87
177 %87 = OpLabel
178 %89 = OpSLessThan %17 %139 %16
179 OpBranchConditional %89 %84 %85
180 %84 = OpLabel
181 OpBranch %86
182 %86 = OpLabel
183 %91 = OpIAdd %6 %139 %20
184 OpStore %82 %91
185 OpBranch %83
186 %85 = OpLabel
187 OpStore %92 %9
188 OpBranch %93
189 %93 = OpLabel
190 %140 = OpPhi %6 %9 %85 %101 %96
191 OpLoopMerge %95 %96 PeelCount 2
192 OpBranch %97
193 %97 = OpLabel
194 %99 = OpSLessThan %17 %140 %16
195 OpBranchConditional %99 %94 %95
196 %94 = OpLabel
197 OpBranch %96
198 %96 = OpLabel
199 %101 = OpIAdd %6 %140 %20
200 OpStore %92 %101
201 OpBranch %93
202 %95 = OpLabel
203 OpStore %102 %9
204 OpBranch %103
205 %103 = OpLabel
206 %141 = OpPhi %6 %9 %95 %111 %106
207 OpLoopMerge %105 %106 PartialCount 3
208 OpBranch %107
209 %107 = OpLabel
210 %109 = OpSLessThan %17 %141 %16
211 OpBranchConditional %109 %104 %105
212 %104 = OpLabel
213 OpBranch %106
214 %106 = OpLabel
215 %111 = OpIAdd %6 %141 %20
216 OpStore %102 %111
217 OpBranch %103
218 %105 = OpLabel
219 OpStore %112 %9
220 OpBranch %113
221 %113 = OpLabel
222 %142 = OpPhi %6 %9 %105 %121 %116
223 OpLoopMerge %115 %116 Unroll|PeelCount|PartialCount 3 4
224 OpBranch %117
225 %117 = OpLabel
226 %119 = OpSLessThan %17 %142 %16
227 OpBranchConditional %119 %114 %115
228 %114 = OpLabel
229 OpBranch %116
230 %116 = OpLabel
231 %121 = OpIAdd %6 %142 %20
232 OpStore %112 %121
233 OpBranch %113
234 %115 = OpLabel
235 OpStore %122 %9
236 OpBranch %123
237 %123 = OpLabel
238 %143 = OpPhi %6 %9 %115 %131 %126
239 OpLoopMerge %125 %126 DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount 2 5 90 4 7 14
240 OpBranch %127
241 %127 = OpLabel
242 %129 = OpSLessThan %17 %143 %16
243 OpBranchConditional %129 %124 %125
244 %124 = OpLabel
245 OpBranch %126
246 %126 = OpLabel
247 %131 = OpIAdd %6 %143 %20
248 OpStore %122 %131
249 OpBranch %123
250 %125 = OpLabel
251 OpReturn
252 OpFunctionEnd
253 )";
254
255 const auto env = SPV_ENV_UNIVERSAL_1_4;
256 const auto consumer = nullptr;
257 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
258
259 spvtools::ValidatorOptions validator_options;
260 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
261 kConsoleMessageConsumer));
262 TransformationContext transformation_context(
263 MakeUnique<FactManager>(context.get()), validator_options);
264 // These are the loop headers together with the selection controls of their
265 // merge instructions:
266 // %10 None
267 // %23 Unroll
268 // %33 DontUnroll
269 // %43 DependencyInfinite
270 // %53 DependencyLength 3
271 // %63 MinIterations 10
272 // %73 MaxIterations 50
273 // %83 IterationMultiple 4
274 // %93 PeelCount 2
275 // %103 PartialCount 3
276 // %113 Unroll|PeelCount|PartialCount 3 4
277 // %123
278 // DependencyLength|MinIterations|MaxIterations|IterationMultiple|PeelCount|PartialCount
279 // 2 5 90 4 7 14
280
281 ASSERT_TRUE(TransformationSetLoopControl(
282 10, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
283 .IsApplicable(context.get(), transformation_context));
284 ASSERT_TRUE(TransformationSetLoopControl(
285 10, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
286 .IsApplicable(context.get(), transformation_context));
287 ASSERT_TRUE(TransformationSetLoopControl(
288 10, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
289 .IsApplicable(context.get(), transformation_context));
290 ASSERT_FALSE(TransformationSetLoopControl(
291 10, (uint32_t)spv::LoopControlMask::DependencyInfinite, 0, 0)
292 .IsApplicable(context.get(), transformation_context));
293 ASSERT_FALSE(TransformationSetLoopControl(
294 10, (uint32_t)spv::LoopControlMask::DependencyLength, 0, 0)
295 .IsApplicable(context.get(), transformation_context));
296 ASSERT_FALSE(TransformationSetLoopControl(
297 10, (uint32_t)spv::LoopControlMask::MinIterations, 0, 0)
298 .IsApplicable(context.get(), transformation_context));
299 ASSERT_FALSE(TransformationSetLoopControl(
300 10, (uint32_t)spv::LoopControlMask::MaxIterations, 0, 0)
301 .IsApplicable(context.get(), transformation_context));
302 ASSERT_FALSE(TransformationSetLoopControl(
303 10, (uint32_t)spv::LoopControlMask::IterationMultiple, 0, 0)
304 .IsApplicable(context.get(), transformation_context));
305 ASSERT_TRUE(TransformationSetLoopControl(
306 10, (uint32_t)spv::LoopControlMask::PeelCount, 3, 0)
307 .IsApplicable(context.get(), transformation_context));
308 ASSERT_FALSE(TransformationSetLoopControl(
309 10, (uint32_t)spv::LoopControlMask::PeelCount, 3, 3)
310 .IsApplicable(context.get(), transformation_context));
311 ASSERT_TRUE(TransformationSetLoopControl(
312 10, (uint32_t)spv::LoopControlMask::PartialCount, 0, 3)
313 .IsApplicable(context.get(), transformation_context));
314 ASSERT_FALSE(TransformationSetLoopControl(
315 10, (uint32_t)spv::LoopControlMask::PartialCount, 3, 3)
316 .IsApplicable(context.get(), transformation_context));
317 ASSERT_TRUE(TransformationSetLoopControl(
318 10,
319 (uint32_t)spv::LoopControlMask::PeelCount |
320 (uint32_t)spv::LoopControlMask::PartialCount,
321 3, 3)
322 .IsApplicable(context.get(), transformation_context));
323 ASSERT_TRUE(TransformationSetLoopControl(
324 10,
325 (uint32_t)spv::LoopControlMask::Unroll |
326 (uint32_t)spv::LoopControlMask::PeelCount |
327 (uint32_t)spv::LoopControlMask::PartialCount,
328 3, 3)
329 .IsApplicable(context.get(), transformation_context));
330 ASSERT_FALSE(TransformationSetLoopControl(
331 10,
332 (uint32_t)spv::LoopControlMask::DontUnroll |
333 (uint32_t)spv::LoopControlMask::PeelCount |
334 (uint32_t)spv::LoopControlMask::PartialCount,
335 3, 3)
336 .IsApplicable(context.get(), transformation_context));
337
338 ASSERT_TRUE(TransformationSetLoopControl(
339 23, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
340 .IsApplicable(context.get(), transformation_context));
341 ASSERT_TRUE(TransformationSetLoopControl(
342 23, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
343 .IsApplicable(context.get(), transformation_context));
344 ASSERT_TRUE(TransformationSetLoopControl(
345 23, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
346 .IsApplicable(context.get(), transformation_context));
347 ASSERT_TRUE(TransformationSetLoopControl(
348 23,
349 (uint32_t)spv::LoopControlMask::PeelCount |
350 (uint32_t)spv::LoopControlMask::PartialCount,
351 3, 3)
352 .IsApplicable(context.get(), transformation_context));
353 ASSERT_FALSE(TransformationSetLoopControl(
354 23, (uint32_t)spv::LoopControlMask::MaxIterations, 2, 3)
355 .IsApplicable(context.get(), transformation_context));
356
357 ASSERT_TRUE(TransformationSetLoopControl(
358 33, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
359 .IsApplicable(context.get(), transformation_context));
360 ASSERT_TRUE(TransformationSetLoopControl(
361 33, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
362 .IsApplicable(context.get(), transformation_context));
363 ASSERT_TRUE(TransformationSetLoopControl(
364 33, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
365 .IsApplicable(context.get(), transformation_context));
366 ASSERT_FALSE(TransformationSetLoopControl(
367 33, (uint32_t)spv::LoopControlMask::MinIterations, 0, 0)
368 .IsApplicable(context.get(), transformation_context));
369 ASSERT_TRUE(TransformationSetLoopControl(
370 33,
371 (uint32_t)spv::LoopControlMask::Unroll |
372 (uint32_t)spv::LoopControlMask::PeelCount,
373 5, 0)
374 .IsApplicable(context.get(), transformation_context));
375 ASSERT_FALSE(TransformationSetLoopControl(
376 33,
377 (uint32_t)spv::LoopControlMask::DontUnroll |
378 (uint32_t)spv::LoopControlMask::PartialCount,
379 0, 10)
380 .IsApplicable(context.get(), transformation_context));
381
382 ASSERT_TRUE(TransformationSetLoopControl(
383 43, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
384 .IsApplicable(context.get(), transformation_context));
385 ASSERT_TRUE(TransformationSetLoopControl(
386 43, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
387 .IsApplicable(context.get(), transformation_context));
388 ASSERT_TRUE(TransformationSetLoopControl(
389 43, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
390 .IsApplicable(context.get(), transformation_context));
391 ASSERT_TRUE(TransformationSetLoopControl(
392 43,
393 (uint32_t)spv::LoopControlMask::MaskNone |
394 (uint32_t)spv::LoopControlMask::DependencyInfinite,
395 0, 0)
396 .IsApplicable(context.get(), transformation_context));
397 ASSERT_TRUE(TransformationSetLoopControl(
398 43,
399 (uint32_t)spv::LoopControlMask::Unroll |
400 (uint32_t)spv::LoopControlMask::DependencyInfinite,
401 0, 0)
402 .IsApplicable(context.get(), transformation_context));
403 ASSERT_TRUE(TransformationSetLoopControl(
404 43,
405 (uint32_t)spv::LoopControlMask::DontUnroll |
406 (uint32_t)spv::LoopControlMask::DependencyInfinite,
407 0, 0)
408 .IsApplicable(context.get(), transformation_context));
409 ASSERT_FALSE(TransformationSetLoopControl(
410 43,
411 (uint32_t)spv::LoopControlMask::DependencyInfinite |
412 (uint32_t)spv::LoopControlMask::DependencyLength,
413 0, 0)
414 .IsApplicable(context.get(), transformation_context));
415 ASSERT_TRUE(TransformationSetLoopControl(
416 43,
417 (uint32_t)spv::LoopControlMask::Unroll |
418 (uint32_t)spv::LoopControlMask::PeelCount,
419 5, 0)
420 .IsApplicable(context.get(), transformation_context));
421
422 ASSERT_TRUE(TransformationSetLoopControl(
423 53, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
424 .IsApplicable(context.get(), transformation_context));
425 ASSERT_TRUE(TransformationSetLoopControl(
426 53, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
427 .IsApplicable(context.get(), transformation_context));
428 ASSERT_TRUE(TransformationSetLoopControl(
429 53, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
430 .IsApplicable(context.get(), transformation_context));
431 ASSERT_FALSE(TransformationSetLoopControl(
432 53, (uint32_t)spv::LoopControlMask::MaxIterations, 0, 0)
433 .IsApplicable(context.get(), transformation_context));
434 ASSERT_TRUE(TransformationSetLoopControl(
435 53,
436 (uint32_t)spv::LoopControlMask::MaskNone |
437 (uint32_t)spv::LoopControlMask::DependencyLength,
438 0, 0)
439 .IsApplicable(context.get(), transformation_context));
440 ASSERT_FALSE(TransformationSetLoopControl(
441 53,
442 (uint32_t)spv::LoopControlMask::Unroll |
443 (uint32_t)spv::LoopControlMask::DependencyInfinite,
444 0, 0)
445 .IsApplicable(context.get(), transformation_context));
446 ASSERT_TRUE(TransformationSetLoopControl(
447 53,
448 (uint32_t)spv::LoopControlMask::DontUnroll |
449 (uint32_t)spv::LoopControlMask::DependencyLength,
450 0, 0)
451 .IsApplicable(context.get(), transformation_context));
452 ASSERT_FALSE(TransformationSetLoopControl(
453 53,
454 (uint32_t)spv::LoopControlMask::DependencyInfinite |
455 (uint32_t)spv::LoopControlMask::DependencyLength,
456 0, 0)
457 .IsApplicable(context.get(), transformation_context));
458 ASSERT_TRUE(TransformationSetLoopControl(
459 53,
460 (uint32_t)spv::LoopControlMask::Unroll |
461 (uint32_t)spv::LoopControlMask::DependencyLength |
462 (uint32_t)spv::LoopControlMask::PeelCount |
463 (uint32_t)spv::LoopControlMask::PartialCount,
464 5, 3)
465 .IsApplicable(context.get(), transformation_context));
466
467 ASSERT_TRUE(TransformationSetLoopControl(
468 63, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
469 .IsApplicable(context.get(), transformation_context));
470 ASSERT_TRUE(TransformationSetLoopControl(
471 63, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
472 .IsApplicable(context.get(), transformation_context));
473 ASSERT_TRUE(TransformationSetLoopControl(
474 63, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
475 .IsApplicable(context.get(), transformation_context));
476 ASSERT_TRUE(TransformationSetLoopControl(
477 63,
478 (uint32_t)spv::LoopControlMask::Unroll |
479 (uint32_t)spv::LoopControlMask::MinIterations |
480 (uint32_t)spv::LoopControlMask::PeelCount |
481 (uint32_t)spv::LoopControlMask::PartialCount,
482 5, 3)
483 .IsApplicable(context.get(), transformation_context));
484 ASSERT_TRUE(TransformationSetLoopControl(
485 63,
486 (uint32_t)spv::LoopControlMask::Unroll |
487 (uint32_t)spv::LoopControlMask::MinIterations |
488 (uint32_t)spv::LoopControlMask::PeelCount,
489 23, 0)
490 .IsApplicable(context.get(), transformation_context));
491 ASSERT_FALSE(TransformationSetLoopControl(
492 63,
493 (uint32_t)spv::LoopControlMask::Unroll |
494 (uint32_t)spv::LoopControlMask::MinIterations |
495 (uint32_t)spv::LoopControlMask::PeelCount,
496 2, 23)
497 .IsApplicable(context.get(), transformation_context));
498
499 ASSERT_TRUE(TransformationSetLoopControl(
500 73, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
501 .IsApplicable(context.get(), transformation_context));
502 ASSERT_TRUE(TransformationSetLoopControl(
503 73, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
504 .IsApplicable(context.get(), transformation_context));
505 ASSERT_TRUE(TransformationSetLoopControl(
506 73, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
507 .IsApplicable(context.get(), transformation_context));
508 ASSERT_FALSE(TransformationSetLoopControl(
509 73,
510 (uint32_t)spv::LoopControlMask::Unroll |
511 (uint32_t)spv::LoopControlMask::MinIterations |
512 (uint32_t)spv::LoopControlMask::PeelCount |
513 (uint32_t)spv::LoopControlMask::PartialCount,
514 5, 3)
515 .IsApplicable(context.get(), transformation_context));
516 ASSERT_TRUE(TransformationSetLoopControl(
517 73,
518 (uint32_t)spv::LoopControlMask::Unroll |
519 (uint32_t)spv::LoopControlMask::MaxIterations |
520 (uint32_t)spv::LoopControlMask::PeelCount,
521 23, 0)
522 .IsApplicable(context.get(), transformation_context));
523 ASSERT_FALSE(TransformationSetLoopControl(
524 73,
525 (uint32_t)spv::LoopControlMask::Unroll |
526 (uint32_t)spv::LoopControlMask::MaxIterations |
527 (uint32_t)spv::LoopControlMask::PeelCount,
528 2, 23)
529 .IsApplicable(context.get(), transformation_context));
530
531 ASSERT_TRUE(TransformationSetLoopControl(
532 83, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
533 .IsApplicable(context.get(), transformation_context));
534 ASSERT_TRUE(TransformationSetLoopControl(
535 83, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
536 .IsApplicable(context.get(), transformation_context));
537 ASSERT_TRUE(TransformationSetLoopControl(
538 83, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
539 .IsApplicable(context.get(), transformation_context));
540 ASSERT_FALSE(TransformationSetLoopControl(
541 83,
542 (uint32_t)spv::LoopControlMask::Unroll |
543 (uint32_t)spv::LoopControlMask::MinIterations |
544 (uint32_t)spv::LoopControlMask::PeelCount |
545 (uint32_t)spv::LoopControlMask::PartialCount,
546 5, 3)
547 .IsApplicable(context.get(), transformation_context));
548 ASSERT_TRUE(TransformationSetLoopControl(
549 83,
550 (uint32_t)spv::LoopControlMask::Unroll |
551 (uint32_t)spv::LoopControlMask::IterationMultiple |
552 (uint32_t)spv::LoopControlMask::PeelCount,
553 23, 0)
554 .IsApplicable(context.get(), transformation_context));
555 ASSERT_FALSE(TransformationSetLoopControl(
556 83,
557 (uint32_t)spv::LoopControlMask::Unroll |
558 (uint32_t)spv::LoopControlMask::IterationMultiple |
559 (uint32_t)spv::LoopControlMask::PeelCount,
560 2, 23)
561 .IsApplicable(context.get(), transformation_context));
562
563 ASSERT_TRUE(TransformationSetLoopControl(
564 93, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
565 .IsApplicable(context.get(), transformation_context));
566 ASSERT_TRUE(TransformationSetLoopControl(
567 93, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
568 .IsApplicable(context.get(), transformation_context));
569 ASSERT_TRUE(TransformationSetLoopControl(
570 93, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
571 .IsApplicable(context.get(), transformation_context));
572 ASSERT_TRUE(TransformationSetLoopControl(
573 93, (uint32_t)spv::LoopControlMask::PeelCount, 8, 0)
574 .IsApplicable(context.get(), transformation_context));
575 ASSERT_FALSE(TransformationSetLoopControl(
576 93, (uint32_t)spv::LoopControlMask::PeelCount, 8, 8)
577 .IsApplicable(context.get(), transformation_context));
578 ASSERT_TRUE(TransformationSetLoopControl(
579 93, (uint32_t)spv::LoopControlMask::PartialCount, 0, 8)
580 .IsApplicable(context.get(), transformation_context));
581 ASSERT_TRUE(TransformationSetLoopControl(
582 93,
583 (uint32_t)spv::LoopControlMask::PeelCount |
584 (uint32_t)spv::LoopControlMask::PartialCount,
585 16, 8)
586 .IsApplicable(context.get(), transformation_context));
587
588 ASSERT_TRUE(TransformationSetLoopControl(
589 103, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
590 .IsApplicable(context.get(), transformation_context));
591 ASSERT_TRUE(TransformationSetLoopControl(
592 103, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
593 .IsApplicable(context.get(), transformation_context));
594 ASSERT_TRUE(TransformationSetLoopControl(
595 103, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
596 .IsApplicable(context.get(), transformation_context));
597 ASSERT_TRUE(TransformationSetLoopControl(
598 103, (uint32_t)spv::LoopControlMask::PartialCount, 0, 60)
599 .IsApplicable(context.get(), transformation_context));
600 ASSERT_FALSE(TransformationSetLoopControl(
601 103,
602 (uint32_t)spv::LoopControlMask::DontUnroll |
603 (uint32_t)spv::LoopControlMask::PartialCount,
604 0, 60)
605 .IsApplicable(context.get(), transformation_context));
606
607 ASSERT_TRUE(TransformationSetLoopControl(
608 113, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
609 .IsApplicable(context.get(), transformation_context));
610 ASSERT_TRUE(TransformationSetLoopControl(
611 113, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
612 .IsApplicable(context.get(), transformation_context));
613 ASSERT_TRUE(TransformationSetLoopControl(
614 113, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
615 .IsApplicable(context.get(), transformation_context));
616 ASSERT_TRUE(TransformationSetLoopControl(
617 113, (uint32_t)spv::LoopControlMask::PeelCount, 12, 0)
618 .IsApplicable(context.get(), transformation_context));
619 ASSERT_FALSE(TransformationSetLoopControl(
620 113,
621 (uint32_t)spv::LoopControlMask::IterationMultiple |
622 (uint32_t)spv::LoopControlMask::PeelCount,
623 12, 0)
624 .IsApplicable(context.get(), transformation_context));
625
626 ASSERT_TRUE(TransformationSetLoopControl(
627 123, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0)
628 .IsApplicable(context.get(), transformation_context));
629 ASSERT_TRUE(TransformationSetLoopControl(
630 123, (uint32_t)spv::LoopControlMask::Unroll, 0, 0)
631 .IsApplicable(context.get(), transformation_context));
632 ASSERT_TRUE(TransformationSetLoopControl(
633 123, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0)
634 .IsApplicable(context.get(), transformation_context));
635 ASSERT_TRUE(TransformationSetLoopControl(
636 123,
637 (uint32_t)spv::LoopControlMask::MinIterations |
638 (uint32_t)spv::LoopControlMask::MaxIterations |
639 (uint32_t)spv::LoopControlMask::IterationMultiple |
640 (uint32_t)spv::LoopControlMask::PeelCount |
641 (uint32_t)spv::LoopControlMask::PartialCount,
642 7, 8)
643 .IsApplicable(context.get(), transformation_context));
644 ASSERT_TRUE(TransformationSetLoopControl(
645 123,
646 (uint32_t)spv::LoopControlMask::Unroll |
647 (uint32_t)spv::LoopControlMask::MinIterations |
648 (uint32_t)spv::LoopControlMask::MaxIterations |
649 (uint32_t)spv::LoopControlMask::PartialCount,
650 0, 9)
651 .IsApplicable(context.get(), transformation_context));
652 ASSERT_FALSE(TransformationSetLoopControl(
653 123,
654 (uint32_t)spv::LoopControlMask::Unroll |
655 (uint32_t)spv::LoopControlMask::MinIterations |
656 (uint32_t)spv::LoopControlMask::MaxIterations |
657 (uint32_t)spv::LoopControlMask::PartialCount,
658 7, 9)
659 .IsApplicable(context.get(), transformation_context));
660 ASSERT_FALSE(TransformationSetLoopControl(
661 123,
662 (uint32_t)spv::LoopControlMask::DontUnroll |
663 (uint32_t)spv::LoopControlMask::MinIterations |
664 (uint32_t)spv::LoopControlMask::MaxIterations |
665 (uint32_t)spv::LoopControlMask::PartialCount,
666 7, 9)
667 .IsApplicable(context.get(), transformation_context));
668
669 ApplyAndCheckFreshIds(TransformationSetLoopControl(
670 10,
671 (uint32_t)spv::LoopControlMask::Unroll |
672 (uint32_t)spv::LoopControlMask::PeelCount |
673 (uint32_t)spv::LoopControlMask::PartialCount,
674 3, 3),
675 context.get(), &transformation_context);
676 ApplyAndCheckFreshIds(
677 TransformationSetLoopControl(
678 23, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0),
679 context.get(), &transformation_context);
680 ApplyAndCheckFreshIds(TransformationSetLoopControl(
681 33, (uint32_t)spv::LoopControlMask::Unroll, 0, 0),
682 context.get(), &transformation_context);
683 ApplyAndCheckFreshIds(
684 TransformationSetLoopControl(
685 43,
686 (uint32_t)spv::LoopControlMask::DontUnroll |
687 (uint32_t)spv::LoopControlMask::DependencyInfinite,
688 0, 0),
689 context.get(), &transformation_context);
690 ApplyAndCheckFreshIds(TransformationSetLoopControl(
691 53, (uint32_t)spv::LoopControlMask::MaskNone, 0, 0),
692 context.get(), &transformation_context);
693 ApplyAndCheckFreshIds(TransformationSetLoopControl(
694 63,
695 (uint32_t)spv::LoopControlMask::Unroll |
696 (uint32_t)spv::LoopControlMask::MinIterations |
697 (uint32_t)spv::LoopControlMask::PeelCount,
698 23, 0),
699 context.get(), &transformation_context);
700 ApplyAndCheckFreshIds(TransformationSetLoopControl(
701 73,
702 (uint32_t)spv::LoopControlMask::Unroll |
703 (uint32_t)spv::LoopControlMask::MaxIterations |
704 (uint32_t)spv::LoopControlMask::PeelCount,
705 23, 0),
706 context.get(), &transformation_context);
707 ApplyAndCheckFreshIds(
708 TransformationSetLoopControl(
709 83, (uint32_t)spv::LoopControlMask::DontUnroll, 0, 0),
710 context.get(), &transformation_context);
711 ApplyAndCheckFreshIds(TransformationSetLoopControl(
712 93,
713 (uint32_t)spv::LoopControlMask::PeelCount |
714 (uint32_t)spv::LoopControlMask::PartialCount,
715 16, 8),
716 context.get(), &transformation_context);
717 ApplyAndCheckFreshIds(
718 TransformationSetLoopControl(
719 103, (uint32_t)spv::LoopControlMask::PartialCount, 0, 60),
720 context.get(), &transformation_context);
721 ApplyAndCheckFreshIds(
722 TransformationSetLoopControl(
723 113, (uint32_t)spv::LoopControlMask::PeelCount, 12, 0),
724 context.get(), &transformation_context);
725 ApplyAndCheckFreshIds(TransformationSetLoopControl(
726 123,
727 (uint32_t)spv::LoopControlMask::Unroll |
728 (uint32_t)spv::LoopControlMask::MinIterations |
729 (uint32_t)spv::LoopControlMask::MaxIterations |
730 (uint32_t)spv::LoopControlMask::PartialCount,
731 0, 9),
732 context.get(), &transformation_context);
733
734 std::string after_transformation = R"(
735 OpCapability Shader
736 %1 = OpExtInstImport "GLSL.std.450"
737 OpMemoryModel Logical GLSL450
738 OpEntryPoint Fragment %4 "main"
739 OpExecutionMode %4 OriginUpperLeft
740 OpSource ESSL 310
741 OpName %4 "main"
742 %2 = OpTypeVoid
743 %3 = OpTypeFunction %2
744 %6 = OpTypeInt 32 1
745 %7 = OpTypePointer Function %6
746 %9 = OpConstant %6 0
747 %16 = OpConstant %6 100
748 %17 = OpTypeBool
749 %20 = OpConstant %6 1
750 %4 = OpFunction %2 None %3
751 %5 = OpLabel
752 %8 = OpVariable %7 Function
753 %22 = OpVariable %7 Function
754 %32 = OpVariable %7 Function
755 %42 = OpVariable %7 Function
756 %52 = OpVariable %7 Function
757 %62 = OpVariable %7 Function
758 %72 = OpVariable %7 Function
759 %82 = OpVariable %7 Function
760 %92 = OpVariable %7 Function
761 %102 = OpVariable %7 Function
762 %112 = OpVariable %7 Function
763 %122 = OpVariable %7 Function
764 OpStore %8 %9
765 OpBranch %10
766 %10 = OpLabel
767 %132 = OpPhi %6 %9 %5 %21 %13
768 OpLoopMerge %12 %13 Unroll|PeelCount|PartialCount 3 3
769 OpBranch %14
770 %14 = OpLabel
771 %18 = OpSLessThan %17 %132 %16
772 OpBranchConditional %18 %11 %12
773 %11 = OpLabel
774 OpBranch %13
775 %13 = OpLabel
776 %21 = OpIAdd %6 %132 %20
777 OpStore %8 %21
778 OpBranch %10
779 %12 = OpLabel
780 OpStore %22 %9
781 OpBranch %23
782 %23 = OpLabel
783 %133 = OpPhi %6 %9 %12 %31 %26
784 OpLoopMerge %25 %26 DontUnroll
785 OpBranch %27
786 %27 = OpLabel
787 %29 = OpSLessThan %17 %133 %16
788 OpBranchConditional %29 %24 %25
789 %24 = OpLabel
790 OpBranch %26
791 %26 = OpLabel
792 %31 = OpIAdd %6 %133 %20
793 OpStore %22 %31
794 OpBranch %23
795 %25 = OpLabel
796 OpStore %32 %9
797 OpBranch %33
798 %33 = OpLabel
799 %134 = OpPhi %6 %9 %25 %41 %36
800 OpLoopMerge %35 %36 Unroll
801 OpBranch %37
802 %37 = OpLabel
803 %39 = OpSLessThan %17 %134 %16
804 OpBranchConditional %39 %34 %35
805 %34 = OpLabel
806 OpBranch %36
807 %36 = OpLabel
808 %41 = OpIAdd %6 %134 %20
809 OpStore %32 %41
810 OpBranch %33
811 %35 = OpLabel
812 OpStore %42 %9
813 OpBranch %43
814 %43 = OpLabel
815 %135 = OpPhi %6 %9 %35 %51 %46
816 OpLoopMerge %45 %46 DontUnroll|DependencyInfinite
817 OpBranch %47
818 %47 = OpLabel
819 %49 = OpSLessThan %17 %135 %16
820 OpBranchConditional %49 %44 %45
821 %44 = OpLabel
822 OpBranch %46
823 %46 = OpLabel
824 %51 = OpIAdd %6 %135 %20
825 OpStore %42 %51
826 OpBranch %43
827 %45 = OpLabel
828 OpStore %52 %9
829 OpBranch %53
830 %53 = OpLabel
831 %136 = OpPhi %6 %9 %45 %61 %56
832 OpLoopMerge %55 %56 None
833 OpBranch %57
834 %57 = OpLabel
835 %59 = OpSLessThan %17 %136 %16
836 OpBranchConditional %59 %54 %55
837 %54 = OpLabel
838 OpBranch %56
839 %56 = OpLabel
840 %61 = OpIAdd %6 %136 %20
841 OpStore %52 %61
842 OpBranch %53
843 %55 = OpLabel
844 OpStore %62 %9
845 OpBranch %63
846 %63 = OpLabel
847 %137 = OpPhi %6 %9 %55 %71 %66
848 OpLoopMerge %65 %66 Unroll|MinIterations|PeelCount 10 23
849 OpBranch %67
850 %67 = OpLabel
851 %69 = OpSLessThan %17 %137 %16
852 OpBranchConditional %69 %64 %65
853 %64 = OpLabel
854 OpBranch %66
855 %66 = OpLabel
856 %71 = OpIAdd %6 %137 %20
857 OpStore %62 %71
858 OpBranch %63
859 %65 = OpLabel
860 OpStore %72 %9
861 OpBranch %73
862 %73 = OpLabel
863 %138 = OpPhi %6 %9 %65 %81 %76
864 OpLoopMerge %75 %76 Unroll|MaxIterations|PeelCount 50 23
865 OpBranch %77
866 %77 = OpLabel
867 %79 = OpSLessThan %17 %138 %16
868 OpBranchConditional %79 %74 %75
869 %74 = OpLabel
870 OpBranch %76
871 %76 = OpLabel
872 %81 = OpIAdd %6 %138 %20
873 OpStore %72 %81
874 OpBranch %73
875 %75 = OpLabel
876 OpStore %82 %9
877 OpBranch %83
878 %83 = OpLabel
879 %139 = OpPhi %6 %9 %75 %91 %86
880 OpLoopMerge %85 %86 DontUnroll
881 OpBranch %87
882 %87 = OpLabel
883 %89 = OpSLessThan %17 %139 %16
884 OpBranchConditional %89 %84 %85
885 %84 = OpLabel
886 OpBranch %86
887 %86 = OpLabel
888 %91 = OpIAdd %6 %139 %20
889 OpStore %82 %91
890 OpBranch %83
891 %85 = OpLabel
892 OpStore %92 %9
893 OpBranch %93
894 %93 = OpLabel
895 %140 = OpPhi %6 %9 %85 %101 %96
896 OpLoopMerge %95 %96 PeelCount|PartialCount 16 8
897 OpBranch %97
898 %97 = OpLabel
899 %99 = OpSLessThan %17 %140 %16
900 OpBranchConditional %99 %94 %95
901 %94 = OpLabel
902 OpBranch %96
903 %96 = OpLabel
904 %101 = OpIAdd %6 %140 %20
905 OpStore %92 %101
906 OpBranch %93
907 %95 = OpLabel
908 OpStore %102 %9
909 OpBranch %103
910 %103 = OpLabel
911 %141 = OpPhi %6 %9 %95 %111 %106
912 OpLoopMerge %105 %106 PartialCount 60
913 OpBranch %107
914 %107 = OpLabel
915 %109 = OpSLessThan %17 %141 %16
916 OpBranchConditional %109 %104 %105
917 %104 = OpLabel
918 OpBranch %106
919 %106 = OpLabel
920 %111 = OpIAdd %6 %141 %20
921 OpStore %102 %111
922 OpBranch %103
923 %105 = OpLabel
924 OpStore %112 %9
925 OpBranch %113
926 %113 = OpLabel
927 %142 = OpPhi %6 %9 %105 %121 %116
928 OpLoopMerge %115 %116 PeelCount 12
929 OpBranch %117
930 %117 = OpLabel
931 %119 = OpSLessThan %17 %142 %16
932 OpBranchConditional %119 %114 %115
933 %114 = OpLabel
934 OpBranch %116
935 %116 = OpLabel
936 %121 = OpIAdd %6 %142 %20
937 OpStore %112 %121
938 OpBranch %113
939 %115 = OpLabel
940 OpStore %122 %9
941 OpBranch %123
942 %123 = OpLabel
943 %143 = OpPhi %6 %9 %115 %131 %126
944 OpLoopMerge %125 %126 Unroll|MinIterations|MaxIterations|PartialCount 5 90 9
945 OpBranch %127
946 %127 = OpLabel
947 %129 = OpSLessThan %17 %143 %16
948 OpBranchConditional %129 %124 %125
949 %124 = OpLabel
950 OpBranch %126
951 %126 = OpLabel
952 %131 = OpIAdd %6 %143 %20
953 OpStore %122 %131
954 OpBranch %123
955 %125 = OpLabel
956 OpReturn
957 OpFunctionEnd
958 )";
959 ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
960 }
961
TEST(TransformationSetLoopControlTest,CheckSPIRVVersionsRespected)962 TEST(TransformationSetLoopControlTest, CheckSPIRVVersionsRespected) {
963 // This test checks that we do not allow introducing PeelCount and
964 // PartialCount loop controls if the SPIR-V version being used does not
965 // support them.
966
967 std::string shader = R"(
968 OpCapability Shader
969 %1 = OpExtInstImport "GLSL.std.450"
970 OpMemoryModel Logical GLSL450
971 OpEntryPoint Fragment %4 "main"
972 OpExecutionMode %4 OriginUpperLeft
973 OpSource ESSL 310
974 OpName %4 "main"
975 OpName %8 "i"
976 %2 = OpTypeVoid
977 %3 = OpTypeFunction %2
978 %6 = OpTypeInt 32 1
979 %7 = OpTypePointer Function %6
980 %9 = OpConstant %6 0
981 %16 = OpConstant %6 10
982 %17 = OpTypeBool
983 %20 = OpConstant %6 1
984 %4 = OpFunction %2 None %3
985 %5 = OpLabel
986 %8 = OpVariable %7 Function
987 OpStore %8 %9
988 OpBranch %10
989 %10 = OpLabel
990 OpLoopMerge %12 %13 None
991 OpBranch %14
992 %14 = OpLabel
993 %15 = OpLoad %6 %8
994 %18 = OpSLessThan %17 %15 %16
995 OpBranchConditional %18 %11 %12
996 %11 = OpLabel
997 OpBranch %13
998 %13 = OpLabel
999 %19 = OpLoad %6 %8
1000 %21 = OpIAdd %6 %19 %20
1001 OpStore %8 %21
1002 OpBranch %10
1003 %12 = OpLabel
1004 OpReturn
1005 OpFunctionEnd
1006 )";
1007
1008 for (auto env :
1009 {SPV_ENV_UNIVERSAL_1_0, SPV_ENV_UNIVERSAL_1_1, SPV_ENV_UNIVERSAL_1_2,
1010 SPV_ENV_UNIVERSAL_1_3, SPV_ENV_UNIVERSAL_1_4, SPV_ENV_UNIVERSAL_1_5,
1011 SPV_ENV_VULKAN_1_0, SPV_ENV_VULKAN_1_1, SPV_ENV_VULKAN_1_1_SPIRV_1_4,
1012 SPV_ENV_VULKAN_1_2}) {
1013 const auto consumer = nullptr;
1014 const auto context =
1015 BuildModule(env, consumer, shader, kFuzzAssembleOption);
1016 spvtools::ValidatorOptions validator_options;
1017 ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1018 context.get(), validator_options, kConsoleMessageConsumer));
1019 TransformationContext transformation_context(
1020 MakeUnique<FactManager>(context.get()), validator_options);
1021 TransformationSetLoopControl peel_count(
1022 10, (uint32_t)spv::LoopControlMask::PeelCount, 4, 0);
1023 TransformationSetLoopControl partial_count(
1024 10, (uint32_t)spv::LoopControlMask::PartialCount, 0, 4);
1025
1026 switch (env) {
1027 case SPV_ENV_UNIVERSAL_1_0:
1028 case SPV_ENV_UNIVERSAL_1_1:
1029 case SPV_ENV_UNIVERSAL_1_2:
1030 case SPV_ENV_UNIVERSAL_1_3:
1031 case SPV_ENV_VULKAN_1_0:
1032 case SPV_ENV_VULKAN_1_1:
1033 // PeelCount and PartialCount were introduced in SPIRV 1.4, so are not
1034 // valid in the context of older versions.
1035 ASSERT_FALSE(
1036 peel_count.IsApplicable(context.get(), transformation_context));
1037 ASSERT_FALSE(
1038 partial_count.IsApplicable(context.get(), transformation_context));
1039 break;
1040 case SPV_ENV_UNIVERSAL_1_4:
1041 case SPV_ENV_UNIVERSAL_1_5:
1042 case SPV_ENV_VULKAN_1_1_SPIRV_1_4:
1043 case SPV_ENV_VULKAN_1_2:
1044 ASSERT_TRUE(
1045 peel_count.IsApplicable(context.get(), transformation_context));
1046 ASSERT_TRUE(
1047 partial_count.IsApplicable(context.get(), transformation_context));
1048 break;
1049 default:
1050 assert(false && "Unhandled environment");
1051 break;
1052 }
1053 }
1054 }
1055
1056 } // namespace
1057 } // namespace fuzz
1058 } // namespace spvtools
1059