1fd4e5da5Sopenharmony_ci// Copyright (c) 2017 Google Inc.
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 <memory>
16fd4e5da5Sopenharmony_ci#include <string>
17fd4e5da5Sopenharmony_ci#include <unordered_set>
18fd4e5da5Sopenharmony_ci#include <vector>
19fd4e5da5Sopenharmony_ci
20fd4e5da5Sopenharmony_ci#include "gmock/gmock.h"
21fd4e5da5Sopenharmony_ci#include "source/opt/iterator.h"
22fd4e5da5Sopenharmony_ci#include "source/opt/loop_descriptor.h"
23fd4e5da5Sopenharmony_ci#include "source/opt/pass.h"
24fd4e5da5Sopenharmony_ci#include "source/opt/tree_iterator.h"
25fd4e5da5Sopenharmony_ci#include "test/opt/assembly_builder.h"
26fd4e5da5Sopenharmony_ci#include "test/opt/function_utils.h"
27fd4e5da5Sopenharmony_ci#include "test/opt/pass_fixture.h"
28fd4e5da5Sopenharmony_ci#include "test/opt/pass_utils.h"
29fd4e5da5Sopenharmony_ci
30fd4e5da5Sopenharmony_cinamespace spvtools {
31fd4e5da5Sopenharmony_cinamespace opt {
32fd4e5da5Sopenharmony_cinamespace {
33fd4e5da5Sopenharmony_ci
34fd4e5da5Sopenharmony_ciusing ::testing::UnorderedElementsAre;
35fd4e5da5Sopenharmony_ci
36fd4e5da5Sopenharmony_cibool Validate(const std::vector<uint32_t>& bin) {
37fd4e5da5Sopenharmony_ci  spv_target_env target_env = SPV_ENV_UNIVERSAL_1_2;
38fd4e5da5Sopenharmony_ci  spv_context spvContext = spvContextCreate(target_env);
39fd4e5da5Sopenharmony_ci  spv_diagnostic diagnostic = nullptr;
40fd4e5da5Sopenharmony_ci  spv_const_binary_t binary = {bin.data(), bin.size()};
41fd4e5da5Sopenharmony_ci  spv_result_t error = spvValidate(spvContext, &binary, &diagnostic);
42fd4e5da5Sopenharmony_ci  if (error != 0) spvDiagnosticPrint(diagnostic);
43fd4e5da5Sopenharmony_ci  spvDiagnosticDestroy(diagnostic);
44fd4e5da5Sopenharmony_ci  spvContextDestroy(spvContext);
45fd4e5da5Sopenharmony_ci  return error == 0;
46fd4e5da5Sopenharmony_ci}
47fd4e5da5Sopenharmony_ci
48fd4e5da5Sopenharmony_ciusing PassClassTest = PassTest<::testing::Test>;
49fd4e5da5Sopenharmony_ci
50fd4e5da5Sopenharmony_ci/*
51fd4e5da5Sopenharmony_ciGenerated from the following GLSL
52fd4e5da5Sopenharmony_ci#version 330 core
53fd4e5da5Sopenharmony_cilayout(location = 0) out vec4 c;
54fd4e5da5Sopenharmony_civoid main() {
55fd4e5da5Sopenharmony_ci  int i = 0;
56fd4e5da5Sopenharmony_ci  for (; i < 10; ++i) {
57fd4e5da5Sopenharmony_ci    int j = 0;
58fd4e5da5Sopenharmony_ci    int k = 0;
59fd4e5da5Sopenharmony_ci    for (; j < 11; ++j) {}
60fd4e5da5Sopenharmony_ci    for (; k < 12; ++k) {}
61fd4e5da5Sopenharmony_ci  }
62fd4e5da5Sopenharmony_ci}
63fd4e5da5Sopenharmony_ci*/
64fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, BasicVisitFromEntryPoint) {
65fd4e5da5Sopenharmony_ci  const std::string text = R"(
66fd4e5da5Sopenharmony_ci               OpCapability Shader
67fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
68fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
69fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main" %3
70fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
71fd4e5da5Sopenharmony_ci               OpSource GLSL 330
72fd4e5da5Sopenharmony_ci               OpName %2 "main"
73fd4e5da5Sopenharmony_ci               OpName %4 "i"
74fd4e5da5Sopenharmony_ci               OpName %5 "j"
75fd4e5da5Sopenharmony_ci               OpName %6 "k"
76fd4e5da5Sopenharmony_ci               OpName %3 "c"
77fd4e5da5Sopenharmony_ci               OpDecorate %3 Location 0
78fd4e5da5Sopenharmony_ci          %7 = OpTypeVoid
79fd4e5da5Sopenharmony_ci          %8 = OpTypeFunction %7
80fd4e5da5Sopenharmony_ci          %9 = OpTypeInt 32 1
81fd4e5da5Sopenharmony_ci         %10 = OpTypePointer Function %9
82fd4e5da5Sopenharmony_ci         %11 = OpConstant %9 0
83fd4e5da5Sopenharmony_ci         %12 = OpConstant %9 10
84fd4e5da5Sopenharmony_ci         %13 = OpTypeBool
85fd4e5da5Sopenharmony_ci         %14 = OpConstant %9 11
86fd4e5da5Sopenharmony_ci         %15 = OpConstant %9 1
87fd4e5da5Sopenharmony_ci         %16 = OpConstant %9 12
88fd4e5da5Sopenharmony_ci         %17 = OpTypeFloat 32
89fd4e5da5Sopenharmony_ci         %18 = OpTypeVector %17 4
90fd4e5da5Sopenharmony_ci         %19 = OpTypePointer Output %18
91fd4e5da5Sopenharmony_ci          %3 = OpVariable %19 Output
92fd4e5da5Sopenharmony_ci          %2 = OpFunction %7 None %8
93fd4e5da5Sopenharmony_ci         %20 = OpLabel
94fd4e5da5Sopenharmony_ci          %4 = OpVariable %10 Function
95fd4e5da5Sopenharmony_ci          %5 = OpVariable %10 Function
96fd4e5da5Sopenharmony_ci          %6 = OpVariable %10 Function
97fd4e5da5Sopenharmony_ci               OpStore %4 %11
98fd4e5da5Sopenharmony_ci               OpBranch %21
99fd4e5da5Sopenharmony_ci         %21 = OpLabel
100fd4e5da5Sopenharmony_ci               OpLoopMerge %22 %23 None
101fd4e5da5Sopenharmony_ci               OpBranch %24
102fd4e5da5Sopenharmony_ci         %24 = OpLabel
103fd4e5da5Sopenharmony_ci         %25 = OpLoad %9 %4
104fd4e5da5Sopenharmony_ci         %26 = OpSLessThan %13 %25 %12
105fd4e5da5Sopenharmony_ci               OpBranchConditional %26 %27 %22
106fd4e5da5Sopenharmony_ci         %27 = OpLabel
107fd4e5da5Sopenharmony_ci               OpStore %5 %11
108fd4e5da5Sopenharmony_ci               OpStore %6 %11
109fd4e5da5Sopenharmony_ci               OpBranch %28
110fd4e5da5Sopenharmony_ci         %28 = OpLabel
111fd4e5da5Sopenharmony_ci               OpLoopMerge %29 %30 None
112fd4e5da5Sopenharmony_ci               OpBranch %31
113fd4e5da5Sopenharmony_ci         %31 = OpLabel
114fd4e5da5Sopenharmony_ci         %32 = OpLoad %9 %5
115fd4e5da5Sopenharmony_ci         %33 = OpSLessThan %13 %32 %14
116fd4e5da5Sopenharmony_ci               OpBranchConditional %33 %34 %29
117fd4e5da5Sopenharmony_ci         %34 = OpLabel
118fd4e5da5Sopenharmony_ci               OpBranch %30
119fd4e5da5Sopenharmony_ci         %30 = OpLabel
120fd4e5da5Sopenharmony_ci         %35 = OpLoad %9 %5
121fd4e5da5Sopenharmony_ci         %36 = OpIAdd %9 %35 %15
122fd4e5da5Sopenharmony_ci               OpStore %5 %36
123fd4e5da5Sopenharmony_ci               OpBranch %28
124fd4e5da5Sopenharmony_ci         %29 = OpLabel
125fd4e5da5Sopenharmony_ci               OpBranch %37
126fd4e5da5Sopenharmony_ci         %37 = OpLabel
127fd4e5da5Sopenharmony_ci               OpLoopMerge %38 %39 None
128fd4e5da5Sopenharmony_ci               OpBranch %40
129fd4e5da5Sopenharmony_ci         %40 = OpLabel
130fd4e5da5Sopenharmony_ci         %41 = OpLoad %9 %6
131fd4e5da5Sopenharmony_ci         %42 = OpSLessThan %13 %41 %16
132fd4e5da5Sopenharmony_ci               OpBranchConditional %42 %43 %38
133fd4e5da5Sopenharmony_ci         %43 = OpLabel
134fd4e5da5Sopenharmony_ci               OpBranch %39
135fd4e5da5Sopenharmony_ci         %39 = OpLabel
136fd4e5da5Sopenharmony_ci         %44 = OpLoad %9 %6
137fd4e5da5Sopenharmony_ci         %45 = OpIAdd %9 %44 %15
138fd4e5da5Sopenharmony_ci               OpStore %6 %45
139fd4e5da5Sopenharmony_ci               OpBranch %37
140fd4e5da5Sopenharmony_ci         %38 = OpLabel
141fd4e5da5Sopenharmony_ci               OpBranch %23
142fd4e5da5Sopenharmony_ci         %23 = OpLabel
143fd4e5da5Sopenharmony_ci         %46 = OpLoad %9 %4
144fd4e5da5Sopenharmony_ci         %47 = OpIAdd %9 %46 %15
145fd4e5da5Sopenharmony_ci               OpStore %4 %47
146fd4e5da5Sopenharmony_ci               OpBranch %21
147fd4e5da5Sopenharmony_ci         %22 = OpLabel
148fd4e5da5Sopenharmony_ci               OpReturn
149fd4e5da5Sopenharmony_ci               OpFunctionEnd
150fd4e5da5Sopenharmony_ci  )";
151fd4e5da5Sopenharmony_ci  // clang-format on
152fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
153fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
154fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
155fd4e5da5Sopenharmony_ci  Module* module = context->module();
156fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
157fd4e5da5Sopenharmony_ci                             << text << std::endl;
158fd4e5da5Sopenharmony_ci  const Function* f = spvtest::GetFunction(module, 2);
159fd4e5da5Sopenharmony_ci  LoopDescriptor& ld = *context->GetLoopDescriptor(f);
160fd4e5da5Sopenharmony_ci
161fd4e5da5Sopenharmony_ci  EXPECT_EQ(ld.NumLoops(), 3u);
162fd4e5da5Sopenharmony_ci
163fd4e5da5Sopenharmony_ci  // Invalid basic block id.
164fd4e5da5Sopenharmony_ci  EXPECT_EQ(ld[0u], nullptr);
165fd4e5da5Sopenharmony_ci  // Not a loop header.
166fd4e5da5Sopenharmony_ci  EXPECT_EQ(ld[20], nullptr);
167fd4e5da5Sopenharmony_ci
168fd4e5da5Sopenharmony_ci  Loop& parent_loop = *ld[21];
169fd4e5da5Sopenharmony_ci  EXPECT_TRUE(parent_loop.HasNestedLoops());
170fd4e5da5Sopenharmony_ci  EXPECT_FALSE(parent_loop.IsNested());
171fd4e5da5Sopenharmony_ci  EXPECT_EQ(parent_loop.GetDepth(), 1u);
172fd4e5da5Sopenharmony_ci  EXPECT_EQ(std::distance(parent_loop.begin(), parent_loop.end()), 2u);
173fd4e5da5Sopenharmony_ci  EXPECT_EQ(parent_loop.GetHeaderBlock(), spvtest::GetBasicBlock(f, 21));
174fd4e5da5Sopenharmony_ci  EXPECT_EQ(parent_loop.GetLatchBlock(), spvtest::GetBasicBlock(f, 23));
175fd4e5da5Sopenharmony_ci  EXPECT_EQ(parent_loop.GetMergeBlock(), spvtest::GetBasicBlock(f, 22));
176fd4e5da5Sopenharmony_ci
177fd4e5da5Sopenharmony_ci  Loop& child_loop_1 = *ld[28];
178fd4e5da5Sopenharmony_ci  EXPECT_FALSE(child_loop_1.HasNestedLoops());
179fd4e5da5Sopenharmony_ci  EXPECT_TRUE(child_loop_1.IsNested());
180fd4e5da5Sopenharmony_ci  EXPECT_EQ(child_loop_1.GetDepth(), 2u);
181fd4e5da5Sopenharmony_ci  EXPECT_EQ(std::distance(child_loop_1.begin(), child_loop_1.end()), 0u);
182fd4e5da5Sopenharmony_ci  EXPECT_EQ(child_loop_1.GetHeaderBlock(), spvtest::GetBasicBlock(f, 28));
183fd4e5da5Sopenharmony_ci  EXPECT_EQ(child_loop_1.GetLatchBlock(), spvtest::GetBasicBlock(f, 30));
184fd4e5da5Sopenharmony_ci  EXPECT_EQ(child_loop_1.GetMergeBlock(), spvtest::GetBasicBlock(f, 29));
185fd4e5da5Sopenharmony_ci
186fd4e5da5Sopenharmony_ci  Loop& child_loop_2 = *ld[37];
187fd4e5da5Sopenharmony_ci  EXPECT_FALSE(child_loop_2.HasNestedLoops());
188fd4e5da5Sopenharmony_ci  EXPECT_TRUE(child_loop_2.IsNested());
189fd4e5da5Sopenharmony_ci  EXPECT_EQ(child_loop_2.GetDepth(), 2u);
190fd4e5da5Sopenharmony_ci  EXPECT_EQ(std::distance(child_loop_2.begin(), child_loop_2.end()), 0u);
191fd4e5da5Sopenharmony_ci  EXPECT_EQ(child_loop_2.GetHeaderBlock(), spvtest::GetBasicBlock(f, 37));
192fd4e5da5Sopenharmony_ci  EXPECT_EQ(child_loop_2.GetLatchBlock(), spvtest::GetBasicBlock(f, 39));
193fd4e5da5Sopenharmony_ci  EXPECT_EQ(child_loop_2.GetMergeBlock(), spvtest::GetBasicBlock(f, 38));
194fd4e5da5Sopenharmony_ci}
195fd4e5da5Sopenharmony_ci
196fd4e5da5Sopenharmony_cistatic void CheckLoopBlocks(Loop* loop,
197fd4e5da5Sopenharmony_ci                            std::unordered_set<uint32_t>* expected_ids) {
198fd4e5da5Sopenharmony_ci  SCOPED_TRACE("Check loop " + std::to_string(loop->GetHeaderBlock()->id()));
199fd4e5da5Sopenharmony_ci  for (uint32_t bb_id : loop->GetBlocks()) {
200fd4e5da5Sopenharmony_ci    EXPECT_EQ(expected_ids->count(bb_id), 1u);
201fd4e5da5Sopenharmony_ci    expected_ids->erase(bb_id);
202fd4e5da5Sopenharmony_ci  }
203fd4e5da5Sopenharmony_ci  EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
204fd4e5da5Sopenharmony_ci  EXPECT_EQ(expected_ids->size(), 0u);
205fd4e5da5Sopenharmony_ci}
206fd4e5da5Sopenharmony_ci
207fd4e5da5Sopenharmony_ci/*
208fd4e5da5Sopenharmony_ciGenerated from the following GLSL
209fd4e5da5Sopenharmony_ci#version 330 core
210fd4e5da5Sopenharmony_cilayout(location = 0) out vec4 c;
211fd4e5da5Sopenharmony_civoid main() {
212fd4e5da5Sopenharmony_ci  int i = 0;
213fd4e5da5Sopenharmony_ci  for (; i < 10; ++i) {
214fd4e5da5Sopenharmony_ci    for (int j = 0; j < 11; ++j) {
215fd4e5da5Sopenharmony_ci      if (j < 5) {
216fd4e5da5Sopenharmony_ci        for (int k = 0; k < 12; ++k) {}
217fd4e5da5Sopenharmony_ci      }
218fd4e5da5Sopenharmony_ci      else {}
219fd4e5da5Sopenharmony_ci      for (int k = 0; k < 12; ++k) {}
220fd4e5da5Sopenharmony_ci    }
221fd4e5da5Sopenharmony_ci  }
222fd4e5da5Sopenharmony_ci}*/
223fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, TripleNestedLoop) {
224fd4e5da5Sopenharmony_ci  const std::string text = R"(
225fd4e5da5Sopenharmony_ci               OpCapability Shader
226fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
227fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
228fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main" %3
229fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
230fd4e5da5Sopenharmony_ci               OpSource GLSL 330
231fd4e5da5Sopenharmony_ci               OpName %2 "main"
232fd4e5da5Sopenharmony_ci               OpName %4 "i"
233fd4e5da5Sopenharmony_ci               OpName %5 "j"
234fd4e5da5Sopenharmony_ci               OpName %6 "k"
235fd4e5da5Sopenharmony_ci               OpName %7 "k"
236fd4e5da5Sopenharmony_ci               OpName %3 "c"
237fd4e5da5Sopenharmony_ci               OpDecorate %3 Location 0
238fd4e5da5Sopenharmony_ci          %8 = OpTypeVoid
239fd4e5da5Sopenharmony_ci          %9 = OpTypeFunction %8
240fd4e5da5Sopenharmony_ci         %10 = OpTypeInt 32 1
241fd4e5da5Sopenharmony_ci         %11 = OpTypePointer Function %10
242fd4e5da5Sopenharmony_ci         %12 = OpConstant %10 0
243fd4e5da5Sopenharmony_ci         %13 = OpConstant %10 10
244fd4e5da5Sopenharmony_ci         %14 = OpTypeBool
245fd4e5da5Sopenharmony_ci         %15 = OpConstant %10 11
246fd4e5da5Sopenharmony_ci         %16 = OpConstant %10 5
247fd4e5da5Sopenharmony_ci         %17 = OpConstant %10 12
248fd4e5da5Sopenharmony_ci         %18 = OpConstant %10 1
249fd4e5da5Sopenharmony_ci         %19 = OpTypeFloat 32
250fd4e5da5Sopenharmony_ci         %20 = OpTypeVector %19 4
251fd4e5da5Sopenharmony_ci         %21 = OpTypePointer Output %20
252fd4e5da5Sopenharmony_ci          %3 = OpVariable %21 Output
253fd4e5da5Sopenharmony_ci          %2 = OpFunction %8 None %9
254fd4e5da5Sopenharmony_ci         %22 = OpLabel
255fd4e5da5Sopenharmony_ci          %4 = OpVariable %11 Function
256fd4e5da5Sopenharmony_ci          %5 = OpVariable %11 Function
257fd4e5da5Sopenharmony_ci          %6 = OpVariable %11 Function
258fd4e5da5Sopenharmony_ci          %7 = OpVariable %11 Function
259fd4e5da5Sopenharmony_ci               OpStore %4 %12
260fd4e5da5Sopenharmony_ci               OpBranch %23
261fd4e5da5Sopenharmony_ci         %23 = OpLabel
262fd4e5da5Sopenharmony_ci               OpLoopMerge %24 %25 None
263fd4e5da5Sopenharmony_ci               OpBranch %26
264fd4e5da5Sopenharmony_ci         %26 = OpLabel
265fd4e5da5Sopenharmony_ci         %27 = OpLoad %10 %4
266fd4e5da5Sopenharmony_ci         %28 = OpSLessThan %14 %27 %13
267fd4e5da5Sopenharmony_ci               OpBranchConditional %28 %29 %24
268fd4e5da5Sopenharmony_ci         %29 = OpLabel
269fd4e5da5Sopenharmony_ci               OpStore %5 %12
270fd4e5da5Sopenharmony_ci               OpBranch %30
271fd4e5da5Sopenharmony_ci         %30 = OpLabel
272fd4e5da5Sopenharmony_ci               OpLoopMerge %31 %32 None
273fd4e5da5Sopenharmony_ci               OpBranch %33
274fd4e5da5Sopenharmony_ci         %33 = OpLabel
275fd4e5da5Sopenharmony_ci         %34 = OpLoad %10 %5
276fd4e5da5Sopenharmony_ci         %35 = OpSLessThan %14 %34 %15
277fd4e5da5Sopenharmony_ci               OpBranchConditional %35 %36 %31
278fd4e5da5Sopenharmony_ci         %36 = OpLabel
279fd4e5da5Sopenharmony_ci         %37 = OpLoad %10 %5
280fd4e5da5Sopenharmony_ci         %38 = OpSLessThan %14 %37 %16
281fd4e5da5Sopenharmony_ci               OpSelectionMerge %39 None
282fd4e5da5Sopenharmony_ci               OpBranchConditional %38 %40 %39
283fd4e5da5Sopenharmony_ci         %40 = OpLabel
284fd4e5da5Sopenharmony_ci               OpStore %6 %12
285fd4e5da5Sopenharmony_ci               OpBranch %41
286fd4e5da5Sopenharmony_ci         %41 = OpLabel
287fd4e5da5Sopenharmony_ci               OpLoopMerge %42 %43 None
288fd4e5da5Sopenharmony_ci               OpBranch %44
289fd4e5da5Sopenharmony_ci         %44 = OpLabel
290fd4e5da5Sopenharmony_ci         %45 = OpLoad %10 %6
291fd4e5da5Sopenharmony_ci         %46 = OpSLessThan %14 %45 %17
292fd4e5da5Sopenharmony_ci               OpBranchConditional %46 %47 %42
293fd4e5da5Sopenharmony_ci         %47 = OpLabel
294fd4e5da5Sopenharmony_ci               OpBranch %43
295fd4e5da5Sopenharmony_ci         %43 = OpLabel
296fd4e5da5Sopenharmony_ci         %48 = OpLoad %10 %6
297fd4e5da5Sopenharmony_ci         %49 = OpIAdd %10 %48 %18
298fd4e5da5Sopenharmony_ci               OpStore %6 %49
299fd4e5da5Sopenharmony_ci               OpBranch %41
300fd4e5da5Sopenharmony_ci         %42 = OpLabel
301fd4e5da5Sopenharmony_ci               OpBranch %39
302fd4e5da5Sopenharmony_ci         %39 = OpLabel
303fd4e5da5Sopenharmony_ci               OpStore %7 %12
304fd4e5da5Sopenharmony_ci               OpBranch %50
305fd4e5da5Sopenharmony_ci         %50 = OpLabel
306fd4e5da5Sopenharmony_ci               OpLoopMerge %51 %52 None
307fd4e5da5Sopenharmony_ci               OpBranch %53
308fd4e5da5Sopenharmony_ci         %53 = OpLabel
309fd4e5da5Sopenharmony_ci         %54 = OpLoad %10 %7
310fd4e5da5Sopenharmony_ci         %55 = OpSLessThan %14 %54 %17
311fd4e5da5Sopenharmony_ci               OpBranchConditional %55 %56 %51
312fd4e5da5Sopenharmony_ci         %56 = OpLabel
313fd4e5da5Sopenharmony_ci               OpBranch %52
314fd4e5da5Sopenharmony_ci         %52 = OpLabel
315fd4e5da5Sopenharmony_ci         %57 = OpLoad %10 %7
316fd4e5da5Sopenharmony_ci         %58 = OpIAdd %10 %57 %18
317fd4e5da5Sopenharmony_ci               OpStore %7 %58
318fd4e5da5Sopenharmony_ci               OpBranch %50
319fd4e5da5Sopenharmony_ci         %51 = OpLabel
320fd4e5da5Sopenharmony_ci               OpBranch %32
321fd4e5da5Sopenharmony_ci         %32 = OpLabel
322fd4e5da5Sopenharmony_ci         %59 = OpLoad %10 %5
323fd4e5da5Sopenharmony_ci         %60 = OpIAdd %10 %59 %18
324fd4e5da5Sopenharmony_ci               OpStore %5 %60
325fd4e5da5Sopenharmony_ci               OpBranch %30
326fd4e5da5Sopenharmony_ci         %31 = OpLabel
327fd4e5da5Sopenharmony_ci               OpBranch %25
328fd4e5da5Sopenharmony_ci         %25 = OpLabel
329fd4e5da5Sopenharmony_ci         %61 = OpLoad %10 %4
330fd4e5da5Sopenharmony_ci         %62 = OpIAdd %10 %61 %18
331fd4e5da5Sopenharmony_ci               OpStore %4 %62
332fd4e5da5Sopenharmony_ci               OpBranch %23
333fd4e5da5Sopenharmony_ci         %24 = OpLabel
334fd4e5da5Sopenharmony_ci               OpReturn
335fd4e5da5Sopenharmony_ci               OpFunctionEnd
336fd4e5da5Sopenharmony_ci  )";
337fd4e5da5Sopenharmony_ci  // clang-format on
338fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
339fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
340fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
341fd4e5da5Sopenharmony_ci  Module* module = context->module();
342fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
343fd4e5da5Sopenharmony_ci                             << text << std::endl;
344fd4e5da5Sopenharmony_ci  const Function* f = spvtest::GetFunction(module, 2);
345fd4e5da5Sopenharmony_ci  LoopDescriptor& ld = *context->GetLoopDescriptor(f);
346fd4e5da5Sopenharmony_ci
347fd4e5da5Sopenharmony_ci  EXPECT_EQ(ld.NumLoops(), 4u);
348fd4e5da5Sopenharmony_ci
349fd4e5da5Sopenharmony_ci  // Invalid basic block id.
350fd4e5da5Sopenharmony_ci  EXPECT_EQ(ld[0u], nullptr);
351fd4e5da5Sopenharmony_ci  // Not in a loop.
352fd4e5da5Sopenharmony_ci  EXPECT_EQ(ld[22], nullptr);
353fd4e5da5Sopenharmony_ci
354fd4e5da5Sopenharmony_ci  // Check that we can map basic block to the correct loop.
355fd4e5da5Sopenharmony_ci  // The following block ids do not belong to a loop.
356fd4e5da5Sopenharmony_ci  for (uint32_t bb_id : {22, 24}) EXPECT_EQ(ld[bb_id], nullptr);
357fd4e5da5Sopenharmony_ci
358fd4e5da5Sopenharmony_ci  {
359fd4e5da5Sopenharmony_ci    std::unordered_set<uint32_t> basic_block_in_loop = {
360fd4e5da5Sopenharmony_ci        {23, 26, 29, 30, 33, 36, 40, 41, 44, 47, 43,
361fd4e5da5Sopenharmony_ci         42, 39, 50, 53, 56, 52, 51, 32, 31, 25}};
362fd4e5da5Sopenharmony_ci    Loop* loop = ld[23];
363fd4e5da5Sopenharmony_ci    CheckLoopBlocks(loop, &basic_block_in_loop);
364fd4e5da5Sopenharmony_ci
365fd4e5da5Sopenharmony_ci    EXPECT_TRUE(loop->HasNestedLoops());
366fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop->IsNested());
367fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetDepth(), 1u);
368fd4e5da5Sopenharmony_ci    EXPECT_EQ(std::distance(loop->begin(), loop->end()), 1u);
369fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 22));
370fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 23));
371fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 25));
372fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 24));
373fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
374fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock()));
375fd4e5da5Sopenharmony_ci  }
376fd4e5da5Sopenharmony_ci
377fd4e5da5Sopenharmony_ci  {
378fd4e5da5Sopenharmony_ci    std::unordered_set<uint32_t> basic_block_in_loop = {
379fd4e5da5Sopenharmony_ci        {30, 33, 36, 40, 41, 44, 47, 43, 42, 39, 50, 53, 56, 52, 51, 32}};
380fd4e5da5Sopenharmony_ci    Loop* loop = ld[30];
381fd4e5da5Sopenharmony_ci    CheckLoopBlocks(loop, &basic_block_in_loop);
382fd4e5da5Sopenharmony_ci
383fd4e5da5Sopenharmony_ci    EXPECT_TRUE(loop->HasNestedLoops());
384fd4e5da5Sopenharmony_ci    EXPECT_TRUE(loop->IsNested());
385fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetDepth(), 2u);
386fd4e5da5Sopenharmony_ci    EXPECT_EQ(std::distance(loop->begin(), loop->end()), 2u);
387fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 29));
388fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 30));
389fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 32));
390fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 31));
391fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
392fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock()));
393fd4e5da5Sopenharmony_ci  }
394fd4e5da5Sopenharmony_ci
395fd4e5da5Sopenharmony_ci  {
396fd4e5da5Sopenharmony_ci    std::unordered_set<uint32_t> basic_block_in_loop = {{41, 44, 47, 43}};
397fd4e5da5Sopenharmony_ci    Loop* loop = ld[41];
398fd4e5da5Sopenharmony_ci    CheckLoopBlocks(loop, &basic_block_in_loop);
399fd4e5da5Sopenharmony_ci
400fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop->HasNestedLoops());
401fd4e5da5Sopenharmony_ci    EXPECT_TRUE(loop->IsNested());
402fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetDepth(), 3u);
403fd4e5da5Sopenharmony_ci    EXPECT_EQ(std::distance(loop->begin(), loop->end()), 0u);
404fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 40));
405fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 41));
406fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 43));
407fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 42));
408fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
409fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock()));
410fd4e5da5Sopenharmony_ci  }
411fd4e5da5Sopenharmony_ci
412fd4e5da5Sopenharmony_ci  {
413fd4e5da5Sopenharmony_ci    std::unordered_set<uint32_t> basic_block_in_loop = {{50, 53, 56, 52}};
414fd4e5da5Sopenharmony_ci    Loop* loop = ld[50];
415fd4e5da5Sopenharmony_ci    CheckLoopBlocks(loop, &basic_block_in_loop);
416fd4e5da5Sopenharmony_ci
417fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop->HasNestedLoops());
418fd4e5da5Sopenharmony_ci    EXPECT_TRUE(loop->IsNested());
419fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetDepth(), 3u);
420fd4e5da5Sopenharmony_ci    EXPECT_EQ(std::distance(loop->begin(), loop->end()), 0u);
421fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetPreHeaderBlock(), spvtest::GetBasicBlock(f, 39));
422fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetHeaderBlock(), spvtest::GetBasicBlock(f, 50));
423fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetLatchBlock(), spvtest::GetBasicBlock(f, 52));
424fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop->GetMergeBlock(), spvtest::GetBasicBlock(f, 51));
425fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop->IsInsideLoop(loop->GetMergeBlock()));
426fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop->IsInsideLoop(loop->GetPreHeaderBlock()));
427fd4e5da5Sopenharmony_ci  }
428fd4e5da5Sopenharmony_ci
429fd4e5da5Sopenharmony_ci  // Make sure LoopDescriptor gives us the inner most loop when we query for
430fd4e5da5Sopenharmony_ci  // loops.
431fd4e5da5Sopenharmony_ci  for (const BasicBlock& bb : *f) {
432fd4e5da5Sopenharmony_ci    if (Loop* loop = ld[&bb]) {
433fd4e5da5Sopenharmony_ci      for (Loop& sub_loop :
434fd4e5da5Sopenharmony_ci           make_range(++TreeDFIterator<Loop>(loop), TreeDFIterator<Loop>())) {
435fd4e5da5Sopenharmony_ci        EXPECT_FALSE(sub_loop.IsInsideLoop(bb.id()));
436fd4e5da5Sopenharmony_ci      }
437fd4e5da5Sopenharmony_ci    }
438fd4e5da5Sopenharmony_ci  }
439fd4e5da5Sopenharmony_ci}
440fd4e5da5Sopenharmony_ci
441fd4e5da5Sopenharmony_ci/*
442fd4e5da5Sopenharmony_ciGenerated from the following GLSL
443fd4e5da5Sopenharmony_ci#version 330 core
444fd4e5da5Sopenharmony_cilayout(location = 0) out vec4 c;
445fd4e5da5Sopenharmony_civoid main() {
446fd4e5da5Sopenharmony_ci  for (int i = 0; i < 10; ++i) {
447fd4e5da5Sopenharmony_ci    for (int j = 0; j < 11; ++j) {
448fd4e5da5Sopenharmony_ci      for (int k = 0; k < 11; ++k) {}
449fd4e5da5Sopenharmony_ci    }
450fd4e5da5Sopenharmony_ci    for (int k = 0; k < 12; ++k) {}
451fd4e5da5Sopenharmony_ci  }
452fd4e5da5Sopenharmony_ci}
453fd4e5da5Sopenharmony_ci*/
454fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, LoopParentTest) {
455fd4e5da5Sopenharmony_ci  const std::string text = R"(
456fd4e5da5Sopenharmony_ci               OpCapability Shader
457fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
458fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
459fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main" %3
460fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
461fd4e5da5Sopenharmony_ci               OpSource GLSL 330
462fd4e5da5Sopenharmony_ci               OpName %2 "main"
463fd4e5da5Sopenharmony_ci               OpName %4 "i"
464fd4e5da5Sopenharmony_ci               OpName %5 "j"
465fd4e5da5Sopenharmony_ci               OpName %6 "k"
466fd4e5da5Sopenharmony_ci               OpName %7 "k"
467fd4e5da5Sopenharmony_ci               OpName %3 "c"
468fd4e5da5Sopenharmony_ci               OpDecorate %3 Location 0
469fd4e5da5Sopenharmony_ci          %8 = OpTypeVoid
470fd4e5da5Sopenharmony_ci          %9 = OpTypeFunction %8
471fd4e5da5Sopenharmony_ci         %10 = OpTypeInt 32 1
472fd4e5da5Sopenharmony_ci         %11 = OpTypePointer Function %10
473fd4e5da5Sopenharmony_ci         %12 = OpConstant %10 0
474fd4e5da5Sopenharmony_ci         %13 = OpConstant %10 10
475fd4e5da5Sopenharmony_ci         %14 = OpTypeBool
476fd4e5da5Sopenharmony_ci         %15 = OpConstant %10 11
477fd4e5da5Sopenharmony_ci         %16 = OpConstant %10 1
478fd4e5da5Sopenharmony_ci         %17 = OpConstant %10 12
479fd4e5da5Sopenharmony_ci         %18 = OpTypeFloat 32
480fd4e5da5Sopenharmony_ci         %19 = OpTypeVector %18 4
481fd4e5da5Sopenharmony_ci         %20 = OpTypePointer Output %19
482fd4e5da5Sopenharmony_ci          %3 = OpVariable %20 Output
483fd4e5da5Sopenharmony_ci          %2 = OpFunction %8 None %9
484fd4e5da5Sopenharmony_ci         %21 = OpLabel
485fd4e5da5Sopenharmony_ci          %4 = OpVariable %11 Function
486fd4e5da5Sopenharmony_ci          %5 = OpVariable %11 Function
487fd4e5da5Sopenharmony_ci          %6 = OpVariable %11 Function
488fd4e5da5Sopenharmony_ci          %7 = OpVariable %11 Function
489fd4e5da5Sopenharmony_ci               OpStore %4 %12
490fd4e5da5Sopenharmony_ci               OpBranch %22
491fd4e5da5Sopenharmony_ci         %22 = OpLabel
492fd4e5da5Sopenharmony_ci               OpLoopMerge %23 %24 None
493fd4e5da5Sopenharmony_ci               OpBranch %25
494fd4e5da5Sopenharmony_ci         %25 = OpLabel
495fd4e5da5Sopenharmony_ci         %26 = OpLoad %10 %4
496fd4e5da5Sopenharmony_ci         %27 = OpSLessThan %14 %26 %13
497fd4e5da5Sopenharmony_ci               OpBranchConditional %27 %28 %23
498fd4e5da5Sopenharmony_ci         %28 = OpLabel
499fd4e5da5Sopenharmony_ci               OpStore %5 %12
500fd4e5da5Sopenharmony_ci               OpBranch %29
501fd4e5da5Sopenharmony_ci         %29 = OpLabel
502fd4e5da5Sopenharmony_ci               OpLoopMerge %30 %31 None
503fd4e5da5Sopenharmony_ci               OpBranch %32
504fd4e5da5Sopenharmony_ci         %32 = OpLabel
505fd4e5da5Sopenharmony_ci         %33 = OpLoad %10 %5
506fd4e5da5Sopenharmony_ci         %34 = OpSLessThan %14 %33 %15
507fd4e5da5Sopenharmony_ci               OpBranchConditional %34 %35 %30
508fd4e5da5Sopenharmony_ci         %35 = OpLabel
509fd4e5da5Sopenharmony_ci               OpStore %6 %12
510fd4e5da5Sopenharmony_ci               OpBranch %36
511fd4e5da5Sopenharmony_ci         %36 = OpLabel
512fd4e5da5Sopenharmony_ci               OpLoopMerge %37 %38 None
513fd4e5da5Sopenharmony_ci               OpBranch %39
514fd4e5da5Sopenharmony_ci         %39 = OpLabel
515fd4e5da5Sopenharmony_ci         %40 = OpLoad %10 %6
516fd4e5da5Sopenharmony_ci         %41 = OpSLessThan %14 %40 %15
517fd4e5da5Sopenharmony_ci               OpBranchConditional %41 %42 %37
518fd4e5da5Sopenharmony_ci         %42 = OpLabel
519fd4e5da5Sopenharmony_ci               OpBranch %38
520fd4e5da5Sopenharmony_ci         %38 = OpLabel
521fd4e5da5Sopenharmony_ci         %43 = OpLoad %10 %6
522fd4e5da5Sopenharmony_ci         %44 = OpIAdd %10 %43 %16
523fd4e5da5Sopenharmony_ci               OpStore %6 %44
524fd4e5da5Sopenharmony_ci               OpBranch %36
525fd4e5da5Sopenharmony_ci         %37 = OpLabel
526fd4e5da5Sopenharmony_ci               OpBranch %31
527fd4e5da5Sopenharmony_ci         %31 = OpLabel
528fd4e5da5Sopenharmony_ci         %45 = OpLoad %10 %5
529fd4e5da5Sopenharmony_ci         %46 = OpIAdd %10 %45 %16
530fd4e5da5Sopenharmony_ci               OpStore %5 %46
531fd4e5da5Sopenharmony_ci               OpBranch %29
532fd4e5da5Sopenharmony_ci         %30 = OpLabel
533fd4e5da5Sopenharmony_ci               OpStore %7 %12
534fd4e5da5Sopenharmony_ci               OpBranch %47
535fd4e5da5Sopenharmony_ci         %47 = OpLabel
536fd4e5da5Sopenharmony_ci               OpLoopMerge %48 %49 None
537fd4e5da5Sopenharmony_ci               OpBranch %50
538fd4e5da5Sopenharmony_ci         %50 = OpLabel
539fd4e5da5Sopenharmony_ci         %51 = OpLoad %10 %7
540fd4e5da5Sopenharmony_ci         %52 = OpSLessThan %14 %51 %17
541fd4e5da5Sopenharmony_ci               OpBranchConditional %52 %53 %48
542fd4e5da5Sopenharmony_ci         %53 = OpLabel
543fd4e5da5Sopenharmony_ci               OpBranch %49
544fd4e5da5Sopenharmony_ci         %49 = OpLabel
545fd4e5da5Sopenharmony_ci         %54 = OpLoad %10 %7
546fd4e5da5Sopenharmony_ci         %55 = OpIAdd %10 %54 %16
547fd4e5da5Sopenharmony_ci               OpStore %7 %55
548fd4e5da5Sopenharmony_ci               OpBranch %47
549fd4e5da5Sopenharmony_ci         %48 = OpLabel
550fd4e5da5Sopenharmony_ci               OpBranch %24
551fd4e5da5Sopenharmony_ci         %24 = OpLabel
552fd4e5da5Sopenharmony_ci         %56 = OpLoad %10 %4
553fd4e5da5Sopenharmony_ci         %57 = OpIAdd %10 %56 %16
554fd4e5da5Sopenharmony_ci               OpStore %4 %57
555fd4e5da5Sopenharmony_ci               OpBranch %22
556fd4e5da5Sopenharmony_ci         %23 = OpLabel
557fd4e5da5Sopenharmony_ci               OpReturn
558fd4e5da5Sopenharmony_ci               OpFunctionEnd
559fd4e5da5Sopenharmony_ci  )";
560fd4e5da5Sopenharmony_ci  // clang-format on
561fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
562fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
563fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
564fd4e5da5Sopenharmony_ci  Module* module = context->module();
565fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
566fd4e5da5Sopenharmony_ci                             << text << std::endl;
567fd4e5da5Sopenharmony_ci  const Function* f = spvtest::GetFunction(module, 2);
568fd4e5da5Sopenharmony_ci  LoopDescriptor& ld = *context->GetLoopDescriptor(f);
569fd4e5da5Sopenharmony_ci
570fd4e5da5Sopenharmony_ci  EXPECT_EQ(ld.NumLoops(), 4u);
571fd4e5da5Sopenharmony_ci
572fd4e5da5Sopenharmony_ci  {
573fd4e5da5Sopenharmony_ci    Loop& loop = *ld[22];
574fd4e5da5Sopenharmony_ci    EXPECT_TRUE(loop.HasNestedLoops());
575fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop.IsNested());
576fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop.GetDepth(), 1u);
577fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop.GetParent(), nullptr);
578fd4e5da5Sopenharmony_ci  }
579fd4e5da5Sopenharmony_ci
580fd4e5da5Sopenharmony_ci  {
581fd4e5da5Sopenharmony_ci    Loop& loop = *ld[29];
582fd4e5da5Sopenharmony_ci    EXPECT_TRUE(loop.HasNestedLoops());
583fd4e5da5Sopenharmony_ci    EXPECT_TRUE(loop.IsNested());
584fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop.GetDepth(), 2u);
585fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop.GetParent(), ld[22]);
586fd4e5da5Sopenharmony_ci  }
587fd4e5da5Sopenharmony_ci
588fd4e5da5Sopenharmony_ci  {
589fd4e5da5Sopenharmony_ci    Loop& loop = *ld[36];
590fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop.HasNestedLoops());
591fd4e5da5Sopenharmony_ci    EXPECT_TRUE(loop.IsNested());
592fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop.GetDepth(), 3u);
593fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop.GetParent(), ld[29]);
594fd4e5da5Sopenharmony_ci  }
595fd4e5da5Sopenharmony_ci
596fd4e5da5Sopenharmony_ci  {
597fd4e5da5Sopenharmony_ci    Loop& loop = *ld[47];
598fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop.HasNestedLoops());
599fd4e5da5Sopenharmony_ci    EXPECT_TRUE(loop.IsNested());
600fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop.GetDepth(), 2u);
601fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop.GetParent(), ld[22]);
602fd4e5da5Sopenharmony_ci  }
603fd4e5da5Sopenharmony_ci}
604fd4e5da5Sopenharmony_ci
605fd4e5da5Sopenharmony_ci/*
606fd4e5da5Sopenharmony_ciGenerated from the following GLSL + --eliminate-local-multi-store
607fd4e5da5Sopenharmony_ciThe preheader of loop %33 and %41 were removed as well.
608fd4e5da5Sopenharmony_ci
609fd4e5da5Sopenharmony_ci#version 330 core
610fd4e5da5Sopenharmony_civoid main() {
611fd4e5da5Sopenharmony_ci  int a = 0;
612fd4e5da5Sopenharmony_ci  for (int i = 0; i < 10; ++i) {
613fd4e5da5Sopenharmony_ci    if (i == 0) {
614fd4e5da5Sopenharmony_ci      a = 1;
615fd4e5da5Sopenharmony_ci    } else {
616fd4e5da5Sopenharmony_ci      a = 2;
617fd4e5da5Sopenharmony_ci    }
618fd4e5da5Sopenharmony_ci    for (int j = 0; j < 11; ++j) {
619fd4e5da5Sopenharmony_ci      a++;
620fd4e5da5Sopenharmony_ci    }
621fd4e5da5Sopenharmony_ci  }
622fd4e5da5Sopenharmony_ci  for (int k = 0; k < 12; ++k) {}
623fd4e5da5Sopenharmony_ci}
624fd4e5da5Sopenharmony_ci*/
625fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, CreatePreheaderTest) {
626fd4e5da5Sopenharmony_ci  const std::string text = R"(
627fd4e5da5Sopenharmony_ci               OpCapability Shader
628fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
629fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
630fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %2 "main"
631fd4e5da5Sopenharmony_ci               OpExecutionMode %2 OriginUpperLeft
632fd4e5da5Sopenharmony_ci               OpSource GLSL 330
633fd4e5da5Sopenharmony_ci               OpName %2 "main"
634fd4e5da5Sopenharmony_ci          %3 = OpTypeVoid
635fd4e5da5Sopenharmony_ci          %4 = OpTypeFunction %3
636fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 1
637fd4e5da5Sopenharmony_ci          %6 = OpTypePointer Function %5
638fd4e5da5Sopenharmony_ci          %7 = OpConstant %5 0
639fd4e5da5Sopenharmony_ci          %8 = OpConstant %5 10
640fd4e5da5Sopenharmony_ci          %9 = OpTypeBool
641fd4e5da5Sopenharmony_ci         %10 = OpConstant %5 1
642fd4e5da5Sopenharmony_ci         %11 = OpConstant %5 2
643fd4e5da5Sopenharmony_ci         %12 = OpConstant %5 11
644fd4e5da5Sopenharmony_ci         %13 = OpConstant %5 12
645fd4e5da5Sopenharmony_ci         %14 = OpUndef %5
646fd4e5da5Sopenharmony_ci          %2 = OpFunction %3 None %4
647fd4e5da5Sopenharmony_ci         %15 = OpLabel
648fd4e5da5Sopenharmony_ci               OpBranch %16
649fd4e5da5Sopenharmony_ci         %16 = OpLabel
650fd4e5da5Sopenharmony_ci         %17 = OpPhi %5 %7 %15 %18 %19
651fd4e5da5Sopenharmony_ci         %20 = OpPhi %5 %7 %15 %21 %19
652fd4e5da5Sopenharmony_ci         %22 = OpPhi %5 %14 %15 %23 %19
653fd4e5da5Sopenharmony_ci               OpLoopMerge %41 %19 None
654fd4e5da5Sopenharmony_ci               OpBranch %25
655fd4e5da5Sopenharmony_ci         %25 = OpLabel
656fd4e5da5Sopenharmony_ci         %26 = OpSLessThan %9 %20 %8
657fd4e5da5Sopenharmony_ci               OpBranchConditional %26 %27 %41
658fd4e5da5Sopenharmony_ci         %27 = OpLabel
659fd4e5da5Sopenharmony_ci         %28 = OpIEqual %9 %20 %7
660fd4e5da5Sopenharmony_ci               OpSelectionMerge %33 None
661fd4e5da5Sopenharmony_ci               OpBranchConditional %28 %30 %31
662fd4e5da5Sopenharmony_ci         %30 = OpLabel
663fd4e5da5Sopenharmony_ci               OpBranch %33
664fd4e5da5Sopenharmony_ci         %31 = OpLabel
665fd4e5da5Sopenharmony_ci               OpBranch %33
666fd4e5da5Sopenharmony_ci         %33 = OpLabel
667fd4e5da5Sopenharmony_ci         %18 = OpPhi %5 %10 %30 %11 %31 %34 %35
668fd4e5da5Sopenharmony_ci         %23 = OpPhi %5 %7 %30 %7 %31 %36 %35
669fd4e5da5Sopenharmony_ci               OpLoopMerge %37 %35 None
670fd4e5da5Sopenharmony_ci               OpBranch %38
671fd4e5da5Sopenharmony_ci         %38 = OpLabel
672fd4e5da5Sopenharmony_ci         %39 = OpSLessThan %9 %23 %12
673fd4e5da5Sopenharmony_ci               OpBranchConditional %39 %40 %37
674fd4e5da5Sopenharmony_ci         %40 = OpLabel
675fd4e5da5Sopenharmony_ci         %34 = OpIAdd %5 %18 %10
676fd4e5da5Sopenharmony_ci               OpBranch %35
677fd4e5da5Sopenharmony_ci         %35 = OpLabel
678fd4e5da5Sopenharmony_ci         %36 = OpIAdd %5 %23 %10
679fd4e5da5Sopenharmony_ci               OpBranch %33
680fd4e5da5Sopenharmony_ci         %37 = OpLabel
681fd4e5da5Sopenharmony_ci               OpBranch %19
682fd4e5da5Sopenharmony_ci         %19 = OpLabel
683fd4e5da5Sopenharmony_ci         %21 = OpIAdd %5 %20 %10
684fd4e5da5Sopenharmony_ci               OpBranch %16
685fd4e5da5Sopenharmony_ci         %41 = OpLabel
686fd4e5da5Sopenharmony_ci         %42 = OpPhi %5 %7 %25 %43 %44
687fd4e5da5Sopenharmony_ci               OpLoopMerge %45 %44 None
688fd4e5da5Sopenharmony_ci               OpBranch %46
689fd4e5da5Sopenharmony_ci         %46 = OpLabel
690fd4e5da5Sopenharmony_ci         %47 = OpSLessThan %9 %42 %13
691fd4e5da5Sopenharmony_ci               OpBranchConditional %47 %48 %45
692fd4e5da5Sopenharmony_ci         %48 = OpLabel
693fd4e5da5Sopenharmony_ci               OpBranch %44
694fd4e5da5Sopenharmony_ci         %44 = OpLabel
695fd4e5da5Sopenharmony_ci         %43 = OpIAdd %5 %42 %10
696fd4e5da5Sopenharmony_ci               OpBranch %41
697fd4e5da5Sopenharmony_ci         %45 = OpLabel
698fd4e5da5Sopenharmony_ci               OpReturn
699fd4e5da5Sopenharmony_ci               OpFunctionEnd
700fd4e5da5Sopenharmony_ci  )";
701fd4e5da5Sopenharmony_ci  // clang-format on
702fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
703fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, text,
704fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
705fd4e5da5Sopenharmony_ci  Module* module = context->module();
706fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
707fd4e5da5Sopenharmony_ci                             << text << std::endl;
708fd4e5da5Sopenharmony_ci  const Function* f = spvtest::GetFunction(module, 2);
709fd4e5da5Sopenharmony_ci  LoopDescriptor& ld = *context->GetLoopDescriptor(f);
710fd4e5da5Sopenharmony_ci  // No invalidation of the cfg should occur during this test.
711fd4e5da5Sopenharmony_ci  CFG* cfg = context->cfg();
712fd4e5da5Sopenharmony_ci
713fd4e5da5Sopenharmony_ci  EXPECT_EQ(ld.NumLoops(), 3u);
714fd4e5da5Sopenharmony_ci
715fd4e5da5Sopenharmony_ci  {
716fd4e5da5Sopenharmony_ci    Loop& loop = *ld[16];
717fd4e5da5Sopenharmony_ci    EXPECT_TRUE(loop.HasNestedLoops());
718fd4e5da5Sopenharmony_ci    EXPECT_FALSE(loop.IsNested());
719fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop.GetDepth(), 1u);
720fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop.GetParent(), nullptr);
721fd4e5da5Sopenharmony_ci  }
722fd4e5da5Sopenharmony_ci
723fd4e5da5Sopenharmony_ci  {
724fd4e5da5Sopenharmony_ci    Loop& loop = *ld[33];
725fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop.GetPreHeaderBlock(), nullptr);
726fd4e5da5Sopenharmony_ci    EXPECT_NE(loop.GetOrCreatePreHeaderBlock(), nullptr);
727fd4e5da5Sopenharmony_ci    // Make sure the loop descriptor was properly updated.
728fd4e5da5Sopenharmony_ci    EXPECT_EQ(ld[loop.GetPreHeaderBlock()], ld[16]);
729fd4e5da5Sopenharmony_ci    {
730fd4e5da5Sopenharmony_ci      const std::vector<uint32_t>& preds =
731fd4e5da5Sopenharmony_ci          cfg->preds(loop.GetPreHeaderBlock()->id());
732fd4e5da5Sopenharmony_ci      std::unordered_set<uint32_t> pred_set(preds.begin(), preds.end());
733fd4e5da5Sopenharmony_ci      EXPECT_EQ(pred_set.size(), 2u);
734fd4e5da5Sopenharmony_ci      EXPECT_TRUE(pred_set.count(30));
735fd4e5da5Sopenharmony_ci      EXPECT_TRUE(pred_set.count(31));
736fd4e5da5Sopenharmony_ci      // Check the phi instructions.
737fd4e5da5Sopenharmony_ci      loop.GetPreHeaderBlock()->ForEachPhiInst([&pred_set](Instruction* phi) {
738fd4e5da5Sopenharmony_ci        for (uint32_t i = 1; i < phi->NumInOperands(); i += 2) {
739fd4e5da5Sopenharmony_ci          EXPECT_TRUE(pred_set.count(phi->GetSingleWordInOperand(i)));
740fd4e5da5Sopenharmony_ci        }
741fd4e5da5Sopenharmony_ci      });
742fd4e5da5Sopenharmony_ci    }
743fd4e5da5Sopenharmony_ci    {
744fd4e5da5Sopenharmony_ci      const std::vector<uint32_t>& preds =
745fd4e5da5Sopenharmony_ci          cfg->preds(loop.GetHeaderBlock()->id());
746fd4e5da5Sopenharmony_ci      std::unordered_set<uint32_t> pred_set(preds.begin(), preds.end());
747fd4e5da5Sopenharmony_ci      EXPECT_EQ(pred_set.size(), 2u);
748fd4e5da5Sopenharmony_ci      EXPECT_TRUE(pred_set.count(loop.GetPreHeaderBlock()->id()));
749fd4e5da5Sopenharmony_ci      EXPECT_TRUE(pred_set.count(35));
750fd4e5da5Sopenharmony_ci      // Check the phi instructions.
751fd4e5da5Sopenharmony_ci      loop.GetHeaderBlock()->ForEachPhiInst([&pred_set](Instruction* phi) {
752fd4e5da5Sopenharmony_ci        for (uint32_t i = 1; i < phi->NumInOperands(); i += 2) {
753fd4e5da5Sopenharmony_ci          EXPECT_TRUE(pred_set.count(phi->GetSingleWordInOperand(i)));
754fd4e5da5Sopenharmony_ci        }
755fd4e5da5Sopenharmony_ci      });
756fd4e5da5Sopenharmony_ci    }
757fd4e5da5Sopenharmony_ci  }
758fd4e5da5Sopenharmony_ci
759fd4e5da5Sopenharmony_ci  {
760fd4e5da5Sopenharmony_ci    Loop& loop = *ld[41];
761fd4e5da5Sopenharmony_ci    EXPECT_EQ(loop.GetPreHeaderBlock(), nullptr);
762fd4e5da5Sopenharmony_ci    EXPECT_NE(loop.GetOrCreatePreHeaderBlock(), nullptr);
763fd4e5da5Sopenharmony_ci    EXPECT_EQ(ld[loop.GetPreHeaderBlock()], nullptr);
764fd4e5da5Sopenharmony_ci    EXPECT_EQ(cfg->preds(loop.GetPreHeaderBlock()->id()).size(), 1u);
765fd4e5da5Sopenharmony_ci    EXPECT_EQ(cfg->preds(loop.GetPreHeaderBlock()->id())[0], 25u);
766fd4e5da5Sopenharmony_ci    // Check the phi instructions.
767fd4e5da5Sopenharmony_ci    loop.GetPreHeaderBlock()->ForEachPhiInst([](Instruction* phi) {
768fd4e5da5Sopenharmony_ci      EXPECT_EQ(phi->NumInOperands(), 2u);
769fd4e5da5Sopenharmony_ci      EXPECT_EQ(phi->GetSingleWordInOperand(1), 25u);
770fd4e5da5Sopenharmony_ci    });
771fd4e5da5Sopenharmony_ci    {
772fd4e5da5Sopenharmony_ci      const std::vector<uint32_t>& preds =
773fd4e5da5Sopenharmony_ci          cfg->preds(loop.GetHeaderBlock()->id());
774fd4e5da5Sopenharmony_ci      std::unordered_set<uint32_t> pred_set(preds.begin(), preds.end());
775fd4e5da5Sopenharmony_ci      EXPECT_EQ(pred_set.size(), 2u);
776fd4e5da5Sopenharmony_ci      EXPECT_TRUE(pred_set.count(loop.GetPreHeaderBlock()->id()));
777fd4e5da5Sopenharmony_ci      EXPECT_TRUE(pred_set.count(44));
778fd4e5da5Sopenharmony_ci      // Check the phi instructions.
779fd4e5da5Sopenharmony_ci      loop.GetHeaderBlock()->ForEachPhiInst([&pred_set](Instruction* phi) {
780fd4e5da5Sopenharmony_ci        for (uint32_t i = 1; i < phi->NumInOperands(); i += 2) {
781fd4e5da5Sopenharmony_ci          EXPECT_TRUE(pred_set.count(phi->GetSingleWordInOperand(i)));
782fd4e5da5Sopenharmony_ci        }
783fd4e5da5Sopenharmony_ci      });
784fd4e5da5Sopenharmony_ci    }
785fd4e5da5Sopenharmony_ci  }
786fd4e5da5Sopenharmony_ci
787fd4e5da5Sopenharmony_ci  // Make sure pre-header insertion leaves the module valid.
788fd4e5da5Sopenharmony_ci  std::vector<uint32_t> bin;
789fd4e5da5Sopenharmony_ci  context->module()->ToBinary(&bin, true);
790fd4e5da5Sopenharmony_ci  EXPECT_TRUE(Validate(bin));
791fd4e5da5Sopenharmony_ci}
792fd4e5da5Sopenharmony_ci
793fd4e5da5Sopenharmony_ci}  // namespace
794fd4e5da5Sopenharmony_ci}  // namespace opt
795fd4e5da5Sopenharmony_ci}  // namespace spvtools
796