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_replace_boolean_constant_with_constant_binary.h"
16
17 #include "source/fuzz/fuzzer_util.h"
18 #include "source/fuzz/id_use_descriptor.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(TransformationReplaceBooleanConstantWithConstantBinaryTest,BasicReplacements)26 TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
27 BasicReplacements) {
28 // The test came from the following pseudo-GLSL, where int64 and uint64 denote
29 // 64-bit integer types (they were replaced with int and uint during
30 // translation to SPIR-V, and the generated SPIR-V has been doctored to
31 // accommodate them).
32 //
33 // #version 450
34 //
35 // void main() {
36 // double d1, d2;
37 // d1 = 1.0;
38 // d2 = 2.0;
39 // float f1, f2;
40 // f1 = 4.0;
41 // f2 = 8.0;
42 // int i1, i2;
43 // i1 = 100;
44 // i2 = 200;
45 //
46 // uint u1, u2;
47 // u1 = 300u;
48 // u2 = 400u;
49 //
50 // int64 i64_1, i64_2;
51 // i64_1 = 500;
52 // i64_2 = 600;
53 //
54 // uint64 u64_1, u64_2;
55 // u64_1 = 700u;
56 // u64_2 = 800u;
57 //
58 // bool b, c, d, e;
59 // b = true;
60 // c = false;
61 // d = true || c;
62 // c = c && false;
63 // }
64 std::string shader = R"(
65 OpCapability Shader
66 OpCapability Float64
67 OpCapability Int64
68 %1 = OpExtInstImport "GLSL.std.450"
69 OpMemoryModel Logical GLSL450
70 OpEntryPoint Fragment %4 "main"
71 OpExecutionMode %4 OriginUpperLeft
72 OpSource GLSL 450
73 OpName %4 "main"
74 OpName %8 "d1"
75 OpName %10 "d2"
76 OpName %14 "f1"
77 OpName %16 "f2"
78 OpName %20 "i1"
79 OpName %22 "i2"
80 OpName %26 "u1"
81 OpName %28 "u2"
82 OpName %30 "i64_1"
83 OpName %32 "i64_2"
84 OpName %34 "u64_1"
85 OpName %36 "u64_2"
86 OpName %40 "b"
87 OpName %42 "c"
88 OpName %44 "d"
89 %2 = OpTypeVoid
90 %3 = OpTypeFunction %2
91 %6 = OpTypeFloat 64
92 %7 = OpTypePointer Function %6
93 %9 = OpConstant %6 1
94 %11 = OpConstant %6 2
95 %12 = OpTypeFloat 32
96 %13 = OpTypePointer Function %12
97 %15 = OpConstant %12 4
98 %17 = OpConstant %12 8
99 %18 = OpTypeInt 32 1
100 %60 = OpTypeInt 64 1
101 %61 = OpTypePointer Function %60
102 %19 = OpTypePointer Function %18
103 %21 = OpConstant %18 -100
104 %23 = OpConstant %18 200
105 %24 = OpTypeInt 32 0
106 %62 = OpTypeInt 64 0
107 %63 = OpTypePointer Function %62
108 %25 = OpTypePointer Function %24
109 %27 = OpConstant %24 300
110 %29 = OpConstant %24 400
111 %31 = OpConstant %60 -600
112 %33 = OpConstant %60 -500
113 %35 = OpConstant %62 700
114 %37 = OpConstant %62 800
115 %38 = OpTypeBool
116 %39 = OpTypePointer Function %38
117 %41 = OpConstantTrue %38
118 %43 = OpConstantFalse %38
119 %4 = OpFunction %2 None %3
120 %5 = OpLabel
121 %8 = OpVariable %7 Function
122 %10 = OpVariable %7 Function
123 %14 = OpVariable %13 Function
124 %16 = OpVariable %13 Function
125 %20 = OpVariable %19 Function
126 %22 = OpVariable %19 Function
127 %26 = OpVariable %25 Function
128 %28 = OpVariable %25 Function
129 %30 = OpVariable %61 Function
130 %32 = OpVariable %61 Function
131 %34 = OpVariable %63 Function
132 %36 = OpVariable %63 Function
133 %40 = OpVariable %39 Function
134 %42 = OpVariable %39 Function
135 %44 = OpVariable %39 Function
136 OpStore %8 %9
137 OpStore %10 %11
138 OpStore %14 %15
139 OpStore %16 %17
140 OpStore %20 %21
141 OpStore %22 %23
142 OpStore %26 %27
143 OpStore %28 %29
144 OpStore %30 %31
145 OpStore %32 %33
146 OpStore %34 %35
147 OpStore %36 %37
148 OpStore %40 %41
149 OpStore %42 %43
150 %45 = OpLoad %38 %42
151 %46 = OpLogicalOr %38 %41 %45
152 OpStore %44 %46
153 %47 = OpLoad %38 %42
154 %48 = OpLogicalAnd %38 %47 %43
155 OpStore %42 %48
156 OpReturn
157 OpFunctionEnd
158 )";
159
160 const auto env = SPV_ENV_UNIVERSAL_1_3;
161 const auto consumer = nullptr;
162 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
163 ASSERT_TRUE(IsValid(env, context.get()));
164
165 FactManager fact_manager;
166
167 std::vector<protobufs::IdUseDescriptor> uses_of_true = {
168 MakeIdUseDescriptor(41, MakeInstructionDescriptor(44, SpvOpStore, 12), 1),
169 MakeIdUseDescriptor(41, MakeInstructionDescriptor(46, SpvOpLogicalOr, 0),
170 0)};
171
172 std::vector<protobufs::IdUseDescriptor> uses_of_false = {
173 MakeIdUseDescriptor(43, MakeInstructionDescriptor(44, SpvOpStore, 13), 1),
174 MakeIdUseDescriptor(43, MakeInstructionDescriptor(48, SpvOpLogicalAnd, 0),
175 1)};
176
177 const uint32_t fresh_id = 100;
178
179 std::vector<SpvOp> fp_gt_opcodes = {
180 SpvOpFOrdGreaterThan, SpvOpFOrdGreaterThanEqual, SpvOpFUnordGreaterThan,
181 SpvOpFUnordGreaterThanEqual};
182
183 std::vector<SpvOp> fp_lt_opcodes = {SpvOpFOrdLessThan, SpvOpFOrdLessThanEqual,
184 SpvOpFUnordLessThan,
185 SpvOpFUnordLessThanEqual};
186
187 std::vector<SpvOp> int_gt_opcodes = {SpvOpSGreaterThan,
188 SpvOpSGreaterThanEqual};
189
190 std::vector<SpvOp> int_lt_opcodes = {SpvOpSLessThan, SpvOpSLessThanEqual};
191
192 std::vector<SpvOp> uint_gt_opcodes = {SpvOpUGreaterThan,
193 SpvOpUGreaterThanEqual};
194
195 std::vector<SpvOp> uint_lt_opcodes = {SpvOpULessThan, SpvOpULessThanEqual};
196
197 #define CHECK_OPERATOR(USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID) \
198 ASSERT_TRUE(TransformationReplaceBooleanConstantWithConstantBinary( \
199 USE_DESCRIPTOR, LHS_ID, RHS_ID, OPCODE, FRESH_ID) \
200 .IsApplicable(context.get(), fact_manager)); \
201 ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary( \
202 USE_DESCRIPTOR, RHS_ID, LHS_ID, OPCODE, FRESH_ID) \
203 .IsApplicable(context.get(), fact_manager));
204
205 #define CHECK_TRANSFORMATION_APPLICABILITY(GT_OPCODES, LT_OPCODES, SMALL_ID, \
206 LARGE_ID) \
207 for (auto gt_opcode : GT_OPCODES) { \
208 for (auto& true_use : uses_of_true) { \
209 CHECK_OPERATOR(true_use, LARGE_ID, SMALL_ID, gt_opcode, fresh_id); \
210 } \
211 for (auto& false_use : uses_of_false) { \
212 CHECK_OPERATOR(false_use, SMALL_ID, LARGE_ID, gt_opcode, fresh_id); \
213 } \
214 } \
215 for (auto lt_opcode : LT_OPCODES) { \
216 for (auto& true_use : uses_of_true) { \
217 CHECK_OPERATOR(true_use, SMALL_ID, LARGE_ID, lt_opcode, fresh_id); \
218 } \
219 for (auto& false_use : uses_of_false) { \
220 CHECK_OPERATOR(false_use, LARGE_ID, SMALL_ID, lt_opcode, fresh_id); \
221 } \
222 }
223
224 // Float
225 { CHECK_TRANSFORMATION_APPLICABILITY(fp_gt_opcodes, fp_lt_opcodes, 15, 17); }
226
227 // Double
228 { CHECK_TRANSFORMATION_APPLICABILITY(fp_gt_opcodes, fp_lt_opcodes, 9, 11); }
229
230 // Int32
231 {
232 CHECK_TRANSFORMATION_APPLICABILITY(int_gt_opcodes, int_lt_opcodes, 21, 23);
233 }
234
235 // Int64
236 {
237 CHECK_TRANSFORMATION_APPLICABILITY(int_gt_opcodes, int_lt_opcodes, 31, 33);
238 }
239
240 // Uint32
241 {
242 CHECK_TRANSFORMATION_APPLICABILITY(uint_gt_opcodes, uint_lt_opcodes, 27,
243 29);
244 }
245
246 // Uint64
247 {
248 CHECK_TRANSFORMATION_APPLICABILITY(uint_gt_opcodes, uint_lt_opcodes, 35,
249 37);
250 }
251
252 // Target id is not fresh
253 ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
254 uses_of_true[0], 15, 17, SpvOpFOrdLessThan, 15)
255 .IsApplicable(context.get(), fact_manager));
256
257 // LHS id does not exist
258 ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
259 uses_of_true[0], 300, 17, SpvOpFOrdLessThan, 200)
260 .IsApplicable(context.get(), fact_manager));
261
262 // RHS id does not exist
263 ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
264 uses_of_true[0], 15, 300, SpvOpFOrdLessThan, 200)
265 .IsApplicable(context.get(), fact_manager));
266
267 // LHS and RHS ids do not match type
268 ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
269 uses_of_true[0], 11, 17, SpvOpFOrdLessThan, 200)
270 .IsApplicable(context.get(), fact_manager));
271
272 // Opcode not appropriate
273 ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
274 uses_of_true[0], 15, 17, SpvOpFDiv, 200)
275 .IsApplicable(context.get(), fact_manager));
276
277 auto replace_true_with_double_comparison =
278 TransformationReplaceBooleanConstantWithConstantBinary(
279 uses_of_true[0], 11, 9, SpvOpFUnordGreaterThan, 100);
280 auto replace_true_with_uint32_comparison =
281 TransformationReplaceBooleanConstantWithConstantBinary(
282 uses_of_true[1], 27, 29, SpvOpULessThanEqual, 101);
283 auto replace_false_with_float_comparison =
284 TransformationReplaceBooleanConstantWithConstantBinary(
285 uses_of_false[0], 17, 15, SpvOpFOrdLessThan, 102);
286 auto replace_false_with_sint64_comparison =
287 TransformationReplaceBooleanConstantWithConstantBinary(
288 uses_of_false[1], 33, 31, SpvOpSLessThan, 103);
289
290 ASSERT_TRUE(replace_true_with_double_comparison.IsApplicable(context.get(),
291 fact_manager));
292 replace_true_with_double_comparison.Apply(context.get(), &fact_manager);
293 ASSERT_TRUE(IsValid(env, context.get()));
294 ASSERT_TRUE(replace_true_with_uint32_comparison.IsApplicable(context.get(),
295 fact_manager));
296 replace_true_with_uint32_comparison.Apply(context.get(), &fact_manager);
297 ASSERT_TRUE(IsValid(env, context.get()));
298 ASSERT_TRUE(replace_false_with_float_comparison.IsApplicable(context.get(),
299 fact_manager));
300 replace_false_with_float_comparison.Apply(context.get(), &fact_manager);
301 ASSERT_TRUE(IsValid(env, context.get()));
302 ASSERT_TRUE(replace_false_with_sint64_comparison.IsApplicable(context.get(),
303 fact_manager));
304 replace_false_with_sint64_comparison.Apply(context.get(), &fact_manager);
305 ASSERT_TRUE(IsValid(env, context.get()));
306
307 std::string after = R"(
308 OpCapability Shader
309 OpCapability Float64
310 OpCapability Int64
311 %1 = OpExtInstImport "GLSL.std.450"
312 OpMemoryModel Logical GLSL450
313 OpEntryPoint Fragment %4 "main"
314 OpExecutionMode %4 OriginUpperLeft
315 OpSource GLSL 450
316 OpName %4 "main"
317 OpName %8 "d1"
318 OpName %10 "d2"
319 OpName %14 "f1"
320 OpName %16 "f2"
321 OpName %20 "i1"
322 OpName %22 "i2"
323 OpName %26 "u1"
324 OpName %28 "u2"
325 OpName %30 "i64_1"
326 OpName %32 "i64_2"
327 OpName %34 "u64_1"
328 OpName %36 "u64_2"
329 OpName %40 "b"
330 OpName %42 "c"
331 OpName %44 "d"
332 %2 = OpTypeVoid
333 %3 = OpTypeFunction %2
334 %6 = OpTypeFloat 64
335 %7 = OpTypePointer Function %6
336 %9 = OpConstant %6 1
337 %11 = OpConstant %6 2
338 %12 = OpTypeFloat 32
339 %13 = OpTypePointer Function %12
340 %15 = OpConstant %12 4
341 %17 = OpConstant %12 8
342 %18 = OpTypeInt 32 1
343 %60 = OpTypeInt 64 1
344 %61 = OpTypePointer Function %60
345 %19 = OpTypePointer Function %18
346 %21 = OpConstant %18 -100
347 %23 = OpConstant %18 200
348 %24 = OpTypeInt 32 0
349 %62 = OpTypeInt 64 0
350 %63 = OpTypePointer Function %62
351 %25 = OpTypePointer Function %24
352 %27 = OpConstant %24 300
353 %29 = OpConstant %24 400
354 %31 = OpConstant %60 -600
355 %33 = OpConstant %60 -500
356 %35 = OpConstant %62 700
357 %37 = OpConstant %62 800
358 %38 = OpTypeBool
359 %39 = OpTypePointer Function %38
360 %41 = OpConstantTrue %38
361 %43 = OpConstantFalse %38
362 %4 = OpFunction %2 None %3
363 %5 = OpLabel
364 %8 = OpVariable %7 Function
365 %10 = OpVariable %7 Function
366 %14 = OpVariable %13 Function
367 %16 = OpVariable %13 Function
368 %20 = OpVariable %19 Function
369 %22 = OpVariable %19 Function
370 %26 = OpVariable %25 Function
371 %28 = OpVariable %25 Function
372 %30 = OpVariable %61 Function
373 %32 = OpVariable %61 Function
374 %34 = OpVariable %63 Function
375 %36 = OpVariable %63 Function
376 %40 = OpVariable %39 Function
377 %42 = OpVariable %39 Function
378 %44 = OpVariable %39 Function
379 OpStore %8 %9
380 OpStore %10 %11
381 OpStore %14 %15
382 OpStore %16 %17
383 OpStore %20 %21
384 OpStore %22 %23
385 OpStore %26 %27
386 OpStore %28 %29
387 OpStore %30 %31
388 OpStore %32 %33
389 OpStore %34 %35
390 OpStore %36 %37
391 %100 = OpFUnordGreaterThan %38 %11 %9
392 OpStore %40 %100
393 %102 = OpFOrdLessThan %38 %17 %15
394 OpStore %42 %102
395 %45 = OpLoad %38 %42
396 %101 = OpULessThanEqual %38 %27 %29
397 %46 = OpLogicalOr %38 %101 %45
398 OpStore %44 %46
399 %47 = OpLoad %38 %42
400 %103 = OpSLessThan %38 %33 %31
401 %48 = OpLogicalAnd %38 %47 %103
402 OpStore %42 %48
403 OpReturn
404 OpFunctionEnd
405 )";
406 ASSERT_TRUE(IsEqual(env, after, context.get()));
407
408 if (std::numeric_limits<double>::has_quiet_NaN) {
409 double quiet_nan_double = std::numeric_limits<double>::quiet_NaN();
410 uint32_t words[2];
411 memcpy(words, &quiet_nan_double, sizeof(double));
412 opt::Instruction::OperandList operands = {
413 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[0]}},
414 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[1]}}};
415 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
416 context.get(), SpvOpConstant, 6, 200, operands));
417 fuzzerutil::UpdateModuleIdBound(context.get(), 200);
418 ASSERT_TRUE(IsValid(env, context.get()));
419 // The transformation is not applicable because %200 is NaN.
420 ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
421 uses_of_true[0], 11, 200, SpvOpFOrdLessThan, 300)
422 .IsApplicable(context.get(), fact_manager));
423 }
424 if (std::numeric_limits<double>::has_infinity) {
425 double positive_infinity_double = std::numeric_limits<double>::infinity();
426 uint32_t words[2];
427 memcpy(words, &positive_infinity_double, sizeof(double));
428 opt::Instruction::OperandList operands = {
429 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[0]}},
430 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words[1]}}};
431 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
432 context.get(), SpvOpConstant, 6, 201, operands));
433 fuzzerutil::UpdateModuleIdBound(context.get(), 201);
434 ASSERT_TRUE(IsValid(env, context.get()));
435 // Even though the double constant %11 is less than the infinity %201, the
436 // transformation is restricted to only apply to finite values.
437 ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
438 uses_of_true[0], 11, 201, SpvOpFOrdLessThan, 300)
439 .IsApplicable(context.get(), fact_manager));
440 }
441 if (std::numeric_limits<float>::has_infinity) {
442 float positive_infinity_float = std::numeric_limits<float>::infinity();
443 float negative_infinity_float = -1 * positive_infinity_float;
444 uint32_t words_positive_infinity[1];
445 uint32_t words_negative_infinity[1];
446 memcpy(words_positive_infinity, &positive_infinity_float, sizeof(float));
447 memcpy(words_negative_infinity, &negative_infinity_float, sizeof(float));
448 opt::Instruction::OperandList operands_positive_infinity = {
449 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words_positive_infinity[0]}}};
450 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
451 context.get(), SpvOpConstant, 12, 202, operands_positive_infinity));
452 fuzzerutil::UpdateModuleIdBound(context.get(), 202);
453 opt::Instruction::OperandList operands = {
454 {SPV_OPERAND_TYPE_LITERAL_INTEGER, {words_negative_infinity[0]}}};
455 context->module()->AddGlobalValue(MakeUnique<opt::Instruction>(
456 context.get(), SpvOpConstant, 12, 203, operands));
457 fuzzerutil::UpdateModuleIdBound(context.get(), 203);
458 ASSERT_TRUE(IsValid(env, context.get()));
459 // Even though the negative infinity at %203 is less than the positive
460 // infinity %202, the transformation is restricted to only apply to finite
461 // values.
462 ASSERT_FALSE(TransformationReplaceBooleanConstantWithConstantBinary(
463 uses_of_true[0], 203, 202, SpvOpFOrdLessThan, 300)
464 .IsApplicable(context.get(), fact_manager));
465 }
466 }
467
TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,MergeInstructions)468 TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,
469 MergeInstructions) {
470 // The test came from the following GLSL:
471 //
472 // void main() {
473 // int x = 1;
474 // int y = 2;
475 // if (true) {
476 // x = 2;
477 // }
478 // while(false) {
479 // y = 2;
480 // }
481 // }
482
483 std::string shader = R"(
484 OpCapability Shader
485 %1 = OpExtInstImport "GLSL.std.450"
486 OpMemoryModel Logical GLSL450
487 OpEntryPoint Fragment %4 "main"
488 OpExecutionMode %4 OriginUpperLeft
489 OpSource GLSL 450
490 OpName %4 "main"
491 OpName %8 "x"
492 OpName %10 "y"
493 %2 = OpTypeVoid
494 %3 = OpTypeFunction %2
495 %6 = OpTypeInt 32 1
496 %7 = OpTypePointer Function %6
497 %9 = OpConstant %6 1
498 %11 = OpConstant %6 2
499 %12 = OpTypeBool
500 %13 = OpConstantTrue %12
501 %21 = OpConstantFalse %12
502 %4 = OpFunction %2 None %3
503 %5 = OpLabel
504 %8 = OpVariable %7 Function
505 %10 = OpVariable %7 Function
506 OpStore %8 %9
507 OpStore %10 %11
508 OpSelectionMerge %15 None
509 OpBranchConditional %13 %14 %15
510 %14 = OpLabel
511 OpStore %8 %11
512 OpBranch %15
513 %15 = OpLabel
514 OpBranch %16
515 %16 = OpLabel
516 OpLoopMerge %18 %19 None
517 OpBranchConditional %21 %17 %18
518 %17 = OpLabel
519 OpStore %10 %11
520 OpBranch %19
521 %19 = OpLabel
522 OpBranch %16
523 %18 = OpLabel
524 OpReturn
525 OpFunctionEnd
526 )";
527
528 const auto env = SPV_ENV_UNIVERSAL_1_3;
529 const auto consumer = nullptr;
530 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
531 ASSERT_TRUE(IsValid(env, context.get()));
532
533 FactManager fact_manager;
534
535 auto use_of_true_in_if = MakeIdUseDescriptor(
536 13, MakeInstructionDescriptor(10, SpvOpBranchConditional, 0), 0);
537 auto use_of_false_in_while = MakeIdUseDescriptor(
538 21, MakeInstructionDescriptor(16, SpvOpBranchConditional, 0), 0);
539
540 auto replacement_1 = TransformationReplaceBooleanConstantWithConstantBinary(
541 use_of_true_in_if, 9, 11, SpvOpSLessThan, 100);
542 auto replacement_2 = TransformationReplaceBooleanConstantWithConstantBinary(
543 use_of_false_in_while, 9, 11, SpvOpSGreaterThanEqual, 101);
544
545 ASSERT_TRUE(replacement_1.IsApplicable(context.get(), fact_manager));
546 replacement_1.Apply(context.get(), &fact_manager);
547 ASSERT_TRUE(IsValid(env, context.get()));
548
549 ASSERT_TRUE(replacement_2.IsApplicable(context.get(), fact_manager));
550 replacement_2.Apply(context.get(), &fact_manager);
551 ASSERT_TRUE(IsValid(env, context.get()));
552
553 std::string after = R"(
554 OpCapability Shader
555 %1 = OpExtInstImport "GLSL.std.450"
556 OpMemoryModel Logical GLSL450
557 OpEntryPoint Fragment %4 "main"
558 OpExecutionMode %4 OriginUpperLeft
559 OpSource GLSL 450
560 OpName %4 "main"
561 OpName %8 "x"
562 OpName %10 "y"
563 %2 = OpTypeVoid
564 %3 = OpTypeFunction %2
565 %6 = OpTypeInt 32 1
566 %7 = OpTypePointer Function %6
567 %9 = OpConstant %6 1
568 %11 = OpConstant %6 2
569 %12 = OpTypeBool
570 %13 = OpConstantTrue %12
571 %21 = OpConstantFalse %12
572 %4 = OpFunction %2 None %3
573 %5 = OpLabel
574 %8 = OpVariable %7 Function
575 %10 = OpVariable %7 Function
576 OpStore %8 %9
577 OpStore %10 %11
578 %100 = OpSLessThan %12 %9 %11
579 OpSelectionMerge %15 None
580 OpBranchConditional %100 %14 %15
581 %14 = OpLabel
582 OpStore %8 %11
583 OpBranch %15
584 %15 = OpLabel
585 OpBranch %16
586 %16 = OpLabel
587 %101 = OpSGreaterThanEqual %12 %9 %11
588 OpLoopMerge %18 %19 None
589 OpBranchConditional %101 %17 %18
590 %17 = OpLabel
591 OpStore %10 %11
592 OpBranch %19
593 %19 = OpLabel
594 OpBranch %16
595 %18 = OpLabel
596 OpReturn
597 OpFunctionEnd
598 )";
599
600 ASSERT_TRUE(IsEqual(env, after, context.get()));
601 }
602
TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest,OpPhi)603 TEST(TransformationReplaceBooleanConstantWithConstantBinaryTest, OpPhi) {
604 // Hand-written SPIR-V to check applicability of the transformation on an
605 // OpPhi argument.
606
607 std::string shader = R"(
608 OpCapability Shader
609 %1 = OpExtInstImport "GLSL.std.450"
610 OpMemoryModel Logical GLSL450
611 OpEntryPoint Fragment %4 "main"
612 OpExecutionMode %4 OriginUpperLeft
613 OpSource ESSL 310
614 OpName %4 "main"
615 %2 = OpTypeVoid
616 %3 = OpTypeFunction %2
617 %6 = OpTypeBool
618 %7 = OpTypePointer Function %6
619 %9 = OpConstantTrue %6
620 %16 = OpConstantFalse %6
621 %10 = OpTypeInt 32 1
622 %11 = OpTypePointer Function %10
623 %13 = OpConstant %10 0
624 %15 = OpConstant %10 1
625 %4 = OpFunction %2 None %3
626 %5 = OpLabel
627 OpSelectionMerge %20 None
628 OpBranchConditional %9 %21 %22
629 %21 = OpLabel
630 OpBranch %20
631 %22 = OpLabel
632 OpBranch %20
633 %20 = OpLabel
634 %23 = OpPhi %6 %9 %21 %16 %22
635 OpReturn
636 OpFunctionEnd
637 )";
638
639 const auto env = SPV_ENV_UNIVERSAL_1_3;
640 const auto consumer = nullptr;
641 const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
642 ASSERT_TRUE(IsValid(env, context.get()));
643
644 FactManager fact_manager;
645
646 auto replacement = TransformationReplaceBooleanConstantWithConstantBinary(
647 MakeIdUseDescriptor(9, MakeInstructionDescriptor(23, SpvOpPhi, 0), 0), 13,
648 15, SpvOpSLessThan, 100);
649
650 ASSERT_FALSE(replacement.IsApplicable(context.get(), fact_manager));
651 }
652
653 } // namespace
654 } // namespace fuzz
655 } // namespace spvtools
656