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_add_function.h"
16 
17 #include "gtest/gtest.h"
18 #include "source/fuzz/fuzzer_util.h"
19 #include "source/fuzz/instruction_message.h"
20 #include "test/fuzz/fuzz_test_util.h"
21 
22 namespace spvtools {
23 namespace fuzz {
24 namespace {
25 
MakeAccessClampingInfo( uint32_t access_chain_id, const std::vector<std::pair<uint32_t, uint32_t>>& compare_and_select_ids)26 protobufs::AccessChainClampingInfo MakeAccessClampingInfo(
27     uint32_t access_chain_id,
28     const std::vector<std::pair<uint32_t, uint32_t>>& compare_and_select_ids) {
29   protobufs::AccessChainClampingInfo result;
30   result.set_access_chain_id(access_chain_id);
31   for (auto& compare_and_select_id : compare_and_select_ids) {
32     auto pair = result.add_compare_and_select_ids();
33     pair->set_first(compare_and_select_id.first);
34     pair->set_second(compare_and_select_id.second);
35   }
36   return result;
37 }
38 
GetInstructionsForFunction( spv_target_env env, const MessageConsumer& consumer, const std::string& donor, uint32_t function_id)39 std::vector<protobufs::Instruction> GetInstructionsForFunction(
40     spv_target_env env, const MessageConsumer& consumer,
41     const std::string& donor, uint32_t function_id) {
42   std::vector<protobufs::Instruction> result;
43   const auto donor_context =
44       BuildModule(env, consumer, donor, kFuzzAssembleOption);
45   spvtools::ValidatorOptions validator_options;
46   assert(fuzzerutil::IsValidAndWellFormed(
47              donor_context.get(), validator_options, kConsoleMessageConsumer) &&
48          "The given donor must be valid.");
49   for (auto& function : *donor_context->module()) {
50     if (function.result_id() == function_id) {
51       function.ForEachInst([&result](opt::Instruction* inst) {
52         opt::Instruction::OperandList input_operands;
53         for (uint32_t i = 0; i < inst->NumInOperands(); i++) {
54           input_operands.push_back(inst->GetInOperand(i));
55         }
56         result.push_back(MakeInstructionMessage(inst->opcode(), inst->type_id(),
57                                                 inst->result_id(),
58                                                 input_operands));
59       });
60       break;
61     }
62   }
63   assert(!result.empty() && "The required function should have been found.");
64   return result;
65 }
66 
67 // Returns true if and only if every pointer parameter and variable associated
68 // with |function_id| in |context| is known by |transformation_context| to be
69 // irrelevant, with the exception of |loop_limiter_id|, which must not be
70 // irrelevant.  (It can be 0 if no loop limiter is expected, and 0 should not be
71 // deemed irrelevant).
AllVariablesAndParametersExceptLoopLimiterAreIrrelevant( opt::IRContext* context, const TransformationContext& transformation_context, uint32_t function_id, uint32_t loop_limiter_id)72 bool AllVariablesAndParametersExceptLoopLimiterAreIrrelevant(
73     opt::IRContext* context,
74     const TransformationContext& transformation_context, uint32_t function_id,
75     uint32_t loop_limiter_id) {
76   // Look at all the functions until the function of interest is found.
77   for (auto& function : *context->module()) {
78     if (function.result_id() != function_id) {
79       continue;
80     }
81     // Check that the parameters are all irrelevant.
82     bool found_non_irrelevant_parameter = false;
83     function.ForEachParam([context, &transformation_context,
84                            &found_non_irrelevant_parameter](
85                               opt::Instruction* inst) {
86       if (context->get_def_use_mgr()->GetDef(inst->type_id())->opcode() ==
87               spv::Op::OpTypePointer &&
88           !transformation_context.GetFactManager()->PointeeValueIsIrrelevant(
89               inst->result_id())) {
90         found_non_irrelevant_parameter = true;
91       }
92     });
93     if (found_non_irrelevant_parameter) {
94       // A non-irrelevant parameter was found.
95       return false;
96     }
97     // Look through the instructions in the function's first block.
98     for (auto& inst : *function.begin()) {
99       if (inst.opcode() != spv::Op::OpVariable) {
100         // We have found a non-variable instruction; this means we have gotten
101         // past all variables, so we are done.
102         return true;
103       }
104       // The variable should be irrelevant if and only if it is not the loop
105       // limiter.
106       if ((inst.result_id() == loop_limiter_id) ==
107           transformation_context.GetFactManager()->PointeeValueIsIrrelevant(
108               inst.result_id())) {
109         return false;
110       }
111     }
112     assert(false &&
113            "We should have processed all variables and returned by "
114            "this point.");
115   }
116   assert(false && "We should have found the function of interest.");
117   return true;
118 }
119 
TEST(TransformationAddFunctionTest, BasicTest)120 TEST(TransformationAddFunctionTest, BasicTest) {
121   std::string shader = R"(
122                OpCapability Shader
123           %1 = OpExtInstImport "GLSL.std.450"
124                OpMemoryModel Logical GLSL450
125                OpEntryPoint Fragment %4 "main"
126                OpExecutionMode %4 OriginUpperLeft
127                OpSource ESSL 310
128           %2 = OpTypeVoid
129           %3 = OpTypeFunction %2
130           %6 = OpTypeInt 32 1
131           %7 = OpTypePointer Function %6
132           %8 = OpTypeFloat 32
133           %9 = OpTypePointer Function %8
134          %10 = OpTypeFunction %8 %7 %9
135          %18 = OpConstant %8 0
136          %20 = OpConstant %6 0
137          %28 = OpTypeBool
138          %37 = OpConstant %6 1
139          %42 = OpTypePointer Private %8
140          %43 = OpVariable %42 Private
141          %47 = OpConstant %8 1
142           %4 = OpFunction %2 None %3
143           %5 = OpLabel
144                OpReturn
145                OpFunctionEnd
146   )";
147 
148   const auto env = SPV_ENV_UNIVERSAL_1_4;
149   const auto consumer = nullptr;
150   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
151   spvtools::ValidatorOptions validator_options;
152   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
153                                                kConsoleMessageConsumer));
154   TransformationContext transformation_context(
155       MakeUnique<FactManager>(context.get()), validator_options);
156   TransformationAddFunction transformation1(std::vector<protobufs::Instruction>(
157       {MakeInstructionMessage(spv::Op::OpFunction, 8, 13,
158                               {{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
159                                 {uint32_t(spv::FunctionControlMask::MaskNone)}},
160                                {SPV_OPERAND_TYPE_ID, {10}}}),
161        MakeInstructionMessage(spv::Op::OpFunctionParameter, 7, 11, {}),
162        MakeInstructionMessage(spv::Op::OpFunctionParameter, 9, 12, {}),
163        MakeInstructionMessage(spv::Op::OpLabel, 0, 14, {}),
164        MakeInstructionMessage(spv::Op::OpVariable, 9, 17,
165                               {{SPV_OPERAND_TYPE_STORAGE_CLASS,
166                                 {uint32_t(spv::StorageClass::Function)}}}),
167        MakeInstructionMessage(spv::Op::OpVariable, 7, 19,
168                               {{SPV_OPERAND_TYPE_STORAGE_CLASS,
169                                 {uint32_t(spv::StorageClass::Function)}}}),
170        MakeInstructionMessage(
171            spv::Op::OpStore, 0, 0,
172            {{SPV_OPERAND_TYPE_ID, {17}}, {SPV_OPERAND_TYPE_ID, {18}}}),
173        MakeInstructionMessage(
174            spv::Op::OpStore, 0, 0,
175            {{SPV_OPERAND_TYPE_ID, {19}}, {SPV_OPERAND_TYPE_ID, {20}}}),
176        MakeInstructionMessage(spv::Op::OpBranch, 0, 0,
177                               {{SPV_OPERAND_TYPE_ID, {21}}}),
178        MakeInstructionMessage(spv::Op::OpLabel, 0, 21, {}),
179        MakeInstructionMessage(spv::Op::OpLoopMerge, 0, 0,
180                               {{SPV_OPERAND_TYPE_ID, {23}},
181                                {SPV_OPERAND_TYPE_ID, {24}},
182                                {SPV_OPERAND_TYPE_LOOP_CONTROL,
183                                 {uint32_t(spv::LoopControlMask::MaskNone)}}}),
184        MakeInstructionMessage(spv::Op::OpBranch, 0, 0,
185                               {{SPV_OPERAND_TYPE_ID, {25}}}),
186        MakeInstructionMessage(spv::Op::OpLabel, 0, 25, {}),
187        MakeInstructionMessage(spv::Op::OpLoad, 6, 26,
188                               {{SPV_OPERAND_TYPE_ID, {19}}}),
189        MakeInstructionMessage(spv::Op::OpLoad, 6, 27,
190                               {{SPV_OPERAND_TYPE_ID, {11}}}),
191        MakeInstructionMessage(
192            spv::Op::OpSLessThan, 28, 29,
193            {{SPV_OPERAND_TYPE_ID, {26}}, {SPV_OPERAND_TYPE_ID, {27}}}),
194        MakeInstructionMessage(spv::Op::OpBranchConditional, 0, 0,
195                               {{SPV_OPERAND_TYPE_ID, {29}},
196                                {SPV_OPERAND_TYPE_ID, {22}},
197                                {SPV_OPERAND_TYPE_ID, {23}}}),
198        MakeInstructionMessage(spv::Op::OpLabel, 0, 22, {}),
199        MakeInstructionMessage(spv::Op::OpLoad, 8, 30,
200                               {{SPV_OPERAND_TYPE_ID, {12}}}),
201        MakeInstructionMessage(spv::Op::OpLoad, 6, 31,
202                               {{SPV_OPERAND_TYPE_ID, {19}}}),
203        MakeInstructionMessage(spv::Op::OpConvertSToF, 8, 32,
204                               {{SPV_OPERAND_TYPE_ID, {31}}}),
205        MakeInstructionMessage(
206            spv::Op::OpFMul, 8, 33,
207            {{SPV_OPERAND_TYPE_ID, {30}}, {SPV_OPERAND_TYPE_ID, {32}}}),
208        MakeInstructionMessage(spv::Op::OpLoad, 8, 34,
209                               {{SPV_OPERAND_TYPE_ID, {17}}}),
210        MakeInstructionMessage(
211            spv::Op::OpFAdd, 8, 35,
212            {{SPV_OPERAND_TYPE_ID, {34}}, {SPV_OPERAND_TYPE_ID, {33}}}),
213        MakeInstructionMessage(
214            spv::Op::OpStore, 0, 0,
215            {{SPV_OPERAND_TYPE_ID, {17}}, {SPV_OPERAND_TYPE_ID, {35}}}),
216        MakeInstructionMessage(spv::Op::OpBranch, 0, 0,
217                               {{SPV_OPERAND_TYPE_ID, {24}}}),
218        MakeInstructionMessage(spv::Op::OpLabel, 0, 24, {}),
219        MakeInstructionMessage(spv::Op::OpLoad, 6, 36,
220                               {{SPV_OPERAND_TYPE_ID, {19}}}),
221        MakeInstructionMessage(
222            spv::Op::OpIAdd, 6, 38,
223            {{SPV_OPERAND_TYPE_ID, {36}}, {SPV_OPERAND_TYPE_ID, {37}}}),
224        MakeInstructionMessage(
225            spv::Op::OpStore, 0, 0,
226            {{SPV_OPERAND_TYPE_ID, {19}}, {SPV_OPERAND_TYPE_ID, {38}}}),
227        MakeInstructionMessage(spv::Op::OpBranch, 0, 0,
228                               {{SPV_OPERAND_TYPE_ID, {21}}}),
229        MakeInstructionMessage(spv::Op::OpLabel, 0, 23, {}),
230        MakeInstructionMessage(spv::Op::OpLoad, 8, 39,
231                               {{SPV_OPERAND_TYPE_ID, {17}}}),
232        MakeInstructionMessage(spv::Op::OpReturnValue, 0, 0,
233                               {{SPV_OPERAND_TYPE_ID, {39}}}),
234        MakeInstructionMessage(spv::Op::OpFunctionEnd, 0, 0, {})}));
235 
236   ASSERT_TRUE(
237       transformation1.IsApplicable(context.get(), transformation_context));
238   ApplyAndCheckFreshIds(transformation1, context.get(),
239                         &transformation_context);
240   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
241                                                kConsoleMessageConsumer));
242 
243   std::string after_transformation1 = R"(
244                OpCapability Shader
245           %1 = OpExtInstImport "GLSL.std.450"
246                OpMemoryModel Logical GLSL450
247                OpEntryPoint Fragment %4 "main"
248                OpExecutionMode %4 OriginUpperLeft
249                OpSource ESSL 310
250           %2 = OpTypeVoid
251           %3 = OpTypeFunction %2
252           %6 = OpTypeInt 32 1
253           %7 = OpTypePointer Function %6
254           %8 = OpTypeFloat 32
255           %9 = OpTypePointer Function %8
256          %10 = OpTypeFunction %8 %7 %9
257          %18 = OpConstant %8 0
258          %20 = OpConstant %6 0
259          %28 = OpTypeBool
260          %37 = OpConstant %6 1
261          %42 = OpTypePointer Private %8
262          %43 = OpVariable %42 Private
263          %47 = OpConstant %8 1
264           %4 = OpFunction %2 None %3
265           %5 = OpLabel
266                OpReturn
267                OpFunctionEnd
268          %13 = OpFunction %8 None %10
269          %11 = OpFunctionParameter %7
270          %12 = OpFunctionParameter %9
271          %14 = OpLabel
272          %17 = OpVariable %9 Function
273          %19 = OpVariable %7 Function
274                OpStore %17 %18
275                OpStore %19 %20
276                OpBranch %21
277          %21 = OpLabel
278                OpLoopMerge %23 %24 None
279                OpBranch %25
280          %25 = OpLabel
281          %26 = OpLoad %6 %19
282          %27 = OpLoad %6 %11
283          %29 = OpSLessThan %28 %26 %27
284                OpBranchConditional %29 %22 %23
285          %22 = OpLabel
286          %30 = OpLoad %8 %12
287          %31 = OpLoad %6 %19
288          %32 = OpConvertSToF %8 %31
289          %33 = OpFMul %8 %30 %32
290          %34 = OpLoad %8 %17
291          %35 = OpFAdd %8 %34 %33
292                OpStore %17 %35
293                OpBranch %24
294          %24 = OpLabel
295          %36 = OpLoad %6 %19
296          %38 = OpIAdd %6 %36 %37
297                OpStore %19 %38
298                OpBranch %21
299          %23 = OpLabel
300          %39 = OpLoad %8 %17
301                OpReturnValue %39
302                OpFunctionEnd
303   )";
304   ASSERT_TRUE(IsEqual(env, after_transformation1, context.get()));
305   ASSERT_TRUE(transformation_context.GetFactManager()->BlockIsDead(14));
306   ASSERT_TRUE(transformation_context.GetFactManager()->BlockIsDead(21));
307   ASSERT_TRUE(transformation_context.GetFactManager()->BlockIsDead(22));
308   ASSERT_TRUE(transformation_context.GetFactManager()->BlockIsDead(23));
309   ASSERT_TRUE(transformation_context.GetFactManager()->BlockIsDead(24));
310   ASSERT_TRUE(transformation_context.GetFactManager()->BlockIsDead(25));
311 
312   TransformationAddFunction transformation2(std::vector<protobufs::Instruction>(
313       {MakeInstructionMessage(spv::Op::OpFunction, 2, 15,
314                               {{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
315                                 {uint32_t(spv::FunctionControlMask::MaskNone)}},
316                                {SPV_OPERAND_TYPE_ID, {3}}}),
317        MakeInstructionMessage(spv::Op::OpLabel, 0, 16, {}),
318        MakeInstructionMessage(spv::Op::OpVariable, 7, 44,
319                               {{SPV_OPERAND_TYPE_STORAGE_CLASS,
320                                 {uint32_t(spv::StorageClass::Function)}}}),
321        MakeInstructionMessage(spv::Op::OpVariable, 9, 45,
322                               {{SPV_OPERAND_TYPE_STORAGE_CLASS,
323                                 {uint32_t(spv::StorageClass::Function)}}}),
324        MakeInstructionMessage(spv::Op::OpVariable, 7, 48,
325                               {{SPV_OPERAND_TYPE_STORAGE_CLASS,
326                                 {uint32_t(spv::StorageClass::Function)}}}),
327        MakeInstructionMessage(spv::Op::OpVariable, 9, 49,
328                               {{SPV_OPERAND_TYPE_STORAGE_CLASS,
329                                 {uint32_t(spv::StorageClass::Function)}}}),
330        MakeInstructionMessage(
331            spv::Op::OpStore, 0, 0,
332            {{SPV_OPERAND_TYPE_ID, {44}}, {SPV_OPERAND_TYPE_ID, {20}}}),
333        MakeInstructionMessage(
334            spv::Op::OpStore, 0, 0,
335            {{SPV_OPERAND_TYPE_ID, {45}}, {SPV_OPERAND_TYPE_ID, {18}}}),
336        MakeInstructionMessage(spv::Op::OpFunctionCall, 8, 46,
337                               {{SPV_OPERAND_TYPE_ID, {13}},
338                                {SPV_OPERAND_TYPE_ID, {44}},
339                                {SPV_OPERAND_TYPE_ID, {45}}}),
340        MakeInstructionMessage(
341            spv::Op::OpStore, 0, 0,
342            {{SPV_OPERAND_TYPE_ID, {48}}, {SPV_OPERAND_TYPE_ID, {37}}}),
343        MakeInstructionMessage(
344            spv::Op::OpStore, 0, 0,
345            {{SPV_OPERAND_TYPE_ID, {49}}, {SPV_OPERAND_TYPE_ID, {47}}}),
346        MakeInstructionMessage(spv::Op::OpFunctionCall, 8, 50,
347                               {{SPV_OPERAND_TYPE_ID, {13}},
348                                {SPV_OPERAND_TYPE_ID, {48}},
349                                {SPV_OPERAND_TYPE_ID, {49}}}),
350        MakeInstructionMessage(
351            spv::Op::OpFAdd, 8, 51,
352            {{SPV_OPERAND_TYPE_ID, {46}}, {SPV_OPERAND_TYPE_ID, {50}}}),
353        MakeInstructionMessage(
354            spv::Op::OpStore, 0, 0,
355            {{SPV_OPERAND_TYPE_ID, {43}}, {SPV_OPERAND_TYPE_ID, {51}}}),
356        MakeInstructionMessage(spv::Op::OpReturn, 0, 0, {}),
357        MakeInstructionMessage(spv::Op::OpFunctionEnd, 0, 0, {})}));
358 
359   ASSERT_TRUE(
360       transformation2.IsApplicable(context.get(), transformation_context));
361   ApplyAndCheckFreshIds(transformation2, context.get(),
362                         &transformation_context);
363   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
364                                                kConsoleMessageConsumer));
365 
366   std::string after_transformation2 = R"(
367                OpCapability Shader
368           %1 = OpExtInstImport "GLSL.std.450"
369                OpMemoryModel Logical GLSL450
370                OpEntryPoint Fragment %4 "main"
371                OpExecutionMode %4 OriginUpperLeft
372                OpSource ESSL 310
373           %2 = OpTypeVoid
374           %3 = OpTypeFunction %2
375           %6 = OpTypeInt 32 1
376           %7 = OpTypePointer Function %6
377           %8 = OpTypeFloat 32
378           %9 = OpTypePointer Function %8
379          %10 = OpTypeFunction %8 %7 %9
380          %18 = OpConstant %8 0
381          %20 = OpConstant %6 0
382          %28 = OpTypeBool
383          %37 = OpConstant %6 1
384          %42 = OpTypePointer Private %8
385          %43 = OpVariable %42 Private
386          %47 = OpConstant %8 1
387           %4 = OpFunction %2 None %3
388           %5 = OpLabel
389                OpReturn
390                OpFunctionEnd
391          %13 = OpFunction %8 None %10
392          %11 = OpFunctionParameter %7
393          %12 = OpFunctionParameter %9
394          %14 = OpLabel
395          %17 = OpVariable %9 Function
396          %19 = OpVariable %7 Function
397                OpStore %17 %18
398                OpStore %19 %20
399                OpBranch %21
400          %21 = OpLabel
401                OpLoopMerge %23 %24 None
402                OpBranch %25
403          %25 = OpLabel
404          %26 = OpLoad %6 %19
405          %27 = OpLoad %6 %11
406          %29 = OpSLessThan %28 %26 %27
407                OpBranchConditional %29 %22 %23
408          %22 = OpLabel
409          %30 = OpLoad %8 %12
410          %31 = OpLoad %6 %19
411          %32 = OpConvertSToF %8 %31
412          %33 = OpFMul %8 %30 %32
413          %34 = OpLoad %8 %17
414          %35 = OpFAdd %8 %34 %33
415                OpStore %17 %35
416                OpBranch %24
417          %24 = OpLabel
418          %36 = OpLoad %6 %19
419          %38 = OpIAdd %6 %36 %37
420                OpStore %19 %38
421                OpBranch %21
422          %23 = OpLabel
423          %39 = OpLoad %8 %17
424                OpReturnValue %39
425                OpFunctionEnd
426          %15 = OpFunction %2 None %3
427          %16 = OpLabel
428          %44 = OpVariable %7 Function
429          %45 = OpVariable %9 Function
430          %48 = OpVariable %7 Function
431          %49 = OpVariable %9 Function
432                OpStore %44 %20
433                OpStore %45 %18
434          %46 = OpFunctionCall %8 %13 %44 %45
435                OpStore %48 %37
436                OpStore %49 %47
437          %50 = OpFunctionCall %8 %13 %48 %49
438          %51 = OpFAdd %8 %46 %50
439                OpStore %43 %51
440                OpReturn
441                OpFunctionEnd
442   )";
443   ASSERT_TRUE(IsEqual(env, after_transformation2, context.get()));
444   ASSERT_TRUE(transformation_context.GetFactManager()->BlockIsDead(16));
445 }
446 
TEST(TransformationAddFunctionTest, InapplicableTransformations)447 TEST(TransformationAddFunctionTest, InapplicableTransformations) {
448   std::string shader = R"(
449                OpCapability Shader
450           %1 = OpExtInstImport "GLSL.std.450"
451                OpMemoryModel Logical GLSL450
452                OpEntryPoint Fragment %4 "main"
453                OpExecutionMode %4 OriginUpperLeft
454                OpSource ESSL 310
455           %2 = OpTypeVoid
456           %3 = OpTypeFunction %2
457           %6 = OpTypeInt 32 1
458           %7 = OpTypePointer Function %6
459           %8 = OpTypeFloat 32
460           %9 = OpTypePointer Function %8
461          %10 = OpTypeFunction %8 %7 %9
462          %18 = OpConstant %8 0
463          %20 = OpConstant %6 0
464          %28 = OpTypeBool
465          %37 = OpConstant %6 1
466          %42 = OpTypePointer Private %8
467          %43 = OpVariable %42 Private
468          %47 = OpConstant %8 1
469           %4 = OpFunction %2 None %3
470           %5 = OpLabel
471                OpReturn
472                OpFunctionEnd
473          %13 = OpFunction %8 None %10
474          %11 = OpFunctionParameter %7
475          %12 = OpFunctionParameter %9
476          %14 = OpLabel
477          %17 = OpVariable %9 Function
478          %19 = OpVariable %7 Function
479                OpStore %17 %18
480                OpStore %19 %20
481                OpBranch %21
482          %21 = OpLabel
483                OpLoopMerge %23 %24 None
484                OpBranch %25
485          %25 = OpLabel
486          %26 = OpLoad %6 %19
487          %27 = OpLoad %6 %11
488          %29 = OpSLessThan %28 %26 %27
489                OpBranchConditional %29 %22 %23
490          %22 = OpLabel
491          %30 = OpLoad %8 %12
492          %31 = OpLoad %6 %19
493          %32 = OpConvertSToF %8 %31
494          %33 = OpFMul %8 %30 %32
495          %34 = OpLoad %8 %17
496          %35 = OpFAdd %8 %34 %33
497                OpStore %17 %35
498                OpBranch %24
499          %24 = OpLabel
500          %36 = OpLoad %6 %19
501          %38 = OpIAdd %6 %36 %37
502                OpStore %19 %38
503                OpBranch %21
504          %23 = OpLabel
505          %39 = OpLoad %8 %17
506                OpReturnValue %39
507                OpFunctionEnd
508   )";
509 
510   const auto env = SPV_ENV_UNIVERSAL_1_4;
511   const auto consumer = nullptr;
512   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
513   spvtools::ValidatorOptions validator_options;
514   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
515                                                kConsoleMessageConsumer));
516   TransformationContext transformation_context(
517       MakeUnique<FactManager>(context.get()), validator_options);
518   // No instructions
519   ASSERT_FALSE(
520       TransformationAddFunction(std::vector<protobufs::Instruction>({}))
521           .IsApplicable(context.get(), transformation_context));
522 
523   // No function begin
524   ASSERT_FALSE(
525       TransformationAddFunction(
526           std::vector<protobufs::Instruction>(
527               {MakeInstructionMessage(spv::Op::OpFunctionParameter, 7, 11, {}),
528                MakeInstructionMessage(spv::Op::OpFunctionParameter, 9, 12, {}),
529                MakeInstructionMessage(spv::Op::OpLabel, 0, 14, {})}))
530           .IsApplicable(context.get(), transformation_context));
531 
532   // No OpLabel
533   ASSERT_FALSE(
534       TransformationAddFunction(
535           std::vector<protobufs::Instruction>(
536               {MakeInstructionMessage(
537                    spv::Op::OpFunction, 8, 13,
538                    {{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
539                      {uint32_t(spv::FunctionControlMask::MaskNone)}},
540                     {SPV_OPERAND_TYPE_ID, {10}}}),
541                MakeInstructionMessage(spv::Op::OpReturnValue, 0, 0,
542                                       {{SPV_OPERAND_TYPE_ID, {39}}}),
543                MakeInstructionMessage(spv::Op::OpFunctionEnd, 0, 0, {})}))
544           .IsApplicable(context.get(), transformation_context));
545 
546   // Abrupt end of instructions
547   ASSERT_FALSE(TransformationAddFunction(
548                    std::vector<protobufs::Instruction>({MakeInstructionMessage(
549                        spv::Op::OpFunction, 8, 13,
550                        {{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
551                          {uint32_t(spv::FunctionControlMask::MaskNone)}},
552                         {SPV_OPERAND_TYPE_ID, {10}}})}))
553                    .IsApplicable(context.get(), transformation_context));
554 
555   // No function end
556   ASSERT_FALSE(TransformationAddFunction(
557                    std::vector<protobufs::Instruction>(
558                        {MakeInstructionMessage(
559                             spv::Op::OpFunction, 8, 13,
560                             {{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
561                               {uint32_t(spv::FunctionControlMask::MaskNone)}},
562                              {SPV_OPERAND_TYPE_ID, {10}}}),
563                         MakeInstructionMessage(spv::Op::OpLabel, 0, 14, {}),
564                         MakeInstructionMessage(spv::Op::OpReturnValue, 0, 0,
565                                                {{SPV_OPERAND_TYPE_ID, {39}}})}))
566                    .IsApplicable(context.get(), transformation_context));
567 }
568 
TEST(TransformationAddFunctionTest, LoopLimiters)569 TEST(TransformationAddFunctionTest, LoopLimiters) {
570   std::string shader = R"(
571                OpCapability Shader
572           %1 = OpExtInstImport "GLSL.std.450"
573                OpMemoryModel Logical GLSL450
574                OpEntryPoint Fragment %4 "main"
575                OpExecutionMode %4 OriginUpperLeft
576                OpSource ESSL 310
577           %2 = OpTypeVoid
578           %3 = OpTypeFunction %2
579           %6 = OpTypeInt 32 0
580           %7 = OpTypePointer Function %6
581           %8 = OpConstant %6 0
582           %9 = OpConstant %6 1
583          %10 = OpConstant %6 5
584          %11 = OpTypeBool
585          %12 = OpConstantTrue %11
586           %4 = OpFunction %2 None %3
587           %5 = OpLabel
588                OpReturn
589                OpFunctionEnd
590   )";
591 
592   const auto env = SPV_ENV_UNIVERSAL_1_4;
593   const auto consumer = nullptr;
594 
595   std::vector<protobufs::Instruction> instructions;
596   instructions.push_back(
597       MakeInstructionMessage(spv::Op::OpFunction, 2, 30,
598                              {{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
599                                {uint32_t(spv::FunctionControlMask::MaskNone)}},
600                               {SPV_OPERAND_TYPE_TYPE_ID, {3}}}));
601   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 31, {}));
602   instructions.push_back(MakeInstructionMessage(spv::Op::OpBranch, 0, 0,
603                                                 {{SPV_OPERAND_TYPE_ID, {20}}}));
604   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 20, {}));
605   instructions.push_back(
606       MakeInstructionMessage(spv::Op::OpLoopMerge, 0, 0,
607                              {{SPV_OPERAND_TYPE_ID, {21}},
608                               {SPV_OPERAND_TYPE_ID, {22}},
609                               {SPV_OPERAND_TYPE_LOOP_CONTROL,
610                                {uint32_t(spv::LoopControlMask::MaskNone)}}}));
611   instructions.push_back(MakeInstructionMessage(spv::Op::OpBranchConditional, 0,
612                                                 0,
613                                                 {{SPV_OPERAND_TYPE_ID, {12}},
614                                                  {SPV_OPERAND_TYPE_ID, {23}},
615                                                  {SPV_OPERAND_TYPE_ID, {21}}}));
616   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 23, {}));
617   instructions.push_back(
618       MakeInstructionMessage(spv::Op::OpLoopMerge, 0, 0,
619                              {{SPV_OPERAND_TYPE_ID, {25}},
620                               {SPV_OPERAND_TYPE_ID, {26}},
621                               {SPV_OPERAND_TYPE_LOOP_CONTROL,
622                                {uint32_t(spv::LoopControlMask::MaskNone)}}}));
623   instructions.push_back(MakeInstructionMessage(spv::Op::OpBranch, 0, 0,
624                                                 {{SPV_OPERAND_TYPE_ID, {28}}}));
625   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 28, {}));
626   instructions.push_back(MakeInstructionMessage(spv::Op::OpBranchConditional, 0,
627                                                 0,
628                                                 {{SPV_OPERAND_TYPE_ID, {12}},
629                                                  {SPV_OPERAND_TYPE_ID, {26}},
630                                                  {SPV_OPERAND_TYPE_ID, {25}}}));
631   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 26, {}));
632   instructions.push_back(MakeInstructionMessage(spv::Op::OpBranch, 0, 0,
633                                                 {{SPV_OPERAND_TYPE_ID, {23}}}));
634   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 25, {}));
635   instructions.push_back(
636       MakeInstructionMessage(spv::Op::OpLoopMerge, 0, 0,
637                              {{SPV_OPERAND_TYPE_ID, {24}},
638                               {SPV_OPERAND_TYPE_ID, {27}},
639                               {SPV_OPERAND_TYPE_LOOP_CONTROL,
640                                {uint32_t(spv::LoopControlMask::MaskNone)}}}));
641   instructions.push_back(MakeInstructionMessage(spv::Op::OpBranchConditional, 0,
642                                                 0,
643                                                 {{SPV_OPERAND_TYPE_ID, {12}},
644                                                  {SPV_OPERAND_TYPE_ID, {24}},
645                                                  {SPV_OPERAND_TYPE_ID, {27}}}));
646   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 27, {}));
647   instructions.push_back(MakeInstructionMessage(spv::Op::OpBranch, 0, 0,
648                                                 {{SPV_OPERAND_TYPE_ID, {25}}}));
649   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 24, {}));
650   instructions.push_back(MakeInstructionMessage(spv::Op::OpBranch, 0, 0,
651                                                 {{SPV_OPERAND_TYPE_ID, {22}}}));
652   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 22, {}));
653   instructions.push_back(MakeInstructionMessage(spv::Op::OpBranch, 0, 0,
654                                                 {{SPV_OPERAND_TYPE_ID, {20}}}));
655   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 21, {}));
656   instructions.push_back(MakeInstructionMessage(spv::Op::OpReturn, 0, 0, {}));
657   instructions.push_back(
658       MakeInstructionMessage(spv::Op::OpFunctionEnd, 0, 0, {}));
659 
660   spvtools::ValidatorOptions validator_options;
661 
662   const auto context1 = BuildModule(env, consumer, shader, kFuzzAssembleOption);
663   const auto context2 = BuildModule(env, consumer, shader, kFuzzAssembleOption);
664   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
665       context1.get(), validator_options, kConsoleMessageConsumer));
666 
667   TransformationContext transformation_context1(
668       MakeUnique<FactManager>(context1.get()), validator_options);
669   TransformationContext transformation_context2(
670       MakeUnique<FactManager>(context2.get()), validator_options);
671 
672   TransformationAddFunction add_dead_function(instructions);
673   ASSERT_TRUE(
674       add_dead_function.IsApplicable(context1.get(), transformation_context1));
675   ApplyAndCheckFreshIds(add_dead_function, context1.get(),
676                         &transformation_context1);
677   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
678       context1.get(), validator_options, kConsoleMessageConsumer));
679   // The added function should not be deemed livesafe.
680   ASSERT_FALSE(
681       transformation_context1.GetFactManager()->FunctionIsLivesafe(30));
682   // All variables/parameters in the function should be deemed irrelevant.
683   ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreIrrelevant(
684       context1.get(), transformation_context1, 30, 0));
685 
686   std::string added_as_dead_code = R"(
687                OpCapability Shader
688           %1 = OpExtInstImport "GLSL.std.450"
689                OpMemoryModel Logical GLSL450
690                OpEntryPoint Fragment %4 "main"
691                OpExecutionMode %4 OriginUpperLeft
692                OpSource ESSL 310
693           %2 = OpTypeVoid
694           %3 = OpTypeFunction %2
695           %6 = OpTypeInt 32 0
696           %7 = OpTypePointer Function %6
697           %8 = OpConstant %6 0
698           %9 = OpConstant %6 1
699          %10 = OpConstant %6 5
700          %11 = OpTypeBool
701          %12 = OpConstantTrue %11
702           %4 = OpFunction %2 None %3
703           %5 = OpLabel
704                OpReturn
705                OpFunctionEnd
706          %30 = OpFunction %2 None %3
707          %31 = OpLabel
708                OpBranch %20
709          %20 = OpLabel
710                OpLoopMerge %21 %22 None
711                OpBranchConditional %12 %23 %21
712          %23 = OpLabel
713                OpLoopMerge %25 %26 None
714                OpBranch %28
715          %28 = OpLabel
716                OpBranchConditional %12 %26 %25
717          %26 = OpLabel
718                OpBranch %23
719          %25 = OpLabel
720                OpLoopMerge %24 %27 None
721                OpBranchConditional %12 %24 %27
722          %27 = OpLabel
723                OpBranch %25
724          %24 = OpLabel
725                OpBranch %22
726          %22 = OpLabel
727                OpBranch %20
728          %21 = OpLabel
729                OpReturn
730                OpFunctionEnd
731   )";
732   ASSERT_TRUE(IsEqual(env, added_as_dead_code, context1.get()));
733 
734   protobufs::LoopLimiterInfo loop_limiter1;
735   loop_limiter1.set_loop_header_id(20);
736   loop_limiter1.set_load_id(101);
737   loop_limiter1.set_increment_id(102);
738   loop_limiter1.set_compare_id(103);
739   loop_limiter1.set_logical_op_id(104);
740 
741   protobufs::LoopLimiterInfo loop_limiter2;
742   loop_limiter2.set_loop_header_id(23);
743   loop_limiter2.set_load_id(105);
744   loop_limiter2.set_increment_id(106);
745   loop_limiter2.set_compare_id(107);
746   loop_limiter2.set_logical_op_id(108);
747 
748   protobufs::LoopLimiterInfo loop_limiter3;
749   loop_limiter3.set_loop_header_id(25);
750   loop_limiter3.set_load_id(109);
751   loop_limiter3.set_increment_id(110);
752   loop_limiter3.set_compare_id(111);
753   loop_limiter3.set_logical_op_id(112);
754 
755   std::vector<protobufs::LoopLimiterInfo> loop_limiters = {
756       loop_limiter1, loop_limiter2, loop_limiter3};
757 
758   TransformationAddFunction add_livesafe_function(instructions, 100, 10,
759                                                   loop_limiters, 0, {});
760   ASSERT_TRUE(add_livesafe_function.IsApplicable(context2.get(),
761                                                  transformation_context2));
762   ApplyAndCheckFreshIds(add_livesafe_function, context2.get(),
763                         &transformation_context2);
764   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
765       context2.get(), validator_options, kConsoleMessageConsumer));
766   // The added function should indeed be deemed livesafe.
767   ASSERT_TRUE(transformation_context2.GetFactManager()->FunctionIsLivesafe(30));
768   // All variables/parameters in the function should be deemed irrelevant,
769   // except the loop limiter.
770   ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreIrrelevant(
771       context2.get(), transformation_context2, 30, 100));
772   std::string added_as_livesafe_code = R"(
773                OpCapability Shader
774           %1 = OpExtInstImport "GLSL.std.450"
775                OpMemoryModel Logical GLSL450
776                OpEntryPoint Fragment %4 "main"
777                OpExecutionMode %4 OriginUpperLeft
778                OpSource ESSL 310
779           %2 = OpTypeVoid
780           %3 = OpTypeFunction %2
781           %6 = OpTypeInt 32 0
782           %7 = OpTypePointer Function %6
783           %8 = OpConstant %6 0
784           %9 = OpConstant %6 1
785          %10 = OpConstant %6 5
786          %11 = OpTypeBool
787          %12 = OpConstantTrue %11
788           %4 = OpFunction %2 None %3
789           %5 = OpLabel
790                OpReturn
791                OpFunctionEnd
792          %30 = OpFunction %2 None %3
793          %31 = OpLabel
794         %100 = OpVariable %7 Function %8
795                OpBranch %20
796          %20 = OpLabel
797                OpLoopMerge %21 %22 None
798                OpBranchConditional %12 %23 %21
799          %23 = OpLabel
800                OpLoopMerge %25 %26 None
801                OpBranch %28
802          %28 = OpLabel
803                OpBranchConditional %12 %26 %25
804          %26 = OpLabel
805         %105 = OpLoad %6 %100
806         %106 = OpIAdd %6 %105 %9
807                OpStore %100 %106
808         %107 = OpUGreaterThanEqual %11 %105 %10
809                OpBranchConditional %107 %25 %23
810          %25 = OpLabel
811                OpLoopMerge %24 %27 None
812                OpBranchConditional %12 %24 %27
813          %27 = OpLabel
814         %109 = OpLoad %6 %100
815         %110 = OpIAdd %6 %109 %9
816                OpStore %100 %110
817         %111 = OpUGreaterThanEqual %11 %109 %10
818                OpBranchConditional %111 %24 %25
819          %24 = OpLabel
820                OpBranch %22
821          %22 = OpLabel
822         %101 = OpLoad %6 %100
823         %102 = OpIAdd %6 %101 %9
824                OpStore %100 %102
825         %103 = OpUGreaterThanEqual %11 %101 %10
826                OpBranchConditional %103 %21 %20
827          %21 = OpLabel
828                OpReturn
829                OpFunctionEnd
830   )";
831   ASSERT_TRUE(IsEqual(env, added_as_livesafe_code, context2.get()));
832 }
833 
TEST(TransformationAddFunctionTest, KillAndUnreachableInVoidFunction)834 TEST(TransformationAddFunctionTest, KillAndUnreachableInVoidFunction) {
835   std::string shader = R"(
836                OpCapability Shader
837           %1 = OpExtInstImport "GLSL.std.450"
838                OpMemoryModel Logical GLSL450
839                OpEntryPoint Fragment %4 "main"
840                OpExecutionMode %4 OriginUpperLeft
841                OpSource ESSL 310
842           %2 = OpTypeVoid
843           %3 = OpTypeFunction %2
844           %6 = OpTypeInt 32 1
845           %7 = OpTypePointer Function %6
846           %8 = OpTypeFunction %2 %7
847          %13 = OpConstant %6 2
848          %14 = OpTypeBool
849           %4 = OpFunction %2 None %3
850           %5 = OpLabel
851                OpReturn
852                OpFunctionEnd
853   )";
854 
855   const auto env = SPV_ENV_UNIVERSAL_1_4;
856   const auto consumer = nullptr;
857 
858   std::vector<protobufs::Instruction> instructions;
859 
860   instructions.push_back(
861       MakeInstructionMessage(spv::Op::OpFunction, 2, 10,
862                              {{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
863                                {uint32_t(spv::FunctionControlMask::MaskNone)}},
864                               {SPV_OPERAND_TYPE_TYPE_ID, {8}}}));
865   instructions.push_back(
866       MakeInstructionMessage(spv::Op::OpFunctionParameter, 7, 9, {}));
867   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 11, {}));
868   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 12,
869                                                 {{SPV_OPERAND_TYPE_ID, {9}}}));
870   instructions.push_back(MakeInstructionMessage(
871       spv::Op::OpIEqual, 14, 15,
872       {{SPV_OPERAND_TYPE_ID, {12}}, {SPV_OPERAND_TYPE_ID, {13}}}));
873   instructions.push_back(MakeInstructionMessage(
874       spv::Op::OpSelectionMerge, 0, 0,
875       {{SPV_OPERAND_TYPE_ID, {17}},
876        {SPV_OPERAND_TYPE_SELECTION_CONTROL,
877         {uint32_t(spv::SelectionControlMask::MaskNone)}}}));
878   instructions.push_back(MakeInstructionMessage(spv::Op::OpBranchConditional, 0,
879                                                 0,
880                                                 {{SPV_OPERAND_TYPE_ID, {15}},
881                                                  {SPV_OPERAND_TYPE_ID, {16}},
882                                                  {SPV_OPERAND_TYPE_ID, {17}}}));
883   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 16, {}));
884   instructions.push_back(
885       MakeInstructionMessage(spv::Op::OpUnreachable, 0, 0, {}));
886   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 17, {}));
887   instructions.push_back(MakeInstructionMessage(spv::Op::OpKill, 0, 0, {}));
888   instructions.push_back(
889       MakeInstructionMessage(spv::Op::OpFunctionEnd, 0, 0, {}));
890 
891   spvtools::ValidatorOptions validator_options;
892 
893   const auto context1 = BuildModule(env, consumer, shader, kFuzzAssembleOption);
894   const auto context2 = BuildModule(env, consumer, shader, kFuzzAssembleOption);
895   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
896       context1.get(), validator_options, kConsoleMessageConsumer));
897 
898   TransformationContext transformation_context1(
899       MakeUnique<FactManager>(context1.get()), validator_options);
900   TransformationContext transformation_context2(
901       MakeUnique<FactManager>(context2.get()), validator_options);
902 
903   TransformationAddFunction add_dead_function(instructions);
904   ASSERT_TRUE(
905       add_dead_function.IsApplicable(context1.get(), transformation_context1));
906   ApplyAndCheckFreshIds(add_dead_function, context1.get(),
907                         &transformation_context1);
908   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
909       context1.get(), validator_options, kConsoleMessageConsumer));
910   // The added function should not be deemed livesafe.
911   ASSERT_FALSE(
912       transformation_context1.GetFactManager()->FunctionIsLivesafe(10));
913   // All variables/parameters in the function should be deemed irrelevant.
914   ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreIrrelevant(
915       context1.get(), transformation_context1, 10, 0));
916 
917   std::string added_as_dead_code = R"(
918                OpCapability Shader
919           %1 = OpExtInstImport "GLSL.std.450"
920                OpMemoryModel Logical GLSL450
921                OpEntryPoint Fragment %4 "main"
922                OpExecutionMode %4 OriginUpperLeft
923                OpSource ESSL 310
924           %2 = OpTypeVoid
925           %3 = OpTypeFunction %2
926           %6 = OpTypeInt 32 1
927           %7 = OpTypePointer Function %6
928           %8 = OpTypeFunction %2 %7
929          %13 = OpConstant %6 2
930          %14 = OpTypeBool
931           %4 = OpFunction %2 None %3
932           %5 = OpLabel
933                OpReturn
934                OpFunctionEnd
935          %10 = OpFunction %2 None %8
936           %9 = OpFunctionParameter %7
937          %11 = OpLabel
938          %12 = OpLoad %6 %9
939          %15 = OpIEqual %14 %12 %13
940                OpSelectionMerge %17 None
941                OpBranchConditional %15 %16 %17
942          %16 = OpLabel
943                OpUnreachable
944          %17 = OpLabel
945                OpKill
946                OpFunctionEnd
947   )";
948   ASSERT_TRUE(IsEqual(env, added_as_dead_code, context1.get()));
949 
950   TransformationAddFunction add_livesafe_function(instructions, 0, 0, {}, 0,
951                                                   {});
952   ASSERT_TRUE(add_livesafe_function.IsApplicable(context2.get(),
953                                                  transformation_context2));
954   ApplyAndCheckFreshIds(add_livesafe_function, context2.get(),
955                         &transformation_context2);
956   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
957       context2.get(), validator_options, kConsoleMessageConsumer));
958   // The added function should indeed be deemed livesafe.
959   ASSERT_TRUE(transformation_context2.GetFactManager()->FunctionIsLivesafe(10));
960   // All variables/parameters in the function should be deemed irrelevant.
961   ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreIrrelevant(
962       context2.get(), transformation_context2, 10, 0));
963   std::string added_as_livesafe_code = R"(
964                OpCapability Shader
965           %1 = OpExtInstImport "GLSL.std.450"
966                OpMemoryModel Logical GLSL450
967                OpEntryPoint Fragment %4 "main"
968                OpExecutionMode %4 OriginUpperLeft
969                OpSource ESSL 310
970           %2 = OpTypeVoid
971           %3 = OpTypeFunction %2
972           %6 = OpTypeInt 32 1
973           %7 = OpTypePointer Function %6
974           %8 = OpTypeFunction %2 %7
975          %13 = OpConstant %6 2
976          %14 = OpTypeBool
977           %4 = OpFunction %2 None %3
978           %5 = OpLabel
979                OpReturn
980                OpFunctionEnd
981          %10 = OpFunction %2 None %8
982           %9 = OpFunctionParameter %7
983          %11 = OpLabel
984          %12 = OpLoad %6 %9
985          %15 = OpIEqual %14 %12 %13
986                OpSelectionMerge %17 None
987                OpBranchConditional %15 %16 %17
988          %16 = OpLabel
989                OpReturn
990          %17 = OpLabel
991                OpReturn
992                OpFunctionEnd
993   )";
994   ASSERT_TRUE(IsEqual(env, added_as_livesafe_code, context2.get()));
995 }
996 
TEST(TransformationAddFunctionTest, KillAndUnreachableInNonVoidFunction)997 TEST(TransformationAddFunctionTest, KillAndUnreachableInNonVoidFunction) {
998   std::string shader = R"(
999                OpCapability Shader
1000           %1 = OpExtInstImport "GLSL.std.450"
1001                OpMemoryModel Logical GLSL450
1002                OpEntryPoint Fragment %4 "main"
1003                OpExecutionMode %4 OriginUpperLeft
1004                OpSource ESSL 310
1005           %2 = OpTypeVoid
1006           %3 = OpTypeFunction %2
1007           %6 = OpTypeInt 32 1
1008           %7 = OpTypePointer Function %6
1009           %8 = OpTypeFunction %2 %7
1010          %50 = OpTypeFunction %6 %7
1011          %13 = OpConstant %6 2
1012          %14 = OpTypeBool
1013           %4 = OpFunction %2 None %3
1014           %5 = OpLabel
1015                OpReturn
1016                OpFunctionEnd
1017   )";
1018 
1019   const auto env = SPV_ENV_UNIVERSAL_1_4;
1020   const auto consumer = nullptr;
1021 
1022   std::vector<protobufs::Instruction> instructions;
1023 
1024   instructions.push_back(
1025       MakeInstructionMessage(spv::Op::OpFunction, 6, 10,
1026                              {{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
1027                                {uint32_t(spv::FunctionControlMask::MaskNone)}},
1028                               {SPV_OPERAND_TYPE_TYPE_ID, {50}}}));
1029   instructions.push_back(
1030       MakeInstructionMessage(spv::Op::OpFunctionParameter, 7, 9, {}));
1031   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 11, {}));
1032   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 12,
1033                                                 {{SPV_OPERAND_TYPE_ID, {9}}}));
1034   instructions.push_back(MakeInstructionMessage(
1035       spv::Op::OpIEqual, 14, 15,
1036       {{SPV_OPERAND_TYPE_ID, {12}}, {SPV_OPERAND_TYPE_ID, {13}}}));
1037   instructions.push_back(MakeInstructionMessage(
1038       spv::Op::OpSelectionMerge, 0, 0,
1039       {{SPV_OPERAND_TYPE_ID, {17}},
1040        {SPV_OPERAND_TYPE_SELECTION_CONTROL,
1041         {uint32_t(spv::SelectionControlMask::MaskNone)}}}));
1042   instructions.push_back(MakeInstructionMessage(spv::Op::OpBranchConditional, 0,
1043                                                 0,
1044                                                 {{SPV_OPERAND_TYPE_ID, {15}},
1045                                                  {SPV_OPERAND_TYPE_ID, {16}},
1046                                                  {SPV_OPERAND_TYPE_ID, {17}}}));
1047   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 16, {}));
1048   instructions.push_back(
1049       MakeInstructionMessage(spv::Op::OpUnreachable, 0, 0, {}));
1050   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 17, {}));
1051   instructions.push_back(MakeInstructionMessage(spv::Op::OpKill, 0, 0, {}));
1052   instructions.push_back(
1053       MakeInstructionMessage(spv::Op::OpFunctionEnd, 0, 0, {}));
1054 
1055   spvtools::ValidatorOptions validator_options;
1056 
1057   const auto context1 = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1058   const auto context2 = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1059   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1060       context1.get(), validator_options, kConsoleMessageConsumer));
1061 
1062   TransformationContext transformation_context1(
1063       MakeUnique<FactManager>(context1.get()), validator_options);
1064   TransformationContext transformation_context2(
1065       MakeUnique<FactManager>(context2.get()), validator_options);
1066 
1067   TransformationAddFunction add_dead_function(instructions);
1068   ASSERT_TRUE(
1069       add_dead_function.IsApplicable(context1.get(), transformation_context1));
1070   ApplyAndCheckFreshIds(add_dead_function, context1.get(),
1071                         &transformation_context1);
1072   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1073       context1.get(), validator_options, kConsoleMessageConsumer));
1074   // The added function should not be deemed livesafe.
1075   ASSERT_FALSE(
1076       transformation_context1.GetFactManager()->FunctionIsLivesafe(10));
1077   // All variables/parameters in the function should be deemed irrelevant.
1078   ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreIrrelevant(
1079       context1.get(), transformation_context1, 10, 0));
1080 
1081   std::string added_as_dead_code = R"(
1082                OpCapability Shader
1083           %1 = OpExtInstImport "GLSL.std.450"
1084                OpMemoryModel Logical GLSL450
1085                OpEntryPoint Fragment %4 "main"
1086                OpExecutionMode %4 OriginUpperLeft
1087                OpSource ESSL 310
1088           %2 = OpTypeVoid
1089           %3 = OpTypeFunction %2
1090           %6 = OpTypeInt 32 1
1091           %7 = OpTypePointer Function %6
1092           %8 = OpTypeFunction %2 %7
1093          %50 = OpTypeFunction %6 %7
1094          %13 = OpConstant %6 2
1095          %14 = OpTypeBool
1096           %4 = OpFunction %2 None %3
1097           %5 = OpLabel
1098                OpReturn
1099                OpFunctionEnd
1100          %10 = OpFunction %6 None %50
1101           %9 = OpFunctionParameter %7
1102          %11 = OpLabel
1103          %12 = OpLoad %6 %9
1104          %15 = OpIEqual %14 %12 %13
1105                OpSelectionMerge %17 None
1106                OpBranchConditional %15 %16 %17
1107          %16 = OpLabel
1108                OpUnreachable
1109          %17 = OpLabel
1110                OpKill
1111                OpFunctionEnd
1112   )";
1113   ASSERT_TRUE(IsEqual(env, added_as_dead_code, context1.get()));
1114 
1115   TransformationAddFunction add_livesafe_function(instructions, 0, 0, {}, 13,
1116                                                   {});
1117   ASSERT_TRUE(add_livesafe_function.IsApplicable(context2.get(),
1118                                                  transformation_context2));
1119   ApplyAndCheckFreshIds(add_livesafe_function, context2.get(),
1120                         &transformation_context2);
1121   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1122       context2.get(), validator_options, kConsoleMessageConsumer));
1123   // The added function should indeed be deemed livesafe.
1124   ASSERT_TRUE(transformation_context2.GetFactManager()->FunctionIsLivesafe(10));
1125   // All variables/parameters in the function should be deemed irrelevant.
1126   ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreIrrelevant(
1127       context2.get(), transformation_context2, 10, 0));
1128   std::string added_as_livesafe_code = R"(
1129                OpCapability Shader
1130           %1 = OpExtInstImport "GLSL.std.450"
1131                OpMemoryModel Logical GLSL450
1132                OpEntryPoint Fragment %4 "main"
1133                OpExecutionMode %4 OriginUpperLeft
1134                OpSource ESSL 310
1135           %2 = OpTypeVoid
1136           %3 = OpTypeFunction %2
1137           %6 = OpTypeInt 32 1
1138           %7 = OpTypePointer Function %6
1139           %8 = OpTypeFunction %2 %7
1140          %50 = OpTypeFunction %6 %7
1141          %13 = OpConstant %6 2
1142          %14 = OpTypeBool
1143           %4 = OpFunction %2 None %3
1144           %5 = OpLabel
1145                OpReturn
1146                OpFunctionEnd
1147          %10 = OpFunction %6 None %50
1148           %9 = OpFunctionParameter %7
1149          %11 = OpLabel
1150          %12 = OpLoad %6 %9
1151          %15 = OpIEqual %14 %12 %13
1152                OpSelectionMerge %17 None
1153                OpBranchConditional %15 %16 %17
1154          %16 = OpLabel
1155                OpReturnValue %13
1156          %17 = OpLabel
1157                OpReturnValue %13
1158                OpFunctionEnd
1159   )";
1160   ASSERT_TRUE(IsEqual(env, added_as_livesafe_code, context2.get()));
1161 }
1162 
TEST(TransformationAddFunctionTest, ClampedAccessChains)1163 TEST(TransformationAddFunctionTest, ClampedAccessChains) {
1164   std::string shader = R"(
1165                OpCapability Shader
1166           %1 = OpExtInstImport "GLSL.std.450"
1167                OpMemoryModel Logical GLSL450
1168                OpEntryPoint Fragment %4 "main"
1169                OpExecutionMode %4 OriginUpperLeft
1170                OpSource ESSL 310
1171           %2 = OpTypeVoid
1172         %100 = OpTypeBool
1173           %3 = OpTypeFunction %2
1174           %6 = OpTypeInt 32 1
1175           %7 = OpTypePointer Function %6
1176          %15 = OpTypeInt 32 0
1177         %102 = OpTypePointer Function %15
1178           %8 = OpTypeFunction %2 %7 %102 %7
1179          %16 = OpConstant %15 5
1180          %17 = OpTypeArray %6 %16
1181          %18 = OpTypeArray %17 %16
1182          %19 = OpTypePointer Private %18
1183          %20 = OpVariable %19 Private
1184          %21 = OpConstant %6 0
1185          %23 = OpTypePointer Private %6
1186          %26 = OpTypePointer Function %17
1187          %29 = OpTypePointer Private %17
1188          %33 = OpConstant %6 4
1189         %200 = OpConstant %15 4
1190          %35 = OpConstant %15 10
1191          %36 = OpTypeArray %6 %35
1192          %37 = OpTypePointer Private %36
1193          %38 = OpVariable %37 Private
1194          %54 = OpTypeFloat 32
1195          %55 = OpTypeVector %54 4
1196          %56 = OpTypePointer Private %55
1197          %57 = OpVariable %56 Private
1198          %59 = OpTypeVector %54 3
1199          %60 = OpTypeMatrix %59 2
1200          %61 = OpTypePointer Private %60
1201          %62 = OpVariable %61 Private
1202          %64 = OpTypePointer Private %54
1203          %69 = OpConstant %54 2
1204          %71 = OpConstant %6 1
1205          %72 = OpConstant %6 2
1206         %201 = OpConstant %15 2
1207          %73 = OpConstant %6 3
1208         %202 = OpConstant %15 3
1209         %203 = OpConstant %6 1
1210         %204 = OpConstant %6 9
1211           %4 = OpFunction %2 None %3
1212           %5 = OpLabel
1213                OpReturn
1214                OpFunctionEnd
1215   )";
1216 
1217   const auto env = SPV_ENV_UNIVERSAL_1_4;
1218   const auto consumer = nullptr;
1219 
1220   std::vector<protobufs::Instruction> instructions;
1221 
1222   instructions.push_back(
1223       MakeInstructionMessage(spv::Op::OpFunction, 2, 12,
1224                              {{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
1225                                {uint32_t(spv::FunctionControlMask::MaskNone)}},
1226                               {SPV_OPERAND_TYPE_TYPE_ID, {8}}}));
1227   instructions.push_back(
1228       MakeInstructionMessage(spv::Op::OpFunctionParameter, 7, 9, {}));
1229   instructions.push_back(
1230       MakeInstructionMessage(spv::Op::OpFunctionParameter, 102, 10, {}));
1231   instructions.push_back(
1232       MakeInstructionMessage(spv::Op::OpFunctionParameter, 7, 11, {}));
1233   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 13, {}));
1234 
1235   instructions.push_back(
1236       MakeInstructionMessage(spv::Op::OpVariable, 7, 14,
1237                              {{SPV_OPERAND_TYPE_STORAGE_CLASS,
1238                                {uint32_t(spv::StorageClass::Function)}}}));
1239   instructions.push_back(
1240       MakeInstructionMessage(spv::Op::OpVariable, 26, 27,
1241                              {{SPV_OPERAND_TYPE_STORAGE_CLASS,
1242                                {uint32_t(spv::StorageClass::Function)}}}));
1243   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 22,
1244                                                 {{SPV_OPERAND_TYPE_ID, {11}}}));
1245   instructions.push_back(MakeInstructionMessage(spv::Op::OpAccessChain, 23, 24,
1246                                                 {{SPV_OPERAND_TYPE_ID, {20}},
1247                                                  {SPV_OPERAND_TYPE_ID, {21}},
1248                                                  {SPV_OPERAND_TYPE_ID, {22}}}));
1249   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 25,
1250                                                 {{SPV_OPERAND_TYPE_ID, {24}}}));
1251   instructions.push_back(MakeInstructionMessage(
1252       spv::Op::OpStore, 0, 0,
1253       {{SPV_OPERAND_TYPE_ID, {14}}, {SPV_OPERAND_TYPE_ID, {25}}}));
1254   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 15, 28,
1255                                                 {{SPV_OPERAND_TYPE_ID, {10}}}));
1256   instructions.push_back(MakeInstructionMessage(
1257       spv::Op::OpAccessChain, 29, 30,
1258       {{SPV_OPERAND_TYPE_ID, {20}}, {SPV_OPERAND_TYPE_ID, {28}}}));
1259   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 17, 31,
1260                                                 {{SPV_OPERAND_TYPE_ID, {30}}}));
1261   instructions.push_back(MakeInstructionMessage(
1262       spv::Op::OpStore, 0, 0,
1263       {{SPV_OPERAND_TYPE_ID, {27}}, {SPV_OPERAND_TYPE_ID, {31}}}));
1264   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 32,
1265                                                 {{SPV_OPERAND_TYPE_ID, {9}}}));
1266   instructions.push_back(MakeInstructionMessage(
1267       spv::Op::OpInBoundsAccessChain, 7, 34,
1268       {{SPV_OPERAND_TYPE_ID, {27}}, {SPV_OPERAND_TYPE_ID, {32}}}));
1269   instructions.push_back(MakeInstructionMessage(
1270       spv::Op::OpStore, 0, 0,
1271       {{SPV_OPERAND_TYPE_ID, {34}}, {SPV_OPERAND_TYPE_ID, {33}}}));
1272   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 39,
1273                                                 {{SPV_OPERAND_TYPE_ID, {9}}}));
1274   instructions.push_back(MakeInstructionMessage(
1275       spv::Op::OpAccessChain, 23, 40,
1276       {{SPV_OPERAND_TYPE_ID, {38}}, {SPV_OPERAND_TYPE_ID, {33}}}));
1277   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 41,
1278                                                 {{SPV_OPERAND_TYPE_ID, {40}}}));
1279   instructions.push_back(MakeInstructionMessage(
1280       spv::Op::OpInBoundsAccessChain, 23, 42,
1281       {{SPV_OPERAND_TYPE_ID, {38}}, {SPV_OPERAND_TYPE_ID, {39}}}));
1282   instructions.push_back(MakeInstructionMessage(
1283       spv::Op::OpStore, 0, 0,
1284       {{SPV_OPERAND_TYPE_ID, {42}}, {SPV_OPERAND_TYPE_ID, {41}}}));
1285   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 15, 43,
1286                                                 {{SPV_OPERAND_TYPE_ID, {10}}}));
1287   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 44,
1288                                                 {{SPV_OPERAND_TYPE_ID, {11}}}));
1289   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 45,
1290                                                 {{SPV_OPERAND_TYPE_ID, {9}}}));
1291   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 15, 46,
1292                                                 {{SPV_OPERAND_TYPE_ID, {10}}}));
1293   instructions.push_back(MakeInstructionMessage(
1294       spv::Op::OpIAdd, 6, 47,
1295       {{SPV_OPERAND_TYPE_ID, {45}}, {SPV_OPERAND_TYPE_ID, {46}}}));
1296   instructions.push_back(MakeInstructionMessage(
1297       spv::Op::OpAccessChain, 23, 48,
1298       {{SPV_OPERAND_TYPE_ID, {38}}, {SPV_OPERAND_TYPE_ID, {47}}}));
1299   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 49,
1300                                                 {{SPV_OPERAND_TYPE_ID, {48}}}));
1301   instructions.push_back(MakeInstructionMessage(spv::Op::OpInBoundsAccessChain,
1302                                                 23, 50,
1303                                                 {{SPV_OPERAND_TYPE_ID, {20}},
1304                                                  {SPV_OPERAND_TYPE_ID, {43}},
1305                                                  {SPV_OPERAND_TYPE_ID, {44}}}));
1306   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 51,
1307                                                 {{SPV_OPERAND_TYPE_ID, {50}}}));
1308   instructions.push_back(MakeInstructionMessage(
1309       spv::Op::OpIAdd, 6, 52,
1310       {{SPV_OPERAND_TYPE_ID, {51}}, {SPV_OPERAND_TYPE_ID, {49}}}));
1311   instructions.push_back(MakeInstructionMessage(spv::Op::OpAccessChain, 23, 53,
1312                                                 {{SPV_OPERAND_TYPE_ID, {20}},
1313                                                  {SPV_OPERAND_TYPE_ID, {43}},
1314                                                  {SPV_OPERAND_TYPE_ID, {44}}}));
1315   instructions.push_back(MakeInstructionMessage(
1316       spv::Op::OpStore, 0, 0,
1317       {{SPV_OPERAND_TYPE_ID, {53}}, {SPV_OPERAND_TYPE_ID, {52}}}));
1318   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 15, 58,
1319                                                 {{SPV_OPERAND_TYPE_ID, {10}}}));
1320   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 63,
1321                                                 {{SPV_OPERAND_TYPE_ID, {11}}}));
1322   instructions.push_back(MakeInstructionMessage(spv::Op::OpAccessChain, 64, 65,
1323                                                 {{SPV_OPERAND_TYPE_ID, {62}},
1324                                                  {SPV_OPERAND_TYPE_ID, {21}},
1325                                                  {SPV_OPERAND_TYPE_ID, {63}}}));
1326   instructions.push_back(MakeInstructionMessage(spv::Op::OpAccessChain, 64, 101,
1327                                                 {{SPV_OPERAND_TYPE_ID, {62}},
1328                                                  {SPV_OPERAND_TYPE_ID, {45}},
1329                                                  {SPV_OPERAND_TYPE_ID, {46}}}));
1330   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 54, 66,
1331                                                 {{SPV_OPERAND_TYPE_ID, {65}}}));
1332   instructions.push_back(MakeInstructionMessage(
1333       spv::Op::OpAccessChain, 64, 67,
1334       {{SPV_OPERAND_TYPE_ID, {57}}, {SPV_OPERAND_TYPE_ID, {58}}}));
1335   instructions.push_back(MakeInstructionMessage(
1336       spv::Op::OpStore, 0, 0,
1337       {{SPV_OPERAND_TYPE_ID, {67}}, {SPV_OPERAND_TYPE_ID, {66}}}));
1338   instructions.push_back(MakeInstructionMessage(spv::Op::OpLoad, 6, 68,
1339                                                 {{SPV_OPERAND_TYPE_ID, {9}}}));
1340   instructions.push_back(MakeInstructionMessage(
1341       spv::Op::OpInBoundsAccessChain, 64, 70,
1342       {{SPV_OPERAND_TYPE_ID, {57}}, {SPV_OPERAND_TYPE_ID, {68}}}));
1343   instructions.push_back(MakeInstructionMessage(
1344       spv::Op::OpStore, 0, 0,
1345       {{SPV_OPERAND_TYPE_ID, {70}}, {SPV_OPERAND_TYPE_ID, {69}}}));
1346   instructions.push_back(MakeInstructionMessage(spv::Op::OpReturn, 0, 0, {}));
1347   instructions.push_back(
1348       MakeInstructionMessage(spv::Op::OpFunctionEnd, 0, 0, {}));
1349 
1350   spvtools::ValidatorOptions validator_options;
1351 
1352   const auto context1 = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1353   const auto context2 = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1354   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1355       context1.get(), validator_options, kConsoleMessageConsumer));
1356 
1357   TransformationContext transformation_context1(
1358       MakeUnique<FactManager>(context1.get()), validator_options);
1359   TransformationContext transformation_context2(
1360       MakeUnique<FactManager>(context2.get()), validator_options);
1361 
1362   TransformationAddFunction add_dead_function(instructions);
1363   ASSERT_TRUE(
1364       add_dead_function.IsApplicable(context1.get(), transformation_context1));
1365   ApplyAndCheckFreshIds(add_dead_function, context1.get(),
1366                         &transformation_context1);
1367   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1368       context1.get(), validator_options, kConsoleMessageConsumer));
1369   // The function should not be deemed livesafe
1370   ASSERT_FALSE(
1371       transformation_context1.GetFactManager()->FunctionIsLivesafe(12));
1372   // All variables/parameters in the function should be deemed irrelevant.
1373   ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreIrrelevant(
1374       context1.get(), transformation_context1, 12, 0));
1375 
1376   std::string added_as_dead_code = R"(
1377                OpCapability Shader
1378           %1 = OpExtInstImport "GLSL.std.450"
1379                OpMemoryModel Logical GLSL450
1380                OpEntryPoint Fragment %4 "main"
1381                OpExecutionMode %4 OriginUpperLeft
1382                OpSource ESSL 310
1383           %2 = OpTypeVoid
1384         %100 = OpTypeBool
1385           %3 = OpTypeFunction %2
1386           %6 = OpTypeInt 32 1
1387           %7 = OpTypePointer Function %6
1388          %15 = OpTypeInt 32 0
1389         %102 = OpTypePointer Function %15
1390           %8 = OpTypeFunction %2 %7 %102 %7
1391          %16 = OpConstant %15 5
1392          %17 = OpTypeArray %6 %16
1393          %18 = OpTypeArray %17 %16
1394          %19 = OpTypePointer Private %18
1395          %20 = OpVariable %19 Private
1396          %21 = OpConstant %6 0
1397          %23 = OpTypePointer Private %6
1398          %26 = OpTypePointer Function %17
1399          %29 = OpTypePointer Private %17
1400          %33 = OpConstant %6 4
1401         %200 = OpConstant %15 4
1402          %35 = OpConstant %15 10
1403          %36 = OpTypeArray %6 %35
1404          %37 = OpTypePointer Private %36
1405          %38 = OpVariable %37 Private
1406          %54 = OpTypeFloat 32
1407          %55 = OpTypeVector %54 4
1408          %56 = OpTypePointer Private %55
1409          %57 = OpVariable %56 Private
1410          %59 = OpTypeVector %54 3
1411          %60 = OpTypeMatrix %59 2
1412          %61 = OpTypePointer Private %60
1413          %62 = OpVariable %61 Private
1414          %64 = OpTypePointer Private %54
1415          %69 = OpConstant %54 2
1416          %71 = OpConstant %6 1
1417          %72 = OpConstant %6 2
1418         %201 = OpConstant %15 2
1419          %73 = OpConstant %6 3
1420         %202 = OpConstant %15 3
1421         %203 = OpConstant %6 1
1422         %204 = OpConstant %6 9
1423           %4 = OpFunction %2 None %3
1424           %5 = OpLabel
1425                OpReturn
1426                OpFunctionEnd
1427          %12 = OpFunction %2 None %8
1428           %9 = OpFunctionParameter %7
1429          %10 = OpFunctionParameter %102
1430          %11 = OpFunctionParameter %7
1431          %13 = OpLabel
1432          %14 = OpVariable %7 Function
1433          %27 = OpVariable %26 Function
1434          %22 = OpLoad %6 %11
1435          %24 = OpAccessChain %23 %20 %21 %22
1436          %25 = OpLoad %6 %24
1437                OpStore %14 %25
1438          %28 = OpLoad %15 %10
1439          %30 = OpAccessChain %29 %20 %28
1440          %31 = OpLoad %17 %30
1441                OpStore %27 %31
1442          %32 = OpLoad %6 %9
1443          %34 = OpInBoundsAccessChain %7 %27 %32
1444                OpStore %34 %33
1445          %39 = OpLoad %6 %9
1446          %40 = OpAccessChain %23 %38 %33
1447          %41 = OpLoad %6 %40
1448          %42 = OpInBoundsAccessChain %23 %38 %39
1449                OpStore %42 %41
1450          %43 = OpLoad %15 %10
1451          %44 = OpLoad %6 %11
1452          %45 = OpLoad %6 %9
1453          %46 = OpLoad %15 %10
1454          %47 = OpIAdd %6 %45 %46
1455          %48 = OpAccessChain %23 %38 %47
1456          %49 = OpLoad %6 %48
1457          %50 = OpInBoundsAccessChain %23 %20 %43 %44
1458          %51 = OpLoad %6 %50
1459          %52 = OpIAdd %6 %51 %49
1460          %53 = OpAccessChain %23 %20 %43 %44
1461                OpStore %53 %52
1462          %58 = OpLoad %15 %10
1463          %63 = OpLoad %6 %11
1464          %65 = OpAccessChain %64 %62 %21 %63
1465         %101 = OpAccessChain %64 %62 %45 %46
1466          %66 = OpLoad %54 %65
1467          %67 = OpAccessChain %64 %57 %58
1468                OpStore %67 %66
1469          %68 = OpLoad %6 %9
1470          %70 = OpInBoundsAccessChain %64 %57 %68
1471                OpStore %70 %69
1472                OpReturn
1473                OpFunctionEnd
1474   )";
1475   ASSERT_TRUE(IsEqual(env, added_as_dead_code, context1.get()));
1476 
1477   std::vector<protobufs::AccessChainClampingInfo> access_chain_clamping_info;
1478   access_chain_clamping_info.push_back(
1479       MakeAccessClampingInfo(24, {{1001, 2001}, {1002, 2002}}));
1480   access_chain_clamping_info.push_back(
1481       MakeAccessClampingInfo(30, {{1003, 2003}}));
1482   access_chain_clamping_info.push_back(
1483       MakeAccessClampingInfo(34, {{1004, 2004}}));
1484   access_chain_clamping_info.push_back(
1485       MakeAccessClampingInfo(40, {{1005, 2005}}));
1486   access_chain_clamping_info.push_back(
1487       MakeAccessClampingInfo(42, {{1006, 2006}}));
1488   access_chain_clamping_info.push_back(
1489       MakeAccessClampingInfo(48, {{1007, 2007}}));
1490   access_chain_clamping_info.push_back(
1491       MakeAccessClampingInfo(50, {{1008, 2008}, {1009, 2009}}));
1492   access_chain_clamping_info.push_back(
1493       MakeAccessClampingInfo(53, {{1010, 2010}, {1011, 2011}}));
1494   access_chain_clamping_info.push_back(
1495       MakeAccessClampingInfo(65, {{1012, 2012}, {1013, 2013}}));
1496   access_chain_clamping_info.push_back(
1497       MakeAccessClampingInfo(101, {{1014, 2014}, {1015, 2015}}));
1498   access_chain_clamping_info.push_back(
1499       MakeAccessClampingInfo(67, {{1016, 2016}}));
1500   access_chain_clamping_info.push_back(
1501       MakeAccessClampingInfo(70, {{1017, 2017}}));
1502 
1503   TransformationAddFunction add_livesafe_function(instructions, 0, 0, {}, 13,
1504                                                   access_chain_clamping_info);
1505   ASSERT_TRUE(add_livesafe_function.IsApplicable(context2.get(),
1506                                                  transformation_context2));
1507   ApplyAndCheckFreshIds(add_livesafe_function, context2.get(),
1508                         &transformation_context2);
1509   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1510       context2.get(), validator_options, kConsoleMessageConsumer));
1511   // The function should be deemed livesafe
1512   ASSERT_TRUE(transformation_context2.GetFactManager()->FunctionIsLivesafe(12));
1513   // All variables/parameters in the function should be deemed irrelevant.
1514   ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreIrrelevant(
1515       context2.get(), transformation_context2, 12, 0));
1516   std::string added_as_livesafe_code = R"(
1517                OpCapability Shader
1518           %1 = OpExtInstImport "GLSL.std.450"
1519                OpMemoryModel Logical GLSL450
1520                OpEntryPoint Fragment %4 "main"
1521                OpExecutionMode %4 OriginUpperLeft
1522                OpSource ESSL 310
1523           %2 = OpTypeVoid
1524         %100 = OpTypeBool
1525           %3 = OpTypeFunction %2
1526           %6 = OpTypeInt 32 1
1527           %7 = OpTypePointer Function %6
1528          %15 = OpTypeInt 32 0
1529         %102 = OpTypePointer Function %15
1530           %8 = OpTypeFunction %2 %7 %102 %7
1531          %16 = OpConstant %15 5
1532          %17 = OpTypeArray %6 %16
1533          %18 = OpTypeArray %17 %16
1534          %19 = OpTypePointer Private %18
1535          %20 = OpVariable %19 Private
1536          %21 = OpConstant %6 0
1537          %23 = OpTypePointer Private %6
1538          %26 = OpTypePointer Function %17
1539          %29 = OpTypePointer Private %17
1540          %33 = OpConstant %6 4
1541         %200 = OpConstant %15 4
1542          %35 = OpConstant %15 10
1543          %36 = OpTypeArray %6 %35
1544          %37 = OpTypePointer Private %36
1545          %38 = OpVariable %37 Private
1546          %54 = OpTypeFloat 32
1547          %55 = OpTypeVector %54 4
1548          %56 = OpTypePointer Private %55
1549          %57 = OpVariable %56 Private
1550          %59 = OpTypeVector %54 3
1551          %60 = OpTypeMatrix %59 2
1552          %61 = OpTypePointer Private %60
1553          %62 = OpVariable %61 Private
1554          %64 = OpTypePointer Private %54
1555          %69 = OpConstant %54 2
1556          %71 = OpConstant %6 1
1557          %72 = OpConstant %6 2
1558         %201 = OpConstant %15 2
1559          %73 = OpConstant %6 3
1560         %202 = OpConstant %15 3
1561         %203 = OpConstant %6 1
1562         %204 = OpConstant %6 9
1563           %4 = OpFunction %2 None %3
1564           %5 = OpLabel
1565                OpReturn
1566                OpFunctionEnd
1567          %12 = OpFunction %2 None %8
1568           %9 = OpFunctionParameter %7
1569          %10 = OpFunctionParameter %102
1570          %11 = OpFunctionParameter %7
1571          %13 = OpLabel
1572          %14 = OpVariable %7 Function
1573          %27 = OpVariable %26 Function
1574          %22 = OpLoad %6 %11
1575        %1002 = OpULessThanEqual %100 %22 %33
1576        %2002 = OpSelect %6 %1002 %22 %33
1577          %24 = OpAccessChain %23 %20 %21 %2002
1578          %25 = OpLoad %6 %24
1579                OpStore %14 %25
1580          %28 = OpLoad %15 %10
1581        %1003 = OpULessThanEqual %100 %28 %200
1582        %2003 = OpSelect %15 %1003 %28 %200
1583          %30 = OpAccessChain %29 %20 %2003
1584          %31 = OpLoad %17 %30
1585                OpStore %27 %31
1586          %32 = OpLoad %6 %9
1587        %1004 = OpULessThanEqual %100 %32 %33
1588        %2004 = OpSelect %6 %1004 %32 %33
1589          %34 = OpInBoundsAccessChain %7 %27 %2004
1590                OpStore %34 %33
1591          %39 = OpLoad %6 %9
1592          %40 = OpAccessChain %23 %38 %33
1593          %41 = OpLoad %6 %40
1594        %1006 = OpULessThanEqual %100 %39 %204
1595        %2006 = OpSelect %6 %1006 %39 %204
1596          %42 = OpInBoundsAccessChain %23 %38 %2006
1597                OpStore %42 %41
1598          %43 = OpLoad %15 %10
1599          %44 = OpLoad %6 %11
1600          %45 = OpLoad %6 %9
1601          %46 = OpLoad %15 %10
1602          %47 = OpIAdd %6 %45 %46
1603        %1007 = OpULessThanEqual %100 %47 %204
1604        %2007 = OpSelect %6 %1007 %47 %204
1605          %48 = OpAccessChain %23 %38 %2007
1606          %49 = OpLoad %6 %48
1607        %1008 = OpULessThanEqual %100 %43 %200
1608        %2008 = OpSelect %15 %1008 %43 %200
1609        %1009 = OpULessThanEqual %100 %44 %33
1610        %2009 = OpSelect %6 %1009 %44 %33
1611          %50 = OpInBoundsAccessChain %23 %20 %2008 %2009
1612          %51 = OpLoad %6 %50
1613          %52 = OpIAdd %6 %51 %49
1614        %1010 = OpULessThanEqual %100 %43 %200
1615        %2010 = OpSelect %15 %1010 %43 %200
1616        %1011 = OpULessThanEqual %100 %44 %33
1617        %2011 = OpSelect %6 %1011 %44 %33
1618          %53 = OpAccessChain %23 %20 %2010 %2011
1619                OpStore %53 %52
1620          %58 = OpLoad %15 %10
1621          %63 = OpLoad %6 %11
1622        %1013 = OpULessThanEqual %100 %63 %72
1623        %2013 = OpSelect %6 %1013 %63 %72
1624          %65 = OpAccessChain %64 %62 %21 %2013
1625        %1014 = OpULessThanEqual %100 %45 %71
1626        %2014 = OpSelect %6 %1014 %45 %71
1627        %1015 = OpULessThanEqual %100 %46 %201
1628        %2015 = OpSelect %15 %1015 %46 %201
1629         %101 = OpAccessChain %64 %62 %2014 %2015
1630          %66 = OpLoad %54 %65
1631        %1016 = OpULessThanEqual %100 %58 %202
1632        %2016 = OpSelect %15 %1016 %58 %202
1633          %67 = OpAccessChain %64 %57 %2016
1634                OpStore %67 %66
1635          %68 = OpLoad %6 %9
1636        %1017 = OpULessThanEqual %100 %68 %73
1637        %2017 = OpSelect %6 %1017 %68 %73
1638          %70 = OpInBoundsAccessChain %64 %57 %2017
1639                OpStore %70 %69
1640                OpReturn
1641                OpFunctionEnd
1642   )";
1643   ASSERT_TRUE(IsEqual(env, added_as_livesafe_code, context2.get()));
1644 }
1645 
TEST(TransformationAddFunctionTest, LivesafeCanCallLivesafe)1646 TEST(TransformationAddFunctionTest, LivesafeCanCallLivesafe) {
1647   std::string shader = R"(
1648                OpCapability Shader
1649           %1 = OpExtInstImport "GLSL.std.450"
1650                OpMemoryModel Logical GLSL450
1651                OpEntryPoint Fragment %4 "main"
1652                OpExecutionMode %4 OriginUpperLeft
1653                OpSource ESSL 310
1654           %2 = OpTypeVoid
1655           %3 = OpTypeFunction %2
1656           %4 = OpFunction %2 None %3
1657           %5 = OpLabel
1658                OpReturn
1659                OpFunctionEnd
1660           %6 = OpFunction %2 None %3
1661           %7 = OpLabel
1662                OpReturn
1663                OpFunctionEnd
1664   )";
1665 
1666   const auto env = SPV_ENV_UNIVERSAL_1_4;
1667   const auto consumer = nullptr;
1668 
1669   std::vector<protobufs::Instruction> instructions;
1670 
1671   instructions.push_back(
1672       MakeInstructionMessage(spv::Op::OpFunction, 2, 8,
1673                              {{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
1674                                {uint32_t(spv::FunctionControlMask::MaskNone)}},
1675                               {SPV_OPERAND_TYPE_TYPE_ID, {3}}}));
1676   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 9, {}));
1677   instructions.push_back(MakeInstructionMessage(spv::Op::OpFunctionCall, 2, 11,
1678                                                 {{SPV_OPERAND_TYPE_ID, {6}}}));
1679   instructions.push_back(MakeInstructionMessage(spv::Op::OpReturn, 0, 0, {}));
1680   instructions.push_back(
1681       MakeInstructionMessage(spv::Op::OpFunctionEnd, 0, 0, {}));
1682 
1683   spvtools::ValidatorOptions validator_options;
1684 
1685   const auto context1 = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1686   const auto context2 = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1687   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1688       context1.get(), validator_options, kConsoleMessageConsumer));
1689 
1690   TransformationContext transformation_context1(
1691       MakeUnique<FactManager>(context1.get()), validator_options);
1692   TransformationContext transformation_context2(
1693       MakeUnique<FactManager>(context2.get()), validator_options);
1694 
1695   // Mark function 6 as livesafe.
1696   transformation_context2.GetFactManager()->AddFactFunctionIsLivesafe(6);
1697 
1698   TransformationAddFunction add_dead_function(instructions);
1699   ASSERT_TRUE(
1700       add_dead_function.IsApplicable(context1.get(), transformation_context1));
1701   ApplyAndCheckFreshIds(add_dead_function, context1.get(),
1702                         &transformation_context1);
1703   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1704       context1.get(), validator_options, kConsoleMessageConsumer));
1705   // The function should not be deemed livesafe
1706   ASSERT_FALSE(transformation_context1.GetFactManager()->FunctionIsLivesafe(8));
1707   // All variables/parameters in the function should be deemed irrelevant.
1708   ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreIrrelevant(
1709       context1.get(), transformation_context1, 8, 0));
1710 
1711   std::string added_as_live_or_dead_code = R"(
1712                OpCapability Shader
1713           %1 = OpExtInstImport "GLSL.std.450"
1714                OpMemoryModel Logical GLSL450
1715                OpEntryPoint Fragment %4 "main"
1716                OpExecutionMode %4 OriginUpperLeft
1717                OpSource ESSL 310
1718           %2 = OpTypeVoid
1719           %3 = OpTypeFunction %2
1720           %4 = OpFunction %2 None %3
1721           %5 = OpLabel
1722                OpReturn
1723                OpFunctionEnd
1724           %6 = OpFunction %2 None %3
1725           %7 = OpLabel
1726                OpReturn
1727                OpFunctionEnd
1728           %8 = OpFunction %2 None %3
1729           %9 = OpLabel
1730          %11 = OpFunctionCall %2 %6
1731                OpReturn
1732                OpFunctionEnd
1733   )";
1734   ASSERT_TRUE(IsEqual(env, added_as_live_or_dead_code, context1.get()));
1735 
1736   TransformationAddFunction add_livesafe_function(instructions, 0, 0, {}, 0,
1737                                                   {});
1738   ASSERT_TRUE(add_livesafe_function.IsApplicable(context2.get(),
1739                                                  transformation_context2));
1740   ApplyAndCheckFreshIds(add_livesafe_function, context2.get(),
1741                         &transformation_context2);
1742   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1743       context2.get(), validator_options, kConsoleMessageConsumer));
1744   // The function should be deemed livesafe
1745   ASSERT_TRUE(transformation_context2.GetFactManager()->FunctionIsLivesafe(8));
1746   // All variables/parameters in the function should be deemed irrelevant.
1747   ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreIrrelevant(
1748       context2.get(), transformation_context2, 8, 0));
1749   ASSERT_TRUE(IsEqual(env, added_as_live_or_dead_code, context2.get()));
1750 }
1751 
TEST(TransformationAddFunctionTest, LivesafeOnlyCallsLivesafe)1752 TEST(TransformationAddFunctionTest, LivesafeOnlyCallsLivesafe) {
1753   std::string shader = R"(
1754                OpCapability Shader
1755           %1 = OpExtInstImport "GLSL.std.450"
1756                OpMemoryModel Logical GLSL450
1757                OpEntryPoint Fragment %4 "main"
1758                OpExecutionMode %4 OriginUpperLeft
1759                OpSource ESSL 310
1760           %2 = OpTypeVoid
1761           %3 = OpTypeFunction %2
1762           %4 = OpFunction %2 None %3
1763           %5 = OpLabel
1764                OpReturn
1765                OpFunctionEnd
1766           %6 = OpFunction %2 None %3
1767           %7 = OpLabel
1768                OpKill
1769                OpFunctionEnd
1770   )";
1771 
1772   const auto env = SPV_ENV_UNIVERSAL_1_4;
1773   const auto consumer = nullptr;
1774 
1775   std::vector<protobufs::Instruction> instructions;
1776 
1777   instructions.push_back(
1778       MakeInstructionMessage(spv::Op::OpFunction, 2, 8,
1779                              {{SPV_OPERAND_TYPE_FUNCTION_CONTROL,
1780                                {uint32_t(spv::FunctionControlMask::MaskNone)}},
1781                               {SPV_OPERAND_TYPE_TYPE_ID, {3}}}));
1782   instructions.push_back(MakeInstructionMessage(spv::Op::OpLabel, 0, 9, {}));
1783   instructions.push_back(MakeInstructionMessage(spv::Op::OpFunctionCall, 2, 11,
1784                                                 {{SPV_OPERAND_TYPE_ID, {6}}}));
1785   instructions.push_back(MakeInstructionMessage(spv::Op::OpReturn, 0, 0, {}));
1786   instructions.push_back(
1787       MakeInstructionMessage(spv::Op::OpFunctionEnd, 0, 0, {}));
1788 
1789   spvtools::ValidatorOptions validator_options;
1790 
1791   const auto context1 = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1792   const auto context2 = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1793   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1794       context1.get(), validator_options, kConsoleMessageConsumer));
1795 
1796   TransformationContext transformation_context1(
1797       MakeUnique<FactManager>(context1.get()), validator_options);
1798   TransformationContext transformation_context2(
1799       MakeUnique<FactManager>(context2.get()), validator_options);
1800 
1801   TransformationAddFunction add_dead_function(instructions);
1802   ASSERT_TRUE(
1803       add_dead_function.IsApplicable(context1.get(), transformation_context1));
1804   ApplyAndCheckFreshIds(add_dead_function, context1.get(),
1805                         &transformation_context1);
1806   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
1807       context1.get(), validator_options, kConsoleMessageConsumer));
1808   // The function should not be deemed livesafe
1809   ASSERT_FALSE(transformation_context1.GetFactManager()->FunctionIsLivesafe(8));
1810   // All variables/parameters in the function should be deemed irrelevant.
1811   ASSERT_TRUE(AllVariablesAndParametersExceptLoopLimiterAreIrrelevant(
1812       context1.get(), transformation_context1, 8, 0));
1813 
1814   std::string added_as_dead_code = R"(
1815                OpCapability Shader
1816           %1 = OpExtInstImport "GLSL.std.450"
1817                OpMemoryModel Logical GLSL450
1818                OpEntryPoint Fragment %4 "main"
1819                OpExecutionMode %4 OriginUpperLeft
1820                OpSource ESSL 310
1821           %2 = OpTypeVoid
1822           %3 = OpTypeFunction %2
1823           %4 = OpFunction %2 None %3
1824           %5 = OpLabel
1825                OpReturn
1826                OpFunctionEnd
1827           %6 = OpFunction %2 None %3
1828           %7 = OpLabel
1829                OpKill
1830                OpFunctionEnd
1831           %8 = OpFunction %2 None %3
1832           %9 = OpLabel
1833          %11 = OpFunctionCall %2 %6
1834                OpReturn
1835                OpFunctionEnd
1836   )";
1837   ASSERT_TRUE(IsEqual(env, added_as_dead_code, context1.get()));
1838 
1839   TransformationAddFunction add_livesafe_function(instructions, 0, 0, {}, 0,
1840                                                   {});
1841   ASSERT_FALSE(add_livesafe_function.IsApplicable(context2.get(),
1842                                                   transformation_context2));
1843 }
1844 
TEST(TransformationAddFunctionTest, LoopLimitersBackEdgeBlockEndsWithConditional1)1845 TEST(TransformationAddFunctionTest,
1846      LoopLimitersBackEdgeBlockEndsWithConditional1) {
1847   std::string shader = R"(
1848                OpCapability Shader
1849           %1 = OpExtInstImport "GLSL.std.450"
1850                OpMemoryModel Logical GLSL450
1851                OpEntryPoint Fragment %4 "main"
1852                OpExecutionMode %4 OriginUpperLeft
1853                OpSource ESSL 310
1854           %2 = OpTypeVoid
1855           %3 = OpTypeFunction %2
1856           %8 = OpTypeInt 32 1
1857           %9 = OpTypePointer Function %8
1858          %11 = OpConstant %8 0
1859          %18 = OpConstant %8 10
1860          %19 = OpTypeBool
1861          %26 = OpConstantTrue %19
1862          %27 = OpConstantFalse %19
1863          %28 = OpTypeInt 32 0
1864          %29 = OpTypePointer Function %28
1865          %30 = OpConstant %28 0
1866          %31 = OpConstant %28 1
1867          %32 = OpConstant %28 5
1868          %22 = OpConstant %8 1
1869           %4 = OpFunction %2 None %3
1870           %5 = OpLabel
1871                OpReturn
1872                OpFunctionEnd
1873   )";
1874 
1875   std::string donor = R"(
1876                OpCapability Shader
1877           %1 = OpExtInstImport "GLSL.std.450"
1878                OpMemoryModel Logical GLSL450
1879                OpEntryPoint Fragment %4 "main"
1880                OpExecutionMode %4 OriginUpperLeft
1881                OpSource ESSL 310
1882           %2 = OpTypeVoid
1883           %3 = OpTypeFunction %2
1884           %8 = OpTypeInt 32 1
1885           %9 = OpTypePointer Function %8
1886          %11 = OpConstant %8 0
1887          %18 = OpConstant %8 10
1888          %19 = OpTypeBool
1889          %26 = OpConstantTrue %19
1890          %27 = OpConstantFalse %19
1891          %28 = OpTypeInt 32 0
1892          %29 = OpTypePointer Function %28
1893          %30 = OpConstant %28 0
1894          %31 = OpConstant %28 1
1895          %32 = OpConstant %28 5
1896          %22 = OpConstant %8 1
1897           %4 = OpFunction %2 None %3
1898           %5 = OpLabel
1899                OpReturn
1900                OpFunctionEnd
1901           %6 = OpFunction %2 None %3
1902           %7 = OpLabel
1903          %10 = OpVariable %9 Function
1904                OpStore %10 %11
1905                OpBranch %12
1906          %12 = OpLabel
1907                OpLoopMerge %14 %15 None
1908                OpBranch %15
1909          %15 = OpLabel
1910          %17 = OpLoad %8 %10
1911          %20 = OpSLessThan %19 %17 %18
1912          %21 = OpLoad %8 %10
1913          %23 = OpIAdd %8 %21 %22
1914                OpStore %10 %23
1915                OpBranchConditional %20 %12 %14
1916          %14 = OpLabel
1917                OpReturn
1918                OpFunctionEnd
1919   )";
1920   const auto env = SPV_ENV_UNIVERSAL_1_4;
1921   const auto consumer = nullptr;
1922   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
1923   spvtools::ValidatorOptions validator_options;
1924   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1925                                                kConsoleMessageConsumer));
1926   TransformationContext transformation_context(
1927       MakeUnique<FactManager>(context.get()), validator_options);
1928   // Make a sequence of instruction messages corresponding to function %6 in
1929   // |donor|.
1930   std::vector<protobufs::Instruction> instructions =
1931       GetInstructionsForFunction(env, consumer, donor, 6);
1932 
1933   protobufs::LoopLimiterInfo loop_limiter_info;
1934   loop_limiter_info.set_loop_header_id(12);
1935   loop_limiter_info.set_load_id(102);
1936   loop_limiter_info.set_increment_id(103);
1937   loop_limiter_info.set_compare_id(104);
1938   loop_limiter_info.set_logical_op_id(105);
1939   TransformationAddFunction add_livesafe_function(instructions, 100, 32,
1940                                                   {loop_limiter_info}, 0, {});
1941   ASSERT_TRUE(add_livesafe_function.IsApplicable(context.get(),
1942                                                  transformation_context));
1943   ApplyAndCheckFreshIds(add_livesafe_function, context.get(),
1944                         &transformation_context);
1945   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
1946                                                kConsoleMessageConsumer));
1947   std::string expected = R"(
1948                OpCapability Shader
1949           %1 = OpExtInstImport "GLSL.std.450"
1950                OpMemoryModel Logical GLSL450
1951                OpEntryPoint Fragment %4 "main"
1952                OpExecutionMode %4 OriginUpperLeft
1953                OpSource ESSL 310
1954           %2 = OpTypeVoid
1955           %3 = OpTypeFunction %2
1956           %8 = OpTypeInt 32 1
1957           %9 = OpTypePointer Function %8
1958          %11 = OpConstant %8 0
1959          %18 = OpConstant %8 10
1960          %19 = OpTypeBool
1961          %26 = OpConstantTrue %19
1962          %27 = OpConstantFalse %19
1963          %28 = OpTypeInt 32 0
1964          %29 = OpTypePointer Function %28
1965          %30 = OpConstant %28 0
1966          %31 = OpConstant %28 1
1967          %32 = OpConstant %28 5
1968          %22 = OpConstant %8 1
1969           %4 = OpFunction %2 None %3
1970           %5 = OpLabel
1971                OpReturn
1972                OpFunctionEnd
1973           %6 = OpFunction %2 None %3
1974           %7 = OpLabel
1975         %100 = OpVariable %29 Function %30
1976          %10 = OpVariable %9 Function
1977                OpStore %10 %11
1978                OpBranch %12
1979          %12 = OpLabel
1980                OpLoopMerge %14 %15 None
1981                OpBranch %15
1982          %15 = OpLabel
1983          %17 = OpLoad %8 %10
1984          %20 = OpSLessThan %19 %17 %18
1985          %21 = OpLoad %8 %10
1986          %23 = OpIAdd %8 %21 %22
1987                OpStore %10 %23
1988         %102 = OpLoad %28 %100
1989         %103 = OpIAdd %28 %102 %31
1990                OpStore %100 %103
1991         %104 = OpULessThan %19 %102 %32
1992         %105 = OpLogicalAnd %19 %20 %104
1993                OpBranchConditional %105 %12 %14
1994          %14 = OpLabel
1995                OpReturn
1996                OpFunctionEnd
1997   )";
1998   ASSERT_TRUE(IsEqual(env, expected, context.get()));
1999 }
2000 
TEST(TransformationAddFunctionTest, LoopLimitersBackEdgeBlockEndsWithConditional2)2001 TEST(TransformationAddFunctionTest,
2002      LoopLimitersBackEdgeBlockEndsWithConditional2) {
2003   std::string shader = R"(
2004                OpCapability Shader
2005           %1 = OpExtInstImport "GLSL.std.450"
2006                OpMemoryModel Logical GLSL450
2007                OpEntryPoint Fragment %4 "main"
2008                OpExecutionMode %4 OriginUpperLeft
2009                OpSource ESSL 310
2010           %2 = OpTypeVoid
2011           %3 = OpTypeFunction %2
2012           %8 = OpTypeInt 32 1
2013           %9 = OpTypePointer Function %8
2014          %11 = OpConstant %8 0
2015          %18 = OpConstant %8 10
2016          %19 = OpTypeBool
2017          %26 = OpConstantTrue %19
2018          %27 = OpConstantFalse %19
2019          %28 = OpTypeInt 32 0
2020          %29 = OpTypePointer Function %28
2021          %30 = OpConstant %28 0
2022          %31 = OpConstant %28 1
2023          %32 = OpConstant %28 5
2024          %22 = OpConstant %8 1
2025           %4 = OpFunction %2 None %3
2026           %5 = OpLabel
2027                OpReturn
2028                OpFunctionEnd
2029   )";
2030 
2031   std::string donor = R"(
2032                OpCapability Shader
2033           %1 = OpExtInstImport "GLSL.std.450"
2034                OpMemoryModel Logical GLSL450
2035                OpEntryPoint Fragment %4 "main"
2036                OpExecutionMode %4 OriginUpperLeft
2037                OpSource ESSL 310
2038           %2 = OpTypeVoid
2039           %3 = OpTypeFunction %2
2040           %8 = OpTypeInt 32 1
2041           %9 = OpTypePointer Function %8
2042          %11 = OpConstant %8 0
2043          %18 = OpConstant %8 10
2044          %19 = OpTypeBool
2045          %26 = OpConstantTrue %19
2046          %27 = OpConstantFalse %19
2047          %28 = OpTypeInt 32 0
2048          %29 = OpTypePointer Function %28
2049          %30 = OpConstant %28 0
2050          %31 = OpConstant %28 1
2051          %32 = OpConstant %28 5
2052          %22 = OpConstant %8 1
2053           %4 = OpFunction %2 None %3
2054           %5 = OpLabel
2055                OpReturn
2056                OpFunctionEnd
2057           %6 = OpFunction %2 None %3
2058           %7 = OpLabel
2059          %10 = OpVariable %9 Function
2060                OpStore %10 %11
2061                OpBranch %12
2062          %12 = OpLabel
2063                OpLoopMerge %14 %15 None
2064                OpBranch %15
2065          %15 = OpLabel
2066          %17 = OpLoad %8 %10
2067          %20 = OpSLessThan %19 %17 %18
2068          %21 = OpLoad %8 %10
2069          %23 = OpIAdd %8 %21 %22
2070                OpStore %10 %23
2071          %50 = OpLogicalNot %19 %20
2072                OpBranchConditional %50 %14 %12
2073          %14 = OpLabel
2074                OpReturn
2075                OpFunctionEnd
2076   )";
2077   const auto env = SPV_ENV_UNIVERSAL_1_4;
2078   const auto consumer = nullptr;
2079   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
2080   spvtools::ValidatorOptions validator_options;
2081   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2082                                                kConsoleMessageConsumer));
2083   TransformationContext transformation_context(
2084       MakeUnique<FactManager>(context.get()), validator_options);
2085   // Make a sequence of instruction messages corresponding to function %6 in
2086   // |donor|.
2087   std::vector<protobufs::Instruction> instructions =
2088       GetInstructionsForFunction(env, consumer, donor, 6);
2089 
2090   protobufs::LoopLimiterInfo loop_limiter_info;
2091   loop_limiter_info.set_loop_header_id(12);
2092   loop_limiter_info.set_load_id(102);
2093   loop_limiter_info.set_increment_id(103);
2094   loop_limiter_info.set_compare_id(104);
2095   loop_limiter_info.set_logical_op_id(105);
2096   TransformationAddFunction add_livesafe_function(instructions, 100, 32,
2097                                                   {loop_limiter_info}, 0, {});
2098   ASSERT_TRUE(add_livesafe_function.IsApplicable(context.get(),
2099                                                  transformation_context));
2100   ApplyAndCheckFreshIds(add_livesafe_function, context.get(),
2101                         &transformation_context);
2102   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2103                                                kConsoleMessageConsumer));
2104   std::string expected = R"(
2105                OpCapability Shader
2106           %1 = OpExtInstImport "GLSL.std.450"
2107                OpMemoryModel Logical GLSL450
2108                OpEntryPoint Fragment %4 "main"
2109                OpExecutionMode %4 OriginUpperLeft
2110                OpSource ESSL 310
2111           %2 = OpTypeVoid
2112           %3 = OpTypeFunction %2
2113           %8 = OpTypeInt 32 1
2114           %9 = OpTypePointer Function %8
2115          %11 = OpConstant %8 0
2116          %18 = OpConstant %8 10
2117          %19 = OpTypeBool
2118          %26 = OpConstantTrue %19
2119          %27 = OpConstantFalse %19
2120          %28 = OpTypeInt 32 0
2121          %29 = OpTypePointer Function %28
2122          %30 = OpConstant %28 0
2123          %31 = OpConstant %28 1
2124          %32 = OpConstant %28 5
2125          %22 = OpConstant %8 1
2126           %4 = OpFunction %2 None %3
2127           %5 = OpLabel
2128                OpReturn
2129                OpFunctionEnd
2130           %6 = OpFunction %2 None %3
2131           %7 = OpLabel
2132         %100 = OpVariable %29 Function %30
2133          %10 = OpVariable %9 Function
2134                OpStore %10 %11
2135                OpBranch %12
2136          %12 = OpLabel
2137                OpLoopMerge %14 %15 None
2138                OpBranch %15
2139          %15 = OpLabel
2140          %17 = OpLoad %8 %10
2141          %20 = OpSLessThan %19 %17 %18
2142          %21 = OpLoad %8 %10
2143          %23 = OpIAdd %8 %21 %22
2144                OpStore %10 %23
2145          %50 = OpLogicalNot %19 %20
2146         %102 = OpLoad %28 %100
2147         %103 = OpIAdd %28 %102 %31
2148                OpStore %100 %103
2149         %104 = OpUGreaterThanEqual %19 %102 %32
2150         %105 = OpLogicalOr %19 %50 %104
2151                OpBranchConditional %105 %14 %12
2152          %14 = OpLabel
2153                OpReturn
2154                OpFunctionEnd
2155   )";
2156   ASSERT_TRUE(IsEqual(env, expected, context.get()));
2157 }
2158 
TEST(TransformationAddFunctionTest, LoopLimitersHeaderIsBackEdgeBlock)2159 TEST(TransformationAddFunctionTest, LoopLimitersHeaderIsBackEdgeBlock) {
2160   std::string shader = R"(
2161                OpCapability Shader
2162           %1 = OpExtInstImport "GLSL.std.450"
2163                OpMemoryModel Logical GLSL450
2164                OpEntryPoint Fragment %4 "main"
2165                OpExecutionMode %4 OriginUpperLeft
2166                OpSource ESSL 310
2167           %2 = OpTypeVoid
2168           %3 = OpTypeFunction %2
2169           %8 = OpTypeInt 32 1
2170           %9 = OpTypePointer Function %8
2171          %11 = OpConstant %8 0
2172          %18 = OpConstant %8 10
2173          %19 = OpTypeBool
2174          %26 = OpConstantTrue %19
2175          %27 = OpConstantFalse %19
2176          %28 = OpTypeInt 32 0
2177          %29 = OpTypePointer Function %28
2178          %30 = OpConstant %28 0
2179          %31 = OpConstant %28 1
2180          %32 = OpConstant %28 5
2181          %22 = OpConstant %8 1
2182           %4 = OpFunction %2 None %3
2183           %5 = OpLabel
2184                OpReturn
2185                OpFunctionEnd
2186   )";
2187 
2188   std::string donor = R"(
2189                OpCapability Shader
2190           %1 = OpExtInstImport "GLSL.std.450"
2191                OpMemoryModel Logical GLSL450
2192                OpEntryPoint Fragment %4 "main"
2193                OpExecutionMode %4 OriginUpperLeft
2194                OpSource ESSL 310
2195           %2 = OpTypeVoid
2196           %3 = OpTypeFunction %2
2197           %8 = OpTypeInt 32 1
2198           %9 = OpTypePointer Function %8
2199          %11 = OpConstant %8 0
2200          %18 = OpConstant %8 10
2201          %19 = OpTypeBool
2202          %26 = OpConstantTrue %19
2203          %27 = OpConstantFalse %19
2204          %28 = OpTypeInt 32 0
2205          %29 = OpTypePointer Function %28
2206          %30 = OpConstant %28 0
2207          %31 = OpConstant %28 1
2208          %32 = OpConstant %28 5
2209          %22 = OpConstant %8 1
2210           %4 = OpFunction %2 None %3
2211           %5 = OpLabel
2212                OpReturn
2213                OpFunctionEnd
2214           %6 = OpFunction %2 None %3
2215           %7 = OpLabel
2216          %10 = OpVariable %9 Function
2217                OpStore %10 %11
2218                OpBranch %12
2219          %12 = OpLabel
2220          %17 = OpLoad %8 %10
2221          %20 = OpSLessThan %19 %17 %18
2222          %21 = OpLoad %8 %10
2223          %23 = OpIAdd %8 %21 %22
2224                OpStore %10 %23
2225          %50 = OpLogicalNot %19 %20
2226                OpLoopMerge %14 %12 None
2227                OpBranchConditional %50 %14 %12
2228          %14 = OpLabel
2229                OpReturn
2230                OpFunctionEnd
2231   )";
2232   const auto env = SPV_ENV_UNIVERSAL_1_4;
2233   const auto consumer = nullptr;
2234   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
2235   spvtools::ValidatorOptions validator_options;
2236   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2237                                                kConsoleMessageConsumer));
2238   TransformationContext transformation_context(
2239       MakeUnique<FactManager>(context.get()), validator_options);
2240   // Make a sequence of instruction messages corresponding to function %6 in
2241   // |donor|.
2242   std::vector<protobufs::Instruction> instructions =
2243       GetInstructionsForFunction(env, consumer, donor, 6);
2244 
2245   protobufs::LoopLimiterInfo loop_limiter_info;
2246   loop_limiter_info.set_loop_header_id(12);
2247   loop_limiter_info.set_load_id(102);
2248   loop_limiter_info.set_increment_id(103);
2249   loop_limiter_info.set_compare_id(104);
2250   loop_limiter_info.set_logical_op_id(105);
2251   TransformationAddFunction add_livesafe_function(instructions, 100, 32,
2252                                                   {loop_limiter_info}, 0, {});
2253   ASSERT_TRUE(add_livesafe_function.IsApplicable(context.get(),
2254                                                  transformation_context));
2255   ApplyAndCheckFreshIds(add_livesafe_function, context.get(),
2256                         &transformation_context);
2257   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2258                                                kConsoleMessageConsumer));
2259   std::string expected = R"(
2260                OpCapability Shader
2261           %1 = OpExtInstImport "GLSL.std.450"
2262                OpMemoryModel Logical GLSL450
2263                OpEntryPoint Fragment %4 "main"
2264                OpExecutionMode %4 OriginUpperLeft
2265                OpSource ESSL 310
2266           %2 = OpTypeVoid
2267           %3 = OpTypeFunction %2
2268           %8 = OpTypeInt 32 1
2269           %9 = OpTypePointer Function %8
2270          %11 = OpConstant %8 0
2271          %18 = OpConstant %8 10
2272          %19 = OpTypeBool
2273          %26 = OpConstantTrue %19
2274          %27 = OpConstantFalse %19
2275          %28 = OpTypeInt 32 0
2276          %29 = OpTypePointer Function %28
2277          %30 = OpConstant %28 0
2278          %31 = OpConstant %28 1
2279          %32 = OpConstant %28 5
2280          %22 = OpConstant %8 1
2281           %4 = OpFunction %2 None %3
2282           %5 = OpLabel
2283                OpReturn
2284                OpFunctionEnd
2285           %6 = OpFunction %2 None %3
2286           %7 = OpLabel
2287         %100 = OpVariable %29 Function %30
2288          %10 = OpVariable %9 Function
2289                OpStore %10 %11
2290                OpBranch %12
2291          %12 = OpLabel
2292          %17 = OpLoad %8 %10
2293          %20 = OpSLessThan %19 %17 %18
2294          %21 = OpLoad %8 %10
2295          %23 = OpIAdd %8 %21 %22
2296                OpStore %10 %23
2297          %50 = OpLogicalNot %19 %20
2298         %102 = OpLoad %28 %100
2299         %103 = OpIAdd %28 %102 %31
2300                OpStore %100 %103
2301         %104 = OpUGreaterThanEqual %19 %102 %32
2302         %105 = OpLogicalOr %19 %50 %104
2303                OpLoopMerge %14 %12 None
2304                OpBranchConditional %105 %14 %12
2305          %14 = OpLabel
2306                OpReturn
2307                OpFunctionEnd
2308   )";
2309   ASSERT_TRUE(IsEqual(env, expected, context.get()));
2310 }
2311 
TEST(TransformationAddFunctionTest, InfiniteLoop)2312 TEST(TransformationAddFunctionTest, InfiniteLoop) {
2313   std::string shader = R"(
2314                OpCapability Shader
2315           %1 = OpExtInstImport "GLSL.std.450"
2316                OpMemoryModel Logical GLSL450
2317                OpEntryPoint Fragment %4 "main"
2318                OpExecutionMode %4 OriginUpperLeft
2319                OpSource ESSL 310
2320           %2 = OpTypeVoid
2321           %3 = OpTypeFunction %2
2322           %8 = OpTypeInt 32 1
2323           %9 = OpTypePointer Function %8
2324          %11 = OpConstant %8 0
2325          %18 = OpConstant %8 10
2326          %19 = OpTypeBool
2327          %26 = OpConstantTrue %19
2328          %27 = OpConstantFalse %19
2329          %28 = OpTypeInt 32 0
2330          %29 = OpTypePointer Function %28
2331          %30 = OpConstant %28 0
2332          %31 = OpConstant %28 1
2333          %32 = OpConstant %28 5
2334          %22 = OpConstant %8 1
2335           %4 = OpFunction %2 None %3
2336           %5 = OpLabel
2337                OpReturn
2338                OpFunctionEnd
2339   )";
2340 
2341   std::string donor = R"(
2342                OpCapability Shader
2343           %1 = OpExtInstImport "GLSL.std.450"
2344                OpMemoryModel Logical GLSL450
2345                OpEntryPoint Fragment %4 "main"
2346                OpExecutionMode %4 OriginUpperLeft
2347                OpSource ESSL 310
2348           %2 = OpTypeVoid
2349           %3 = OpTypeFunction %2
2350           %8 = OpTypeInt 32 1
2351           %9 = OpTypePointer Function %8
2352          %11 = OpConstant %8 0
2353          %18 = OpConstant %8 10
2354          %19 = OpTypeBool
2355          %26 = OpConstantTrue %19
2356          %27 = OpConstantFalse %19
2357          %28 = OpTypeInt 32 0
2358          %29 = OpTypePointer Function %28
2359          %30 = OpConstant %28 0
2360          %31 = OpConstant %28 1
2361          %32 = OpConstant %28 5
2362          %22 = OpConstant %8 1
2363           %4 = OpFunction %2 None %3
2364           %5 = OpLabel
2365                OpReturn
2366                OpFunctionEnd
2367           %6 = OpFunction %2 None %3
2368           %7 = OpLabel
2369          %10 = OpVariable %9 Function
2370                OpStore %10 %11
2371                OpBranch %12
2372          %12 = OpLabel
2373                OpLoopMerge %14 %12 None
2374                OpBranch %12
2375          %14 = OpLabel
2376                OpReturn
2377                OpFunctionEnd
2378   )";
2379   const auto env = SPV_ENV_UNIVERSAL_1_4;
2380   const auto consumer = nullptr;
2381   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
2382   spvtools::ValidatorOptions validator_options;
2383   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2384                                                kConsoleMessageConsumer));
2385   TransformationContext transformation_context(
2386       MakeUnique<FactManager>(context.get()), validator_options);
2387   // Make a sequence of instruction messages corresponding to function %6 in
2388   // |donor|.
2389   std::vector<protobufs::Instruction> instructions =
2390       GetInstructionsForFunction(env, consumer, donor, 6);
2391 
2392   protobufs::LoopLimiterInfo loop_limiter_info;
2393   loop_limiter_info.set_loop_header_id(12);
2394   loop_limiter_info.set_load_id(102);
2395   loop_limiter_info.set_increment_id(103);
2396   loop_limiter_info.set_compare_id(104);
2397   loop_limiter_info.set_logical_op_id(105);
2398   TransformationAddFunction add_livesafe_function(instructions, 100, 32,
2399                                                   {loop_limiter_info}, 0, {});
2400 
2401   // To make sure the loop's merge block is reachable, it must be dominated by
2402   // the loop header.
2403   ASSERT_FALSE(add_livesafe_function.IsApplicable(context.get(),
2404                                                   transformation_context));
2405 }
2406 
TEST(TransformationAddFunctionTest, UnreachableContinueConstruct)2407 TEST(TransformationAddFunctionTest, UnreachableContinueConstruct) {
2408   // This captures the case where the loop's continue construct is statically
2409   // unreachable.  In this case the loop cannot iterate and so we do not add
2410   // a loop limiter.  (The reason we do not just add one anyway is that
2411   // detecting which block would be the back-edge block is difficult in the
2412   // absence of reliable dominance information.)
2413   std::string shader = R"(
2414                OpCapability Shader
2415           %1 = OpExtInstImport "GLSL.std.450"
2416                OpMemoryModel Logical GLSL450
2417                OpEntryPoint Fragment %4 "main"
2418                OpExecutionMode %4 OriginUpperLeft
2419                OpSource ESSL 310
2420           %2 = OpTypeVoid
2421           %3 = OpTypeFunction %2
2422           %8 = OpTypeInt 32 1
2423           %9 = OpTypePointer Function %8
2424          %11 = OpConstant %8 0
2425          %18 = OpConstant %8 10
2426          %19 = OpTypeBool
2427          %23 = OpConstant %8 1
2428          %26 = OpConstantTrue %19
2429          %27 = OpConstantFalse %19
2430          %28 = OpTypeInt 32 0
2431          %29 = OpTypePointer Function %28
2432          %30 = OpConstant %28 0
2433          %31 = OpConstant %28 1
2434          %32 = OpConstant %28 5
2435           %4 = OpFunction %2 None %3
2436           %5 = OpLabel
2437                OpReturn
2438                OpFunctionEnd
2439   )";
2440 
2441   std::string donor = R"(
2442                OpCapability Shader
2443           %1 = OpExtInstImport "GLSL.std.450"
2444                OpMemoryModel Logical GLSL450
2445                OpEntryPoint Fragment %4 "main"
2446                OpExecutionMode %4 OriginUpperLeft
2447                OpSource ESSL 310
2448           %2 = OpTypeVoid
2449           %3 = OpTypeFunction %2
2450           %8 = OpTypeInt 32 1
2451           %9 = OpTypePointer Function %8
2452          %11 = OpConstant %8 0
2453          %18 = OpConstant %8 10
2454          %19 = OpTypeBool
2455          %23 = OpConstant %8 1
2456          %26 = OpConstantTrue %19
2457          %27 = OpConstantFalse %19
2458          %28 = OpTypeInt 32 0
2459          %29 = OpTypePointer Function %28
2460          %30 = OpConstant %28 0
2461          %31 = OpConstant %28 1
2462          %32 = OpConstant %28 5
2463           %4 = OpFunction %2 None %3
2464           %5 = OpLabel
2465                OpReturn
2466                OpFunctionEnd
2467           %6 = OpFunction %2 None %3
2468           %7 = OpLabel
2469          %10 = OpVariable %9 Function
2470                OpStore %10 %11
2471                OpBranch %12
2472          %12 = OpLabel
2473                OpLoopMerge %14 %15 None
2474                OpBranch %16
2475          %16 = OpLabel
2476          %17 = OpLoad %8 %10
2477          %20 = OpSLessThan %19 %17 %18
2478                OpBranchConditional %20 %13 %14
2479          %13 = OpLabel
2480                OpBranch %14
2481          %15 = OpLabel
2482          %22 = OpLoad %8 %10
2483          %24 = OpIAdd %8 %22 %23
2484                OpStore %10 %24
2485                OpBranch %12
2486          %14 = OpLabel
2487                OpReturn
2488                OpFunctionEnd
2489   )";
2490 
2491   const auto env = SPV_ENV_UNIVERSAL_1_4;
2492   const auto consumer = nullptr;
2493   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
2494   spvtools::ValidatorOptions validator_options;
2495   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2496                                                kConsoleMessageConsumer));
2497   TransformationContext transformation_context(
2498       MakeUnique<FactManager>(context.get()), validator_options);
2499   // Make a sequence of instruction messages corresponding to function %6 in
2500   // |donor|.
2501   std::vector<protobufs::Instruction> instructions =
2502       GetInstructionsForFunction(env, consumer, donor, 6);
2503 
2504   protobufs::LoopLimiterInfo loop_limiter_info;
2505   loop_limiter_info.set_loop_header_id(12);
2506   loop_limiter_info.set_load_id(102);
2507   loop_limiter_info.set_increment_id(103);
2508   loop_limiter_info.set_compare_id(104);
2509   loop_limiter_info.set_logical_op_id(105);
2510   TransformationAddFunction add_livesafe_function(instructions, 100, 32,
2511                                                   {loop_limiter_info}, 0, {});
2512   ASSERT_TRUE(add_livesafe_function.IsApplicable(context.get(),
2513                                                  transformation_context));
2514   ApplyAndCheckFreshIds(add_livesafe_function, context.get(),
2515                         &transformation_context);
2516   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2517                                                kConsoleMessageConsumer));
2518   std::string expected = R"(
2519                OpCapability Shader
2520           %1 = OpExtInstImport "GLSL.std.450"
2521                OpMemoryModel Logical GLSL450
2522                OpEntryPoint Fragment %4 "main"
2523                OpExecutionMode %4 OriginUpperLeft
2524                OpSource ESSL 310
2525           %2 = OpTypeVoid
2526           %3 = OpTypeFunction %2
2527           %8 = OpTypeInt 32 1
2528           %9 = OpTypePointer Function %8
2529          %11 = OpConstant %8 0
2530          %18 = OpConstant %8 10
2531          %19 = OpTypeBool
2532          %23 = OpConstant %8 1
2533          %26 = OpConstantTrue %19
2534          %27 = OpConstantFalse %19
2535          %28 = OpTypeInt 32 0
2536          %29 = OpTypePointer Function %28
2537          %30 = OpConstant %28 0
2538          %31 = OpConstant %28 1
2539          %32 = OpConstant %28 5
2540           %4 = OpFunction %2 None %3
2541           %5 = OpLabel
2542                OpReturn
2543                OpFunctionEnd
2544           %6 = OpFunction %2 None %3
2545           %7 = OpLabel
2546         %100 = OpVariable %29 Function %30
2547          %10 = OpVariable %9 Function
2548                OpStore %10 %11
2549                OpBranch %12
2550          %12 = OpLabel
2551                OpLoopMerge %14 %15 None
2552                OpBranch %16
2553          %16 = OpLabel
2554          %17 = OpLoad %8 %10
2555          %20 = OpSLessThan %19 %17 %18
2556                OpBranchConditional %20 %13 %14
2557          %13 = OpLabel
2558                OpBranch %14
2559          %15 = OpLabel
2560          %22 = OpLoad %8 %10
2561          %24 = OpIAdd %8 %22 %23
2562                OpStore %10 %24
2563                OpBranch %12
2564          %14 = OpLabel
2565                OpReturn
2566                OpFunctionEnd
2567   )";
2568   ASSERT_TRUE(IsEqual(env, expected, context.get()));
2569 }
2570 
TEST(TransformationAddFunctionTest, LoopLimitersAndOpPhi1)2571 TEST(TransformationAddFunctionTest, LoopLimitersAndOpPhi1) {
2572   // This captures the scenario where breaking a loop due to a loop limiter
2573   // requires patching up OpPhi instructions occurring at the loop merge block.
2574 
2575   std::string shader = R"(
2576                OpCapability Shader
2577           %1 = OpExtInstImport "GLSL.std.450"
2578                OpMemoryModel Logical GLSL450
2579                OpEntryPoint Fragment %4 "main"
2580                OpExecutionMode %4 OriginUpperLeft
2581                OpSource ESSL 310
2582           %2 = OpTypeVoid
2583           %3 = OpTypeFunction %2
2584           %6 = OpTypeInt 32 1
2585          %50 = OpTypeInt 32 0
2586          %51 = OpConstant %50 0
2587          %52 = OpConstant %50 1
2588          %53 = OpTypePointer Function %50
2589           %7 = OpTypeFunction %6
2590          %10 = OpTypePointer Function %6
2591          %12 = OpConstant %6 0
2592          %19 = OpConstant %6 100
2593          %20 = OpTypeBool
2594          %23 = OpConstant %6 20
2595          %28 = OpConstant %6 1
2596           %4 = OpFunction %2 None %3
2597           %5 = OpLabel
2598                OpReturn
2599                OpFunctionEnd
2600   )";
2601 
2602   std::string donor = R"(
2603                OpCapability Shader
2604           %1 = OpExtInstImport "GLSL.std.450"
2605                OpMemoryModel Logical GLSL450
2606                OpEntryPoint Fragment %4 "main"
2607                OpExecutionMode %4 OriginUpperLeft
2608                OpSource ESSL 310
2609           %2 = OpTypeVoid
2610           %3 = OpTypeFunction %2
2611           %6 = OpTypeInt 32 1
2612           %7 = OpTypeFunction %6
2613          %10 = OpTypePointer Function %6
2614          %12 = OpConstant %6 0
2615          %19 = OpConstant %6 100
2616          %20 = OpTypeBool
2617          %23 = OpConstant %6 20
2618          %28 = OpConstant %6 1
2619           %4 = OpFunction %2 None %3
2620           %5 = OpLabel
2621          %36 = OpFunctionCall %6 %8
2622                OpReturn
2623                OpFunctionEnd
2624           %8 = OpFunction %6 None %7
2625           %9 = OpLabel
2626          %11 = OpVariable %10 Function
2627                OpStore %11 %12
2628                OpBranch %13
2629          %13 = OpLabel
2630          %37 = OpPhi %6 %12 %9 %32 %16
2631                OpLoopMerge %15 %16 None
2632                OpBranch %17
2633          %17 = OpLabel
2634          %21 = OpSLessThan %20 %37 %19
2635                OpBranchConditional %21 %14 %15
2636          %14 = OpLabel
2637          %24 = OpSGreaterThan %20 %37 %23
2638                OpSelectionMerge %26 None
2639                OpBranchConditional %24 %25 %26
2640          %25 = OpLabel
2641          %29 = OpIAdd %6 %37 %28
2642                OpStore %11 %29
2643                OpBranch %15
2644          %26 = OpLabel
2645                OpBranch %16
2646          %16 = OpLabel
2647          %32 = OpIAdd %6 %37 %28
2648                OpStore %11 %32
2649                OpBranch %13
2650          %15 = OpLabel
2651          %38 = OpPhi %6 %37 %17 %29 %25
2652                OpReturnValue %38
2653                OpFunctionEnd
2654   )";
2655 
2656   const auto env = SPV_ENV_UNIVERSAL_1_4;
2657   const auto consumer = nullptr;
2658   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
2659   spvtools::ValidatorOptions validator_options;
2660   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2661                                                kConsoleMessageConsumer));
2662   TransformationContext transformation_context(
2663       MakeUnique<FactManager>(context.get()), validator_options);
2664   // Make a sequence of instruction messages corresponding to function %8 in
2665   // |donor|.
2666   std::vector<protobufs::Instruction> instructions =
2667       GetInstructionsForFunction(env, consumer, donor, 8);
2668 
2669   protobufs::LoopLimiterInfo loop_limiter_info;
2670   loop_limiter_info.set_loop_header_id(13);
2671   loop_limiter_info.set_load_id(102);
2672   loop_limiter_info.set_increment_id(103);
2673   loop_limiter_info.set_compare_id(104);
2674   loop_limiter_info.set_logical_op_id(105);
2675 
2676   TransformationAddFunction no_op_phi_data(instructions, 100, 28,
2677                                            {loop_limiter_info}, 0, {});
2678   // The loop limiter info is not good enough; it does not include ids to patch
2679   // up the OpPhi at the loop merge.
2680   ASSERT_FALSE(
2681       no_op_phi_data.IsApplicable(context.get(), transformation_context));
2682 
2683   // Add a phi id for the new edge from the loop back edge block to the loop
2684   // merge.
2685   loop_limiter_info.add_phi_id(28);
2686   TransformationAddFunction with_op_phi_data(instructions, 100, 28,
2687                                              {loop_limiter_info}, 0, {});
2688   ASSERT_TRUE(
2689       with_op_phi_data.IsApplicable(context.get(), transformation_context));
2690   ApplyAndCheckFreshIds(with_op_phi_data, context.get(),
2691                         &transformation_context);
2692   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2693                                                kConsoleMessageConsumer));
2694   std::string expected = R"(
2695                OpCapability Shader
2696           %1 = OpExtInstImport "GLSL.std.450"
2697                OpMemoryModel Logical GLSL450
2698                OpEntryPoint Fragment %4 "main"
2699                OpExecutionMode %4 OriginUpperLeft
2700                OpSource ESSL 310
2701           %2 = OpTypeVoid
2702           %3 = OpTypeFunction %2
2703           %6 = OpTypeInt 32 1
2704          %50 = OpTypeInt 32 0
2705          %51 = OpConstant %50 0
2706          %52 = OpConstant %50 1
2707          %53 = OpTypePointer Function %50
2708           %7 = OpTypeFunction %6
2709          %10 = OpTypePointer Function %6
2710          %12 = OpConstant %6 0
2711          %19 = OpConstant %6 100
2712          %20 = OpTypeBool
2713          %23 = OpConstant %6 20
2714          %28 = OpConstant %6 1
2715           %4 = OpFunction %2 None %3
2716           %5 = OpLabel
2717                OpReturn
2718                OpFunctionEnd
2719           %8 = OpFunction %6 None %7
2720           %9 = OpLabel
2721         %100 = OpVariable %53 Function %51
2722          %11 = OpVariable %10 Function
2723                OpStore %11 %12
2724                OpBranch %13
2725          %13 = OpLabel
2726          %37 = OpPhi %6 %12 %9 %32 %16
2727                OpLoopMerge %15 %16 None
2728                OpBranch %17
2729          %17 = OpLabel
2730          %21 = OpSLessThan %20 %37 %19
2731                OpBranchConditional %21 %14 %15
2732          %14 = OpLabel
2733          %24 = OpSGreaterThan %20 %37 %23
2734                OpSelectionMerge %26 None
2735                OpBranchConditional %24 %25 %26
2736          %25 = OpLabel
2737          %29 = OpIAdd %6 %37 %28
2738                OpStore %11 %29
2739                OpBranch %15
2740          %26 = OpLabel
2741                OpBranch %16
2742          %16 = OpLabel
2743          %32 = OpIAdd %6 %37 %28
2744                OpStore %11 %32
2745         %102 = OpLoad %50 %100
2746         %103 = OpIAdd %50 %102 %52
2747                OpStore %100 %103
2748         %104 = OpUGreaterThanEqual %20 %102 %28
2749                OpBranchConditional %104 %15 %13
2750          %15 = OpLabel
2751          %38 = OpPhi %6 %37 %17 %29 %25 %28 %16
2752                OpReturnValue %38
2753                OpFunctionEnd
2754   )";
2755   ASSERT_TRUE(IsEqual(env, expected, context.get()));
2756 }
2757 
TEST(TransformationAddFunctionTest, LoopLimitersAndOpPhi2)2758 TEST(TransformationAddFunctionTest, LoopLimitersAndOpPhi2) {
2759   // This captures the scenario where the loop merge block already has an OpPhi
2760   // with the loop back edge block as a predecessor.
2761 
2762   std::string shader = R"(
2763                OpCapability Shader
2764           %1 = OpExtInstImport "GLSL.std.450"
2765                OpMemoryModel Logical GLSL450
2766                OpEntryPoint Fragment %4 "main"
2767                OpExecutionMode %4 OriginUpperLeft
2768                OpSource ESSL 310
2769           %2 = OpTypeVoid
2770           %3 = OpTypeFunction %2
2771           %6 = OpTypeInt 32 1
2772          %50 = OpTypeInt 32 0
2773          %51 = OpConstant %50 0
2774          %52 = OpConstant %50 1
2775          %53 = OpTypePointer Function %50
2776           %7 = OpTypeFunction %6
2777          %10 = OpTypePointer Function %6
2778          %12 = OpConstant %6 0
2779          %19 = OpConstant %6 100
2780          %20 = OpTypeBool
2781          %60 = OpConstantTrue %20
2782          %23 = OpConstant %6 20
2783          %28 = OpConstant %6 1
2784           %4 = OpFunction %2 None %3
2785           %5 = OpLabel
2786                OpReturn
2787                OpFunctionEnd
2788   )";
2789 
2790   std::string donor = R"(
2791                OpCapability Shader
2792           %1 = OpExtInstImport "GLSL.std.450"
2793                OpMemoryModel Logical GLSL450
2794                OpEntryPoint Fragment %4 "main"
2795                OpExecutionMode %4 OriginUpperLeft
2796                OpSource ESSL 310
2797           %2 = OpTypeVoid
2798           %3 = OpTypeFunction %2
2799           %6 = OpTypeInt 32 1
2800          %50 = OpTypeInt 32 0
2801          %51 = OpConstant %50 0
2802          %52 = OpConstant %50 1
2803          %53 = OpTypePointer Function %50
2804           %7 = OpTypeFunction %6
2805          %10 = OpTypePointer Function %6
2806          %12 = OpConstant %6 0
2807          %19 = OpConstant %6 100
2808          %20 = OpTypeBool
2809          %60 = OpConstantTrue %20
2810          %23 = OpConstant %6 20
2811          %28 = OpConstant %6 1
2812           %4 = OpFunction %2 None %3
2813           %5 = OpLabel
2814                OpReturn
2815                OpFunctionEnd
2816           %8 = OpFunction %6 None %7
2817           %9 = OpLabel
2818          %11 = OpVariable %10 Function
2819                OpStore %11 %12
2820                OpBranch %13
2821          %13 = OpLabel
2822          %37 = OpPhi %6 %12 %9 %32 %16
2823                OpLoopMerge %15 %16 None
2824                OpBranch %17
2825          %17 = OpLabel
2826          %21 = OpSLessThan %20 %37 %19
2827                OpBranchConditional %21 %14 %15
2828          %14 = OpLabel
2829          %24 = OpSGreaterThan %20 %37 %23
2830                OpSelectionMerge %26 None
2831                OpBranchConditional %24 %25 %26
2832          %25 = OpLabel
2833          %29 = OpIAdd %6 %37 %28
2834                OpStore %11 %29
2835                OpBranch %15
2836          %26 = OpLabel
2837                OpBranch %16
2838          %16 = OpLabel
2839          %32 = OpIAdd %6 %37 %28
2840                OpStore %11 %32
2841                OpBranchConditional %60 %15 %13
2842          %15 = OpLabel
2843          %38 = OpPhi %6 %37 %17 %29 %25 %23 %16
2844                OpReturnValue %38
2845                OpFunctionEnd
2846   )";
2847 
2848   const auto env = SPV_ENV_UNIVERSAL_1_4;
2849   const auto consumer = nullptr;
2850   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
2851   spvtools::ValidatorOptions validator_options;
2852   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2853                                                kConsoleMessageConsumer));
2854   TransformationContext transformation_context(
2855       MakeUnique<FactManager>(context.get()), validator_options);
2856   // Make a sequence of instruction messages corresponding to function %8 in
2857   // |donor|.
2858   std::vector<protobufs::Instruction> instructions =
2859       GetInstructionsForFunction(env, consumer, donor, 8);
2860 
2861   protobufs::LoopLimiterInfo loop_limiter_info;
2862   loop_limiter_info.set_loop_header_id(13);
2863   loop_limiter_info.set_load_id(102);
2864   loop_limiter_info.set_increment_id(103);
2865   loop_limiter_info.set_compare_id(104);
2866   loop_limiter_info.set_logical_op_id(105);
2867 
2868   TransformationAddFunction transformation(instructions, 100, 28,
2869                                            {loop_limiter_info}, 0, {});
2870   ASSERT_TRUE(
2871       transformation.IsApplicable(context.get(), transformation_context));
2872   ApplyAndCheckFreshIds(transformation, context.get(), &transformation_context);
2873   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
2874                                                kConsoleMessageConsumer));
2875   std::string expected = R"(
2876                OpCapability Shader
2877           %1 = OpExtInstImport "GLSL.std.450"
2878                OpMemoryModel Logical GLSL450
2879                OpEntryPoint Fragment %4 "main"
2880                OpExecutionMode %4 OriginUpperLeft
2881                OpSource ESSL 310
2882           %2 = OpTypeVoid
2883           %3 = OpTypeFunction %2
2884           %6 = OpTypeInt 32 1
2885          %50 = OpTypeInt 32 0
2886          %51 = OpConstant %50 0
2887          %52 = OpConstant %50 1
2888          %53 = OpTypePointer Function %50
2889           %7 = OpTypeFunction %6
2890          %10 = OpTypePointer Function %6
2891          %12 = OpConstant %6 0
2892          %19 = OpConstant %6 100
2893          %20 = OpTypeBool
2894          %60 = OpConstantTrue %20
2895          %23 = OpConstant %6 20
2896          %28 = OpConstant %6 1
2897           %4 = OpFunction %2 None %3
2898           %5 = OpLabel
2899                OpReturn
2900                OpFunctionEnd
2901           %8 = OpFunction %6 None %7
2902           %9 = OpLabel
2903         %100 = OpVariable %53 Function %51
2904          %11 = OpVariable %10 Function
2905                OpStore %11 %12
2906                OpBranch %13
2907          %13 = OpLabel
2908          %37 = OpPhi %6 %12 %9 %32 %16
2909                OpLoopMerge %15 %16 None
2910                OpBranch %17
2911          %17 = OpLabel
2912          %21 = OpSLessThan %20 %37 %19
2913                OpBranchConditional %21 %14 %15
2914          %14 = OpLabel
2915          %24 = OpSGreaterThan %20 %37 %23
2916                OpSelectionMerge %26 None
2917                OpBranchConditional %24 %25 %26
2918          %25 = OpLabel
2919          %29 = OpIAdd %6 %37 %28
2920                OpStore %11 %29
2921                OpBranch %15
2922          %26 = OpLabel
2923                OpBranch %16
2924          %16 = OpLabel
2925          %32 = OpIAdd %6 %37 %28
2926                OpStore %11 %32
2927         %102 = OpLoad %50 %100
2928         %103 = OpIAdd %50 %102 %52
2929                OpStore %100 %103
2930         %104 = OpUGreaterThanEqual %20 %102 %28
2931         %105 = OpLogicalOr %20 %60 %104
2932                OpBranchConditional %105 %15 %13
2933          %15 = OpLabel
2934          %38 = OpPhi %6 %37 %17 %29 %25 %23 %16
2935                OpReturnValue %38
2936                OpFunctionEnd
2937   )";
2938   ASSERT_TRUE(IsEqual(env, expected, context.get()));
2939 }
2940 
TEST(TransformationAddFunctionTest, StaticallyOutOfBoundsArrayAccess)2941 TEST(TransformationAddFunctionTest, StaticallyOutOfBoundsArrayAccess) {
2942   std::string shader = R"(
2943                OpCapability Shader
2944           %1 = OpExtInstImport "GLSL.std.450"
2945                OpMemoryModel Logical GLSL450
2946                OpEntryPoint Fragment %4 "main"
2947                OpExecutionMode %4 OriginUpperLeft
2948                OpSource ESSL 310
2949           %2 = OpTypeVoid
2950           %3 = OpTypeFunction %2
2951           %8 = OpTypeInt 32 1
2952           %9 = OpTypeInt 32 0
2953          %10 = OpConstant %9 3
2954          %11 = OpTypeArray %8 %10
2955          %12 = OpTypePointer Private %11
2956          %13 = OpVariable %12 Private
2957          %14 = OpConstant %8 3
2958          %20 = OpConstant %8 2
2959          %15 = OpConstant %8 1
2960          %21 = OpTypeBool
2961          %16 = OpTypePointer Private %8
2962           %4 = OpFunction %2 None %3
2963           %5 = OpLabel
2964                OpReturn
2965                OpFunctionEnd
2966   )";
2967 
2968   std::string donor = R"(
2969                OpCapability Shader
2970           %1 = OpExtInstImport "GLSL.std.450"
2971                OpMemoryModel Logical GLSL450
2972                OpEntryPoint Fragment %4 "main"
2973                OpExecutionMode %4 OriginUpperLeft
2974                OpSource ESSL 310
2975           %2 = OpTypeVoid
2976           %3 = OpTypeFunction %2
2977           %8 = OpTypeInt 32 1
2978           %9 = OpTypeInt 32 0
2979          %10 = OpConstant %9 3
2980          %11 = OpTypeArray %8 %10
2981          %12 = OpTypePointer Private %11
2982          %13 = OpVariable %12 Private
2983          %14 = OpConstant %8 3
2984          %15 = OpConstant %8 1
2985          %16 = OpTypePointer Private %8
2986           %4 = OpFunction %2 None %3
2987           %5 = OpLabel
2988                OpReturn
2989                OpFunctionEnd
2990           %6 = OpFunction %2 None %3
2991           %7 = OpLabel
2992          %17 = OpAccessChain %16 %13 %14
2993                OpStore %17 %15
2994                OpReturn
2995                OpFunctionEnd
2996   )";
2997   const auto env = SPV_ENV_UNIVERSAL_1_4;
2998   const auto consumer = nullptr;
2999   const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
3000   spvtools::ValidatorOptions validator_options;
3001   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
3002                                                kConsoleMessageConsumer));
3003   TransformationContext transformation_context(
3004       MakeUnique<FactManager>(context.get()), validator_options);
3005   // Make a sequence of instruction messages corresponding to function %6 in
3006   // |donor|.
3007   std::vector<protobufs::Instruction> instructions =
3008       GetInstructionsForFunction(env, consumer, donor, 6);
3009 
3010   TransformationAddFunction add_livesafe_function(
3011       instructions, 0, 0, {}, 0, {MakeAccessClampingInfo(17, {{100, 101}})});
3012   ASSERT_TRUE(add_livesafe_function.IsApplicable(context.get(),
3013                                                  transformation_context));
3014   ApplyAndCheckFreshIds(add_livesafe_function, context.get(),
3015                         &transformation_context);
3016   ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
3017                                                kConsoleMessageConsumer));
3018   std::string expected = R"(
3019                OpCapability Shader
3020           %1 = OpExtInstImport "GLSL.std.450"
3021                OpMemoryModel Logical GLSL450
3022                OpEntryPoint Fragment %4 "main"
3023                OpExecutionMode %4 OriginUpperLeft
3024                OpSource ESSL 310
3025           %2 = OpTypeVoid
3026           %3 = OpTypeFunction %2
3027           %8 = OpTypeInt 32 1
3028           %9 = OpTypeInt 32 0
3029          %10 = OpConstant %9 3
3030          %11 = OpTypeArray %8 %10
3031          %12 = OpTypePointer Private %11
3032          %13 = OpVariable %12 Private
3033          %14 = OpConstant %8 3
3034          %20 = OpConstant %8 2
3035          %15 = OpConstant %8 1
3036          %21 = OpTypeBool
3037          %16 = OpTypePointer Private %8
3038           %4 = OpFunction %2 None %3
3039           %5 = OpLabel
3040                OpReturn
3041                OpFunctionEnd
3042           %6 = OpFunction %2 None %3
3043           %7 = OpLabel
3044         %100 = OpULessThanEqual %21 %14 %20
3045         %101 = OpSelect %8 %100 %14 %20
3046          %17 = OpAccessChain %16 %13 %101
3047                OpStore %17 %15
3048                OpReturn
3049                OpFunctionEnd
3050   )";
3051   ASSERT_TRUE(IsEqual(env, expected, context.get()));
3052 }
3053 
3054 }  // namespace
3055 }  // namespace fuzz
3056 }  // namespace spvtools
3057