1fd4e5da5Sopenharmony_ci// Copyright (c) 2020 Google LLC
2fd4e5da5Sopenharmony_ci//
3fd4e5da5Sopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4fd4e5da5Sopenharmony_ci// you may not use this file except in compliance with the License.
5fd4e5da5Sopenharmony_ci// You may obtain a copy of the License at
6fd4e5da5Sopenharmony_ci//
7fd4e5da5Sopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8fd4e5da5Sopenharmony_ci//
9fd4e5da5Sopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10fd4e5da5Sopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11fd4e5da5Sopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fd4e5da5Sopenharmony_ci// See the License for the specific language governing permissions and
13fd4e5da5Sopenharmony_ci// limitations under the License.
14fd4e5da5Sopenharmony_ci
15fd4e5da5Sopenharmony_ci#include "source/fuzz/transformation_function_call.h"
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include "gtest/gtest.h"
18fd4e5da5Sopenharmony_ci#include "source/fuzz/fuzzer_util.h"
19fd4e5da5Sopenharmony_ci#include "source/fuzz/instruction_descriptor.h"
20fd4e5da5Sopenharmony_ci#include "test/fuzz/fuzz_test_util.h"
21fd4e5da5Sopenharmony_ci
22fd4e5da5Sopenharmony_cinamespace spvtools {
23fd4e5da5Sopenharmony_cinamespace fuzz {
24fd4e5da5Sopenharmony_cinamespace {
25fd4e5da5Sopenharmony_ci
26fd4e5da5Sopenharmony_ciTEST(TransformationFunctionCallTest, BasicTest) {
27fd4e5da5Sopenharmony_ci  std::string shader = R"(
28fd4e5da5Sopenharmony_ci               OpCapability Shader
29fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
30fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
31fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
32fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
33fd4e5da5Sopenharmony_ci               OpSource ESSL 310
34fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
35fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
36fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
37fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
38fd4e5da5Sopenharmony_ci          %8 = OpTypeFunction %6 %7
39fd4e5da5Sopenharmony_ci         %12 = OpTypeFloat 32
40fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
41fd4e5da5Sopenharmony_ci         %14 = OpTypeFunction %6 %7 %13
42fd4e5da5Sopenharmony_ci         %27 = OpConstant %6 1
43fd4e5da5Sopenharmony_ci         %50 = OpConstant %12 1
44fd4e5da5Sopenharmony_ci         %57 = OpTypeBool
45fd4e5da5Sopenharmony_ci         %58 = OpConstantFalse %57
46fd4e5da5Sopenharmony_ci        %204 = OpUndef %6
47fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
48fd4e5da5Sopenharmony_ci          %5 = OpLabel
49fd4e5da5Sopenharmony_ci         %61 = OpVariable %7 Function
50fd4e5da5Sopenharmony_ci         %62 = OpVariable %7 Function
51fd4e5da5Sopenharmony_ci         %65 = OpVariable %13 Function
52fd4e5da5Sopenharmony_ci         %66 = OpVariable %7 Function
53fd4e5da5Sopenharmony_ci         %68 = OpVariable %13 Function
54fd4e5da5Sopenharmony_ci         %71 = OpVariable %7 Function
55fd4e5da5Sopenharmony_ci         %72 = OpVariable %13 Function
56fd4e5da5Sopenharmony_ci         %73 = OpVariable %7 Function
57fd4e5da5Sopenharmony_ci         %75 = OpVariable %13 Function
58fd4e5da5Sopenharmony_ci         %78 = OpVariable %7 Function
59fd4e5da5Sopenharmony_ci         %98 = OpAccessChain %7 %71
60fd4e5da5Sopenharmony_ci         %99 = OpCopyObject %7 %71
61fd4e5da5Sopenharmony_ci               OpSelectionMerge %60 None
62fd4e5da5Sopenharmony_ci               OpBranchConditional %58 %59 %60
63fd4e5da5Sopenharmony_ci         %59 = OpLabel
64fd4e5da5Sopenharmony_ci               OpBranch %60
65fd4e5da5Sopenharmony_ci         %60 = OpLabel
66fd4e5da5Sopenharmony_ci               OpReturn
67fd4e5da5Sopenharmony_ci               OpFunctionEnd
68fd4e5da5Sopenharmony_ci         %10 = OpFunction %6 None %8
69fd4e5da5Sopenharmony_ci          %9 = OpFunctionParameter %7
70fd4e5da5Sopenharmony_ci         %11 = OpLabel
71fd4e5da5Sopenharmony_ci         %26 = OpLoad %6 %9
72fd4e5da5Sopenharmony_ci         %28 = OpIAdd %6 %26 %27
73fd4e5da5Sopenharmony_ci               OpSelectionMerge %97 None
74fd4e5da5Sopenharmony_ci               OpBranchConditional %58 %96 %97
75fd4e5da5Sopenharmony_ci         %96 = OpLabel
76fd4e5da5Sopenharmony_ci               OpBranch %97
77fd4e5da5Sopenharmony_ci         %97 = OpLabel
78fd4e5da5Sopenharmony_ci               OpReturnValue %28
79fd4e5da5Sopenharmony_ci               OpFunctionEnd
80fd4e5da5Sopenharmony_ci         %17 = OpFunction %6 None %14
81fd4e5da5Sopenharmony_ci         %15 = OpFunctionParameter %7
82fd4e5da5Sopenharmony_ci         %16 = OpFunctionParameter %13
83fd4e5da5Sopenharmony_ci         %18 = OpLabel
84fd4e5da5Sopenharmony_ci         %31 = OpVariable %7 Function
85fd4e5da5Sopenharmony_ci         %32 = OpLoad %6 %15
86fd4e5da5Sopenharmony_ci               OpStore %31 %32
87fd4e5da5Sopenharmony_ci         %33 = OpFunctionCall %6 %10 %31
88fd4e5da5Sopenharmony_ci               OpReturnValue %33
89fd4e5da5Sopenharmony_ci               OpFunctionEnd
90fd4e5da5Sopenharmony_ci         %21 = OpFunction %6 None %14
91fd4e5da5Sopenharmony_ci         %19 = OpFunctionParameter %7
92fd4e5da5Sopenharmony_ci         %20 = OpFunctionParameter %13
93fd4e5da5Sopenharmony_ci         %22 = OpLabel
94fd4e5da5Sopenharmony_ci         %36 = OpLoad %6 %19
95fd4e5da5Sopenharmony_ci         %37 = OpLoad %12 %20
96fd4e5da5Sopenharmony_ci         %38 = OpConvertFToS %6 %37
97fd4e5da5Sopenharmony_ci         %39 = OpIAdd %6 %36 %38
98fd4e5da5Sopenharmony_ci               OpReturnValue %39
99fd4e5da5Sopenharmony_ci               OpFunctionEnd
100fd4e5da5Sopenharmony_ci         %24 = OpFunction %6 None %8
101fd4e5da5Sopenharmony_ci         %23 = OpFunctionParameter %7
102fd4e5da5Sopenharmony_ci         %25 = OpLabel
103fd4e5da5Sopenharmony_ci         %44 = OpVariable %7 Function
104fd4e5da5Sopenharmony_ci         %46 = OpVariable %13 Function
105fd4e5da5Sopenharmony_ci         %51 = OpVariable %7 Function
106fd4e5da5Sopenharmony_ci         %52 = OpVariable %13 Function
107fd4e5da5Sopenharmony_ci         %42 = OpLoad %6 %23
108fd4e5da5Sopenharmony_ci         %43 = OpConvertSToF %12 %42
109fd4e5da5Sopenharmony_ci         %45 = OpLoad %6 %23
110fd4e5da5Sopenharmony_ci               OpStore %44 %45
111fd4e5da5Sopenharmony_ci               OpStore %46 %43
112fd4e5da5Sopenharmony_ci         %47 = OpFunctionCall %6 %17 %44 %46
113fd4e5da5Sopenharmony_ci         %48 = OpLoad %6 %23
114fd4e5da5Sopenharmony_ci         %49 = OpIAdd %6 %48 %27
115fd4e5da5Sopenharmony_ci               OpStore %51 %49
116fd4e5da5Sopenharmony_ci               OpStore %52 %50
117fd4e5da5Sopenharmony_ci         %53 = OpFunctionCall %6 %17 %51 %52
118fd4e5da5Sopenharmony_ci         %54 = OpIAdd %6 %47 %53
119fd4e5da5Sopenharmony_ci               OpReturnValue %54
120fd4e5da5Sopenharmony_ci               OpFunctionEnd
121fd4e5da5Sopenharmony_ci        %200 = OpFunction %6 None %14
122fd4e5da5Sopenharmony_ci        %201 = OpFunctionParameter %7
123fd4e5da5Sopenharmony_ci        %202 = OpFunctionParameter %13
124fd4e5da5Sopenharmony_ci        %203 = OpLabel
125fd4e5da5Sopenharmony_ci               OpSelectionMerge %206 None
126fd4e5da5Sopenharmony_ci               OpBranchConditional %58 %205 %206
127fd4e5da5Sopenharmony_ci        %205 = OpLabel
128fd4e5da5Sopenharmony_ci               OpBranch %206
129fd4e5da5Sopenharmony_ci        %206 = OpLabel
130fd4e5da5Sopenharmony_ci               OpReturnValue %204
131fd4e5da5Sopenharmony_ci               OpFunctionEnd
132fd4e5da5Sopenharmony_ci  )";
133fd4e5da5Sopenharmony_ci
134fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
135fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
136fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
137fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
138fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
139fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
140fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
141fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
142fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactBlockIsDead(59);
143fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactBlockIsDead(11);
144fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactBlockIsDead(18);
145fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactBlockIsDead(25);
146fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactBlockIsDead(96);
147fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactBlockIsDead(205);
148fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactFunctionIsLivesafe(21);
149fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactFunctionIsLivesafe(200);
150fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
151fd4e5da5Sopenharmony_ci      71);
152fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
153fd4e5da5Sopenharmony_ci      72);
154fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
155fd4e5da5Sopenharmony_ci      19);
156fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
157fd4e5da5Sopenharmony_ci      20);
158fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
159fd4e5da5Sopenharmony_ci      23);
160fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
161fd4e5da5Sopenharmony_ci      44);
162fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
163fd4e5da5Sopenharmony_ci      46);
164fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
165fd4e5da5Sopenharmony_ci      51);
166fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactValueOfPointeeIsIrrelevant(
167fd4e5da5Sopenharmony_ci      52);
168fd4e5da5Sopenharmony_ci
169fd4e5da5Sopenharmony_ci  // Livesafe functions with argument types: 21(7, 13), 200(7, 13)
170fd4e5da5Sopenharmony_ci  // Non-livesafe functions with argument types: 4(), 10(7), 17(7, 13), 24(7)
171fd4e5da5Sopenharmony_ci  // Call graph edges:
172fd4e5da5Sopenharmony_ci  //    17 -> 10
173fd4e5da5Sopenharmony_ci  //    24 -> 17
174fd4e5da5Sopenharmony_ci
175fd4e5da5Sopenharmony_ci  // Bad transformations
176fd4e5da5Sopenharmony_ci  // Too many arguments
177fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationFunctionCall(
178fd4e5da5Sopenharmony_ci                   100, 21, {71, 72, 71},
179fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
180fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
181fd4e5da5Sopenharmony_ci  // Too few arguments
182fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
183fd4e5da5Sopenharmony_ci      TransformationFunctionCall(
184fd4e5da5Sopenharmony_ci          100, 21, {71}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
185fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
186fd4e5da5Sopenharmony_ci  // Arguments are the wrong way around (types do not match)
187fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationFunctionCall(
188fd4e5da5Sopenharmony_ci                   100, 21, {72, 71},
189fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
190fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
191fd4e5da5Sopenharmony_ci  // 21 is not an appropriate argument
192fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationFunctionCall(
193fd4e5da5Sopenharmony_ci                   100, 21, {21, 72},
194fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
195fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
196fd4e5da5Sopenharmony_ci  // 300 does not exist
197fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationFunctionCall(
198fd4e5da5Sopenharmony_ci                   100, 21, {300, 72},
199fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
200fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
201fd4e5da5Sopenharmony_ci  // 71 is not a function
202fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationFunctionCall(
203fd4e5da5Sopenharmony_ci                   100, 71, {71, 72},
204fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
205fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
206fd4e5da5Sopenharmony_ci  // 500 does not exist
207fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationFunctionCall(
208fd4e5da5Sopenharmony_ci                   100, 500, {71, 72},
209fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
210fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
211fd4e5da5Sopenharmony_ci  // Id is not fresh
212fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
213fd4e5da5Sopenharmony_ci      TransformationFunctionCall(
214fd4e5da5Sopenharmony_ci          21, 21, {71, 72}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
215fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
216fd4e5da5Sopenharmony_ci  // Access chain as pointer parameter
217fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationFunctionCall(
218fd4e5da5Sopenharmony_ci                   100, 21, {98, 72},
219fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
220fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
221fd4e5da5Sopenharmony_ci  // Copied object as pointer parameter
222fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationFunctionCall(
223fd4e5da5Sopenharmony_ci                   100, 21, {99, 72},
224fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
225fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
226fd4e5da5Sopenharmony_ci  // Non-livesafe called from original live block
227fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationFunctionCall(
228fd4e5da5Sopenharmony_ci                   100, 10, {71},
229fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(99, spv::Op::OpSelectionMerge, 0))
230fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
231fd4e5da5Sopenharmony_ci  // Non-livesafe called from livesafe function
232fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationFunctionCall(
233fd4e5da5Sopenharmony_ci                   100, 10, {19},
234fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(38, spv::Op::OpConvertFToS, 0))
235fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
236fd4e5da5Sopenharmony_ci  // Livesafe function called with pointer to non-arbitrary local variable
237fd4e5da5Sopenharmony_ci  ASSERT_FALSE(TransformationFunctionCall(
238fd4e5da5Sopenharmony_ci                   100, 21, {61, 72},
239fd4e5da5Sopenharmony_ci                   MakeInstructionDescriptor(38, spv::Op::OpConvertFToS, 0))
240fd4e5da5Sopenharmony_ci                   .IsApplicable(context.get(), transformation_context));
241fd4e5da5Sopenharmony_ci  // Direct recursion
242fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
243fd4e5da5Sopenharmony_ci      TransformationFunctionCall(
244fd4e5da5Sopenharmony_ci          100, 4, {}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0))
245fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
246fd4e5da5Sopenharmony_ci  // Indirect recursion
247fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
248fd4e5da5Sopenharmony_ci      TransformationFunctionCall(
249fd4e5da5Sopenharmony_ci          100, 24, {9}, MakeInstructionDescriptor(96, spv::Op::OpBranch, 0))
250fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
251fd4e5da5Sopenharmony_ci  // Parameter 23 is not available at the call site
252fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
253fd4e5da5Sopenharmony_ci      TransformationFunctionCall(
254fd4e5da5Sopenharmony_ci          104, 10, {23}, MakeInstructionDescriptor(205, spv::Op::OpBranch, 0))
255fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
256fd4e5da5Sopenharmony_ci
257fd4e5da5Sopenharmony_ci  // Good transformations
258fd4e5da5Sopenharmony_ci  {
259fd4e5da5Sopenharmony_ci    // Livesafe called from dead block: fine
260fd4e5da5Sopenharmony_ci    TransformationFunctionCall transformation(
261fd4e5da5Sopenharmony_ci        100, 21, {71, 72}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0));
262fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
263fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
264fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
265fd4e5da5Sopenharmony_ci                          &transformation_context);
266fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
267fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
268fd4e5da5Sopenharmony_ci  }
269fd4e5da5Sopenharmony_ci  {
270fd4e5da5Sopenharmony_ci    // Livesafe called from original live block: fine
271fd4e5da5Sopenharmony_ci    TransformationFunctionCall transformation(
272fd4e5da5Sopenharmony_ci        101, 21, {71, 72},
273fd4e5da5Sopenharmony_ci        MakeInstructionDescriptor(98, spv::Op::OpAccessChain, 0));
274fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
275fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
276fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
277fd4e5da5Sopenharmony_ci                          &transformation_context);
278fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
279fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
280fd4e5da5Sopenharmony_ci  }
281fd4e5da5Sopenharmony_ci  {
282fd4e5da5Sopenharmony_ci    // Livesafe called from livesafe function: fine
283fd4e5da5Sopenharmony_ci    TransformationFunctionCall transformation(
284fd4e5da5Sopenharmony_ci        102, 200, {19, 20}, MakeInstructionDescriptor(36, spv::Op::OpLoad, 0));
285fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
286fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
287fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
288fd4e5da5Sopenharmony_ci                          &transformation_context);
289fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
290fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
291fd4e5da5Sopenharmony_ci  }
292fd4e5da5Sopenharmony_ci  {
293fd4e5da5Sopenharmony_ci    // Dead called from dead block in injected function: fine
294fd4e5da5Sopenharmony_ci    TransformationFunctionCall transformation(
295fd4e5da5Sopenharmony_ci        103, 10, {23}, MakeInstructionDescriptor(45, spv::Op::OpLoad, 0));
296fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
297fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
298fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
299fd4e5da5Sopenharmony_ci                          &transformation_context);
300fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
301fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
302fd4e5da5Sopenharmony_ci  }
303fd4e5da5Sopenharmony_ci  {
304fd4e5da5Sopenharmony_ci    // Non-livesafe called from dead block in livesafe function: OK
305fd4e5da5Sopenharmony_ci    TransformationFunctionCall transformation(
306fd4e5da5Sopenharmony_ci        104, 10, {201}, MakeInstructionDescriptor(205, spv::Op::OpBranch, 0));
307fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
308fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
309fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
310fd4e5da5Sopenharmony_ci                          &transformation_context);
311fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
312fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
313fd4e5da5Sopenharmony_ci  }
314fd4e5da5Sopenharmony_ci  {
315fd4e5da5Sopenharmony_ci    // Livesafe called from dead block with non-arbitrary parameter
316fd4e5da5Sopenharmony_ci    TransformationFunctionCall transformation(
317fd4e5da5Sopenharmony_ci        105, 21, {62, 65}, MakeInstructionDescriptor(59, spv::Op::OpBranch, 0));
318fd4e5da5Sopenharmony_ci    ASSERT_TRUE(
319fd4e5da5Sopenharmony_ci        transformation.IsApplicable(context.get(), transformation_context));
320fd4e5da5Sopenharmony_ci    ApplyAndCheckFreshIds(transformation, context.get(),
321fd4e5da5Sopenharmony_ci                          &transformation_context);
322fd4e5da5Sopenharmony_ci    ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(
323fd4e5da5Sopenharmony_ci        context.get(), validator_options, kConsoleMessageConsumer));
324fd4e5da5Sopenharmony_ci  }
325fd4e5da5Sopenharmony_ci
326fd4e5da5Sopenharmony_ci  std::string after_transformation = R"(
327fd4e5da5Sopenharmony_ci               OpCapability Shader
328fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
329fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
330fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
331fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
332fd4e5da5Sopenharmony_ci               OpSource ESSL 310
333fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
334fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
335fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
336fd4e5da5Sopenharmony_ci          %7 = OpTypePointer Function %6
337fd4e5da5Sopenharmony_ci          %8 = OpTypeFunction %6 %7
338fd4e5da5Sopenharmony_ci         %12 = OpTypeFloat 32
339fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
340fd4e5da5Sopenharmony_ci         %14 = OpTypeFunction %6 %7 %13
341fd4e5da5Sopenharmony_ci         %27 = OpConstant %6 1
342fd4e5da5Sopenharmony_ci         %50 = OpConstant %12 1
343fd4e5da5Sopenharmony_ci         %57 = OpTypeBool
344fd4e5da5Sopenharmony_ci         %58 = OpConstantFalse %57
345fd4e5da5Sopenharmony_ci        %204 = OpUndef %6
346fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
347fd4e5da5Sopenharmony_ci          %5 = OpLabel
348fd4e5da5Sopenharmony_ci         %61 = OpVariable %7 Function
349fd4e5da5Sopenharmony_ci         %62 = OpVariable %7 Function
350fd4e5da5Sopenharmony_ci         %65 = OpVariable %13 Function
351fd4e5da5Sopenharmony_ci         %66 = OpVariable %7 Function
352fd4e5da5Sopenharmony_ci         %68 = OpVariable %13 Function
353fd4e5da5Sopenharmony_ci         %71 = OpVariable %7 Function
354fd4e5da5Sopenharmony_ci         %72 = OpVariable %13 Function
355fd4e5da5Sopenharmony_ci         %73 = OpVariable %7 Function
356fd4e5da5Sopenharmony_ci         %75 = OpVariable %13 Function
357fd4e5da5Sopenharmony_ci         %78 = OpVariable %7 Function
358fd4e5da5Sopenharmony_ci        %101 = OpFunctionCall %6 %21 %71 %72
359fd4e5da5Sopenharmony_ci         %98 = OpAccessChain %7 %71
360fd4e5da5Sopenharmony_ci         %99 = OpCopyObject %7 %71
361fd4e5da5Sopenharmony_ci               OpSelectionMerge %60 None
362fd4e5da5Sopenharmony_ci               OpBranchConditional %58 %59 %60
363fd4e5da5Sopenharmony_ci         %59 = OpLabel
364fd4e5da5Sopenharmony_ci        %100 = OpFunctionCall %6 %21 %71 %72
365fd4e5da5Sopenharmony_ci        %105 = OpFunctionCall %6 %21 %62 %65
366fd4e5da5Sopenharmony_ci               OpBranch %60
367fd4e5da5Sopenharmony_ci         %60 = OpLabel
368fd4e5da5Sopenharmony_ci               OpReturn
369fd4e5da5Sopenharmony_ci               OpFunctionEnd
370fd4e5da5Sopenharmony_ci         %10 = OpFunction %6 None %8
371fd4e5da5Sopenharmony_ci          %9 = OpFunctionParameter %7
372fd4e5da5Sopenharmony_ci         %11 = OpLabel
373fd4e5da5Sopenharmony_ci         %26 = OpLoad %6 %9
374fd4e5da5Sopenharmony_ci         %28 = OpIAdd %6 %26 %27
375fd4e5da5Sopenharmony_ci               OpSelectionMerge %97 None
376fd4e5da5Sopenharmony_ci               OpBranchConditional %58 %96 %97
377fd4e5da5Sopenharmony_ci         %96 = OpLabel
378fd4e5da5Sopenharmony_ci               OpBranch %97
379fd4e5da5Sopenharmony_ci         %97 = OpLabel
380fd4e5da5Sopenharmony_ci               OpReturnValue %28
381fd4e5da5Sopenharmony_ci               OpFunctionEnd
382fd4e5da5Sopenharmony_ci         %17 = OpFunction %6 None %14
383fd4e5da5Sopenharmony_ci         %15 = OpFunctionParameter %7
384fd4e5da5Sopenharmony_ci         %16 = OpFunctionParameter %13
385fd4e5da5Sopenharmony_ci         %18 = OpLabel
386fd4e5da5Sopenharmony_ci         %31 = OpVariable %7 Function
387fd4e5da5Sopenharmony_ci         %32 = OpLoad %6 %15
388fd4e5da5Sopenharmony_ci               OpStore %31 %32
389fd4e5da5Sopenharmony_ci         %33 = OpFunctionCall %6 %10 %31
390fd4e5da5Sopenharmony_ci               OpReturnValue %33
391fd4e5da5Sopenharmony_ci               OpFunctionEnd
392fd4e5da5Sopenharmony_ci         %21 = OpFunction %6 None %14
393fd4e5da5Sopenharmony_ci         %19 = OpFunctionParameter %7
394fd4e5da5Sopenharmony_ci         %20 = OpFunctionParameter %13
395fd4e5da5Sopenharmony_ci         %22 = OpLabel
396fd4e5da5Sopenharmony_ci        %102 = OpFunctionCall %6 %200 %19 %20
397fd4e5da5Sopenharmony_ci         %36 = OpLoad %6 %19
398fd4e5da5Sopenharmony_ci         %37 = OpLoad %12 %20
399fd4e5da5Sopenharmony_ci         %38 = OpConvertFToS %6 %37
400fd4e5da5Sopenharmony_ci         %39 = OpIAdd %6 %36 %38
401fd4e5da5Sopenharmony_ci               OpReturnValue %39
402fd4e5da5Sopenharmony_ci               OpFunctionEnd
403fd4e5da5Sopenharmony_ci         %24 = OpFunction %6 None %8
404fd4e5da5Sopenharmony_ci         %23 = OpFunctionParameter %7
405fd4e5da5Sopenharmony_ci         %25 = OpLabel
406fd4e5da5Sopenharmony_ci         %44 = OpVariable %7 Function
407fd4e5da5Sopenharmony_ci         %46 = OpVariable %13 Function
408fd4e5da5Sopenharmony_ci         %51 = OpVariable %7 Function
409fd4e5da5Sopenharmony_ci         %52 = OpVariable %13 Function
410fd4e5da5Sopenharmony_ci         %42 = OpLoad %6 %23
411fd4e5da5Sopenharmony_ci         %43 = OpConvertSToF %12 %42
412fd4e5da5Sopenharmony_ci        %103 = OpFunctionCall %6 %10 %23
413fd4e5da5Sopenharmony_ci         %45 = OpLoad %6 %23
414fd4e5da5Sopenharmony_ci               OpStore %44 %45
415fd4e5da5Sopenharmony_ci               OpStore %46 %43
416fd4e5da5Sopenharmony_ci         %47 = OpFunctionCall %6 %17 %44 %46
417fd4e5da5Sopenharmony_ci         %48 = OpLoad %6 %23
418fd4e5da5Sopenharmony_ci         %49 = OpIAdd %6 %48 %27
419fd4e5da5Sopenharmony_ci               OpStore %51 %49
420fd4e5da5Sopenharmony_ci               OpStore %52 %50
421fd4e5da5Sopenharmony_ci         %53 = OpFunctionCall %6 %17 %51 %52
422fd4e5da5Sopenharmony_ci         %54 = OpIAdd %6 %47 %53
423fd4e5da5Sopenharmony_ci               OpReturnValue %54
424fd4e5da5Sopenharmony_ci               OpFunctionEnd
425fd4e5da5Sopenharmony_ci        %200 = OpFunction %6 None %14
426fd4e5da5Sopenharmony_ci        %201 = OpFunctionParameter %7
427fd4e5da5Sopenharmony_ci        %202 = OpFunctionParameter %13
428fd4e5da5Sopenharmony_ci        %203 = OpLabel
429fd4e5da5Sopenharmony_ci               OpSelectionMerge %206 None
430fd4e5da5Sopenharmony_ci               OpBranchConditional %58 %205 %206
431fd4e5da5Sopenharmony_ci        %205 = OpLabel
432fd4e5da5Sopenharmony_ci        %104 = OpFunctionCall %6 %10 %201
433fd4e5da5Sopenharmony_ci               OpBranch %206
434fd4e5da5Sopenharmony_ci        %206 = OpLabel
435fd4e5da5Sopenharmony_ci               OpReturnValue %204
436fd4e5da5Sopenharmony_ci               OpFunctionEnd
437fd4e5da5Sopenharmony_ci  )";
438fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, after_transformation, context.get()));
439fd4e5da5Sopenharmony_ci}
440fd4e5da5Sopenharmony_ci
441fd4e5da5Sopenharmony_ciTEST(TransformationFunctionCallTest, DoNotInvokeEntryPoint) {
442fd4e5da5Sopenharmony_ci  std::string shader = R"(
443fd4e5da5Sopenharmony_ci               OpCapability Shader
444fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
445fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
446fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
447fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
448fd4e5da5Sopenharmony_ci               OpSource ESSL 310
449fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
450fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
451fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
452fd4e5da5Sopenharmony_ci          %5 = OpLabel
453fd4e5da5Sopenharmony_ci               OpReturn
454fd4e5da5Sopenharmony_ci               OpFunctionEnd
455fd4e5da5Sopenharmony_ci         %10 = OpFunction %2 None %3
456fd4e5da5Sopenharmony_ci         %11 = OpLabel
457fd4e5da5Sopenharmony_ci               OpReturn
458fd4e5da5Sopenharmony_ci               OpFunctionEnd
459fd4e5da5Sopenharmony_ci  )";
460fd4e5da5Sopenharmony_ci
461fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_4;
462fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
463fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
464fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
465fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
466fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
467fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
468fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
469fd4e5da5Sopenharmony_ci  transformation_context.GetFactManager()->AddFactBlockIsDead(11);
470fd4e5da5Sopenharmony_ci
471fd4e5da5Sopenharmony_ci  // 4 is an entry point, so it is not legal for it to be the target of a call.
472fd4e5da5Sopenharmony_ci  ASSERT_FALSE(
473fd4e5da5Sopenharmony_ci      TransformationFunctionCall(
474fd4e5da5Sopenharmony_ci          100, 4, {}, MakeInstructionDescriptor(11, spv::Op::OpReturn, 0))
475fd4e5da5Sopenharmony_ci          .IsApplicable(context.get(), transformation_context));
476fd4e5da5Sopenharmony_ci}
477fd4e5da5Sopenharmony_ci
478fd4e5da5Sopenharmony_ci}  // namespace
479fd4e5da5Sopenharmony_ci}  // namespace fuzz
480fd4e5da5Sopenharmony_ci}  // namespace spvtools
481