• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2020 Vasyl Teliman
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_propagate_instruction_up.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(TransformationPropagateInstructionUpTest,BasicTest)25 TEST(TransformationPropagateInstructionUpTest, BasicTest) {
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           %2 = OpTypeVoid
34           %3 = OpTypeFunction %2
35           %6 = OpTypeFloat 32
36           %7 = OpTypePointer Function %6
37           %9 = OpConstant %6 3.5
38          %11 = OpConstant %6 3.4000001
39          %12 = OpTypeBool
40          %17 = OpConstant %6 4
41          %20 = OpConstant %6 45
42          %27 = OpTypePointer Function %6
43           %4 = OpFunction %2 None %3
44 
45           %5 = OpLabel
46          %26 = OpVariable %27 Function
47          %13 = OpFOrdEqual %12 %9 %11
48                OpSelectionMerge %15 None
49                OpBranchConditional %13 %14 %19
50 
51          %14 = OpLabel
52          %18 = OpFMod %6 %9 %17
53                OpBranch %15
54 
55          %19 = OpLabel
56          %22 = OpFAdd %6 %11 %20
57                OpBranch %15
58 
59          %15 = OpLabel
60          %21 = OpPhi %6 %18 %14 %22 %19
61          %23 = OpFMul %6 %21 %21
62          %24 = OpFDiv %6 %21 %23
63                OpBranch %25
64 
65          %25 = OpLabel
66          %28 = OpPhi %6 %20 %15
67                OpStore %26 %28
68                OpReturn
69 
70                OpFunctionEnd
71   )";
72 
73   const auto env = SPV_ENV_UNIVERSAL_1_3;
74   const auto consumer = nullptr;
75   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
76   spvtools::ValidatorOptions validator_options;
77   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
78                                                kConsoleMessageConsumer));
79   TransformationContext transformation_context(
80       MakeUnique<FactManager>(context.get()), validator_options);
81   // |block_id| is invalid.
82   ASSERT_FALSE(TransformationPropagateInstructionUp(40, {{}}).IsApplicable(
83       context.get(), transformation_context));
84   ASSERT_FALSE(TransformationPropagateInstructionUp(26, {{}}).IsApplicable(
85       context.get(), transformation_context));
86 
87   // |block_id| has no predecessors.
88   ASSERT_FALSE(TransformationPropagateInstructionUp(5, {{}}).IsApplicable(
89       context.get(), transformation_context));
90 
91   // |block_id| has no valid instructions to propagate.
92   ASSERT_FALSE(TransformationPropagateInstructionUp(25, {{{15, 40}}})
93                    .IsApplicable(context.get(), transformation_context));
94 
95   // Not all predecessors have fresh ids.
96   ASSERT_FALSE(TransformationPropagateInstructionUp(15, {{{19, 40}, {40, 41}}})
97                    .IsApplicable(context.get(), transformation_context));
98 
99   // Not all ids are fresh.
100   ASSERT_FALSE(
101       TransformationPropagateInstructionUp(15, {{{19, 40}, {14, 14}, {40, 42}}})
102           .IsApplicable(context.get(), transformation_context));
103   ASSERT_FALSE(
104       TransformationPropagateInstructionUp(15, {{{19, 19}, {14, 40}, {40, 42}}})
105           .IsApplicable(context.get(), transformation_context));
106 
107   // Fresh ids have duplicates.
108   ASSERT_FALSE(
109       TransformationPropagateInstructionUp(15, {{{19, 40}, {14, 40}, {19, 41}}})
110           .IsApplicable(context.get(), transformation_context));
111 
112   // Valid transformations.
113   {
114     TransformationPropagateInstructionUp transformation(14, {{{5, 40}}});
115     ASSERT_TRUE(
116         transformation.IsApplicable(context.get(), transformation_context));
117     ApplyAndCheckFreshIds(transformation, context.get(),
118                           &transformation_context);
119     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
120         context.get(), validator_options, kConsoleMessageConsumer));
121   }
122   {
123     TransformationPropagateInstructionUp transformation(19, {{{5, 41}}});
124     ASSERT_TRUE(
125         transformation.IsApplicable(context.get(), transformation_context));
126     ApplyAndCheckFreshIds(transformation, context.get(),
127                           &transformation_context);
128     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
129         context.get(), validator_options, kConsoleMessageConsumer));
130   }
131 
132   std::string after_transformation = R"(
133                OpCapability Shader
134           %1 = OpExtInstImport "GLSL.std.450"
135                OpMemoryModel Logical GLSL450
136                OpEntryPoint Fragment %4 "main"
137                OpExecutionMode %4 OriginUpperLeft
138                OpSource ESSL 310
139           %2 = OpTypeVoid
140           %3 = OpTypeFunction %2
141           %6 = OpTypeFloat 32
142           %7 = OpTypePointer Function %6
143           %9 = OpConstant %6 3.5
144          %11 = OpConstant %6 3.4000001
145          %12 = OpTypeBool
146          %17 = OpConstant %6 4
147          %20 = OpConstant %6 45
148          %27 = OpTypePointer Function %6
149           %4 = OpFunction %2 None %3
150 
151           %5 = OpLabel
152          %26 = OpVariable %27 Function
153          %13 = OpFOrdEqual %12 %9 %11
154          %40 = OpFMod %6 %9 %17 ; propagated from %14
155          %41 = OpFAdd %6 %11 %20 ; propagated from %19
156                OpSelectionMerge %15 None
157                OpBranchConditional %13 %14 %19
158 
159          %14 = OpLabel
160          %18 = OpPhi %6 %40 %5 ; propagated into %5
161                OpBranch %15
162 
163          %19 = OpLabel
164          %22 = OpPhi %6 %41 %5 ; propagated into %5
165                OpBranch %15
166 
167          %15 = OpLabel
168          %21 = OpPhi %6 %18 %14 %22 %19
169          %23 = OpFMul %6 %21 %21
170          %24 = OpFDiv %6 %21 %23
171                OpBranch %25
172 
173          %25 = OpLabel
174          %28 = OpPhi %6 %20 %15
175                OpStore %26 %28
176                OpReturn
177 
178                OpFunctionEnd
179   )";
180 
181   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
182 
183   {
184     TransformationPropagateInstructionUp transformation(15,
185                                                         {{{14, 43}, {19, 44}}});
186     ASSERT_TRUE(
187         transformation.IsApplicable(context.get(), transformation_context));
188     ApplyAndCheckFreshIds(transformation, context.get(),
189                           &transformation_context);
190     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
191         context.get(), validator_options, kConsoleMessageConsumer));
192   }
193 
194   after_transformation = R"(
195                OpCapability Shader
196           %1 = OpExtInstImport "GLSL.std.450"
197                OpMemoryModel Logical GLSL450
198                OpEntryPoint Fragment %4 "main"
199                OpExecutionMode %4 OriginUpperLeft
200                OpSource ESSL 310
201           %2 = OpTypeVoid
202           %3 = OpTypeFunction %2
203           %6 = OpTypeFloat 32
204           %7 = OpTypePointer Function %6
205           %9 = OpConstant %6 3.5
206          %11 = OpConstant %6 3.4000001
207          %12 = OpTypeBool
208          %17 = OpConstant %6 4
209          %20 = OpConstant %6 45
210          %27 = OpTypePointer Function %6
211           %4 = OpFunction %2 None %3
212 
213           %5 = OpLabel
214          %26 = OpVariable %27 Function
215          %13 = OpFOrdEqual %12 %9 %11
216          %40 = OpFMod %6 %9 %17
217          %41 = OpFAdd %6 %11 %20
218                OpSelectionMerge %15 None
219                OpBranchConditional %13 %14 %19
220 
221          %14 = OpLabel
222          %18 = OpPhi %6 %40 %5
223          %43 = OpFMul %6 %18 %18 ; propagated from %15
224                OpBranch %15
225 
226          %19 = OpLabel
227          %22 = OpPhi %6 %41 %5
228          %44 = OpFMul %6 %22 %22 ; propagated from %15
229                OpBranch %15
230 
231          %15 = OpLabel
232          %23 = OpPhi %6 %43 %14 %44 %19 ; propagated into %14 and %19
233          %21 = OpPhi %6 %18 %14 %22 %19
234          %24 = OpFDiv %6 %21 %23
235                OpBranch %25
236 
237          %25 = OpLabel
238          %28 = OpPhi %6 %20 %15
239                OpStore %26 %28
240                OpReturn
241 
242                OpFunctionEnd
243   )";
244 
245   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
246 
247   {
248     TransformationPropagateInstructionUp transformation(15,
249                                                         {{{14, 45}, {19, 46}}});
250     ASSERT_TRUE(
251         transformation.IsApplicable(context.get(), transformation_context));
252     ApplyAndCheckFreshIds(transformation, context.get(),
253                           &transformation_context);
254     ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
255         context.get(), validator_options, kConsoleMessageConsumer));
256   }
257 
258   after_transformation = R"(
259                OpCapability Shader
260           %1 = OpExtInstImport "GLSL.std.450"
261                OpMemoryModel Logical GLSL450
262                OpEntryPoint Fragment %4 "main"
263                OpExecutionMode %4 OriginUpperLeft
264                OpSource ESSL 310
265           %2 = OpTypeVoid
266           %3 = OpTypeFunction %2
267           %6 = OpTypeFloat 32
268           %7 = OpTypePointer Function %6
269           %9 = OpConstant %6 3.5
270          %11 = OpConstant %6 3.4000001
271          %12 = OpTypeBool
272          %17 = OpConstant %6 4
273          %20 = OpConstant %6 45
274          %27 = OpTypePointer Function %6
275           %4 = OpFunction %2 None %3
276 
277           %5 = OpLabel
278          %26 = OpVariable %27 Function
279          %13 = OpFOrdEqual %12 %9 %11
280          %40 = OpFMod %6 %9 %17
281          %41 = OpFAdd %6 %11 %20
282                OpSelectionMerge %15 None
283                OpBranchConditional %13 %14 %19
284 
285          %14 = OpLabel
286          %18 = OpPhi %6 %40 %5
287          %43 = OpFMul %6 %18 %18
288          %45 = OpFDiv %6 %18 %43 ; propagated from %15
289                OpBranch %15
290 
291          %19 = OpLabel
292          %22 = OpPhi %6 %41 %5
293          %44 = OpFMul %6 %22 %22
294          %46 = OpFDiv %6 %22 %44 ; propagated from %15
295                OpBranch %15
296 
297          %15 = OpLabel
298          %24 = OpPhi %6 %45 %14 %46 %19 ; propagated into %14 and %19
299          %23 = OpPhi %6 %43 %14 %44 %19
300          %21 = OpPhi %6 %18 %14 %22 %19
301                OpBranch %25
302 
303          %25 = OpLabel
304          %28 = OpPhi %6 %20 %15
305                OpStore %26 %28
306                OpReturn
307 
308                OpFunctionEnd
309   )";
310 
311   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
312 }
313 
TEST(TransformationPropagateInstructionUpTest,BlockDominatesPredecessor1)314 TEST(TransformationPropagateInstructionUpTest, BlockDominatesPredecessor1) {
315   std::string shader = R"(
316                OpCapability Shader
317           %1 = OpExtInstImport "GLSL.std.450"
318                OpMemoryModel Logical GLSL450
319                OpEntryPoint Fragment %4 "main"
320                OpExecutionMode %4 OriginUpperLeft
321                OpSource ESSL 310
322           %2 = OpTypeVoid
323           %3 = OpTypeFunction %2
324           %6 = OpTypeFloat 32
325           %7 = OpTypePointer Function %6
326           %9 = OpConstant %6 3.5
327          %11 = OpConstant %6 3.4000001
328          %12 = OpTypeBool
329          %17 = OpConstant %6 4
330          %20 = OpConstant %6 45
331           %4 = OpFunction %2 None %3
332 
333           %5 = OpLabel
334          %13 = OpFOrdEqual %12 %9 %11
335                OpSelectionMerge %15 None
336                OpBranchConditional %13 %14 %19
337 
338          %14 = OpLabel
339          %18 = OpFMod %6 %9 %17
340                OpBranch %15
341 
342          %19 = OpLabel
343          %22 = OpFAdd %6 %11 %20
344                OpBranch %15
345 
346          %15 = OpLabel ; dominates %26
347          %21 = OpPhi %6 %18 %14 %22 %19 %28 %26
348          %23 = OpFMul %6 %21 %21
349          %24 = OpFDiv %6 %21 %23
350                OpLoopMerge %27 %26 None
351                OpBranch %26
352 
353          %26 = OpLabel
354          %28 = OpFAdd %6 %24 %23
355                OpBranch %15
356 
357          %27 = OpLabel
358                OpReturn
359 
360                OpFunctionEnd
361   )";
362 
363   const auto env = SPV_ENV_UNIVERSAL_1_3;
364   const auto consumer = nullptr;
365   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
366   spvtools::ValidatorOptions validator_options;
367   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
368                                                kConsoleMessageConsumer));
369   TransformationContext transformation_context(
370       MakeUnique<FactManager>(context.get()), validator_options);
371   TransformationPropagateInstructionUp transformation(
372       15, {{{14, 40}, {19, 41}, {26, 42}}});
373   ASSERT_TRUE(
374       transformation.IsApplicable(context.get(), transformation_context));
375   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
376   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
377                                                kConsoleMessageConsumer));
378 
379   std::string after_transformation = R"(
380                OpCapability Shader
381           %1 = OpExtInstImport "GLSL.std.450"
382                OpMemoryModel Logical GLSL450
383                OpEntryPoint Fragment %4 "main"
384                OpExecutionMode %4 OriginUpperLeft
385                OpSource ESSL 310
386           %2 = OpTypeVoid
387           %3 = OpTypeFunction %2
388           %6 = OpTypeFloat 32
389           %7 = OpTypePointer Function %6
390           %9 = OpConstant %6 3.5
391          %11 = OpConstant %6 3.4000001
392          %12 = OpTypeBool
393          %17 = OpConstant %6 4
394          %20 = OpConstant %6 45
395           %4 = OpFunction %2 None %3
396 
397           %5 = OpLabel
398          %13 = OpFOrdEqual %12 %9 %11
399                OpSelectionMerge %15 None
400                OpBranchConditional %13 %14 %19
401 
402          %14 = OpLabel
403          %18 = OpFMod %6 %9 %17
404          %40 = OpFMul %6 %18 %18 ; propagated from %15
405                OpBranch %15
406 
407          %19 = OpLabel
408          %22 = OpFAdd %6 %11 %20
409          %41 = OpFMul %6 %22 %22 ; propagated from %15
410                OpBranch %15
411 
412          %15 = OpLabel
413          %23 = OpPhi %6 %40 %14 %41 %19 %42 %26 ; propagated into %14, %19, %26
414          %21 = OpPhi %6 %18 %14 %22 %19 %28 %26
415          %24 = OpFDiv %6 %21 %23
416                OpLoopMerge %27 %26 None
417                OpBranch %26
418 
419          %26 = OpLabel
420          %28 = OpFAdd %6 %24 %23
421          %42 = OpFMul %6 %28 %28 ; propagated from %15
422                OpBranch %15
423 
424          %27 = OpLabel
425                OpReturn
426 
427                OpFunctionEnd
428   )";
429 
430   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
431 }
432 
TEST(TransformationPropagateInstructionUpTest,BlockDominatesPredecessor2)433 TEST(TransformationPropagateInstructionUpTest, BlockDominatesPredecessor2) {
434   std::string shader = R"(
435                OpCapability Shader
436           %1 = OpExtInstImport "GLSL.std.450"
437                OpMemoryModel Logical GLSL450
438                OpEntryPoint Fragment %4 "main"
439                OpExecutionMode %4 OriginUpperLeft
440                OpSource ESSL 310
441           %2 = OpTypeVoid
442           %3 = OpTypeFunction %2
443           %6 = OpTypeFloat 32
444           %7 = OpTypePointer Function %6
445           %9 = OpConstant %6 3.5
446          %11 = OpConstant %6 3.4000001
447          %12 = OpTypeBool
448          %17 = OpConstant %6 4
449          %20 = OpConstant %6 45
450           %4 = OpFunction %2 None %3
451 
452           %5 = OpLabel
453          %13 = OpFOrdEqual %12 %9 %11
454                OpSelectionMerge %15 None
455                OpBranchConditional %13 %14 %19
456 
457          %14 = OpLabel
458          %18 = OpFMod %6 %9 %17
459                OpBranch %15
460 
461          %19 = OpLabel
462          %22 = OpFAdd %6 %11 %20
463                OpBranch %15
464 
465          %15 = OpLabel ; doesn't dominate %26
466          %21 = OpPhi %6 %18 %14 %22 %19 %20 %26
467          %23 = OpFMul %6 %21 %21
468          %24 = OpFDiv %6 %21 %23
469                OpLoopMerge %27 %26 None
470                OpBranch %27
471 
472          %26 = OpLabel
473                OpBranch %15
474 
475          %27 = OpLabel
476                OpReturn
477 
478                OpFunctionEnd
479   )";
480 
481   const auto env = SPV_ENV_UNIVERSAL_1_3;
482   const auto consumer = nullptr;
483   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
484   spvtools::ValidatorOptions validator_options;
485   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
486                                                kConsoleMessageConsumer));
487   TransformationContext transformation_context(
488       MakeUnique<FactManager>(context.get()), validator_options);
489   TransformationPropagateInstructionUp transformation(
490       15, {{{14, 40}, {19, 41}, {26, 42}}});
491   ASSERT_TRUE(
492       transformation.IsApplicable(context.get(), transformation_context));
493   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
494   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
495                                                kConsoleMessageConsumer));
496 
497   std::string after_transformation = R"(
498                OpCapability Shader
499           %1 = OpExtInstImport "GLSL.std.450"
500                OpMemoryModel Logical GLSL450
501                OpEntryPoint Fragment %4 "main"
502                OpExecutionMode %4 OriginUpperLeft
503                OpSource ESSL 310
504           %2 = OpTypeVoid
505           %3 = OpTypeFunction %2
506           %6 = OpTypeFloat 32
507           %7 = OpTypePointer Function %6
508           %9 = OpConstant %6 3.5
509          %11 = OpConstant %6 3.4000001
510          %12 = OpTypeBool
511          %17 = OpConstant %6 4
512          %20 = OpConstant %6 45
513           %4 = OpFunction %2 None %3
514 
515           %5 = OpLabel
516          %13 = OpFOrdEqual %12 %9 %11
517                OpSelectionMerge %15 None
518                OpBranchConditional %13 %14 %19
519 
520          %14 = OpLabel
521          %18 = OpFMod %6 %9 %17
522          %40 = OpFMul %6 %18 %18 ; propagated from %15
523                OpBranch %15
524 
525          %19 = OpLabel
526          %22 = OpFAdd %6 %11 %20
527          %41 = OpFMul %6 %22 %22 ; propagated from %15
528                OpBranch %15
529 
530          %15 = OpLabel
531          %23 = OpPhi %6 %40 %14 %41 %19 %42 %26 ; propagated into %14, %19, %26
532          %21 = OpPhi %6 %18 %14 %22 %19 %20 %26
533          %24 = OpFDiv %6 %21 %23
534                OpLoopMerge %27 %26 None
535                OpBranch %27
536 
537          %26 = OpLabel
538          %42 = OpFMul %6 %20 %20 ; propagated from %15
539                OpBranch %15
540 
541          %27 = OpLabel
542                OpReturn
543 
544                OpFunctionEnd
545   )";
546 
547   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
548 }
549 
TEST(TransformationPropagateInstructionUpTest,BlockDominatesPredecessor3)550 TEST(TransformationPropagateInstructionUpTest, BlockDominatesPredecessor3) {
551   std::string shader = R"(
552                OpCapability Shader
553           %1 = OpExtInstImport "GLSL.std.450"
554                OpMemoryModel Logical GLSL450
555                OpEntryPoint Fragment %4 "main"
556                OpExecutionMode %4 OriginUpperLeft
557                OpSource ESSL 310
558           %2 = OpTypeVoid
559           %3 = OpTypeFunction %2
560           %6 = OpTypeFloat 32
561           %7 = OpTypePointer Function %6
562           %9 = OpConstant %6 3.5
563          %11 = OpConstant %6 3.4000001
564          %12 = OpTypeBool
565          %17 = OpConstant %6 4
566          %20 = OpConstant %6 45
567           %4 = OpFunction %2 None %3
568 
569           %5 = OpLabel
570          %13 = OpFOrdEqual %12 %9 %11
571                OpSelectionMerge %15 None
572                OpBranchConditional %13 %14 %19
573 
574          %14 = OpLabel
575          %18 = OpFMod %6 %9 %17
576                OpBranch %15
577 
578          %19 = OpLabel
579          %22 = OpFAdd %6 %11 %20
580                OpBranch %15
581 
582          %15 = OpLabel ; branches to itself
583          %21 = OpPhi %6 %18 %14 %22 %19 %24 %15
584          %23 = OpFMul %6 %21 %21
585          %24 = OpFDiv %6 %21 %23
586                OpLoopMerge %27 %15 None
587                OpBranch %15
588 
589          %27 = OpLabel
590                OpReturn
591 
592                OpFunctionEnd
593   )";
594 
595   const auto env = SPV_ENV_UNIVERSAL_1_3;
596   const auto consumer = nullptr;
597   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
598   spvtools::ValidatorOptions validator_options;
599   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
600                                                kConsoleMessageConsumer));
601   TransformationContext transformation_context(
602       MakeUnique<FactManager>(context.get()), validator_options);
603   TransformationPropagateInstructionUp transformation(
604       15, {{{14, 40}, {19, 41}, {15, 42}}});
605   ASSERT_TRUE(
606       transformation.IsApplicable(context.get(), transformation_context));
607   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
608   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
609                                                kConsoleMessageConsumer));
610 
611   std::string after_transformation = R"(
612                OpCapability Shader
613           %1 = OpExtInstImport "GLSL.std.450"
614                OpMemoryModel Logical GLSL450
615                OpEntryPoint Fragment %4 "main"
616                OpExecutionMode %4 OriginUpperLeft
617                OpSource ESSL 310
618           %2 = OpTypeVoid
619           %3 = OpTypeFunction %2
620           %6 = OpTypeFloat 32
621           %7 = OpTypePointer Function %6
622           %9 = OpConstant %6 3.5
623          %11 = OpConstant %6 3.4000001
624          %12 = OpTypeBool
625          %17 = OpConstant %6 4
626          %20 = OpConstant %6 45
627           %4 = OpFunction %2 None %3
628 
629           %5 = OpLabel
630          %13 = OpFOrdEqual %12 %9 %11
631                OpSelectionMerge %15 None
632                OpBranchConditional %13 %14 %19
633 
634          %14 = OpLabel
635          %18 = OpFMod %6 %9 %17
636          %40 = OpFMul %6 %18 %18 ; propagated from %15
637                OpBranch %15
638 
639          %19 = OpLabel
640          %22 = OpFAdd %6 %11 %20
641          %41 = OpFMul %6 %22 %22 ; propagated from %15
642                OpBranch %15
643 
644          %15 = OpLabel
645          %23 = OpPhi %6 %40 %14 %41 %19 %42 %15 ; propagated into %14, %19, %15
646          %21 = OpPhi %6 %18 %14 %22 %19 %24 %15
647          %24 = OpFDiv %6 %21 %23
648          %42 = OpFMul %6 %24 %24 ; propagated from %15
649                OpLoopMerge %27 %15 None
650                OpBranch %15
651 
652          %27 = OpLabel
653                OpReturn
654 
655                OpFunctionEnd
656   )";
657 
658   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
659 }
660 
TEST(TransformationPropagateInstructionUpTest,HandlesVariablePointersCapability)661 TEST(TransformationPropagateInstructionUpTest,
662      HandlesVariablePointersCapability) {
663   std::string shader = R"(
664                OpCapability Shader
665           %1 = OpExtInstImport "GLSL.std.450"
666                OpMemoryModel Logical GLSL450
667                OpEntryPoint Fragment %4 "main"
668                OpExecutionMode %4 OriginUpperLeft
669                OpSource ESSL 310
670           %2 = OpTypeVoid
671           %3 = OpTypeFunction %2
672           %6 = OpTypeFloat 32
673          %11 = OpConstant %6 23
674           %7 = OpTypePointer Function %6
675           %4 = OpFunction %2 None %3
676 
677           %5 = OpLabel
678           %8 = OpVariable %7 Function
679                OpBranch %9
680 
681           %9 = OpLabel
682          %10 = OpCopyObject %7 %8
683                OpStore %10 %11
684                OpReturn
685 
686                OpFunctionEnd
687   )";
688 
689   const auto env = SPV_ENV_UNIVERSAL_1_3;
690   const auto consumer = nullptr;
691   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
692   spvtools::ValidatorOptions validator_options;
693   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
694                                                kConsoleMessageConsumer));
695   TransformationContext transformation_context(
696       MakeUnique<FactManager>(context.get()), validator_options);
697   // Required capabilities haven't yet been specified.
698   TransformationPropagateInstructionUp transformation(9, {{{5, 40}}});
699   ASSERT_FALSE(
700       transformation.IsApplicable(context.get(), transformation_context));
701 
702   context->AddCapability(SpvCapabilityVariablePointers);
703 
704   ASSERT_TRUE(
705       transformation.IsApplicable(context.get(), transformation_context));
706   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
707   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
708                                                kConsoleMessageConsumer));
709 
710   std::string after_transformation = R"(
711                OpCapability Shader
712                OpCapability VariablePointers
713           %1 = OpExtInstImport "GLSL.std.450"
714                OpMemoryModel Logical GLSL450
715                OpEntryPoint Fragment %4 "main"
716                OpExecutionMode %4 OriginUpperLeft
717                OpSource ESSL 310
718           %2 = OpTypeVoid
719           %3 = OpTypeFunction %2
720           %6 = OpTypeFloat 32
721          %11 = OpConstant %6 23
722           %7 = OpTypePointer Function %6
723           %4 = OpFunction %2 None %3
724 
725           %5 = OpLabel
726           %8 = OpVariable %7 Function
727          %40 = OpCopyObject %7 %8 ; propagated from %9
728                OpBranch %9
729 
730           %9 = OpLabel
731          %10 = OpPhi %7 %40 %5 ; propagated into %5
732                OpStore %10 %11
733                OpReturn
734 
735                OpFunctionEnd
736   )";
737 
738   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
739 }
740 
TEST(TransformationPropagateInstructionUpTest,HandlesVariablePointersStorageBufferCapability)741 TEST(TransformationPropagateInstructionUpTest,
742      HandlesVariablePointersStorageBufferCapability) {
743   std::string shader = R"(
744                OpCapability Shader
745           %1 = OpExtInstImport "GLSL.std.450"
746                OpMemoryModel Logical GLSL450
747                OpEntryPoint Fragment %4 "main"
748                OpExecutionMode %4 OriginUpperLeft
749                OpSource ESSL 310
750           %2 = OpTypeVoid
751           %3 = OpTypeFunction %2
752           %6 = OpTypeFloat 32
753          %11 = OpConstant %6 23
754           %7 = OpTypePointer Function %6
755           %4 = OpFunction %2 None %3
756 
757           %5 = OpLabel
758           %8 = OpVariable %7 Function
759                OpBranch %9
760 
761           %9 = OpLabel
762          %10 = OpCopyObject %7 %8
763                OpStore %10 %11
764                OpReturn
765 
766                OpFunctionEnd
767   )";
768 
769   const auto env = SPV_ENV_UNIVERSAL_1_3;
770   const auto consumer = nullptr;
771   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
772   spvtools::ValidatorOptions validator_options;
773   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
774                                                kConsoleMessageConsumer));
775   TransformationContext transformation_context(
776       MakeUnique<FactManager>(context.get()), validator_options);
777   // Required capabilities haven't yet been specified
778   TransformationPropagateInstructionUp transformation(9, {{{5, 40}}});
779   ASSERT_FALSE(
780       transformation.IsApplicable(context.get(), transformation_context));
781 
782   context->AddCapability(SpvCapabilityVariablePointersStorageBuffer);
783 
784   ASSERT_TRUE(
785       transformation.IsApplicable(context.get(), transformation_context));
786   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
787   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
788                                                kConsoleMessageConsumer));
789 
790   std::string after_transformation = R"(
791                OpCapability Shader
792                OpCapability VariablePointersStorageBuffer
793           %1 = OpExtInstImport "GLSL.std.450"
794                OpMemoryModel Logical GLSL450
795                OpEntryPoint Fragment %4 "main"
796                OpExecutionMode %4 OriginUpperLeft
797                OpSource ESSL 310
798           %2 = OpTypeVoid
799           %3 = OpTypeFunction %2
800           %6 = OpTypeFloat 32
801          %11 = OpConstant %6 23
802           %7 = OpTypePointer Function %6
803           %4 = OpFunction %2 None %3
804 
805           %5 = OpLabel
806           %8 = OpVariable %7 Function
807          %40 = OpCopyObject %7 %8 ; propagated from %9
808                OpBranch %9
809 
810           %9 = OpLabel
811          %10 = OpPhi %7 %40 %5 ; propagated into %5
812                OpStore %10 %11
813                OpReturn
814 
815                OpFunctionEnd
816   )";
817 
818   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
819 }
820 
TEST(TransformationPropagateInstructionUpTest,MultipleIdenticalPredecessors)821 TEST(TransformationPropagateInstructionUpTest, MultipleIdenticalPredecessors) {
822   std::string shader = R"(
823                OpCapability Shader
824           %1 = OpExtInstImport "GLSL.std.450"
825                OpMemoryModel Logical GLSL450
826                OpEntryPoint Fragment %4 "main"
827                OpExecutionMode %4 OriginUpperLeft
828                OpSource ESSL 310
829           %2 = OpTypeVoid
830           %3 = OpTypeFunction %2
831           %6 = OpTypeFloat 32
832          %11 = OpConstant %6 23
833          %12 = OpTypeBool
834          %13 = OpConstantTrue %12
835           %4 = OpFunction %2 None %3
836 
837           %5 = OpLabel
838                OpSelectionMerge %9 None
839                OpBranchConditional %13 %9 %9
840 
841           %9 = OpLabel
842          %14 = OpPhi %6 %11 %5
843          %10 = OpCopyObject %6 %14
844                OpReturn
845 
846                OpFunctionEnd
847   )";
848 
849   const auto env = SPV_ENV_UNIVERSAL_1_3;
850   const auto consumer = nullptr;
851   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
852   spvtools::ValidatorOptions validator_options;
853   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
854                                                kConsoleMessageConsumer));
855   TransformationContext transformation_context(
856       MakeUnique<FactManager>(context.get()), validator_options);
857   TransformationPropagateInstructionUp transformation(9, {{{5, 40}}});
858   ASSERT_TRUE(
859       transformation.IsApplicable(context.get(), transformation_context));
860   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
861   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
862                                                kConsoleMessageConsumer));
863 
864   std::string after_transformation = R"(
865                OpCapability Shader
866           %1 = OpExtInstImport "GLSL.std.450"
867                OpMemoryModel Logical GLSL450
868                OpEntryPoint Fragment %4 "main"
869                OpExecutionMode %4 OriginUpperLeft
870                OpSource ESSL 310
871           %2 = OpTypeVoid
872           %3 = OpTypeFunction %2
873           %6 = OpTypeFloat 32
874          %11 = OpConstant %6 23
875          %12 = OpTypeBool
876          %13 = OpConstantTrue %12
877           %4 = OpFunction %2 None %3
878 
879           %5 = OpLabel
880          %40 = OpCopyObject %6 %11
881                OpSelectionMerge %9 None
882                OpBranchConditional %13 %9 %9
883 
884           %9 = OpLabel
885          %10 = OpPhi %6 %40 %5
886          %14 = OpPhi %6 %11 %5
887                OpReturn
888 
889                OpFunctionEnd
890   )";
891 
892   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
893 }
894 
TEST(TransformationPropagateInstructionUpTest,InapplicableDueToOpTypeSampledImage)895 TEST(TransformationPropagateInstructionUpTest,
896      InapplicableDueToOpTypeSampledImage) {
897   std::string shader = R"(
898                OpCapability Shader
899           %1 = OpExtInstImport "GLSL.std.450"
900                OpMemoryModel Logical GLSL450
901                OpEntryPoint Fragment %4 "main" %10
902                OpExecutionMode %4 OriginUpperLeft
903                OpSource ESSL 320
904                OpDecorate %10 RelaxedPrecision
905                OpDecorate %10 DescriptorSet 0
906                OpDecorate %10 Binding 0
907           %2 = OpTypeVoid
908           %3 = OpTypeFunction %2
909           %6 = OpTypeFloat 32
910           %7 = OpTypeImage %6 2D 0 0 0 1 Unknown
911           %8 = OpTypeSampledImage %7
912           %9 = OpTypePointer UniformConstant %8
913          %10 = OpVariable %9 UniformConstant
914          %12 = OpTypeVector %6 2
915          %13 = OpConstant %6 0
916          %14 = OpConstantComposite %12 %13 %13
917          %15 = OpTypeVector %6 4
918          %30 = OpTypeBool
919          %31 = OpConstantTrue %30
920           %4 = OpFunction %2 None %3
921           %5 = OpLabel
922          %11 = OpLoad %8 %10
923                OpSelectionMerge %20 None
924                OpBranchConditional %31 %40 %41
925          %40 = OpLabel
926                OpBranch %20
927          %41 = OpLabel
928                OpBranch %20
929          %20 = OpLabel
930          %50 = OpCopyObject %8 %11
931          %16 = OpImageSampleImplicitLod %15 %50 %14
932                OpReturn
933                OpFunctionEnd
934 )";
935 
936   const auto env = SPV_ENV_UNIVERSAL_1_5;
937   const auto consumer = nullptr;
938   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
939   spvtools::ValidatorOptions validator_options;
940   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
941                                                kConsoleMessageConsumer));
942   TransformationContext transformation_context(
943       MakeUnique<FactManager>(context.get()), validator_options);
944 
945   ASSERT_FALSE(
946       TransformationPropagateInstructionUp(20, {{{40, 100}, {41, 101}}})
947           .IsApplicable(context.get(), transformation_context));
948 }
949 
950 }  // namespace
951 }  // namespace fuzz
952 }  // namespace spvtools
953