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