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/call_graph.h"
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include "gtest/gtest.h"
18fd4e5da5Sopenharmony_ci#include "source/fuzz/fuzzer_util.h"
19fd4e5da5Sopenharmony_ci#include "test/fuzz/fuzz_test_util.h"
20fd4e5da5Sopenharmony_ci
21fd4e5da5Sopenharmony_cinamespace spvtools {
22fd4e5da5Sopenharmony_cinamespace fuzz {
23fd4e5da5Sopenharmony_cinamespace {
24fd4e5da5Sopenharmony_ci
25fd4e5da5Sopenharmony_ci// The SPIR-V came from this GLSL, slightly modified
26fd4e5da5Sopenharmony_ci// (main is %2, A is %35, B is %48, C is %50, D is %61):
27fd4e5da5Sopenharmony_ci//
28fd4e5da5Sopenharmony_ci//    #version 310 es
29fd4e5da5Sopenharmony_ci//
30fd4e5da5Sopenharmony_ci//    int A (int x) {
31fd4e5da5Sopenharmony_ci//      return x + 1;
32fd4e5da5Sopenharmony_ci//    }
33fd4e5da5Sopenharmony_ci//
34fd4e5da5Sopenharmony_ci//    void D() {
35fd4e5da5Sopenharmony_ci//    }
36fd4e5da5Sopenharmony_ci//
37fd4e5da5Sopenharmony_ci//    void C() {
38fd4e5da5Sopenharmony_ci//      int x = 0;
39fd4e5da5Sopenharmony_ci//      int y = 0;
40fd4e5da5Sopenharmony_ci//
41fd4e5da5Sopenharmony_ci//      while (x < 10) {
42fd4e5da5Sopenharmony_ci//        while (y < 10) {
43fd4e5da5Sopenharmony_ci//          y = A(y);
44fd4e5da5Sopenharmony_ci//        }
45fd4e5da5Sopenharmony_ci//        x = A(x);
46fd4e5da5Sopenharmony_ci//      }
47fd4e5da5Sopenharmony_ci//    }
48fd4e5da5Sopenharmony_ci//
49fd4e5da5Sopenharmony_ci//    void B () {
50fd4e5da5Sopenharmony_ci//      int x = 0;
51fd4e5da5Sopenharmony_ci//      int y = 0;
52fd4e5da5Sopenharmony_ci//
53fd4e5da5Sopenharmony_ci//      while (x < 10) {
54fd4e5da5Sopenharmony_ci//        D();
55fd4e5da5Sopenharmony_ci//        while (y < 10) {
56fd4e5da5Sopenharmony_ci//          y = A(y);
57fd4e5da5Sopenharmony_ci//          C();
58fd4e5da5Sopenharmony_ci//        }
59fd4e5da5Sopenharmony_ci//        x++;
60fd4e5da5Sopenharmony_ci//      }
61fd4e5da5Sopenharmony_ci//
62fd4e5da5Sopenharmony_ci//    }
63fd4e5da5Sopenharmony_ci//
64fd4e5da5Sopenharmony_ci//    void main()
65fd4e5da5Sopenharmony_ci//    {
66fd4e5da5Sopenharmony_ci//      int x = 0;
67fd4e5da5Sopenharmony_ci//      int y = 0;
68fd4e5da5Sopenharmony_ci//      int z = 0;
69fd4e5da5Sopenharmony_ci//
70fd4e5da5Sopenharmony_ci//      while (x < 10) {
71fd4e5da5Sopenharmony_ci//        while(y < 10) {
72fd4e5da5Sopenharmony_ci//          y = A(x);
73fd4e5da5Sopenharmony_ci//          while (z < 10) {
74fd4e5da5Sopenharmony_ci//            z = A(z);
75fd4e5da5Sopenharmony_ci//          }
76fd4e5da5Sopenharmony_ci//        }
77fd4e5da5Sopenharmony_ci//        x += 2;
78fd4e5da5Sopenharmony_ci//      }
79fd4e5da5Sopenharmony_ci//
80fd4e5da5Sopenharmony_ci//      B();
81fd4e5da5Sopenharmony_ci//      C();
82fd4e5da5Sopenharmony_ci//    }
83fd4e5da5Sopenharmony_cistd::string shader = R"(
84fd4e5da5Sopenharmony_ci               OpCapability Shader
85fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
86fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
87fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
88fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
89fd4e5da5Sopenharmony_ci               OpSource ESSL 310
90fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
91fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
92fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
93fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
94fd4e5da5Sopenharmony_ci          %7 = OpTypeFunction %5 %6
95fd4e5da5Sopenharmony_ci          %8 = OpConstant %5 1
96fd4e5da5Sopenharmony_ci          %9 = OpConstant %5 0
97fd4e5da5Sopenharmony_ci         %10 = OpConstant %5 10
98fd4e5da5Sopenharmony_ci         %11 = OpTypeBool
99fd4e5da5Sopenharmony_ci         %12 = OpConstant %5 2
100fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
101fd4e5da5Sopenharmony_ci         %13 = OpLabel
102fd4e5da5Sopenharmony_ci         %14 = OpVariable %6 Function
103fd4e5da5Sopenharmony_ci         %15 = OpVariable %6 Function
104fd4e5da5Sopenharmony_ci         %16 = OpVariable %6 Function
105fd4e5da5Sopenharmony_ci         %17 = OpVariable %6 Function
106fd4e5da5Sopenharmony_ci         %18 = OpVariable %6 Function
107fd4e5da5Sopenharmony_ci               OpStore %14 %9
108fd4e5da5Sopenharmony_ci               OpStore %15 %9
109fd4e5da5Sopenharmony_ci               OpStore %16 %9
110fd4e5da5Sopenharmony_ci               OpBranch %19
111fd4e5da5Sopenharmony_ci         %19 = OpLabel
112fd4e5da5Sopenharmony_ci               OpLoopMerge %20 %21 None
113fd4e5da5Sopenharmony_ci               OpBranch %22
114fd4e5da5Sopenharmony_ci         %22 = OpLabel
115fd4e5da5Sopenharmony_ci         %23 = OpLoad %5 %14
116fd4e5da5Sopenharmony_ci         %24 = OpSLessThan %11 %23 %10
117fd4e5da5Sopenharmony_ci               OpBranchConditional %24 %25 %20
118fd4e5da5Sopenharmony_ci         %25 = OpLabel
119fd4e5da5Sopenharmony_ci               OpBranch %26
120fd4e5da5Sopenharmony_ci         %26 = OpLabel
121fd4e5da5Sopenharmony_ci               OpLoopMerge %27 %28 None
122fd4e5da5Sopenharmony_ci               OpBranch %29
123fd4e5da5Sopenharmony_ci         %29 = OpLabel
124fd4e5da5Sopenharmony_ci         %30 = OpLoad %5 %15
125fd4e5da5Sopenharmony_ci         %31 = OpSLessThan %11 %30 %10
126fd4e5da5Sopenharmony_ci               OpBranchConditional %31 %32 %27
127fd4e5da5Sopenharmony_ci         %32 = OpLabel
128fd4e5da5Sopenharmony_ci         %33 = OpLoad %5 %14
129fd4e5da5Sopenharmony_ci               OpStore %17 %33
130fd4e5da5Sopenharmony_ci         %34 = OpFunctionCall %5 %35 %17
131fd4e5da5Sopenharmony_ci               OpStore %15 %34
132fd4e5da5Sopenharmony_ci               OpBranch %36
133fd4e5da5Sopenharmony_ci         %36 = OpLabel
134fd4e5da5Sopenharmony_ci               OpLoopMerge %37 %38 None
135fd4e5da5Sopenharmony_ci               OpBranch %39
136fd4e5da5Sopenharmony_ci         %39 = OpLabel
137fd4e5da5Sopenharmony_ci         %40 = OpLoad %5 %16
138fd4e5da5Sopenharmony_ci         %41 = OpSLessThan %11 %40 %10
139fd4e5da5Sopenharmony_ci               OpBranchConditional %41 %42 %37
140fd4e5da5Sopenharmony_ci         %42 = OpLabel
141fd4e5da5Sopenharmony_ci         %43 = OpLoad %5 %16
142fd4e5da5Sopenharmony_ci               OpStore %18 %43
143fd4e5da5Sopenharmony_ci         %44 = OpFunctionCall %5 %35 %18
144fd4e5da5Sopenharmony_ci               OpStore %16 %44
145fd4e5da5Sopenharmony_ci               OpBranch %38
146fd4e5da5Sopenharmony_ci         %38 = OpLabel
147fd4e5da5Sopenharmony_ci               OpBranch %36
148fd4e5da5Sopenharmony_ci         %37 = OpLabel
149fd4e5da5Sopenharmony_ci               OpBranch %28
150fd4e5da5Sopenharmony_ci         %28 = OpLabel
151fd4e5da5Sopenharmony_ci               OpBranch %26
152fd4e5da5Sopenharmony_ci         %27 = OpLabel
153fd4e5da5Sopenharmony_ci         %45 = OpLoad %5 %14
154fd4e5da5Sopenharmony_ci         %46 = OpIAdd %5 %45 %12
155fd4e5da5Sopenharmony_ci               OpStore %14 %46
156fd4e5da5Sopenharmony_ci               OpBranch %21
157fd4e5da5Sopenharmony_ci         %21 = OpLabel
158fd4e5da5Sopenharmony_ci               OpBranch %19
159fd4e5da5Sopenharmony_ci         %20 = OpLabel
160fd4e5da5Sopenharmony_ci         %47 = OpFunctionCall %3 %48
161fd4e5da5Sopenharmony_ci         %49 = OpFunctionCall %3 %50
162fd4e5da5Sopenharmony_ci               OpReturn
163fd4e5da5Sopenharmony_ci               OpFunctionEnd
164fd4e5da5Sopenharmony_ci         %35 = OpFunction %5 None %7
165fd4e5da5Sopenharmony_ci         %51 = OpFunctionParameter %6
166fd4e5da5Sopenharmony_ci         %52 = OpLabel
167fd4e5da5Sopenharmony_ci         %53 = OpLoad %5 %51
168fd4e5da5Sopenharmony_ci         %54 = OpIAdd %5 %53 %8
169fd4e5da5Sopenharmony_ci               OpReturnValue %54
170fd4e5da5Sopenharmony_ci               OpFunctionEnd
171fd4e5da5Sopenharmony_ci         %48 = OpFunction %3 None %4
172fd4e5da5Sopenharmony_ci         %55 = OpLabel
173fd4e5da5Sopenharmony_ci         %56 = OpVariable %6 Function
174fd4e5da5Sopenharmony_ci         %57 = OpVariable %6 Function
175fd4e5da5Sopenharmony_ci         %58 = OpVariable %6 Function
176fd4e5da5Sopenharmony_ci               OpStore %56 %9
177fd4e5da5Sopenharmony_ci               OpStore %57 %9
178fd4e5da5Sopenharmony_ci               OpBranch %59
179fd4e5da5Sopenharmony_ci         %59 = OpLabel
180fd4e5da5Sopenharmony_ci         %60 = OpFunctionCall %3 %61
181fd4e5da5Sopenharmony_ci               OpLoopMerge %62 %63 None
182fd4e5da5Sopenharmony_ci               OpBranch %64
183fd4e5da5Sopenharmony_ci         %64 = OpLabel
184fd4e5da5Sopenharmony_ci               OpLoopMerge %65 %66 None
185fd4e5da5Sopenharmony_ci               OpBranch %67
186fd4e5da5Sopenharmony_ci         %67 = OpLabel
187fd4e5da5Sopenharmony_ci         %68 = OpLoad %5 %57
188fd4e5da5Sopenharmony_ci         %69 = OpSLessThan %11 %68 %10
189fd4e5da5Sopenharmony_ci               OpBranchConditional %69 %70 %65
190fd4e5da5Sopenharmony_ci         %70 = OpLabel
191fd4e5da5Sopenharmony_ci         %71 = OpLoad %5 %57
192fd4e5da5Sopenharmony_ci               OpStore %58 %71
193fd4e5da5Sopenharmony_ci         %72 = OpFunctionCall %5 %35 %58
194fd4e5da5Sopenharmony_ci               OpStore %57 %72
195fd4e5da5Sopenharmony_ci         %73 = OpFunctionCall %3 %50
196fd4e5da5Sopenharmony_ci               OpBranch %66
197fd4e5da5Sopenharmony_ci         %66 = OpLabel
198fd4e5da5Sopenharmony_ci               OpBranch %64
199fd4e5da5Sopenharmony_ci         %65 = OpLabel
200fd4e5da5Sopenharmony_ci         %74 = OpLoad %5 %56
201fd4e5da5Sopenharmony_ci         %75 = OpIAdd %5 %74 %8
202fd4e5da5Sopenharmony_ci               OpStore %56 %75
203fd4e5da5Sopenharmony_ci               OpBranch %63
204fd4e5da5Sopenharmony_ci         %63 = OpLabel
205fd4e5da5Sopenharmony_ci         %76 = OpLoad %5 %56
206fd4e5da5Sopenharmony_ci         %77 = OpSLessThan %11 %76 %10
207fd4e5da5Sopenharmony_ci               OpBranchConditional %77 %59 %62
208fd4e5da5Sopenharmony_ci         %62 = OpLabel
209fd4e5da5Sopenharmony_ci               OpReturn
210fd4e5da5Sopenharmony_ci               OpFunctionEnd
211fd4e5da5Sopenharmony_ci         %50 = OpFunction %3 None %4
212fd4e5da5Sopenharmony_ci         %78 = OpLabel
213fd4e5da5Sopenharmony_ci         %79 = OpVariable %6 Function
214fd4e5da5Sopenharmony_ci         %80 = OpVariable %6 Function
215fd4e5da5Sopenharmony_ci         %81 = OpVariable %6 Function
216fd4e5da5Sopenharmony_ci         %82 = OpVariable %6 Function
217fd4e5da5Sopenharmony_ci               OpStore %79 %9
218fd4e5da5Sopenharmony_ci               OpStore %80 %9
219fd4e5da5Sopenharmony_ci               OpBranch %83
220fd4e5da5Sopenharmony_ci         %83 = OpLabel
221fd4e5da5Sopenharmony_ci               OpLoopMerge %84 %85 None
222fd4e5da5Sopenharmony_ci               OpBranch %86
223fd4e5da5Sopenharmony_ci         %86 = OpLabel
224fd4e5da5Sopenharmony_ci         %87 = OpLoad %5 %79
225fd4e5da5Sopenharmony_ci         %88 = OpSLessThan %11 %87 %10
226fd4e5da5Sopenharmony_ci               OpBranchConditional %88 %89 %84
227fd4e5da5Sopenharmony_ci         %89 = OpLabel
228fd4e5da5Sopenharmony_ci               OpBranch %90
229fd4e5da5Sopenharmony_ci         %90 = OpLabel
230fd4e5da5Sopenharmony_ci               OpLoopMerge %91 %92 None
231fd4e5da5Sopenharmony_ci               OpBranch %93
232fd4e5da5Sopenharmony_ci         %93 = OpLabel
233fd4e5da5Sopenharmony_ci         %94 = OpLoad %5 %80
234fd4e5da5Sopenharmony_ci         %95 = OpSLessThan %11 %94 %10
235fd4e5da5Sopenharmony_ci               OpBranchConditional %95 %96 %91
236fd4e5da5Sopenharmony_ci         %96 = OpLabel
237fd4e5da5Sopenharmony_ci         %97 = OpLoad %5 %80
238fd4e5da5Sopenharmony_ci               OpStore %81 %97
239fd4e5da5Sopenharmony_ci         %98 = OpFunctionCall %5 %35 %81
240fd4e5da5Sopenharmony_ci               OpStore %80 %98
241fd4e5da5Sopenharmony_ci               OpBranch %92
242fd4e5da5Sopenharmony_ci         %92 = OpLabel
243fd4e5da5Sopenharmony_ci               OpBranch %90
244fd4e5da5Sopenharmony_ci         %91 = OpLabel
245fd4e5da5Sopenharmony_ci         %99 = OpLoad %5 %79
246fd4e5da5Sopenharmony_ci               OpStore %82 %99
247fd4e5da5Sopenharmony_ci        %100 = OpFunctionCall %5 %35 %82
248fd4e5da5Sopenharmony_ci               OpStore %79 %100
249fd4e5da5Sopenharmony_ci               OpBranch %85
250fd4e5da5Sopenharmony_ci         %85 = OpLabel
251fd4e5da5Sopenharmony_ci               OpBranch %83
252fd4e5da5Sopenharmony_ci         %84 = OpLabel
253fd4e5da5Sopenharmony_ci               OpReturn
254fd4e5da5Sopenharmony_ci               OpFunctionEnd
255fd4e5da5Sopenharmony_ci         %61 = OpFunction %3 None %4
256fd4e5da5Sopenharmony_ci        %101 = OpLabel
257fd4e5da5Sopenharmony_ci               OpReturn
258fd4e5da5Sopenharmony_ci               OpFunctionEnd
259fd4e5da5Sopenharmony_ci)";
260fd4e5da5Sopenharmony_ci
261fd4e5da5Sopenharmony_ci// We have that:
262fd4e5da5Sopenharmony_ci// main calls:
263fd4e5da5Sopenharmony_ci// - A (maximum loop nesting depth of function call: 3)
264fd4e5da5Sopenharmony_ci// - B (0)
265fd4e5da5Sopenharmony_ci// - C (0)
266fd4e5da5Sopenharmony_ci// A calls nothing.
267fd4e5da5Sopenharmony_ci// B calls:
268fd4e5da5Sopenharmony_ci// - A (2)
269fd4e5da5Sopenharmony_ci// - C (2)
270fd4e5da5Sopenharmony_ci// - D (1)
271fd4e5da5Sopenharmony_ci// C calls:
272fd4e5da5Sopenharmony_ci// - A (2)
273fd4e5da5Sopenharmony_ci// D calls nothing.
274fd4e5da5Sopenharmony_ci
275fd4e5da5Sopenharmony_ciTEST(CallGraphTest, FunctionInDegree) {
276fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_5;
277fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
278fd4e5da5Sopenharmony_ci
279fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
280fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
281fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
282fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
283fd4e5da5Sopenharmony_ci
284fd4e5da5Sopenharmony_ci  const auto graph = CallGraph(context.get());
285fd4e5da5Sopenharmony_ci
286fd4e5da5Sopenharmony_ci  const auto& function_in_degree = graph.GetFunctionInDegree();
287fd4e5da5Sopenharmony_ci  // Check the in-degrees of, in order: main, A, B, C, D.
288fd4e5da5Sopenharmony_ci  ASSERT_EQ(function_in_degree.at(2), 0);
289fd4e5da5Sopenharmony_ci  ASSERT_EQ(function_in_degree.at(35), 3);
290fd4e5da5Sopenharmony_ci  ASSERT_EQ(function_in_degree.at(48), 1);
291fd4e5da5Sopenharmony_ci  ASSERT_EQ(function_in_degree.at(50), 2);
292fd4e5da5Sopenharmony_ci  ASSERT_EQ(function_in_degree.at(61), 1);
293fd4e5da5Sopenharmony_ci}
294fd4e5da5Sopenharmony_ci
295fd4e5da5Sopenharmony_ciTEST(CallGraphTest, DirectCallees) {
296fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_5;
297fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
298fd4e5da5Sopenharmony_ci
299fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
300fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
301fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
302fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
303fd4e5da5Sopenharmony_ci
304fd4e5da5Sopenharmony_ci  const auto graph = CallGraph(context.get());
305fd4e5da5Sopenharmony_ci
306fd4e5da5Sopenharmony_ci  // Check the callee sets of, in order: main, A, B, C, D.
307fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetDirectCallees(2), std::set<uint32_t>({35, 48, 50}));
308fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetDirectCallees(35), std::set<uint32_t>({}));
309fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetDirectCallees(48), std::set<uint32_t>({35, 50, 61}));
310fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetDirectCallees(50), std::set<uint32_t>({35}));
311fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetDirectCallees(61), std::set<uint32_t>({}));
312fd4e5da5Sopenharmony_ci}
313fd4e5da5Sopenharmony_ci
314fd4e5da5Sopenharmony_ciTEST(CallGraphTest, IndirectCallees) {
315fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_5;
316fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
317fd4e5da5Sopenharmony_ci
318fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
319fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
320fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
321fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
322fd4e5da5Sopenharmony_ci
323fd4e5da5Sopenharmony_ci  const auto graph = CallGraph(context.get());
324fd4e5da5Sopenharmony_ci
325fd4e5da5Sopenharmony_ci  // Check the callee sets of, in order: main, A, B, C, D.
326fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetIndirectCallees(2), std::set<uint32_t>({35, 48, 50, 61}));
327fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetDirectCallees(35), std::set<uint32_t>({}));
328fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetDirectCallees(48), std::set<uint32_t>({35, 50, 61}));
329fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetDirectCallees(50), std::set<uint32_t>({35}));
330fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetDirectCallees(61), std::set<uint32_t>({}));
331fd4e5da5Sopenharmony_ci}
332fd4e5da5Sopenharmony_ci
333fd4e5da5Sopenharmony_ciTEST(CallGraphTest, TopologicalOrder) {
334fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_5;
335fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
336fd4e5da5Sopenharmony_ci
337fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
338fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
339fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
340fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
341fd4e5da5Sopenharmony_ci
342fd4e5da5Sopenharmony_ci  const auto graph = CallGraph(context.get());
343fd4e5da5Sopenharmony_ci
344fd4e5da5Sopenharmony_ci  const auto& topological_ordering = graph.GetFunctionsInTopologicalOrder();
345fd4e5da5Sopenharmony_ci
346fd4e5da5Sopenharmony_ci  // The possible topological orderings are:
347fd4e5da5Sopenharmony_ci  //  - main, B, D, C, A
348fd4e5da5Sopenharmony_ci  //  - main, B, C, D, A
349fd4e5da5Sopenharmony_ci  //  - main, B, C, A, D
350fd4e5da5Sopenharmony_ci  ASSERT_TRUE(
351fd4e5da5Sopenharmony_ci      topological_ordering == std::vector<uint32_t>({2, 48, 61, 50, 35}) ||
352fd4e5da5Sopenharmony_ci      topological_ordering == std::vector<uint32_t>({2, 48, 50, 61, 35}) ||
353fd4e5da5Sopenharmony_ci      topological_ordering == std::vector<uint32_t>({2, 48, 50, 35, 61}));
354fd4e5da5Sopenharmony_ci}
355fd4e5da5Sopenharmony_ci
356fd4e5da5Sopenharmony_ciTEST(CallGraphTest, LoopNestingDepth) {
357fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_5;
358fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
359fd4e5da5Sopenharmony_ci
360fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
361fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
362fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
363fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
364fd4e5da5Sopenharmony_ci
365fd4e5da5Sopenharmony_ci  const auto graph = CallGraph(context.get());
366fd4e5da5Sopenharmony_ci
367fd4e5da5Sopenharmony_ci  // Check the maximum loop nesting depth for function calls to, in order:
368fd4e5da5Sopenharmony_ci  // main, A, B, C, D
369fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetMaxCallNestingDepth(2), 0);
370fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetMaxCallNestingDepth(35), 4);
371fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetMaxCallNestingDepth(48), 0);
372fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetMaxCallNestingDepth(50), 2);
373fd4e5da5Sopenharmony_ci  ASSERT_EQ(graph.GetMaxCallNestingDepth(61), 1);
374fd4e5da5Sopenharmony_ci}
375fd4e5da5Sopenharmony_ci
376fd4e5da5Sopenharmony_ci}  // namespace
377fd4e5da5Sopenharmony_ci}  // namespace fuzz
378fd4e5da5Sopenharmony_ci}  // namespace spvtools
379