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/fuzzer_pass_outline_functions.h"
16fd4e5da5Sopenharmony_ci
17fd4e5da5Sopenharmony_ci#include "gtest/gtest.h"
18fd4e5da5Sopenharmony_ci#include "source/fuzz/fuzzer_util.h"
19fd4e5da5Sopenharmony_ci#include "source/fuzz/pseudo_random_generator.h"
20fd4e5da5Sopenharmony_ci#include "test/fuzz/fuzz_test_util.h"
21fd4e5da5Sopenharmony_ci
22fd4e5da5Sopenharmony_cinamespace spvtools {
23fd4e5da5Sopenharmony_cinamespace fuzz {
24fd4e5da5Sopenharmony_cinamespace {
25fd4e5da5Sopenharmony_ci
26fd4e5da5Sopenharmony_cistd::string shader = R"(
27fd4e5da5Sopenharmony_ci               OpCapability Shader
28fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
29fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
30fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
31fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
32fd4e5da5Sopenharmony_ci               OpSource ESSL 310
33fd4e5da5Sopenharmony_ci               OpName %2 "main"
34fd4e5da5Sopenharmony_ci               OpName %3 "a"
35fd4e5da5Sopenharmony_ci               OpName %4 "b"
36fd4e5da5Sopenharmony_ci               OpDecorate %3 RelaxedPrecision
37fd4e5da5Sopenharmony_ci               OpDecorate %4 RelaxedPrecision
38fd4e5da5Sopenharmony_ci               OpDecorate %5 RelaxedPrecision
39fd4e5da5Sopenharmony_ci               OpDecorate %6 RelaxedPrecision
40fd4e5da5Sopenharmony_ci               OpDecorate %7 RelaxedPrecision
41fd4e5da5Sopenharmony_ci               OpDecorate %8 RelaxedPrecision
42fd4e5da5Sopenharmony_ci               OpDecorate %9 RelaxedPrecision
43fd4e5da5Sopenharmony_ci         %10 = OpTypeVoid
44fd4e5da5Sopenharmony_ci         %11 = OpTypeFunction %10
45fd4e5da5Sopenharmony_ci         %12 = OpTypeInt 32 1
46fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
47fd4e5da5Sopenharmony_ci         %14 = OpConstant %12 8
48fd4e5da5Sopenharmony_ci         %15 = OpConstant %12 23
49fd4e5da5Sopenharmony_ci         %16 = OpTypeBool
50fd4e5da5Sopenharmony_ci         %17 = OpConstantTrue %16
51fd4e5da5Sopenharmony_ci         %18 = OpConstant %12 0
52fd4e5da5Sopenharmony_ci         %19 = OpConstant %12 1
53fd4e5da5Sopenharmony_ci          %2 = OpFunction %10 None %11
54fd4e5da5Sopenharmony_ci         %20 = OpLabel
55fd4e5da5Sopenharmony_ci          %3 = OpVariable %13 Function
56fd4e5da5Sopenharmony_ci          %4 = OpVariable %13 Function
57fd4e5da5Sopenharmony_ci               OpStore %3 %14
58fd4e5da5Sopenharmony_ci               OpStore %4 %15
59fd4e5da5Sopenharmony_ci               OpBranch %21
60fd4e5da5Sopenharmony_ci         %21 = OpLabel
61fd4e5da5Sopenharmony_ci               OpLoopMerge %22 %23 None
62fd4e5da5Sopenharmony_ci               OpBranch %24
63fd4e5da5Sopenharmony_ci         %24 = OpLabel
64fd4e5da5Sopenharmony_ci         %25 = OpPhi %12 %19 %21 %18 %26
65fd4e5da5Sopenharmony_ci               OpLoopMerge %27 %26 None
66fd4e5da5Sopenharmony_ci               OpBranch %28
67fd4e5da5Sopenharmony_ci         %28 = OpLabel
68fd4e5da5Sopenharmony_ci          %5 = OpLoad %12 %3
69fd4e5da5Sopenharmony_ci         %29 = OpSGreaterThan %16 %5 %18
70fd4e5da5Sopenharmony_ci               OpBranchConditional %29 %30 %27
71fd4e5da5Sopenharmony_ci         %30 = OpLabel
72fd4e5da5Sopenharmony_ci          %6 = OpLoad %12 %4
73fd4e5da5Sopenharmony_ci          %7 = OpISub %12 %6 %19
74fd4e5da5Sopenharmony_ci               OpStore %4 %7
75fd4e5da5Sopenharmony_ci               OpBranch %26
76fd4e5da5Sopenharmony_ci         %26 = OpLabel
77fd4e5da5Sopenharmony_ci          %8 = OpLoad %12 %3
78fd4e5da5Sopenharmony_ci          %9 = OpISub %12 %8 %19
79fd4e5da5Sopenharmony_ci               OpStore %3 %9
80fd4e5da5Sopenharmony_ci               OpBranch %24
81fd4e5da5Sopenharmony_ci         %27 = OpLabel
82fd4e5da5Sopenharmony_ci               OpBranch %23
83fd4e5da5Sopenharmony_ci         %23 = OpLabel
84fd4e5da5Sopenharmony_ci               OpBranch %21
85fd4e5da5Sopenharmony_ci         %22 = OpLabel
86fd4e5da5Sopenharmony_ci               OpBranch %31
87fd4e5da5Sopenharmony_ci         %31 = OpLabel
88fd4e5da5Sopenharmony_ci               OpLoopMerge %32 %31 None
89fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %31 %32
90fd4e5da5Sopenharmony_ci         %32 = OpLabel
91fd4e5da5Sopenharmony_ci               OpSelectionMerge %33 None
92fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %34 %35
93fd4e5da5Sopenharmony_ci         %34 = OpLabel
94fd4e5da5Sopenharmony_ci               OpBranch %33
95fd4e5da5Sopenharmony_ci         %35 = OpLabel
96fd4e5da5Sopenharmony_ci               OpBranch %33
97fd4e5da5Sopenharmony_ci         %33 = OpLabel
98fd4e5da5Sopenharmony_ci         %42 = OpPhi %12 %19 %33 %18 %34 %18 %35
99fd4e5da5Sopenharmony_ci               OpLoopMerge %36 %33 None
100fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %36 %33
101fd4e5da5Sopenharmony_ci         %36 = OpLabel
102fd4e5da5Sopenharmony_ci         %43 = OpPhi %12 %18 %33 %18 %41
103fd4e5da5Sopenharmony_ci               OpReturn
104fd4e5da5Sopenharmony_ci         %37 = OpLabel
105fd4e5da5Sopenharmony_ci               OpLoopMerge %38 %39 None
106fd4e5da5Sopenharmony_ci               OpBranch %40
107fd4e5da5Sopenharmony_ci         %40 = OpLabel
108fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %41 %38
109fd4e5da5Sopenharmony_ci         %41 = OpLabel
110fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %36 %39
111fd4e5da5Sopenharmony_ci         %39 = OpLabel
112fd4e5da5Sopenharmony_ci               OpBranch %37
113fd4e5da5Sopenharmony_ci         %38 = OpLabel
114fd4e5da5Sopenharmony_ci               OpReturn
115fd4e5da5Sopenharmony_ci               OpFunctionEnd
116fd4e5da5Sopenharmony_ci)";
117fd4e5da5Sopenharmony_ci
118fd4e5da5Sopenharmony_ciTEST(FuzzerPassOutlineFunctionsTest, EntryIsAlreadySuitable) {
119fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_5;
120fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
121fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
122fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
123fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
124fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
125fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
126fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
127fd4e5da5Sopenharmony_ci  FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
128fd4e5da5Sopenharmony_ci                               false);
129fd4e5da5Sopenharmony_ci  protobufs::TransformationSequence transformation_sequence;
130fd4e5da5Sopenharmony_ci
131fd4e5da5Sopenharmony_ci  FuzzerPassOutlineFunctions fuzzer_pass(context.get(), &transformation_context,
132fd4e5da5Sopenharmony_ci                                         &fuzzer_context,
133fd4e5da5Sopenharmony_ci                                         &transformation_sequence, false);
134fd4e5da5Sopenharmony_ci
135fd4e5da5Sopenharmony_ci  // Block 28
136fd4e5da5Sopenharmony_ci  auto suitable_entry_block =
137fd4e5da5Sopenharmony_ci      fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining(
138fd4e5da5Sopenharmony_ci          context->get_instr_block(28));
139fd4e5da5Sopenharmony_ci
140fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block);
141fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 28);
142fd4e5da5Sopenharmony_ci
143fd4e5da5Sopenharmony_ci  // Block 32
144fd4e5da5Sopenharmony_ci  suitable_entry_block = fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining(
145fd4e5da5Sopenharmony_ci      context->get_instr_block(32));
146fd4e5da5Sopenharmony_ci
147fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block);
148fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 32);
149fd4e5da5Sopenharmony_ci
150fd4e5da5Sopenharmony_ci  // Block 41
151fd4e5da5Sopenharmony_ci  suitable_entry_block = fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining(
152fd4e5da5Sopenharmony_ci      context->get_instr_block(41));
153fd4e5da5Sopenharmony_ci
154fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block);
155fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 41);
156fd4e5da5Sopenharmony_ci
157fd4e5da5Sopenharmony_ci  // The module should not have been changed.
158fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, shader, context.get()));
159fd4e5da5Sopenharmony_ci}
160fd4e5da5Sopenharmony_ci
161fd4e5da5Sopenharmony_ciTEST(FuzzerPassOutlineFunctionsTest, EntryHasOpVariable) {
162fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_5;
163fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
164fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
165fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
166fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
167fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
168fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
169fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
170fd4e5da5Sopenharmony_ci  FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
171fd4e5da5Sopenharmony_ci                               false);
172fd4e5da5Sopenharmony_ci  protobufs::TransformationSequence transformation_sequence;
173fd4e5da5Sopenharmony_ci
174fd4e5da5Sopenharmony_ci  FuzzerPassOutlineFunctions fuzzer_pass(context.get(), &transformation_context,
175fd4e5da5Sopenharmony_ci                                         &fuzzer_context,
176fd4e5da5Sopenharmony_ci                                         &transformation_sequence, false);
177fd4e5da5Sopenharmony_ci
178fd4e5da5Sopenharmony_ci  // Block 20
179fd4e5da5Sopenharmony_ci  auto suitable_entry_block =
180fd4e5da5Sopenharmony_ci      fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining(
181fd4e5da5Sopenharmony_ci          context->get_instr_block(20));
182fd4e5da5Sopenharmony_ci
183fd4e5da5Sopenharmony_ci  // The block should have been split, the new entry block being the block
184fd4e5da5Sopenharmony_ci  // generated by the splitting.
185fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block);
186fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 100);
187fd4e5da5Sopenharmony_ci
188fd4e5da5Sopenharmony_ci  std::string after_adjustment = R"(
189fd4e5da5Sopenharmony_ci               OpCapability Shader
190fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
191fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
192fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
193fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
194fd4e5da5Sopenharmony_ci               OpSource ESSL 310
195fd4e5da5Sopenharmony_ci               OpName %2 "main"
196fd4e5da5Sopenharmony_ci               OpName %3 "a"
197fd4e5da5Sopenharmony_ci               OpName %4 "b"
198fd4e5da5Sopenharmony_ci               OpDecorate %3 RelaxedPrecision
199fd4e5da5Sopenharmony_ci               OpDecorate %4 RelaxedPrecision
200fd4e5da5Sopenharmony_ci               OpDecorate %5 RelaxedPrecision
201fd4e5da5Sopenharmony_ci               OpDecorate %6 RelaxedPrecision
202fd4e5da5Sopenharmony_ci               OpDecorate %7 RelaxedPrecision
203fd4e5da5Sopenharmony_ci               OpDecorate %8 RelaxedPrecision
204fd4e5da5Sopenharmony_ci               OpDecorate %9 RelaxedPrecision
205fd4e5da5Sopenharmony_ci         %10 = OpTypeVoid
206fd4e5da5Sopenharmony_ci         %11 = OpTypeFunction %10
207fd4e5da5Sopenharmony_ci         %12 = OpTypeInt 32 1
208fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
209fd4e5da5Sopenharmony_ci         %14 = OpConstant %12 8
210fd4e5da5Sopenharmony_ci         %15 = OpConstant %12 23
211fd4e5da5Sopenharmony_ci         %16 = OpTypeBool
212fd4e5da5Sopenharmony_ci         %17 = OpConstantTrue %16
213fd4e5da5Sopenharmony_ci         %18 = OpConstant %12 0
214fd4e5da5Sopenharmony_ci         %19 = OpConstant %12 1
215fd4e5da5Sopenharmony_ci          %2 = OpFunction %10 None %11
216fd4e5da5Sopenharmony_ci         %20 = OpLabel
217fd4e5da5Sopenharmony_ci          %3 = OpVariable %13 Function
218fd4e5da5Sopenharmony_ci          %4 = OpVariable %13 Function
219fd4e5da5Sopenharmony_ci               OpBranch %100
220fd4e5da5Sopenharmony_ci        %100 = OpLabel
221fd4e5da5Sopenharmony_ci               OpStore %3 %14
222fd4e5da5Sopenharmony_ci               OpStore %4 %15
223fd4e5da5Sopenharmony_ci               OpBranch %21
224fd4e5da5Sopenharmony_ci         %21 = OpLabel
225fd4e5da5Sopenharmony_ci               OpLoopMerge %22 %23 None
226fd4e5da5Sopenharmony_ci               OpBranch %24
227fd4e5da5Sopenharmony_ci         %24 = OpLabel
228fd4e5da5Sopenharmony_ci         %25 = OpPhi %12 %19 %21 %18 %26
229fd4e5da5Sopenharmony_ci               OpLoopMerge %27 %26 None
230fd4e5da5Sopenharmony_ci               OpBranch %28
231fd4e5da5Sopenharmony_ci         %28 = OpLabel
232fd4e5da5Sopenharmony_ci          %5 = OpLoad %12 %3
233fd4e5da5Sopenharmony_ci         %29 = OpSGreaterThan %16 %5 %18
234fd4e5da5Sopenharmony_ci               OpBranchConditional %29 %30 %27
235fd4e5da5Sopenharmony_ci         %30 = OpLabel
236fd4e5da5Sopenharmony_ci          %6 = OpLoad %12 %4
237fd4e5da5Sopenharmony_ci          %7 = OpISub %12 %6 %19
238fd4e5da5Sopenharmony_ci               OpStore %4 %7
239fd4e5da5Sopenharmony_ci               OpBranch %26
240fd4e5da5Sopenharmony_ci         %26 = OpLabel
241fd4e5da5Sopenharmony_ci          %8 = OpLoad %12 %3
242fd4e5da5Sopenharmony_ci          %9 = OpISub %12 %8 %19
243fd4e5da5Sopenharmony_ci               OpStore %3 %9
244fd4e5da5Sopenharmony_ci               OpBranch %24
245fd4e5da5Sopenharmony_ci         %27 = OpLabel
246fd4e5da5Sopenharmony_ci               OpBranch %23
247fd4e5da5Sopenharmony_ci         %23 = OpLabel
248fd4e5da5Sopenharmony_ci               OpBranch %21
249fd4e5da5Sopenharmony_ci         %22 = OpLabel
250fd4e5da5Sopenharmony_ci               OpBranch %31
251fd4e5da5Sopenharmony_ci         %31 = OpLabel
252fd4e5da5Sopenharmony_ci               OpLoopMerge %32 %31 None
253fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %31 %32
254fd4e5da5Sopenharmony_ci         %32 = OpLabel
255fd4e5da5Sopenharmony_ci               OpSelectionMerge %33 None
256fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %34 %35
257fd4e5da5Sopenharmony_ci         %34 = OpLabel
258fd4e5da5Sopenharmony_ci               OpBranch %33
259fd4e5da5Sopenharmony_ci         %35 = OpLabel
260fd4e5da5Sopenharmony_ci               OpBranch %33
261fd4e5da5Sopenharmony_ci         %33 = OpLabel
262fd4e5da5Sopenharmony_ci         %42 = OpPhi %12 %19 %33 %18 %34 %18 %35
263fd4e5da5Sopenharmony_ci               OpLoopMerge %36 %33 None
264fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %36 %33
265fd4e5da5Sopenharmony_ci         %36 = OpLabel
266fd4e5da5Sopenharmony_ci         %43 = OpPhi %12 %18 %33 %18 %41
267fd4e5da5Sopenharmony_ci               OpReturn
268fd4e5da5Sopenharmony_ci         %37 = OpLabel
269fd4e5da5Sopenharmony_ci               OpLoopMerge %38 %39 None
270fd4e5da5Sopenharmony_ci               OpBranch %40
271fd4e5da5Sopenharmony_ci         %40 = OpLabel
272fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %41 %38
273fd4e5da5Sopenharmony_ci         %41 = OpLabel
274fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %36 %39
275fd4e5da5Sopenharmony_ci         %39 = OpLabel
276fd4e5da5Sopenharmony_ci               OpBranch %37
277fd4e5da5Sopenharmony_ci         %38 = OpLabel
278fd4e5da5Sopenharmony_ci               OpReturn
279fd4e5da5Sopenharmony_ci               OpFunctionEnd
280fd4e5da5Sopenharmony_ci)";
281fd4e5da5Sopenharmony_ci
282fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, after_adjustment, context.get()));
283fd4e5da5Sopenharmony_ci}
284fd4e5da5Sopenharmony_ci
285fd4e5da5Sopenharmony_ciTEST(FuzzerPassOutlineFunctionsTest, EntryBlockIsHeader) {
286fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_5;
287fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
288fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
289fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
290fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
291fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
292fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
293fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
294fd4e5da5Sopenharmony_ci  FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
295fd4e5da5Sopenharmony_ci                               false);
296fd4e5da5Sopenharmony_ci  protobufs::TransformationSequence transformation_sequence;
297fd4e5da5Sopenharmony_ci
298fd4e5da5Sopenharmony_ci  FuzzerPassOutlineFunctions fuzzer_pass(context.get(), &transformation_context,
299fd4e5da5Sopenharmony_ci                                         &fuzzer_context,
300fd4e5da5Sopenharmony_ci                                         &transformation_sequence, false);
301fd4e5da5Sopenharmony_ci
302fd4e5da5Sopenharmony_ci  // Block 21
303fd4e5da5Sopenharmony_ci  auto suitable_entry_block =
304fd4e5da5Sopenharmony_ci      fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining(
305fd4e5da5Sopenharmony_ci          context->get_instr_block(21));
306fd4e5da5Sopenharmony_ci
307fd4e5da5Sopenharmony_ci  // A suitable entry block should have been found by finding the preheader
308fd4e5da5Sopenharmony_ci  // (%20) and then splitting it.
309fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block);
310fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 100);
311fd4e5da5Sopenharmony_ci
312fd4e5da5Sopenharmony_ci  // Block 24
313fd4e5da5Sopenharmony_ci  suitable_entry_block = fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining(
314fd4e5da5Sopenharmony_ci      context->get_instr_block(24));
315fd4e5da5Sopenharmony_ci
316fd4e5da5Sopenharmony_ci  // A preheader should have been created, because the current one is a loop
317fd4e5da5Sopenharmony_ci  // header.
318fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block);
319fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 101);
320fd4e5da5Sopenharmony_ci
321fd4e5da5Sopenharmony_ci  // Block 31
322fd4e5da5Sopenharmony_ci  suitable_entry_block = fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining(
323fd4e5da5Sopenharmony_ci      context->get_instr_block(31));
324fd4e5da5Sopenharmony_ci
325fd4e5da5Sopenharmony_ci  // An existing suitable entry block should have been found by finding the
326fd4e5da5Sopenharmony_ci  // preheader (%22), which is already suitable.
327fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block);
328fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 22);
329fd4e5da5Sopenharmony_ci
330fd4e5da5Sopenharmony_ci  // Block 33
331fd4e5da5Sopenharmony_ci  suitable_entry_block = fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining(
332fd4e5da5Sopenharmony_ci      context->get_instr_block(33));
333fd4e5da5Sopenharmony_ci
334fd4e5da5Sopenharmony_ci  // An existing suitable entry block should have been found by creating a new
335fd4e5da5Sopenharmony_ci  // preheader (there is not one already), and then splitting it (as it contains
336fd4e5da5Sopenharmony_ci  // OpPhi).
337fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block);
338fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_entry_block->GetLabel()->result_id() == 104);
339fd4e5da5Sopenharmony_ci
340fd4e5da5Sopenharmony_ci  // Block 37
341fd4e5da5Sopenharmony_ci  suitable_entry_block = fuzzer_pass.MaybeGetEntryBlockSuitableForOutlining(
342fd4e5da5Sopenharmony_ci      context->get_instr_block(37));
343fd4e5da5Sopenharmony_ci
344fd4e5da5Sopenharmony_ci  // No suitable entry block can be found for block 37, since it is a loop
345fd4e5da5Sopenharmony_ci  // header with only one predecessor (the back-edge block).
346fd4e5da5Sopenharmony_ci  ASSERT_FALSE(suitable_entry_block);
347fd4e5da5Sopenharmony_ci
348fd4e5da5Sopenharmony_ci  std::string after_adjustments = R"(
349fd4e5da5Sopenharmony_ci               OpCapability Shader
350fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
351fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
352fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
353fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
354fd4e5da5Sopenharmony_ci               OpSource ESSL 310
355fd4e5da5Sopenharmony_ci               OpName %2 "main"
356fd4e5da5Sopenharmony_ci               OpName %3 "a"
357fd4e5da5Sopenharmony_ci               OpName %4 "b"
358fd4e5da5Sopenharmony_ci               OpDecorate %3 RelaxedPrecision
359fd4e5da5Sopenharmony_ci               OpDecorate %4 RelaxedPrecision
360fd4e5da5Sopenharmony_ci               OpDecorate %5 RelaxedPrecision
361fd4e5da5Sopenharmony_ci               OpDecorate %6 RelaxedPrecision
362fd4e5da5Sopenharmony_ci               OpDecorate %7 RelaxedPrecision
363fd4e5da5Sopenharmony_ci               OpDecorate %8 RelaxedPrecision
364fd4e5da5Sopenharmony_ci               OpDecorate %9 RelaxedPrecision
365fd4e5da5Sopenharmony_ci         %10 = OpTypeVoid
366fd4e5da5Sopenharmony_ci         %11 = OpTypeFunction %10
367fd4e5da5Sopenharmony_ci         %12 = OpTypeInt 32 1
368fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
369fd4e5da5Sopenharmony_ci         %14 = OpConstant %12 8
370fd4e5da5Sopenharmony_ci         %15 = OpConstant %12 23
371fd4e5da5Sopenharmony_ci         %16 = OpTypeBool
372fd4e5da5Sopenharmony_ci         %17 = OpConstantTrue %16
373fd4e5da5Sopenharmony_ci         %18 = OpConstant %12 0
374fd4e5da5Sopenharmony_ci         %19 = OpConstant %12 1
375fd4e5da5Sopenharmony_ci          %2 = OpFunction %10 None %11
376fd4e5da5Sopenharmony_ci         %20 = OpLabel
377fd4e5da5Sopenharmony_ci          %3 = OpVariable %13 Function
378fd4e5da5Sopenharmony_ci          %4 = OpVariable %13 Function
379fd4e5da5Sopenharmony_ci               OpBranch %100
380fd4e5da5Sopenharmony_ci        %100 = OpLabel
381fd4e5da5Sopenharmony_ci               OpStore %3 %14
382fd4e5da5Sopenharmony_ci               OpStore %4 %15
383fd4e5da5Sopenharmony_ci               OpBranch %21
384fd4e5da5Sopenharmony_ci         %21 = OpLabel
385fd4e5da5Sopenharmony_ci               OpLoopMerge %22 %23 None
386fd4e5da5Sopenharmony_ci               OpBranch %101
387fd4e5da5Sopenharmony_ci        %101 = OpLabel
388fd4e5da5Sopenharmony_ci               OpBranch %24
389fd4e5da5Sopenharmony_ci         %24 = OpLabel
390fd4e5da5Sopenharmony_ci         %25 = OpPhi %12 %19 %101 %18 %26
391fd4e5da5Sopenharmony_ci               OpLoopMerge %27 %26 None
392fd4e5da5Sopenharmony_ci               OpBranch %28
393fd4e5da5Sopenharmony_ci         %28 = OpLabel
394fd4e5da5Sopenharmony_ci          %5 = OpLoad %12 %3
395fd4e5da5Sopenharmony_ci         %29 = OpSGreaterThan %16 %5 %18
396fd4e5da5Sopenharmony_ci               OpBranchConditional %29 %30 %27
397fd4e5da5Sopenharmony_ci         %30 = OpLabel
398fd4e5da5Sopenharmony_ci          %6 = OpLoad %12 %4
399fd4e5da5Sopenharmony_ci          %7 = OpISub %12 %6 %19
400fd4e5da5Sopenharmony_ci               OpStore %4 %7
401fd4e5da5Sopenharmony_ci               OpBranch %26
402fd4e5da5Sopenharmony_ci         %26 = OpLabel
403fd4e5da5Sopenharmony_ci          %8 = OpLoad %12 %3
404fd4e5da5Sopenharmony_ci          %9 = OpISub %12 %8 %19
405fd4e5da5Sopenharmony_ci               OpStore %3 %9
406fd4e5da5Sopenharmony_ci               OpBranch %24
407fd4e5da5Sopenharmony_ci         %27 = OpLabel
408fd4e5da5Sopenharmony_ci               OpBranch %23
409fd4e5da5Sopenharmony_ci         %23 = OpLabel
410fd4e5da5Sopenharmony_ci               OpBranch %21
411fd4e5da5Sopenharmony_ci         %22 = OpLabel
412fd4e5da5Sopenharmony_ci               OpBranch %31
413fd4e5da5Sopenharmony_ci         %31 = OpLabel
414fd4e5da5Sopenharmony_ci               OpLoopMerge %32 %31 None
415fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %31 %32
416fd4e5da5Sopenharmony_ci         %32 = OpLabel
417fd4e5da5Sopenharmony_ci               OpSelectionMerge %102 None
418fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %34 %35
419fd4e5da5Sopenharmony_ci         %34 = OpLabel
420fd4e5da5Sopenharmony_ci               OpBranch %102
421fd4e5da5Sopenharmony_ci         %35 = OpLabel
422fd4e5da5Sopenharmony_ci               OpBranch %102
423fd4e5da5Sopenharmony_ci        %102 = OpLabel
424fd4e5da5Sopenharmony_ci        %103 = OpPhi %12 %18 %34 %18 %35
425fd4e5da5Sopenharmony_ci               OpBranch %104
426fd4e5da5Sopenharmony_ci        %104 = OpLabel
427fd4e5da5Sopenharmony_ci               OpBranch %33
428fd4e5da5Sopenharmony_ci         %33 = OpLabel
429fd4e5da5Sopenharmony_ci         %42 = OpPhi %12 %103 %104 %19 %33
430fd4e5da5Sopenharmony_ci               OpLoopMerge %36 %33 None
431fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %36 %33
432fd4e5da5Sopenharmony_ci         %36 = OpLabel
433fd4e5da5Sopenharmony_ci         %43 = OpPhi %12 %18 %33 %18 %41
434fd4e5da5Sopenharmony_ci               OpReturn
435fd4e5da5Sopenharmony_ci         %37 = OpLabel
436fd4e5da5Sopenharmony_ci               OpLoopMerge %38 %39 None
437fd4e5da5Sopenharmony_ci               OpBranch %40
438fd4e5da5Sopenharmony_ci         %40 = OpLabel
439fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %41 %38
440fd4e5da5Sopenharmony_ci         %41 = OpLabel
441fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %36 %39
442fd4e5da5Sopenharmony_ci         %39 = OpLabel
443fd4e5da5Sopenharmony_ci               OpBranch %37
444fd4e5da5Sopenharmony_ci         %38 = OpLabel
445fd4e5da5Sopenharmony_ci               OpReturn
446fd4e5da5Sopenharmony_ci               OpFunctionEnd
447fd4e5da5Sopenharmony_ci)";
448fd4e5da5Sopenharmony_ci
449fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, after_adjustments, context.get()));
450fd4e5da5Sopenharmony_ci}
451fd4e5da5Sopenharmony_ci
452fd4e5da5Sopenharmony_ciTEST(FuzzerPassOutlineFunctionsTest, ExitBlock) {
453fd4e5da5Sopenharmony_ci  const auto env = SPV_ENV_UNIVERSAL_1_5;
454fd4e5da5Sopenharmony_ci  const auto consumer = nullptr;
455fd4e5da5Sopenharmony_ci  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
456fd4e5da5Sopenharmony_ci  spvtools::ValidatorOptions validator_options;
457fd4e5da5Sopenharmony_ci  ASSERT_TRUE(fuzzerutil::IsValidAndWellFormed(context.get(), validator_options,
458fd4e5da5Sopenharmony_ci                                               kConsoleMessageConsumer));
459fd4e5da5Sopenharmony_ci  TransformationContext transformation_context(
460fd4e5da5Sopenharmony_ci      MakeUnique<FactManager>(context.get()), validator_options);
461fd4e5da5Sopenharmony_ci  FuzzerContext fuzzer_context(MakeUnique<PseudoRandomGenerator>(0), 100,
462fd4e5da5Sopenharmony_ci                               false);
463fd4e5da5Sopenharmony_ci  protobufs::TransformationSequence transformation_sequence;
464fd4e5da5Sopenharmony_ci
465fd4e5da5Sopenharmony_ci  FuzzerPassOutlineFunctions fuzzer_pass(context.get(), &transformation_context,
466fd4e5da5Sopenharmony_ci                                         &fuzzer_context,
467fd4e5da5Sopenharmony_ci                                         &transformation_sequence, false);
468fd4e5da5Sopenharmony_ci
469fd4e5da5Sopenharmony_ci  // Block 39 is not a merge block, so it is already suitable.
470fd4e5da5Sopenharmony_ci  auto suitable_exit_block = fuzzer_pass.MaybeGetExitBlockSuitableForOutlining(
471fd4e5da5Sopenharmony_ci      context->get_instr_block(39));
472fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_exit_block);
473fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_exit_block->GetLabel()->result_id() == 39);
474fd4e5da5Sopenharmony_ci
475fd4e5da5Sopenharmony_ci  // The following are merge blocks and, thus, they will need to be split.
476fd4e5da5Sopenharmony_ci
477fd4e5da5Sopenharmony_ci  // Block 22
478fd4e5da5Sopenharmony_ci  suitable_exit_block = fuzzer_pass.MaybeGetExitBlockSuitableForOutlining(
479fd4e5da5Sopenharmony_ci      context->get_instr_block(22));
480fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_exit_block);
481fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_exit_block->GetLabel()->result_id() == 100);
482fd4e5da5Sopenharmony_ci
483fd4e5da5Sopenharmony_ci  // Block 27
484fd4e5da5Sopenharmony_ci  suitable_exit_block = fuzzer_pass.MaybeGetExitBlockSuitableForOutlining(
485fd4e5da5Sopenharmony_ci      context->get_instr_block(27));
486fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_exit_block);
487fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_exit_block->GetLabel()->result_id() == 101);
488fd4e5da5Sopenharmony_ci
489fd4e5da5Sopenharmony_ci  // Block 36
490fd4e5da5Sopenharmony_ci  suitable_exit_block = fuzzer_pass.MaybeGetExitBlockSuitableForOutlining(
491fd4e5da5Sopenharmony_ci      context->get_instr_block(36));
492fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_exit_block);
493fd4e5da5Sopenharmony_ci  ASSERT_TRUE(suitable_exit_block->GetLabel()->result_id() == 102);
494fd4e5da5Sopenharmony_ci
495fd4e5da5Sopenharmony_ci  std::string after_adjustments = R"(
496fd4e5da5Sopenharmony_ci               OpCapability Shader
497fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
498fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
499fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
500fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
501fd4e5da5Sopenharmony_ci               OpSource ESSL 310
502fd4e5da5Sopenharmony_ci               OpName %2 "main"
503fd4e5da5Sopenharmony_ci               OpName %3 "a"
504fd4e5da5Sopenharmony_ci               OpName %4 "b"
505fd4e5da5Sopenharmony_ci               OpDecorate %3 RelaxedPrecision
506fd4e5da5Sopenharmony_ci               OpDecorate %4 RelaxedPrecision
507fd4e5da5Sopenharmony_ci               OpDecorate %5 RelaxedPrecision
508fd4e5da5Sopenharmony_ci               OpDecorate %6 RelaxedPrecision
509fd4e5da5Sopenharmony_ci               OpDecorate %7 RelaxedPrecision
510fd4e5da5Sopenharmony_ci               OpDecorate %8 RelaxedPrecision
511fd4e5da5Sopenharmony_ci               OpDecorate %9 RelaxedPrecision
512fd4e5da5Sopenharmony_ci         %10 = OpTypeVoid
513fd4e5da5Sopenharmony_ci         %11 = OpTypeFunction %10
514fd4e5da5Sopenharmony_ci         %12 = OpTypeInt 32 1
515fd4e5da5Sopenharmony_ci         %13 = OpTypePointer Function %12
516fd4e5da5Sopenharmony_ci         %14 = OpConstant %12 8
517fd4e5da5Sopenharmony_ci         %15 = OpConstant %12 23
518fd4e5da5Sopenharmony_ci         %16 = OpTypeBool
519fd4e5da5Sopenharmony_ci         %17 = OpConstantTrue %16
520fd4e5da5Sopenharmony_ci         %18 = OpConstant %12 0
521fd4e5da5Sopenharmony_ci         %19 = OpConstant %12 1
522fd4e5da5Sopenharmony_ci          %2 = OpFunction %10 None %11
523fd4e5da5Sopenharmony_ci         %20 = OpLabel
524fd4e5da5Sopenharmony_ci          %3 = OpVariable %13 Function
525fd4e5da5Sopenharmony_ci          %4 = OpVariable %13 Function
526fd4e5da5Sopenharmony_ci               OpStore %3 %14
527fd4e5da5Sopenharmony_ci               OpStore %4 %15
528fd4e5da5Sopenharmony_ci               OpBranch %21
529fd4e5da5Sopenharmony_ci         %21 = OpLabel
530fd4e5da5Sopenharmony_ci               OpLoopMerge %22 %23 None
531fd4e5da5Sopenharmony_ci               OpBranch %24
532fd4e5da5Sopenharmony_ci         %24 = OpLabel
533fd4e5da5Sopenharmony_ci         %25 = OpPhi %12 %19 %21 %18 %26
534fd4e5da5Sopenharmony_ci               OpLoopMerge %27 %26 None
535fd4e5da5Sopenharmony_ci               OpBranch %28
536fd4e5da5Sopenharmony_ci         %28 = OpLabel
537fd4e5da5Sopenharmony_ci          %5 = OpLoad %12 %3
538fd4e5da5Sopenharmony_ci         %29 = OpSGreaterThan %16 %5 %18
539fd4e5da5Sopenharmony_ci               OpBranchConditional %29 %30 %27
540fd4e5da5Sopenharmony_ci         %30 = OpLabel
541fd4e5da5Sopenharmony_ci          %6 = OpLoad %12 %4
542fd4e5da5Sopenharmony_ci          %7 = OpISub %12 %6 %19
543fd4e5da5Sopenharmony_ci               OpStore %4 %7
544fd4e5da5Sopenharmony_ci               OpBranch %26
545fd4e5da5Sopenharmony_ci         %26 = OpLabel
546fd4e5da5Sopenharmony_ci          %8 = OpLoad %12 %3
547fd4e5da5Sopenharmony_ci          %9 = OpISub %12 %8 %19
548fd4e5da5Sopenharmony_ci               OpStore %3 %9
549fd4e5da5Sopenharmony_ci               OpBranch %24
550fd4e5da5Sopenharmony_ci         %27 = OpLabel
551fd4e5da5Sopenharmony_ci               OpBranch %101
552fd4e5da5Sopenharmony_ci        %101 = OpLabel
553fd4e5da5Sopenharmony_ci               OpBranch %23
554fd4e5da5Sopenharmony_ci         %23 = OpLabel
555fd4e5da5Sopenharmony_ci               OpBranch %21
556fd4e5da5Sopenharmony_ci         %22 = OpLabel
557fd4e5da5Sopenharmony_ci               OpBranch %100
558fd4e5da5Sopenharmony_ci        %100 = OpLabel
559fd4e5da5Sopenharmony_ci               OpBranch %31
560fd4e5da5Sopenharmony_ci         %31 = OpLabel
561fd4e5da5Sopenharmony_ci               OpLoopMerge %32 %31 None
562fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %31 %32
563fd4e5da5Sopenharmony_ci         %32 = OpLabel
564fd4e5da5Sopenharmony_ci               OpSelectionMerge %33 None
565fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %34 %35
566fd4e5da5Sopenharmony_ci         %34 = OpLabel
567fd4e5da5Sopenharmony_ci               OpBranch %33
568fd4e5da5Sopenharmony_ci         %35 = OpLabel
569fd4e5da5Sopenharmony_ci               OpBranch %33
570fd4e5da5Sopenharmony_ci         %33 = OpLabel
571fd4e5da5Sopenharmony_ci         %42 = OpPhi %12 %19 %33 %18 %34 %18 %35
572fd4e5da5Sopenharmony_ci               OpLoopMerge %36 %33 None
573fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %36 %33
574fd4e5da5Sopenharmony_ci         %36 = OpLabel
575fd4e5da5Sopenharmony_ci         %43 = OpPhi %12 %18 %33 %18 %41
576fd4e5da5Sopenharmony_ci               OpBranch %102
577fd4e5da5Sopenharmony_ci        %102 = OpLabel
578fd4e5da5Sopenharmony_ci               OpReturn
579fd4e5da5Sopenharmony_ci         %37 = OpLabel
580fd4e5da5Sopenharmony_ci               OpLoopMerge %38 %39 None
581fd4e5da5Sopenharmony_ci               OpBranch %40
582fd4e5da5Sopenharmony_ci         %40 = OpLabel
583fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %41 %38
584fd4e5da5Sopenharmony_ci         %41 = OpLabel
585fd4e5da5Sopenharmony_ci               OpBranchConditional %17 %36 %39
586fd4e5da5Sopenharmony_ci         %39 = OpLabel
587fd4e5da5Sopenharmony_ci               OpBranch %37
588fd4e5da5Sopenharmony_ci         %38 = OpLabel
589fd4e5da5Sopenharmony_ci               OpReturn
590fd4e5da5Sopenharmony_ci               OpFunctionEnd
591fd4e5da5Sopenharmony_ci)";
592fd4e5da5Sopenharmony_ci
593fd4e5da5Sopenharmony_ci  ASSERT_TRUE(IsEqual(env, after_adjustments, context.get()));
594fd4e5da5Sopenharmony_ci}
595fd4e5da5Sopenharmony_ci}  // namespace
596fd4e5da5Sopenharmony_ci}  // namespace fuzz
597fd4e5da5Sopenharmony_ci}  // namespace spvtools
598