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_composite_extract.h"
16 
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/instruction_descriptor.h"
20 #include "test/fuzz/fuzz_test_util.h"
21 
22 namespace spvtools {
23 namespace fuzz {
24 namespace {
25 
TEST(TransformationCompositeExtractTest,BasicTest)26 TEST(TransformationCompositeExtractTest, BasicTest) {
27   std::string shader = R"(
28                OpCapability Shader
29           %1 = OpExtInstImport "GLSL.std.450"
30                OpMemoryModel Logical GLSL450
31                OpEntryPoint Fragment %4 "main"
32                OpExecutionMode %4 OriginUpperLeft
33                OpSource ESSL 310
34                OpName %4 "main"
35                OpName %8 "a"
36                OpName %10 "b"
37                OpName %17 "FunnyPoint"
38                OpMemberName %17 0 "x"
39                OpMemberName %17 1 "y"
40                OpMemberName %17 2 "z"
41                OpName %19 "p"
42           %2 = OpTypeVoid
43           %3 = OpTypeFunction %2
44           %6 = OpTypeInt 32 1
45           %7 = OpTypePointer Function %6
46          %12 = OpTypeBool
47          %16 = OpTypeFloat 32
48          %17 = OpTypeStruct %16 %16 %6
49          %81 = OpTypeStruct %17 %16
50          %18 = OpTypePointer Function %17
51          %20 = OpConstant %6 0
52          %23 = OpTypePointer Function %16
53          %26 = OpConstant %6 1
54          %30 = OpConstant %6 2
55          %80 = OpUndef %16
56           %4 = OpFunction %2 None %3
57           %5 = OpLabel
58           %8 = OpVariable %7 Function
59          %10 = OpVariable %7 Function
60          %19 = OpVariable %18 Function
61           %9 = OpLoad %6 %8
62          %11 = OpLoad %6 %10
63         %100 = OpCompositeConstruct %17 %80 %80 %26
64         %104 = OpCompositeConstruct %81 %100 %80
65          %13 = OpIEqual %12 %9 %11
66                OpSelectionMerge %15 None
67                OpBranchConditional %13 %14 %25
68          %14 = OpLabel
69          %21 = OpLoad %6 %8
70          %22 = OpConvertSToF %16 %21
71         %101 = OpCompositeConstruct %17 %22 %80 %30
72          %24 = OpAccessChain %23 %19 %20
73                OpStore %24 %22
74                OpBranch %15
75          %25 = OpLabel
76          %27 = OpLoad %6 %10
77          %28 = OpConvertSToF %16 %27
78         %102 = OpCompositeConstruct %17 %80 %28 %27
79          %29 = OpAccessChain %23 %19 %26
80                OpStore %29 %28
81                OpBranch %15
82          %15 = OpLabel
83          %31 = OpAccessChain %23 %19 %20
84          %32 = OpLoad %16 %31
85          %33 = OpAccessChain %23 %19 %26
86          %34 = OpLoad %16 %33
87         %103 = OpCompositeConstruct %17 %34 %32 %9
88          %35 = OpFAdd %16 %32 %34
89          %36 = OpConvertFToS %6 %35
90          %37 = OpAccessChain %7 %19 %30
91                OpStore %37 %36
92                OpReturn
93                OpFunctionEnd
94   )";
95 
96   const auto env = SPV_ENV_UNIVERSAL_1_4;
97   const auto consumer = nullptr;
98   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
99   spvtools::ValidatorOptions validator_options;
100   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
101                                                kConsoleMessageConsumer));
102   TransformationContext transformation_context(
103       MakeUnique<FactManager>(context.get()), validator_options);
104   // Instruction does not exist.
105   ASSERT_FALSE(TransformationCompositeExtract(
106                    MakeInstructionDescriptor(36, SpvOpIAdd, 0), 200, 101, {0})
107                    .IsApplicable(context.get(), transformation_context));
108 
109   // Id for composite is not a composite.
110   ASSERT_FALSE(
111       TransformationCompositeExtract(
112           MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 200, 32, {})
113           .IsApplicable(context.get(), transformation_context));
114 
115   // Composite does not dominate instruction being inserted before.
116   ASSERT_FALSE(
117       TransformationCompositeExtract(
118           MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 200, 101, {0})
119           .IsApplicable(context.get(), transformation_context));
120 
121   // Too many indices for extraction from struct composite.
122   ASSERT_FALSE(
123       TransformationCompositeExtract(
124           MakeInstructionDescriptor(24, SpvOpAccessChain, 0), 200, 101, {0, 0})
125           .IsApplicable(context.get(), transformation_context));
126 
127   // Too many indices for extraction from struct composite.
128   ASSERT_FALSE(
129       TransformationCompositeExtract(
130           MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 0, 0})
131           .IsApplicable(context.get(), transformation_context));
132 
133   // Out of bounds index for extraction from struct composite.
134   ASSERT_FALSE(
135       TransformationCompositeExtract(
136           MakeInstructionDescriptor(13, SpvOpIEqual, 0), 200, 104, {0, 3})
137           .IsApplicable(context.get(), transformation_context));
138 
139   // Result id already used.
140   ASSERT_FALSE(TransformationCompositeExtract(
141                    MakeInstructionDescriptor(35, SpvOpFAdd, 0), 80, 103, {0})
142                    .IsApplicable(context.get(), transformation_context));
143 
144   TransformationCompositeExtract transformation_1(
145       MakeInstructionDescriptor(36, SpvOpConvertFToS, 0), 201, 100, {2});
146   ASSERT_TRUE(
147       transformation_1.IsApplicable(context.get(), transformation_context));
148   ApplyAndCheckFreshIds(transformation_1, context.get(),
149                         &transformation_context);
150   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
151                                                kConsoleMessageConsumer));
152 
153   TransformationCompositeExtract transformation_2(
154       MakeInstructionDescriptor(37, SpvOpAccessChain, 0), 202, 104, {0, 2});
155   ASSERT_TRUE(
156       transformation_2.IsApplicable(context.get(), transformation_context));
157   ApplyAndCheckFreshIds(transformation_2, context.get(),
158                         &transformation_context);
159   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
160                                                kConsoleMessageConsumer));
161 
162   TransformationCompositeExtract transformation_3(
163       MakeInstructionDescriptor(29, SpvOpAccessChain, 0), 203, 104, {0});
164   ASSERT_TRUE(
165       transformation_3.IsApplicable(context.get(), transformation_context));
166   ApplyAndCheckFreshIds(transformation_3, context.get(),
167                         &transformation_context);
168   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
169                                                kConsoleMessageConsumer));
170 
171   TransformationCompositeExtract transformation_4(
172       MakeInstructionDescriptor(24, SpvOpStore, 0), 204, 101, {0});
173   ASSERT_TRUE(
174       transformation_4.IsApplicable(context.get(), transformation_context));
175   ApplyAndCheckFreshIds(transformation_4, context.get(),
176                         &transformation_context);
177   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
178                                                kConsoleMessageConsumer));
179 
180   TransformationCompositeExtract transformation_5(
181       MakeInstructionDescriptor(29, SpvOpBranch, 0), 205, 102, {2});
182   ASSERT_TRUE(
183       transformation_5.IsApplicable(context.get(), transformation_context));
184   ApplyAndCheckFreshIds(transformation_5, context.get(),
185                         &transformation_context);
186   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
187                                                kConsoleMessageConsumer));
188 
189   TransformationCompositeExtract transformation_6(
190       MakeInstructionDescriptor(37, SpvOpReturn, 0), 206, 103, {1});
191   ASSERT_TRUE(
192       transformation_6.IsApplicable(context.get(), transformation_context));
193   ApplyAndCheckFreshIds(transformation_6, context.get(),
194                         &transformation_context);
195   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
196                                                kConsoleMessageConsumer));
197 
198   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
199       MakeDataDescriptor(201, {}), MakeDataDescriptor(100, {2})));
200   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
201       MakeDataDescriptor(202, {}), MakeDataDescriptor(104, {0, 2})));
202   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
203       MakeDataDescriptor(203, {}), MakeDataDescriptor(104, {0})));
204   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
205       MakeDataDescriptor(204, {}), MakeDataDescriptor(101, {0})));
206   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
207       MakeDataDescriptor(205, {}), MakeDataDescriptor(102, {2})));
208   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
209       MakeDataDescriptor(206, {}), MakeDataDescriptor(103, {1})));
210 
211   std::string after_transformation = R"(
212                OpCapability Shader
213           %1 = OpExtInstImport "GLSL.std.450"
214                OpMemoryModel Logical GLSL450
215                OpEntryPoint Fragment %4 "main"
216                OpExecutionMode %4 OriginUpperLeft
217                OpSource ESSL 310
218                OpName %4 "main"
219                OpName %8 "a"
220                OpName %10 "b"
221                OpName %17 "FunnyPoint"
222                OpMemberName %17 0 "x"
223                OpMemberName %17 1 "y"
224                OpMemberName %17 2 "z"
225                OpName %19 "p"
226           %2 = OpTypeVoid
227           %3 = OpTypeFunction %2
228           %6 = OpTypeInt 32 1
229           %7 = OpTypePointer Function %6
230          %12 = OpTypeBool
231          %16 = OpTypeFloat 32
232          %17 = OpTypeStruct %16 %16 %6
233          %81 = OpTypeStruct %17 %16
234          %18 = OpTypePointer Function %17
235          %20 = OpConstant %6 0
236          %23 = OpTypePointer Function %16
237          %26 = OpConstant %6 1
238          %30 = OpConstant %6 2
239          %80 = OpUndef %16
240           %4 = OpFunction %2 None %3
241           %5 = OpLabel
242           %8 = OpVariable %7 Function
243          %10 = OpVariable %7 Function
244          %19 = OpVariable %18 Function
245           %9 = OpLoad %6 %8
246          %11 = OpLoad %6 %10
247         %100 = OpCompositeConstruct %17 %80 %80 %26
248         %104 = OpCompositeConstruct %81 %100 %80
249          %13 = OpIEqual %12 %9 %11
250                OpSelectionMerge %15 None
251                OpBranchConditional %13 %14 %25
252          %14 = OpLabel
253          %21 = OpLoad %6 %8
254          %22 = OpConvertSToF %16 %21
255         %101 = OpCompositeConstruct %17 %22 %80 %30
256          %24 = OpAccessChain %23 %19 %20
257         %204 = OpCompositeExtract %16 %101 0
258                OpStore %24 %22
259                OpBranch %15
260          %25 = OpLabel
261          %27 = OpLoad %6 %10
262          %28 = OpConvertSToF %16 %27
263         %102 = OpCompositeConstruct %17 %80 %28 %27
264         %203 = OpCompositeExtract %17 %104 0
265          %29 = OpAccessChain %23 %19 %26
266                OpStore %29 %28
267         %205 = OpCompositeExtract %6 %102 2
268                OpBranch %15
269          %15 = OpLabel
270          %31 = OpAccessChain %23 %19 %20
271          %32 = OpLoad %16 %31
272          %33 = OpAccessChain %23 %19 %26
273          %34 = OpLoad %16 %33
274         %103 = OpCompositeConstruct %17 %34 %32 %9
275          %35 = OpFAdd %16 %32 %34
276         %201 = OpCompositeExtract %6 %100 2
277          %36 = OpConvertFToS %6 %35
278         %202 = OpCompositeExtract %6 %104 0 2
279          %37 = OpAccessChain %7 %19 %30
280                OpStore %37 %36
281         %206 = OpCompositeExtract %16 %103 1
282                OpReturn
283                OpFunctionEnd
284   )";
285   ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
286 }
287 
TEST(TransformationCompositeExtractTest,IllegalInsertionPoints)288 TEST(TransformationCompositeExtractTest, IllegalInsertionPoints) {
289   std::string shader = R"(
290                OpCapability Shader
291           %1 = OpExtInstImport "GLSL.std.450"
292                OpMemoryModel Logical GLSL450
293                OpEntryPoint Fragment %4 "main" %51 %27
294                OpExecutionMode %4 OriginUpperLeft
295                OpSource ESSL 310
296                OpName %4 "main"
297                OpName %25 "buf"
298                OpMemberName %25 0 "value"
299                OpName %27 ""
300                OpName %51 "color"
301                OpMemberDecorate %25 0 Offset 0
302                OpDecorate %25 Block
303                OpDecorate %27 DescriptorSet 0
304                OpDecorate %27 Binding 0
305                OpDecorate %51 Location 0
306           %2 = OpTypeVoid
307           %3 = OpTypeFunction %2
308           %6 = OpTypeFloat 32
309           %7 = OpTypeVector %6 4
310          %10 = OpConstant %6 0.300000012
311          %11 = OpConstant %6 0.400000006
312          %12 = OpConstant %6 0.5
313          %13 = OpConstant %6 1
314          %14 = OpConstantComposite %7 %10 %11 %12 %13
315          %15 = OpTypeInt 32 1
316          %18 = OpConstant %15 0
317          %25 = OpTypeStruct %6
318          %26 = OpTypePointer Uniform %25
319          %27 = OpVariable %26 Uniform
320          %28 = OpTypePointer Uniform %6
321          %32 = OpTypeBool
322         %103 = OpConstantTrue %32
323          %34 = OpConstant %6 0.100000001
324          %48 = OpConstant %15 1
325          %50 = OpTypePointer Output %7
326          %51 = OpVariable %50 Output
327         %100 = OpTypePointer Function %6
328           %4 = OpFunction %2 None %3
329           %5 = OpLabel
330         %101 = OpVariable %100 Function
331         %102 = OpVariable %100 Function
332                OpBranch %19
333          %19 = OpLabel
334          %60 = OpPhi %7 %14 %5 %58 %20
335          %59 = OpPhi %15 %18 %5 %49 %20
336          %29 = OpAccessChain %28 %27 %18
337          %30 = OpLoad %6 %29
338          %31 = OpConvertFToS %15 %30
339          %33 = OpSLessThan %32 %59 %31
340                OpLoopMerge %21 %20 None
341                OpBranchConditional %33 %20 %21
342          %20 = OpLabel
343          %39 = OpCompositeExtract %6 %60 0
344          %40 = OpFAdd %6 %39 %34
345          %55 = OpCompositeInsert %7 %40 %60 0
346          %44 = OpCompositeExtract %6 %60 1
347          %45 = OpFSub %6 %44 %34
348          %58 = OpCompositeInsert %7 %45 %55 1
349          %49 = OpIAdd %15 %59 %48
350                OpBranch %19
351          %21 = OpLabel
352                OpStore %51 %60
353                OpSelectionMerge %105 None
354                OpBranchConditional %103 %104 %105
355         %104 = OpLabel
356                OpBranch %105
357         %105 = OpLabel
358                OpReturn
359                OpFunctionEnd
360   )";
361 
362   const auto env = SPV_ENV_UNIVERSAL_1_4;
363   const auto consumer = nullptr;
364   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
365   spvtools::ValidatorOptions validator_options;
366   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
367                                                kConsoleMessageConsumer));
368   TransformationContext transformation_context(
369       MakeUnique<FactManager>(context.get()), validator_options);
370   // Cannot insert before the OpVariables of a function.
371   ASSERT_FALSE(
372       TransformationCompositeExtract(
373           MakeInstructionDescriptor(101, SpvOpVariable, 0), 200, 14, {0})
374           .IsApplicable(context.get(), transformation_context));
375   ASSERT_FALSE(
376       TransformationCompositeExtract(
377           MakeInstructionDescriptor(101, SpvOpVariable, 1), 200, 14, {1})
378           .IsApplicable(context.get(), transformation_context));
379   ASSERT_FALSE(
380       TransformationCompositeExtract(
381           MakeInstructionDescriptor(102, SpvOpVariable, 0), 200, 14, {1})
382           .IsApplicable(context.get(), transformation_context));
383   // OK to insert right after the OpVariables.
384   ASSERT_FALSE(TransformationCompositeExtract(
385                    MakeInstructionDescriptor(102, SpvOpBranch, 1), 200, 14, {1})
386                    .IsApplicable(context.get(), transformation_context));
387 
388   // Cannot insert before the OpPhis of a block.
389   ASSERT_FALSE(TransformationCompositeExtract(
390                    MakeInstructionDescriptor(60, SpvOpPhi, 0), 200, 14, {2})
391                    .IsApplicable(context.get(), transformation_context));
392   ASSERT_FALSE(TransformationCompositeExtract(
393                    MakeInstructionDescriptor(59, SpvOpPhi, 0), 200, 14, {3})
394                    .IsApplicable(context.get(), transformation_context));
395   // OK to insert after the OpPhis.
396   ASSERT_TRUE(
397       TransformationCompositeExtract(
398           MakeInstructionDescriptor(59, SpvOpAccessChain, 0), 200, 14, {3})
399           .IsApplicable(context.get(), transformation_context));
400 
401   // Cannot insert before OpLoopMerge
402   ASSERT_FALSE(TransformationCompositeExtract(
403                    MakeInstructionDescriptor(33, SpvOpBranchConditional, 0),
404                    200, 14, {3})
405                    .IsApplicable(context.get(), transformation_context));
406 
407   // Cannot insert before OpSelectionMerge
408   ASSERT_FALSE(TransformationCompositeExtract(
409                    MakeInstructionDescriptor(21, SpvOpBranchConditional, 0),
410                    200, 14, {2})
411                    .IsApplicable(context.get(), transformation_context));
412 }
413 
TEST(TransformationCompositeExtractTest,AddSynonymsForRelevantIds)414 TEST(TransformationCompositeExtractTest, AddSynonymsForRelevantIds) {
415   std::string shader = R"(
416                OpCapability Shader
417           %1 = OpExtInstImport "GLSL.std.450"
418                OpMemoryModel Logical GLSL450
419                OpEntryPoint Fragment %4 "main"
420                OpExecutionMode %4 OriginUpperLeft
421                OpSource ESSL 310
422                OpName %4 "main"
423                OpName %8 "a"
424                OpName %10 "b"
425                OpName %17 "FunnyPoint"
426                OpMemberName %17 0 "x"
427                OpMemberName %17 1 "y"
428                OpMemberName %17 2 "z"
429                OpName %19 "p"
430           %2 = OpTypeVoid
431           %3 = OpTypeFunction %2
432           %6 = OpTypeInt 32 1
433           %7 = OpTypePointer Function %6
434          %12 = OpTypeBool
435          %16 = OpTypeFloat 32
436          %17 = OpTypeStruct %16 %16 %6
437          %81 = OpTypeStruct %17 %16
438          %18 = OpTypePointer Function %17
439          %20 = OpConstant %6 0
440          %23 = OpTypePointer Function %16
441          %26 = OpConstant %6 1
442          %30 = OpConstant %6 2
443          %80 = OpUndef %16
444           %4 = OpFunction %2 None %3
445           %5 = OpLabel
446           %8 = OpVariable %7 Function
447          %10 = OpVariable %7 Function
448          %19 = OpVariable %18 Function
449           %9 = OpLoad %6 %8
450          %11 = OpLoad %6 %10
451         %100 = OpCompositeConstruct %17 %80 %80 %26
452         %104 = OpCompositeConstruct %81 %100 %80
453          %13 = OpIEqual %12 %9 %11
454                OpSelectionMerge %15 None
455                OpBranchConditional %13 %14 %25
456          %14 = OpLabel
457          %21 = OpLoad %6 %8
458          %22 = OpConvertSToF %16 %21
459         %101 = OpCompositeConstruct %17 %22 %80 %30
460          %24 = OpAccessChain %23 %19 %20
461                OpStore %24 %22
462                OpBranch %15
463          %25 = OpLabel
464          %27 = OpLoad %6 %10
465          %28 = OpConvertSToF %16 %27
466         %102 = OpCompositeConstruct %17 %80 %28 %27
467          %29 = OpAccessChain %23 %19 %26
468                OpStore %29 %28
469                OpBranch %15
470          %15 = OpLabel
471          %31 = OpAccessChain %23 %19 %20
472          %32 = OpLoad %16 %31
473          %33 = OpAccessChain %23 %19 %26
474          %34 = OpLoad %16 %33
475         %103 = OpCompositeConstruct %17 %34 %32 %9
476          %35 = OpFAdd %16 %32 %34
477          %36 = OpConvertFToS %6 %35
478          %37 = OpAccessChain %7 %19 %30
479                OpStore %37 %36
480                OpReturn
481                OpFunctionEnd
482   )";
483 
484   const auto env = SPV_ENV_UNIVERSAL_1_4;
485   const auto consumer = nullptr;
486   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
487   spvtools::ValidatorOptions validator_options;
488   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
489                                                kConsoleMessageConsumer));
490   TransformationContext transformation_context(
491       MakeUnique<FactManager>(context.get()), validator_options);
492   TransformationCompositeExtract transformation(
493       MakeInstructionDescriptor(36, SpvOpConvertFToS, 0), 201, 100, {2});
494   ASSERT_TRUE(
495       transformation.IsApplicable(context.get(), transformation_context));
496   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
497   ASSERT_TRUE(transformation_context.GetFactManager()->IsSynonymous(
498       MakeDataDescriptor(201, {}), MakeDataDescriptor(100, {2})));
499 }
500 
TEST(TransformationCompositeExtractTest,DontAddSynonymsForIrrelevantIds)501 TEST(TransformationCompositeExtractTest, DontAddSynonymsForIrrelevantIds) {
502   std::string shader = R"(
503                OpCapability Shader
504           %1 = OpExtInstImport "GLSL.std.450"
505                OpMemoryModel Logical GLSL450
506                OpEntryPoint Fragment %4 "main"
507                OpExecutionMode %4 OriginUpperLeft
508                OpSource ESSL 310
509                OpName %4 "main"
510                OpName %8 "a"
511                OpName %10 "b"
512                OpName %17 "FunnyPoint"
513                OpMemberName %17 0 "x"
514                OpMemberName %17 1 "y"
515                OpMemberName %17 2 "z"
516                OpName %19 "p"
517           %2 = OpTypeVoid
518           %3 = OpTypeFunction %2
519           %6 = OpTypeInt 32 1
520           %7 = OpTypePointer Function %6
521          %12 = OpTypeBool
522          %16 = OpTypeFloat 32
523          %17 = OpTypeStruct %16 %16 %6
524          %81 = OpTypeStruct %17 %16
525          %18 = OpTypePointer Function %17
526          %20 = OpConstant %6 0
527          %23 = OpTypePointer Function %16
528          %26 = OpConstant %6 1
529          %30 = OpConstant %6 2
530          %80 = OpUndef %16
531           %4 = OpFunction %2 None %3
532           %5 = OpLabel
533           %8 = OpVariable %7 Function
534          %10 = OpVariable %7 Function
535          %19 = OpVariable %18 Function
536           %9 = OpLoad %6 %8
537          %11 = OpLoad %6 %10
538         %100 = OpCompositeConstruct %17 %80 %80 %26
539         %104 = OpCompositeConstruct %81 %100 %80
540          %13 = OpIEqual %12 %9 %11
541                OpSelectionMerge %15 None
542                OpBranchConditional %13 %14 %25
543          %14 = OpLabel
544          %21 = OpLoad %6 %8
545          %22 = OpConvertSToF %16 %21
546         %101 = OpCompositeConstruct %17 %22 %80 %30
547          %24 = OpAccessChain %23 %19 %20
548                OpStore %24 %22
549                OpBranch %15
550          %25 = OpLabel
551          %27 = OpLoad %6 %10
552          %28 = OpConvertSToF %16 %27
553         %102 = OpCompositeConstruct %17 %80 %28 %27
554          %29 = OpAccessChain %23 %19 %26
555                OpStore %29 %28
556                OpBranch %15
557          %15 = OpLabel
558          %31 = OpAccessChain %23 %19 %20
559          %32 = OpLoad %16 %31
560          %33 = OpAccessChain %23 %19 %26
561          %34 = OpLoad %16 %33
562         %103 = OpCompositeConstruct %17 %34 %32 %9
563          %35 = OpFAdd %16 %32 %34
564          %36 = OpConvertFToS %6 %35
565          %37 = OpAccessChain %7 %19 %30
566                OpStore %37 %36
567                OpReturn
568                OpFunctionEnd
569   )";
570 
571   const auto env = SPV_ENV_UNIVERSAL_1_4;
572   const auto consumer = nullptr;
573   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
574   spvtools::ValidatorOptions validator_options;
575   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
576                                                kConsoleMessageConsumer));
577   TransformationContext transformation_context(
578       MakeUnique<FactManager>(context.get()), validator_options);
579   transformation_context.GetFactManager()->AddFactIdIsIrrelevant(100);
580   TransformationCompositeExtract transformation(
581       MakeInstructionDescriptor(36, SpvOpConvertFToS, 0), 201, 100, {2});
582   ASSERT_TRUE(
583       transformation.IsApplicable(context.get(), transformation_context));
584   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
585   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
586       MakeDataDescriptor(201, {}), MakeDataDescriptor(100, {2})));
587 }
588 
TEST(TransformationCompositeExtractTest,DontAddSynonymInDeadBlock)589 TEST(TransformationCompositeExtractTest, DontAddSynonymInDeadBlock) {
590   std::string shader = R"(
591                OpCapability Shader
592           %1 = OpExtInstImport "GLSL.std.450"
593                OpMemoryModel Logical GLSL450
594                OpEntryPoint Fragment %4 "main"
595                OpExecutionMode %4 OriginUpperLeft
596                OpSource ESSL 320
597           %2 = OpTypeVoid
598           %3 = OpTypeFunction %2
599           %6 = OpTypeInt 32 1
600           %7 = OpTypeVector %6 2
601           %8 = OpTypePointer Function %7
602          %10 = OpConstant %6 0
603          %11 = OpConstant %6 1
604          %12 = OpConstantComposite %7 %10 %11
605          %13 = OpTypeBool
606          %14 = OpConstantFalse %13
607           %4 = OpFunction %2 None %3
608           %5 = OpLabel
609           %9 = OpVariable %8 Function
610                OpStore %9 %12
611                OpSelectionMerge %16 None
612                OpBranchConditional %14 %15 %16
613          %15 = OpLabel
614                OpBranch %16
615          %16 = OpLabel
616                OpReturn
617                OpFunctionEnd
618   )";
619 
620   const auto env = SPV_ENV_UNIVERSAL_1_4;
621   const auto consumer = nullptr;
622   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
623   spvtools::ValidatorOptions validator_options;
624   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
625                                                kConsoleMessageConsumer));
626   TransformationContext transformation_context(
627       MakeUnique<FactManager>(context.get()), validator_options);
628   transformation_context.GetFactManager()->AddFactBlockIsDead(15);
629   TransformationCompositeExtract transformation(
630       MakeInstructionDescriptor(15, SpvOpBranch, 0), 100, 12, {0});
631   ASSERT_TRUE(
632       transformation.IsApplicable(context.get(), transformation_context));
633   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
634   ASSERT_FALSE(transformation_context.GetFactManager()->IsSynonymous(
635       MakeDataDescriptor(100, {}), MakeDataDescriptor(12, {0})));
636 }
637 
638 }  // namespace
639 }  // namespace fuzz
640 }  // namespace spvtools
641