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