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 <array>
16fd4e5da5Sopenharmony_ci#include <memory>
17fd4e5da5Sopenharmony_ci#include <string>
18fd4e5da5Sopenharmony_ci#include <vector>
19fd4e5da5Sopenharmony_ci
20fd4e5da5Sopenharmony_ci#include "gmock/gmock.h"
21fd4e5da5Sopenharmony_ci#include "source/opt/dominator_analysis.h"
22fd4e5da5Sopenharmony_ci#include "source/opt/iterator.h"
23fd4e5da5Sopenharmony_ci#include "source/opt/pass.h"
24fd4e5da5Sopenharmony_ci#include "test/opt/assembly_builder.h"
25fd4e5da5Sopenharmony_ci#include "test/opt/function_utils.h"
26fd4e5da5Sopenharmony_ci#include "test/opt/pass_fixture.h"
27fd4e5da5Sopenharmony_ci#include "test/opt/pass_utils.h"
28fd4e5da5Sopenharmony_ci
29fd4e5da5Sopenharmony_cinamespace spvtools {
30fd4e5da5Sopenharmony_cinamespace opt {
31fd4e5da5Sopenharmony_cinamespace {
32fd4e5da5Sopenharmony_ci
33fd4e5da5Sopenharmony_ciusing ::testing::UnorderedElementsAre;
34fd4e5da5Sopenharmony_ciusing PassClassTest = PassTest<::testing::Test>;
35fd4e5da5Sopenharmony_ci
36fd4e5da5Sopenharmony_ci// Check that x dominates y, and
37fd4e5da5Sopenharmony_ci//   if x != y then
38fd4e5da5Sopenharmony_ci//      x strictly dominates y and
39fd4e5da5Sopenharmony_ci//      y does not dominate x and
40fd4e5da5Sopenharmony_ci//      y does not strictly dominate x
41fd4e5da5Sopenharmony_ci//   if x == x then
42fd4e5da5Sopenharmony_ci//      x does not strictly dominate itself
43fd4e5da5Sopenharmony_civoid check_dominance(const DominatorAnalysisBase& dom_tree, const Function* fn,
44fd4e5da5Sopenharmony_ci                     uint32_t x, uint32_t y) {
45fd4e5da5Sopenharmony_ci  SCOPED_TRACE("Check dominance properties for Basic Block " +
46fd4e5da5Sopenharmony_ci               std::to_string(x) + " and " + std::to_string(y));
47fd4e5da5Sopenharmony_ci  EXPECT_TRUE(dom_tree.Dominates(spvtest::GetBasicBlock(fn, x),
48fd4e5da5Sopenharmony_ci                                 spvtest::GetBasicBlock(fn, y)));
49fd4e5da5Sopenharmony_ci  EXPECT_TRUE(dom_tree.Dominates(x, y));
50fd4e5da5Sopenharmony_ci  if (x == y) {
51fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(x, x));
52fd4e5da5Sopenharmony_ci  } else {
53fd4e5da5Sopenharmony_ci    EXPECT_TRUE(dom_tree.StrictlyDominates(x, y));
54fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(y, x));
55fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(y, x));
56fd4e5da5Sopenharmony_ci  }
57fd4e5da5Sopenharmony_ci}
58fd4e5da5Sopenharmony_ci
59fd4e5da5Sopenharmony_ci// Check that x does not dominates y and vice versa
60fd4e5da5Sopenharmony_civoid check_no_dominance(const DominatorAnalysisBase& dom_tree,
61fd4e5da5Sopenharmony_ci                        const Function* fn, uint32_t x, uint32_t y) {
62fd4e5da5Sopenharmony_ci  SCOPED_TRACE("Check no domination for Basic Block " + std::to_string(x) +
63fd4e5da5Sopenharmony_ci               " and " + std::to_string(y));
64fd4e5da5Sopenharmony_ci  EXPECT_FALSE(dom_tree.Dominates(spvtest::GetBasicBlock(fn, x),
65fd4e5da5Sopenharmony_ci                                  spvtest::GetBasicBlock(fn, y)));
66fd4e5da5Sopenharmony_ci  EXPECT_FALSE(dom_tree.Dominates(x, y));
67fd4e5da5Sopenharmony_ci  EXPECT_FALSE(dom_tree.StrictlyDominates(spvtest::GetBasicBlock(fn, x),
68fd4e5da5Sopenharmony_ci                                          spvtest::GetBasicBlock(fn, y)));
69fd4e5da5Sopenharmony_ci  EXPECT_FALSE(dom_tree.StrictlyDominates(x, y));
70fd4e5da5Sopenharmony_ci
71fd4e5da5Sopenharmony_ci  EXPECT_FALSE(dom_tree.Dominates(spvtest::GetBasicBlock(fn, y),
72fd4e5da5Sopenharmony_ci                                  spvtest::GetBasicBlock(fn, x)));
73fd4e5da5Sopenharmony_ci  EXPECT_FALSE(dom_tree.Dominates(y, x));
74fd4e5da5Sopenharmony_ci  EXPECT_FALSE(dom_tree.StrictlyDominates(spvtest::GetBasicBlock(fn, y),
75fd4e5da5Sopenharmony_ci                                          spvtest::GetBasicBlock(fn, x)));
76fd4e5da5Sopenharmony_ci  EXPECT_FALSE(dom_tree.StrictlyDominates(y, x));
77fd4e5da5Sopenharmony_ci}
78fd4e5da5Sopenharmony_ci
79fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, DominatorSimpleCFG) {
80fd4e5da5Sopenharmony_ci  const std::string text = R"(
81fd4e5da5Sopenharmony_ci               OpCapability Addresses
82fd4e5da5Sopenharmony_ci               OpCapability Kernel
83fd4e5da5Sopenharmony_ci               OpMemoryModel Physical64 OpenCL
84fd4e5da5Sopenharmony_ci               OpEntryPoint Kernel %1 "main"
85fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
86fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
87fd4e5da5Sopenharmony_ci          %4 = OpTypeBool
88fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 0
89fd4e5da5Sopenharmony_ci          %6 = OpConstant %5 0
90fd4e5da5Sopenharmony_ci          %7 = OpConstantFalse %4
91fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %4
92fd4e5da5Sopenharmony_ci          %9 = OpConstant %5 1
93fd4e5da5Sopenharmony_ci          %1 = OpFunction %2 None %3
94fd4e5da5Sopenharmony_ci         %10 = OpLabel
95fd4e5da5Sopenharmony_ci               OpBranch %11
96fd4e5da5Sopenharmony_ci         %11 = OpLabel
97fd4e5da5Sopenharmony_ci               OpSwitch %6 %12 1 %13
98fd4e5da5Sopenharmony_ci         %12 = OpLabel
99fd4e5da5Sopenharmony_ci               OpBranch %14
100fd4e5da5Sopenharmony_ci         %13 = OpLabel
101fd4e5da5Sopenharmony_ci               OpBranch %14
102fd4e5da5Sopenharmony_ci         %14 = OpLabel
103fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %11 %15
104fd4e5da5Sopenharmony_ci         %15 = OpLabel
105fd4e5da5Sopenharmony_ci               OpReturn
106fd4e5da5Sopenharmony_ci               OpFunctionEnd
107fd4e5da5Sopenharmony_ci)";
108fd4e5da5Sopenharmony_ci  // clang-format on
109fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
110fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_0, nullptr, text,
111fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
112fd4e5da5Sopenharmony_ci  Module* module = context->module();
113fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
114fd4e5da5Sopenharmony_ci                             << text << std::endl;
115fd4e5da5Sopenharmony_ci  const Function* fn = spvtest::GetFunction(module, 1);
116fd4e5da5Sopenharmony_ci  const BasicBlock* entry = spvtest::GetBasicBlock(fn, 10);
117fd4e5da5Sopenharmony_ci  EXPECT_EQ(entry, fn->entry().get())
118fd4e5da5Sopenharmony_ci      << "The entry node is not the expected one";
119fd4e5da5Sopenharmony_ci
120fd4e5da5Sopenharmony_ci  // Test normal dominator tree
121fd4e5da5Sopenharmony_ci  {
122fd4e5da5Sopenharmony_ci    DominatorAnalysis dom_tree;
123fd4e5da5Sopenharmony_ci    const CFG& cfg = *context->cfg();
124fd4e5da5Sopenharmony_ci    dom_tree.InitializeTree(cfg, fn);
125fd4e5da5Sopenharmony_ci
126fd4e5da5Sopenharmony_ci    // Inspect the actual tree
127fd4e5da5Sopenharmony_ci    DominatorTree& tree = dom_tree.GetDomTree();
128fd4e5da5Sopenharmony_ci    EXPECT_EQ(tree.GetRoot()->bb_, cfg.pseudo_entry_block());
129fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
130fd4e5da5Sopenharmony_ci        dom_tree.Dominates(cfg.pseudo_entry_block()->id(), entry->id()));
131fd4e5da5Sopenharmony_ci
132fd4e5da5Sopenharmony_ci    // (strict) dominance checks
133fd4e5da5Sopenharmony_ci    for (uint32_t id : {10, 11, 12, 13, 14, 15})
134fd4e5da5Sopenharmony_ci      check_dominance(dom_tree, fn, id, id);
135fd4e5da5Sopenharmony_ci
136fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 11);
137fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 12);
138fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 13);
139fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 14);
140fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 15);
141fd4e5da5Sopenharmony_ci
142fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 12);
143fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 13);
144fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 14);
145fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 15);
146fd4e5da5Sopenharmony_ci
147fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 14, 15);
148fd4e5da5Sopenharmony_ci
149fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 12, 13);
150fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 12, 14);
151fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 13, 14);
152fd4e5da5Sopenharmony_ci
153fd4e5da5Sopenharmony_ci    // check with some invalid inputs
154fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(nullptr, entry));
155fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(entry, nullptr));
156fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(static_cast<BasicBlock*>(nullptr),
157fd4e5da5Sopenharmony_ci                                    static_cast<BasicBlock*>(nullptr)));
158fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(10, 1));
159fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(1, 10));
160fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(1, 1));
161fd4e5da5Sopenharmony_ci
162fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(nullptr, entry));
163fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(entry, nullptr));
164fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(nullptr, nullptr));
165fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(10, 1));
166fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(1, 10));
167fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(1, 1));
168fd4e5da5Sopenharmony_ci
169fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(cfg.pseudo_entry_block()), nullptr);
170fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(entry), cfg.pseudo_entry_block());
171fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(nullptr), nullptr);
172fd4e5da5Sopenharmony_ci
173fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 11)),
174fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 10));
175fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 12)),
176fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
177fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 13)),
178fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
179fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 14)),
180fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
181fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 15)),
182fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 14));
183fd4e5da5Sopenharmony_ci  }
184fd4e5da5Sopenharmony_ci
185fd4e5da5Sopenharmony_ci  // Test post dominator tree
186fd4e5da5Sopenharmony_ci  {
187fd4e5da5Sopenharmony_ci    PostDominatorAnalysis dom_tree;
188fd4e5da5Sopenharmony_ci    const CFG& cfg = *context->cfg();
189fd4e5da5Sopenharmony_ci    dom_tree.InitializeTree(cfg, fn);
190fd4e5da5Sopenharmony_ci
191fd4e5da5Sopenharmony_ci    // Inspect the actual tree
192fd4e5da5Sopenharmony_ci    DominatorTree& tree = dom_tree.GetDomTree();
193fd4e5da5Sopenharmony_ci    EXPECT_EQ(tree.GetRoot()->bb_, cfg.pseudo_exit_block());
194fd4e5da5Sopenharmony_ci    EXPECT_TRUE(dom_tree.Dominates(cfg.pseudo_exit_block()->id(), 15));
195fd4e5da5Sopenharmony_ci
196fd4e5da5Sopenharmony_ci    // (strict) dominance checks
197fd4e5da5Sopenharmony_ci    for (uint32_t id : {10, 11, 12, 13, 14, 15})
198fd4e5da5Sopenharmony_ci      check_dominance(dom_tree, fn, id, id);
199fd4e5da5Sopenharmony_ci
200fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 14, 10);
201fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 14, 11);
202fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 14, 12);
203fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 14, 13);
204fd4e5da5Sopenharmony_ci
205fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 15, 10);
206fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 15, 11);
207fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 15, 12);
208fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 15, 13);
209fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 15, 14);
210fd4e5da5Sopenharmony_ci
211fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 13, 12);
212fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 12, 11);
213fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 13, 11);
214fd4e5da5Sopenharmony_ci
215fd4e5da5Sopenharmony_ci    // check with some invalid inputs
216fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(nullptr, entry));
217fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(entry, nullptr));
218fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(static_cast<BasicBlock*>(nullptr),
219fd4e5da5Sopenharmony_ci                                    static_cast<BasicBlock*>(nullptr)));
220fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(10, 1));
221fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(1, 10));
222fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.Dominates(1, 1));
223fd4e5da5Sopenharmony_ci
224fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(nullptr, entry));
225fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(entry, nullptr));
226fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(nullptr, nullptr));
227fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(10, 1));
228fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(1, 10));
229fd4e5da5Sopenharmony_ci    EXPECT_FALSE(dom_tree.StrictlyDominates(1, 1));
230fd4e5da5Sopenharmony_ci
231fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(nullptr), nullptr);
232fd4e5da5Sopenharmony_ci
233fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 11)),
234fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 14));
235fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 12)),
236fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 14));
237fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 13)),
238fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 14));
239fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 14)),
240fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 15));
241fd4e5da5Sopenharmony_ci
242fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 15)),
243fd4e5da5Sopenharmony_ci              cfg.pseudo_exit_block());
244fd4e5da5Sopenharmony_ci
245fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(cfg.pseudo_exit_block()), nullptr);
246fd4e5da5Sopenharmony_ci  }
247fd4e5da5Sopenharmony_ci}
248fd4e5da5Sopenharmony_ci
249fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, DominatorIrreducibleCFG) {
250fd4e5da5Sopenharmony_ci  const std::string text = R"(
251fd4e5da5Sopenharmony_ci               OpCapability Addresses
252fd4e5da5Sopenharmony_ci               OpCapability Kernel
253fd4e5da5Sopenharmony_ci               OpMemoryModel Physical64 OpenCL
254fd4e5da5Sopenharmony_ci               OpEntryPoint Kernel %1 "main"
255fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
256fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
257fd4e5da5Sopenharmony_ci          %4 = OpTypeBool
258fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 0
259fd4e5da5Sopenharmony_ci          %6 = OpConstantFalse %4
260fd4e5da5Sopenharmony_ci          %7 = OpConstantTrue %4
261fd4e5da5Sopenharmony_ci          %1 = OpFunction %2 None %3
262fd4e5da5Sopenharmony_ci          %8 = OpLabel
263fd4e5da5Sopenharmony_ci               OpBranch %9
264fd4e5da5Sopenharmony_ci          %9 = OpLabel
265fd4e5da5Sopenharmony_ci               OpBranchConditional %7 %10 %11
266fd4e5da5Sopenharmony_ci         %10 = OpLabel
267fd4e5da5Sopenharmony_ci               OpBranch %11
268fd4e5da5Sopenharmony_ci         %11 = OpLabel
269fd4e5da5Sopenharmony_ci               OpBranchConditional %7 %10 %12
270fd4e5da5Sopenharmony_ci         %12 = OpLabel
271fd4e5da5Sopenharmony_ci               OpReturn
272fd4e5da5Sopenharmony_ci               OpFunctionEnd
273fd4e5da5Sopenharmony_ci)";
274fd4e5da5Sopenharmony_ci  // clang-format on
275fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
276fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_0, nullptr, text,
277fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
278fd4e5da5Sopenharmony_ci  Module* module = context->module();
279fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
280fd4e5da5Sopenharmony_ci                             << text << std::endl;
281fd4e5da5Sopenharmony_ci  const Function* fn = spvtest::GetFunction(module, 1);
282fd4e5da5Sopenharmony_ci
283fd4e5da5Sopenharmony_ci  const BasicBlock* entry = spvtest::GetBasicBlock(fn, 8);
284fd4e5da5Sopenharmony_ci  EXPECT_EQ(entry, fn->entry().get())
285fd4e5da5Sopenharmony_ci      << "The entry node is not the expected one";
286fd4e5da5Sopenharmony_ci
287fd4e5da5Sopenharmony_ci  // Check normal dominator tree
288fd4e5da5Sopenharmony_ci  {
289fd4e5da5Sopenharmony_ci    DominatorAnalysis dom_tree;
290fd4e5da5Sopenharmony_ci    const CFG& cfg = *context->cfg();
291fd4e5da5Sopenharmony_ci    dom_tree.InitializeTree(cfg, fn);
292fd4e5da5Sopenharmony_ci
293fd4e5da5Sopenharmony_ci    // Inspect the actual tree
294fd4e5da5Sopenharmony_ci    DominatorTree& tree = dom_tree.GetDomTree();
295fd4e5da5Sopenharmony_ci    EXPECT_EQ(tree.GetRoot()->bb_, cfg.pseudo_entry_block());
296fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
297fd4e5da5Sopenharmony_ci        dom_tree.Dominates(cfg.pseudo_entry_block()->id(), entry->id()));
298fd4e5da5Sopenharmony_ci
299fd4e5da5Sopenharmony_ci    // (strict) dominance checks
300fd4e5da5Sopenharmony_ci    for (uint32_t id : {8, 9, 10, 11, 12})
301fd4e5da5Sopenharmony_ci      check_dominance(dom_tree, fn, id, id);
302fd4e5da5Sopenharmony_ci
303fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 8, 9);
304fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 8, 10);
305fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 8, 11);
306fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 8, 12);
307fd4e5da5Sopenharmony_ci
308fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 9, 10);
309fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 9, 11);
310fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 9, 12);
311fd4e5da5Sopenharmony_ci
312fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 12);
313fd4e5da5Sopenharmony_ci
314fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 10, 11);
315fd4e5da5Sopenharmony_ci
316fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(cfg.pseudo_entry_block()), nullptr);
317fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(entry), cfg.pseudo_entry_block());
318fd4e5da5Sopenharmony_ci
319fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 9)),
320fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 8));
321fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 10)),
322fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 9));
323fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 11)),
324fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 9));
325fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 12)),
326fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
327fd4e5da5Sopenharmony_ci  }
328fd4e5da5Sopenharmony_ci
329fd4e5da5Sopenharmony_ci  // Check post dominator tree
330fd4e5da5Sopenharmony_ci  {
331fd4e5da5Sopenharmony_ci    PostDominatorAnalysis dom_tree;
332fd4e5da5Sopenharmony_ci    const CFG& cfg = *context->cfg();
333fd4e5da5Sopenharmony_ci    dom_tree.InitializeTree(cfg, fn);
334fd4e5da5Sopenharmony_ci
335fd4e5da5Sopenharmony_ci    // Inspect the actual tree
336fd4e5da5Sopenharmony_ci    DominatorTree& tree = dom_tree.GetDomTree();
337fd4e5da5Sopenharmony_ci    EXPECT_EQ(tree.GetRoot()->bb_, cfg.pseudo_exit_block());
338fd4e5da5Sopenharmony_ci    EXPECT_TRUE(dom_tree.Dominates(cfg.pseudo_exit_block()->id(), 12));
339fd4e5da5Sopenharmony_ci
340fd4e5da5Sopenharmony_ci    // (strict) dominance checks
341fd4e5da5Sopenharmony_ci    for (uint32_t id : {8, 9, 10, 11, 12})
342fd4e5da5Sopenharmony_ci      check_dominance(dom_tree, fn, id, id);
343fd4e5da5Sopenharmony_ci
344fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 12, 8);
345fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 12, 10);
346fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 12, 11);
347fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 12, 12);
348fd4e5da5Sopenharmony_ci
349fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 8);
350fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 9);
351fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 10);
352fd4e5da5Sopenharmony_ci
353fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 9, 8);
354fd4e5da5Sopenharmony_ci
355fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(entry),
356fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 9));
357fd4e5da5Sopenharmony_ci
358fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 9)),
359fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
360fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 10)),
361fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
362fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 11)),
363fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 12));
364fd4e5da5Sopenharmony_ci
365fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 12)),
366fd4e5da5Sopenharmony_ci              cfg.pseudo_exit_block());
367fd4e5da5Sopenharmony_ci
368fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(cfg.pseudo_exit_block()), nullptr);
369fd4e5da5Sopenharmony_ci  }
370fd4e5da5Sopenharmony_ci}
371fd4e5da5Sopenharmony_ci
372fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, DominatorLoopToSelf) {
373fd4e5da5Sopenharmony_ci  const std::string text = R"(
374fd4e5da5Sopenharmony_ci               OpCapability Addresses
375fd4e5da5Sopenharmony_ci               OpCapability Kernel
376fd4e5da5Sopenharmony_ci               OpMemoryModel Physical64 OpenCL
377fd4e5da5Sopenharmony_ci               OpEntryPoint Kernel %1 "main"
378fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
379fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
380fd4e5da5Sopenharmony_ci          %4 = OpTypeBool
381fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 0
382fd4e5da5Sopenharmony_ci          %6 = OpConstant %5 0
383fd4e5da5Sopenharmony_ci          %7 = OpConstantFalse %4
384fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %4
385fd4e5da5Sopenharmony_ci          %9 = OpConstant %5 1
386fd4e5da5Sopenharmony_ci          %1 = OpFunction %2 None %3
387fd4e5da5Sopenharmony_ci         %10 = OpLabel
388fd4e5da5Sopenharmony_ci               OpBranch %11
389fd4e5da5Sopenharmony_ci         %11 = OpLabel
390fd4e5da5Sopenharmony_ci               OpSwitch %6 %12 1 %11
391fd4e5da5Sopenharmony_ci         %12 = OpLabel
392fd4e5da5Sopenharmony_ci               OpReturn
393fd4e5da5Sopenharmony_ci               OpFunctionEnd
394fd4e5da5Sopenharmony_ci)";
395fd4e5da5Sopenharmony_ci  // clang-format on
396fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
397fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_0, nullptr, text,
398fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
399fd4e5da5Sopenharmony_ci  Module* module = context->module();
400fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
401fd4e5da5Sopenharmony_ci                             << text << std::endl;
402fd4e5da5Sopenharmony_ci  const Function* fn = spvtest::GetFunction(module, 1);
403fd4e5da5Sopenharmony_ci
404fd4e5da5Sopenharmony_ci  const BasicBlock* entry = spvtest::GetBasicBlock(fn, 10);
405fd4e5da5Sopenharmony_ci  EXPECT_EQ(entry, fn->entry().get())
406fd4e5da5Sopenharmony_ci      << "The entry node is not the expected one";
407fd4e5da5Sopenharmony_ci
408fd4e5da5Sopenharmony_ci  // Check normal dominator tree
409fd4e5da5Sopenharmony_ci  {
410fd4e5da5Sopenharmony_ci    DominatorAnalysis dom_tree;
411fd4e5da5Sopenharmony_ci    const CFG& cfg = *context->cfg();
412fd4e5da5Sopenharmony_ci    dom_tree.InitializeTree(cfg, fn);
413fd4e5da5Sopenharmony_ci
414fd4e5da5Sopenharmony_ci    // Inspect the actual tree
415fd4e5da5Sopenharmony_ci    DominatorTree& tree = dom_tree.GetDomTree();
416fd4e5da5Sopenharmony_ci    EXPECT_EQ(tree.GetRoot()->bb_, cfg.pseudo_entry_block());
417fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
418fd4e5da5Sopenharmony_ci        dom_tree.Dominates(cfg.pseudo_entry_block()->id(), entry->id()));
419fd4e5da5Sopenharmony_ci
420fd4e5da5Sopenharmony_ci    // (strict) dominance checks
421fd4e5da5Sopenharmony_ci    for (uint32_t id : {10, 11, 12}) check_dominance(dom_tree, fn, id, id);
422fd4e5da5Sopenharmony_ci
423fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 11);
424fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 12);
425fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 12);
426fd4e5da5Sopenharmony_ci
427fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(cfg.pseudo_entry_block()), nullptr);
428fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(entry), cfg.pseudo_entry_block());
429fd4e5da5Sopenharmony_ci
430fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 11)),
431fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 10));
432fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 12)),
433fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
434fd4e5da5Sopenharmony_ci
435fd4e5da5Sopenharmony_ci    std::array<uint32_t, 3> node_order = {{10, 11, 12}};
436fd4e5da5Sopenharmony_ci    {
437fd4e5da5Sopenharmony_ci      // Test dominator tree iteration order.
438fd4e5da5Sopenharmony_ci      DominatorTree::iterator node_it = dom_tree.GetDomTree().begin();
439fd4e5da5Sopenharmony_ci      DominatorTree::iterator node_end = dom_tree.GetDomTree().end();
440fd4e5da5Sopenharmony_ci      for (uint32_t id : node_order) {
441fd4e5da5Sopenharmony_ci        EXPECT_NE(node_it, node_end);
442fd4e5da5Sopenharmony_ci        EXPECT_EQ(node_it->id(), id);
443fd4e5da5Sopenharmony_ci        node_it++;
444fd4e5da5Sopenharmony_ci      }
445fd4e5da5Sopenharmony_ci      EXPECT_EQ(node_it, node_end);
446fd4e5da5Sopenharmony_ci    }
447fd4e5da5Sopenharmony_ci    {
448fd4e5da5Sopenharmony_ci      // Same as above, but with const iterators.
449fd4e5da5Sopenharmony_ci      DominatorTree::const_iterator node_it = dom_tree.GetDomTree().cbegin();
450fd4e5da5Sopenharmony_ci      DominatorTree::const_iterator node_end = dom_tree.GetDomTree().cend();
451fd4e5da5Sopenharmony_ci      for (uint32_t id : node_order) {
452fd4e5da5Sopenharmony_ci        EXPECT_NE(node_it, node_end);
453fd4e5da5Sopenharmony_ci        EXPECT_EQ(node_it->id(), id);
454fd4e5da5Sopenharmony_ci        node_it++;
455fd4e5da5Sopenharmony_ci      }
456fd4e5da5Sopenharmony_ci      EXPECT_EQ(node_it, node_end);
457fd4e5da5Sopenharmony_ci    }
458fd4e5da5Sopenharmony_ci    {
459fd4e5da5Sopenharmony_ci      // Test dominator tree iteration order.
460fd4e5da5Sopenharmony_ci      DominatorTree::post_iterator node_it = dom_tree.GetDomTree().post_begin();
461fd4e5da5Sopenharmony_ci      DominatorTree::post_iterator node_end = dom_tree.GetDomTree().post_end();
462fd4e5da5Sopenharmony_ci      for (uint32_t id : make_range(node_order.rbegin(), node_order.rend())) {
463fd4e5da5Sopenharmony_ci        EXPECT_NE(node_it, node_end);
464fd4e5da5Sopenharmony_ci        EXPECT_EQ(node_it->id(), id);
465fd4e5da5Sopenharmony_ci        node_it++;
466fd4e5da5Sopenharmony_ci      }
467fd4e5da5Sopenharmony_ci      EXPECT_EQ(node_it, node_end);
468fd4e5da5Sopenharmony_ci    }
469fd4e5da5Sopenharmony_ci    {
470fd4e5da5Sopenharmony_ci      // Same as above, but with const iterators.
471fd4e5da5Sopenharmony_ci      DominatorTree::const_post_iterator node_it =
472fd4e5da5Sopenharmony_ci          dom_tree.GetDomTree().post_cbegin();
473fd4e5da5Sopenharmony_ci      DominatorTree::const_post_iterator node_end =
474fd4e5da5Sopenharmony_ci          dom_tree.GetDomTree().post_cend();
475fd4e5da5Sopenharmony_ci      for (uint32_t id : make_range(node_order.rbegin(), node_order.rend())) {
476fd4e5da5Sopenharmony_ci        EXPECT_NE(node_it, node_end);
477fd4e5da5Sopenharmony_ci        EXPECT_EQ(node_it->id(), id);
478fd4e5da5Sopenharmony_ci        node_it++;
479fd4e5da5Sopenharmony_ci      }
480fd4e5da5Sopenharmony_ci      EXPECT_EQ(node_it, node_end);
481fd4e5da5Sopenharmony_ci    }
482fd4e5da5Sopenharmony_ci  }
483fd4e5da5Sopenharmony_ci
484fd4e5da5Sopenharmony_ci  // Check post dominator tree
485fd4e5da5Sopenharmony_ci  {
486fd4e5da5Sopenharmony_ci    PostDominatorAnalysis dom_tree;
487fd4e5da5Sopenharmony_ci    const CFG& cfg = *context->cfg();
488fd4e5da5Sopenharmony_ci    dom_tree.InitializeTree(cfg, fn);
489fd4e5da5Sopenharmony_ci
490fd4e5da5Sopenharmony_ci    // Inspect the actual tree
491fd4e5da5Sopenharmony_ci    DominatorTree& tree = dom_tree.GetDomTree();
492fd4e5da5Sopenharmony_ci    EXPECT_EQ(tree.GetRoot()->bb_, cfg.pseudo_exit_block());
493fd4e5da5Sopenharmony_ci    EXPECT_TRUE(dom_tree.Dominates(cfg.pseudo_exit_block()->id(), 12));
494fd4e5da5Sopenharmony_ci
495fd4e5da5Sopenharmony_ci    // (strict) dominance checks
496fd4e5da5Sopenharmony_ci    for (uint32_t id : {10, 11, 12}) check_dominance(dom_tree, fn, id, id);
497fd4e5da5Sopenharmony_ci
498fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 12, 10);
499fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 12, 11);
500fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 12, 12);
501fd4e5da5Sopenharmony_ci
502fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(entry),
503fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
504fd4e5da5Sopenharmony_ci
505fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 11)),
506fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 12));
507fd4e5da5Sopenharmony_ci
508fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(cfg.pseudo_exit_block()), nullptr);
509fd4e5da5Sopenharmony_ci
510fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 12)),
511fd4e5da5Sopenharmony_ci              cfg.pseudo_exit_block());
512fd4e5da5Sopenharmony_ci
513fd4e5da5Sopenharmony_ci    std::array<uint32_t, 3> node_order = {{12, 11, 10}};
514fd4e5da5Sopenharmony_ci    {
515fd4e5da5Sopenharmony_ci      // Test dominator tree iteration order.
516fd4e5da5Sopenharmony_ci      DominatorTree::iterator node_it = tree.begin();
517fd4e5da5Sopenharmony_ci      DominatorTree::iterator node_end = tree.end();
518fd4e5da5Sopenharmony_ci      for (uint32_t id : node_order) {
519fd4e5da5Sopenharmony_ci        EXPECT_NE(node_it, node_end);
520fd4e5da5Sopenharmony_ci        EXPECT_EQ(node_it->id(), id);
521fd4e5da5Sopenharmony_ci        node_it++;
522fd4e5da5Sopenharmony_ci      }
523fd4e5da5Sopenharmony_ci      EXPECT_EQ(node_it, node_end);
524fd4e5da5Sopenharmony_ci    }
525fd4e5da5Sopenharmony_ci    {
526fd4e5da5Sopenharmony_ci      // Same as above, but with const iterators.
527fd4e5da5Sopenharmony_ci      DominatorTree::const_iterator node_it = tree.cbegin();
528fd4e5da5Sopenharmony_ci      DominatorTree::const_iterator node_end = tree.cend();
529fd4e5da5Sopenharmony_ci      for (uint32_t id : node_order) {
530fd4e5da5Sopenharmony_ci        EXPECT_NE(node_it, node_end);
531fd4e5da5Sopenharmony_ci        EXPECT_EQ(node_it->id(), id);
532fd4e5da5Sopenharmony_ci        node_it++;
533fd4e5da5Sopenharmony_ci      }
534fd4e5da5Sopenharmony_ci      EXPECT_EQ(node_it, node_end);
535fd4e5da5Sopenharmony_ci    }
536fd4e5da5Sopenharmony_ci    {
537fd4e5da5Sopenharmony_ci      // Test dominator tree iteration order.
538fd4e5da5Sopenharmony_ci      DominatorTree::post_iterator node_it = dom_tree.GetDomTree().post_begin();
539fd4e5da5Sopenharmony_ci      DominatorTree::post_iterator node_end = dom_tree.GetDomTree().post_end();
540fd4e5da5Sopenharmony_ci      for (uint32_t id : make_range(node_order.rbegin(), node_order.rend())) {
541fd4e5da5Sopenharmony_ci        EXPECT_NE(node_it, node_end);
542fd4e5da5Sopenharmony_ci        EXPECT_EQ(node_it->id(), id);
543fd4e5da5Sopenharmony_ci        node_it++;
544fd4e5da5Sopenharmony_ci      }
545fd4e5da5Sopenharmony_ci      EXPECT_EQ(node_it, node_end);
546fd4e5da5Sopenharmony_ci    }
547fd4e5da5Sopenharmony_ci    {
548fd4e5da5Sopenharmony_ci      // Same as above, but with const iterators.
549fd4e5da5Sopenharmony_ci      DominatorTree::const_post_iterator node_it =
550fd4e5da5Sopenharmony_ci          dom_tree.GetDomTree().post_cbegin();
551fd4e5da5Sopenharmony_ci      DominatorTree::const_post_iterator node_end =
552fd4e5da5Sopenharmony_ci          dom_tree.GetDomTree().post_cend();
553fd4e5da5Sopenharmony_ci      for (uint32_t id : make_range(node_order.rbegin(), node_order.rend())) {
554fd4e5da5Sopenharmony_ci        EXPECT_NE(node_it, node_end);
555fd4e5da5Sopenharmony_ci        EXPECT_EQ(node_it->id(), id);
556fd4e5da5Sopenharmony_ci        node_it++;
557fd4e5da5Sopenharmony_ci      }
558fd4e5da5Sopenharmony_ci      EXPECT_EQ(node_it, node_end);
559fd4e5da5Sopenharmony_ci    }
560fd4e5da5Sopenharmony_ci  }
561fd4e5da5Sopenharmony_ci}
562fd4e5da5Sopenharmony_ci
563fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, DominatorUnreachableInLoop) {
564fd4e5da5Sopenharmony_ci  const std::string text = R"(
565fd4e5da5Sopenharmony_ci               OpCapability Addresses
566fd4e5da5Sopenharmony_ci               OpCapability Kernel
567fd4e5da5Sopenharmony_ci               OpMemoryModel Physical64 OpenCL
568fd4e5da5Sopenharmony_ci               OpEntryPoint Kernel %1 "main"
569fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
570fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
571fd4e5da5Sopenharmony_ci          %4 = OpTypeBool
572fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 0
573fd4e5da5Sopenharmony_ci          %6 = OpConstant %5 0
574fd4e5da5Sopenharmony_ci          %7 = OpConstantFalse %4
575fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %4
576fd4e5da5Sopenharmony_ci          %9 = OpConstant %5 1
577fd4e5da5Sopenharmony_ci          %1 = OpFunction %2 None %3
578fd4e5da5Sopenharmony_ci         %10 = OpLabel
579fd4e5da5Sopenharmony_ci               OpBranch %11
580fd4e5da5Sopenharmony_ci         %11 = OpLabel
581fd4e5da5Sopenharmony_ci               OpSwitch %6 %12 1 %13
582fd4e5da5Sopenharmony_ci         %12 = OpLabel
583fd4e5da5Sopenharmony_ci               OpBranch %14
584fd4e5da5Sopenharmony_ci         %13 = OpLabel
585fd4e5da5Sopenharmony_ci               OpUnreachable
586fd4e5da5Sopenharmony_ci         %14 = OpLabel
587fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %11 %15
588fd4e5da5Sopenharmony_ci         %15 = OpLabel
589fd4e5da5Sopenharmony_ci               OpReturn
590fd4e5da5Sopenharmony_ci               OpFunctionEnd
591fd4e5da5Sopenharmony_ci)";
592fd4e5da5Sopenharmony_ci  // clang-format on
593fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
594fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_0, nullptr, text,
595fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
596fd4e5da5Sopenharmony_ci  Module* module = context->module();
597fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
598fd4e5da5Sopenharmony_ci                             << text << std::endl;
599fd4e5da5Sopenharmony_ci  const Function* fn = spvtest::GetFunction(module, 1);
600fd4e5da5Sopenharmony_ci
601fd4e5da5Sopenharmony_ci  const BasicBlock* entry = spvtest::GetBasicBlock(fn, 10);
602fd4e5da5Sopenharmony_ci  EXPECT_EQ(entry, fn->entry().get())
603fd4e5da5Sopenharmony_ci      << "The entry node is not the expected one";
604fd4e5da5Sopenharmony_ci
605fd4e5da5Sopenharmony_ci  // Check normal dominator tree
606fd4e5da5Sopenharmony_ci  {
607fd4e5da5Sopenharmony_ci    DominatorAnalysis dom_tree;
608fd4e5da5Sopenharmony_ci    const CFG& cfg = *context->cfg();
609fd4e5da5Sopenharmony_ci    dom_tree.InitializeTree(cfg, fn);
610fd4e5da5Sopenharmony_ci
611fd4e5da5Sopenharmony_ci    // Inspect the actual tree
612fd4e5da5Sopenharmony_ci    DominatorTree& tree = dom_tree.GetDomTree();
613fd4e5da5Sopenharmony_ci    EXPECT_EQ(tree.GetRoot()->bb_, cfg.pseudo_entry_block());
614fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
615fd4e5da5Sopenharmony_ci        dom_tree.Dominates(cfg.pseudo_entry_block()->id(), entry->id()));
616fd4e5da5Sopenharmony_ci
617fd4e5da5Sopenharmony_ci    // (strict) dominance checks
618fd4e5da5Sopenharmony_ci    for (uint32_t id : {10, 11, 12, 13, 14, 15})
619fd4e5da5Sopenharmony_ci      check_dominance(dom_tree, fn, id, id);
620fd4e5da5Sopenharmony_ci
621fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 11);
622fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 13);
623fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 12);
624fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 14);
625fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 15);
626fd4e5da5Sopenharmony_ci
627fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 12);
628fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 13);
629fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 14);
630fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 15);
631fd4e5da5Sopenharmony_ci
632fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 12, 14);
633fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 12, 15);
634fd4e5da5Sopenharmony_ci
635fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 14, 15);
636fd4e5da5Sopenharmony_ci
637fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 13, 12);
638fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 13, 14);
639fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 13, 15);
640fd4e5da5Sopenharmony_ci
641fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(cfg.pseudo_entry_block()), nullptr);
642fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(entry), cfg.pseudo_entry_block());
643fd4e5da5Sopenharmony_ci
644fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 11)),
645fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 10));
646fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 12)),
647fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
648fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 13)),
649fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
650fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 14)),
651fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 12));
652fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 15)),
653fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 14));
654fd4e5da5Sopenharmony_ci  }
655fd4e5da5Sopenharmony_ci
656fd4e5da5Sopenharmony_ci  // Check post dominator tree.
657fd4e5da5Sopenharmony_ci  {
658fd4e5da5Sopenharmony_ci    PostDominatorAnalysis dom_tree;
659fd4e5da5Sopenharmony_ci    const CFG& cfg = *context->cfg();
660fd4e5da5Sopenharmony_ci    dom_tree.InitializeTree(cfg, fn);
661fd4e5da5Sopenharmony_ci
662fd4e5da5Sopenharmony_ci    // (strict) dominance checks.
663fd4e5da5Sopenharmony_ci    for (uint32_t id : {10, 11, 12, 13, 14, 15})
664fd4e5da5Sopenharmony_ci      check_dominance(dom_tree, fn, id, id);
665fd4e5da5Sopenharmony_ci
666fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 15, 10);
667fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 15, 11);
668fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 15, 12);
669fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 15, 13);
670fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 15, 14);
671fd4e5da5Sopenharmony_ci
672fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 14, 12);
673fd4e5da5Sopenharmony_ci
674fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 13, 10);
675fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 13, 11);
676fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 13, 12);
677fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 13, 14);
678fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 13, 15);
679fd4e5da5Sopenharmony_ci
680fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 10)),
681fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
682fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 12)),
683fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 14));
684fd4e5da5Sopenharmony_ci
685fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(cfg.pseudo_exit_block()), nullptr);
686fd4e5da5Sopenharmony_ci
687fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 15)),
688fd4e5da5Sopenharmony_ci              cfg.pseudo_exit_block());
689fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 13)),
690fd4e5da5Sopenharmony_ci              cfg.pseudo_exit_block());
691fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 14)),
692fd4e5da5Sopenharmony_ci              cfg.pseudo_exit_block());
693fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 11)),
694fd4e5da5Sopenharmony_ci              cfg.pseudo_exit_block());
695fd4e5da5Sopenharmony_ci  }
696fd4e5da5Sopenharmony_ci}
697fd4e5da5Sopenharmony_ci
698fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, DominatorInfinitLoop) {
699fd4e5da5Sopenharmony_ci  const std::string text = R"(
700fd4e5da5Sopenharmony_ci               OpCapability Addresses
701fd4e5da5Sopenharmony_ci               OpCapability Kernel
702fd4e5da5Sopenharmony_ci               OpMemoryModel Physical64 OpenCL
703fd4e5da5Sopenharmony_ci               OpEntryPoint Kernel %1 "main"
704fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
705fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
706fd4e5da5Sopenharmony_ci          %4 = OpTypeBool
707fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 0
708fd4e5da5Sopenharmony_ci          %6 = OpConstant %5 0
709fd4e5da5Sopenharmony_ci          %7 = OpConstantFalse %4
710fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %4
711fd4e5da5Sopenharmony_ci          %9 = OpConstant %5 1
712fd4e5da5Sopenharmony_ci          %1 = OpFunction %2 None %3
713fd4e5da5Sopenharmony_ci         %10 = OpLabel
714fd4e5da5Sopenharmony_ci               OpBranch %11
715fd4e5da5Sopenharmony_ci         %11 = OpLabel
716fd4e5da5Sopenharmony_ci               OpSwitch %6 %12 1 %13
717fd4e5da5Sopenharmony_ci         %12 = OpLabel
718fd4e5da5Sopenharmony_ci               OpReturn
719fd4e5da5Sopenharmony_ci         %13 = OpLabel
720fd4e5da5Sopenharmony_ci               OpBranch %13
721fd4e5da5Sopenharmony_ci               OpFunctionEnd
722fd4e5da5Sopenharmony_ci)";
723fd4e5da5Sopenharmony_ci  // clang-format on
724fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
725fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_0, nullptr, text,
726fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
727fd4e5da5Sopenharmony_ci  Module* module = context->module();
728fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
729fd4e5da5Sopenharmony_ci                             << text << std::endl;
730fd4e5da5Sopenharmony_ci  const Function* fn = spvtest::GetFunction(module, 1);
731fd4e5da5Sopenharmony_ci
732fd4e5da5Sopenharmony_ci  const BasicBlock* entry = spvtest::GetBasicBlock(fn, 10);
733fd4e5da5Sopenharmony_ci  EXPECT_EQ(entry, fn->entry().get())
734fd4e5da5Sopenharmony_ci      << "The entry node is not the expected one";
735fd4e5da5Sopenharmony_ci  // Check normal dominator tree
736fd4e5da5Sopenharmony_ci  {
737fd4e5da5Sopenharmony_ci    DominatorAnalysis dom_tree;
738fd4e5da5Sopenharmony_ci    const CFG& cfg = *context->cfg();
739fd4e5da5Sopenharmony_ci    dom_tree.InitializeTree(cfg, fn);
740fd4e5da5Sopenharmony_ci
741fd4e5da5Sopenharmony_ci    // Inspect the actual tree
742fd4e5da5Sopenharmony_ci    DominatorTree& tree = dom_tree.GetDomTree();
743fd4e5da5Sopenharmony_ci    EXPECT_EQ(tree.GetRoot()->bb_, cfg.pseudo_entry_block());
744fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
745fd4e5da5Sopenharmony_ci        dom_tree.Dominates(cfg.pseudo_entry_block()->id(), entry->id()));
746fd4e5da5Sopenharmony_ci
747fd4e5da5Sopenharmony_ci    // (strict) dominance checks
748fd4e5da5Sopenharmony_ci    for (uint32_t id : {10, 11, 12, 13}) check_dominance(dom_tree, fn, id, id);
749fd4e5da5Sopenharmony_ci
750fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 11);
751fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 12);
752fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 10, 13);
753fd4e5da5Sopenharmony_ci
754fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 12);
755fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 11, 13);
756fd4e5da5Sopenharmony_ci
757fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 13, 12);
758fd4e5da5Sopenharmony_ci
759fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(cfg.pseudo_entry_block()), nullptr);
760fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(entry), cfg.pseudo_entry_block());
761fd4e5da5Sopenharmony_ci
762fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 11)),
763fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 10));
764fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 12)),
765fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
766fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 13)),
767fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
768fd4e5da5Sopenharmony_ci  }
769fd4e5da5Sopenharmony_ci
770fd4e5da5Sopenharmony_ci  // Check post dominator tree
771fd4e5da5Sopenharmony_ci  {
772fd4e5da5Sopenharmony_ci    PostDominatorAnalysis dom_tree;
773fd4e5da5Sopenharmony_ci    const CFG& cfg = *context->cfg();
774fd4e5da5Sopenharmony_ci    dom_tree.InitializeTree(cfg, fn);
775fd4e5da5Sopenharmony_ci
776fd4e5da5Sopenharmony_ci    // Inspect the actual tree
777fd4e5da5Sopenharmony_ci    DominatorTree& tree = dom_tree.GetDomTree();
778fd4e5da5Sopenharmony_ci    EXPECT_EQ(tree.GetRoot()->bb_, cfg.pseudo_exit_block());
779fd4e5da5Sopenharmony_ci    EXPECT_TRUE(dom_tree.Dominates(cfg.pseudo_exit_block()->id(), 12));
780fd4e5da5Sopenharmony_ci
781fd4e5da5Sopenharmony_ci    // (strict) dominance checks
782fd4e5da5Sopenharmony_ci    for (uint32_t id : {10, 11, 12}) check_dominance(dom_tree, fn, id, id);
783fd4e5da5Sopenharmony_ci
784fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 12, 11);
785fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 12, 10);
786fd4e5da5Sopenharmony_ci
787fd4e5da5Sopenharmony_ci    // 13 should be completely out of tree as it's unreachable from exit nodes
788fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 12, 13);
789fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 11, 13);
790fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 10, 13);
791fd4e5da5Sopenharmony_ci
792fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(cfg.pseudo_exit_block()), nullptr);
793fd4e5da5Sopenharmony_ci
794fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 12)),
795fd4e5da5Sopenharmony_ci              cfg.pseudo_exit_block());
796fd4e5da5Sopenharmony_ci
797fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 10)),
798fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 11));
799fd4e5da5Sopenharmony_ci
800fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 11)),
801fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 12));
802fd4e5da5Sopenharmony_ci  }
803fd4e5da5Sopenharmony_ci}
804fd4e5da5Sopenharmony_ci
805fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, DominatorUnreachableFromEntry) {
806fd4e5da5Sopenharmony_ci  const std::string text = R"(
807fd4e5da5Sopenharmony_ci               OpCapability Addresses
808fd4e5da5Sopenharmony_ci               OpCapability Addresses
809fd4e5da5Sopenharmony_ci               OpCapability Kernel
810fd4e5da5Sopenharmony_ci               OpMemoryModel Physical64 OpenCL
811fd4e5da5Sopenharmony_ci               OpEntryPoint Kernel %1 "main"
812fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
813fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
814fd4e5da5Sopenharmony_ci          %4 = OpTypeBool
815fd4e5da5Sopenharmony_ci          %5 = OpTypeInt 32 0
816fd4e5da5Sopenharmony_ci          %6 = OpConstantFalse %4
817fd4e5da5Sopenharmony_ci          %7 = OpConstantTrue %4
818fd4e5da5Sopenharmony_ci          %1 = OpFunction %2 None %3
819fd4e5da5Sopenharmony_ci          %8 = OpLabel
820fd4e5da5Sopenharmony_ci               OpBranch %9
821fd4e5da5Sopenharmony_ci          %9 = OpLabel
822fd4e5da5Sopenharmony_ci               OpReturn
823fd4e5da5Sopenharmony_ci         %10 = OpLabel
824fd4e5da5Sopenharmony_ci               OpBranch %9
825fd4e5da5Sopenharmony_ci               OpFunctionEnd
826fd4e5da5Sopenharmony_ci)";
827fd4e5da5Sopenharmony_ci  // clang-format on
828fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
829fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_0, nullptr, text,
830fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
831fd4e5da5Sopenharmony_ci  Module* module = context->module();
832fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, module) << "Assembling failed for shader:\n"
833fd4e5da5Sopenharmony_ci                             << text << std::endl;
834fd4e5da5Sopenharmony_ci  const Function* fn = spvtest::GetFunction(module, 1);
835fd4e5da5Sopenharmony_ci
836fd4e5da5Sopenharmony_ci  const BasicBlock* entry = spvtest::GetBasicBlock(fn, 8);
837fd4e5da5Sopenharmony_ci  EXPECT_EQ(entry, fn->entry().get())
838fd4e5da5Sopenharmony_ci      << "The entry node is not the expected one";
839fd4e5da5Sopenharmony_ci
840fd4e5da5Sopenharmony_ci  // Check dominator tree
841fd4e5da5Sopenharmony_ci  {
842fd4e5da5Sopenharmony_ci    DominatorAnalysis dom_tree;
843fd4e5da5Sopenharmony_ci    const CFG& cfg = *context->cfg();
844fd4e5da5Sopenharmony_ci    dom_tree.InitializeTree(cfg, fn);
845fd4e5da5Sopenharmony_ci
846fd4e5da5Sopenharmony_ci    // Inspect the actual tree
847fd4e5da5Sopenharmony_ci    DominatorTree& tree = dom_tree.GetDomTree();
848fd4e5da5Sopenharmony_ci    EXPECT_EQ(tree.GetRoot()->bb_, cfg.pseudo_entry_block());
849fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
850fd4e5da5Sopenharmony_ci        dom_tree.Dominates(cfg.pseudo_entry_block()->id(), entry->id()));
851fd4e5da5Sopenharmony_ci
852fd4e5da5Sopenharmony_ci    // (strict) dominance checks
853fd4e5da5Sopenharmony_ci    for (uint32_t id : {8, 9}) check_dominance(dom_tree, fn, id, id);
854fd4e5da5Sopenharmony_ci
855fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 8, 9);
856fd4e5da5Sopenharmony_ci
857fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 10, 8);
858fd4e5da5Sopenharmony_ci    check_no_dominance(dom_tree, fn, 10, 9);
859fd4e5da5Sopenharmony_ci
860fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(cfg.pseudo_entry_block()), nullptr);
861fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(entry), cfg.pseudo_entry_block());
862fd4e5da5Sopenharmony_ci
863fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 9)),
864fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 8));
865fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 10)),
866fd4e5da5Sopenharmony_ci              nullptr);
867fd4e5da5Sopenharmony_ci  }
868fd4e5da5Sopenharmony_ci
869fd4e5da5Sopenharmony_ci  // Check post dominator tree
870fd4e5da5Sopenharmony_ci  {
871fd4e5da5Sopenharmony_ci    PostDominatorAnalysis dom_tree;
872fd4e5da5Sopenharmony_ci    const CFG& cfg = *context->cfg();
873fd4e5da5Sopenharmony_ci    dom_tree.InitializeTree(cfg, fn);
874fd4e5da5Sopenharmony_ci
875fd4e5da5Sopenharmony_ci    // Inspect the actual tree
876fd4e5da5Sopenharmony_ci    DominatorTree& tree = dom_tree.GetDomTree();
877fd4e5da5Sopenharmony_ci    EXPECT_EQ(tree.GetRoot()->bb_, cfg.pseudo_exit_block());
878fd4e5da5Sopenharmony_ci    EXPECT_TRUE(dom_tree.Dominates(cfg.pseudo_exit_block()->id(), 9));
879fd4e5da5Sopenharmony_ci
880fd4e5da5Sopenharmony_ci    // (strict) dominance checks
881fd4e5da5Sopenharmony_ci    for (uint32_t id : {8, 9, 10}) check_dominance(dom_tree, fn, id, id);
882fd4e5da5Sopenharmony_ci
883fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 9, 8);
884fd4e5da5Sopenharmony_ci    check_dominance(dom_tree, fn, 9, 10);
885fd4e5da5Sopenharmony_ci
886fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(entry),
887fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 9));
888fd4e5da5Sopenharmony_ci
889fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(cfg.pseudo_exit_block()), nullptr);
890fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 9)),
891fd4e5da5Sopenharmony_ci              cfg.pseudo_exit_block());
892fd4e5da5Sopenharmony_ci    EXPECT_EQ(dom_tree.ImmediateDominator(spvtest::GetBasicBlock(fn, 10)),
893fd4e5da5Sopenharmony_ci              spvtest::GetBasicBlock(fn, 9));
894fd4e5da5Sopenharmony_ci  }
895fd4e5da5Sopenharmony_ci}
896fd4e5da5Sopenharmony_ci
897fd4e5da5Sopenharmony_ciTEST_F(PassClassTest, DominationForInstructions) {
898fd4e5da5Sopenharmony_ci  const std::string text = R"(
899fd4e5da5Sopenharmony_ci               OpCapability Shader
900fd4e5da5Sopenharmony_ci          %1 = OpExtInstImport "GLSL.std.450"
901fd4e5da5Sopenharmony_ci               OpMemoryModel Logical GLSL450
902fd4e5da5Sopenharmony_ci               OpEntryPoint Fragment %4 "main"
903fd4e5da5Sopenharmony_ci               OpExecutionMode %4 OriginUpperLeft
904fd4e5da5Sopenharmony_ci               OpSource ESSL 310
905fd4e5da5Sopenharmony_ci          %2 = OpTypeVoid
906fd4e5da5Sopenharmony_ci          %3 = OpTypeFunction %2
907fd4e5da5Sopenharmony_ci          %6 = OpTypeInt 32 1
908fd4e5da5Sopenharmony_ci          %7 = OpTypeBool
909fd4e5da5Sopenharmony_ci          %8 = OpConstantTrue %7
910fd4e5da5Sopenharmony_ci          %9 = OpConstant %6 37
911fd4e5da5Sopenharmony_ci         %10 = OpConstant %6 3
912fd4e5da5Sopenharmony_ci         %13 = OpConstant %6 5
913fd4e5da5Sopenharmony_ci          %4 = OpFunction %2 None %3
914fd4e5da5Sopenharmony_ci          %5 = OpLabel
915fd4e5da5Sopenharmony_ci         %12 = OpIAdd %6 %9 %10
916fd4e5da5Sopenharmony_ci         %15 = OpISub %6 %12 %13
917fd4e5da5Sopenharmony_ci               OpSelectionMerge %18 None
918fd4e5da5Sopenharmony_ci               OpBranchConditional %8 %16 %17
919fd4e5da5Sopenharmony_ci         %16 = OpLabel
920fd4e5da5Sopenharmony_ci         %20 = OpISub %6 %12 %13
921fd4e5da5Sopenharmony_ci               OpBranch %18
922fd4e5da5Sopenharmony_ci         %17 = OpLabel
923fd4e5da5Sopenharmony_ci         %21 = OpISub %6 %12 %13
924fd4e5da5Sopenharmony_ci               OpBranch %18
925fd4e5da5Sopenharmony_ci         %18 = OpLabel
926fd4e5da5Sopenharmony_ci         %22 = OpISub %6 %12 %13
927fd4e5da5Sopenharmony_ci               OpReturn
928fd4e5da5Sopenharmony_ci               OpFunctionEnd
929fd4e5da5Sopenharmony_ci  )";
930fd4e5da5Sopenharmony_ci
931fd4e5da5Sopenharmony_ci  // clang-format on
932fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
933fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_0, nullptr, text,
934fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
935fd4e5da5Sopenharmony_ci  EXPECT_NE(nullptr, context->module()) << "Assembling failed for shader:\n"
936fd4e5da5Sopenharmony_ci                                        << text << std::endl;
937fd4e5da5Sopenharmony_ci
938fd4e5da5Sopenharmony_ci  {
939fd4e5da5Sopenharmony_ci    const DominatorAnalysis* dominator_analysis = context->GetDominatorAnalysis(
940fd4e5da5Sopenharmony_ci        spvtest::GetFunction(context->module(), 4));
941fd4e5da5Sopenharmony_ci
942fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
943fd4e5da5Sopenharmony_ci        dominator_analysis->Dominates(context->get_def_use_mgr()->GetDef(12),
944fd4e5da5Sopenharmony_ci                                      context->get_def_use_mgr()->GetDef(15)));
945fd4e5da5Sopenharmony_ci    EXPECT_FALSE(
946fd4e5da5Sopenharmony_ci        dominator_analysis->Dominates(context->get_def_use_mgr()->GetDef(15),
947fd4e5da5Sopenharmony_ci                                      context->get_def_use_mgr()->GetDef(12)));
948fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
949fd4e5da5Sopenharmony_ci        dominator_analysis->Dominates(context->get_def_use_mgr()->GetDef(5),
950fd4e5da5Sopenharmony_ci                                      context->get_def_use_mgr()->GetDef(12)));
951fd4e5da5Sopenharmony_ci    EXPECT_FALSE(
952fd4e5da5Sopenharmony_ci        dominator_analysis->Dominates(context->get_def_use_mgr()->GetDef(12),
953fd4e5da5Sopenharmony_ci                                      context->get_def_use_mgr()->GetDef(5)));
954fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
955fd4e5da5Sopenharmony_ci        dominator_analysis->Dominates(context->get_def_use_mgr()->GetDef(15),
956fd4e5da5Sopenharmony_ci                                      context->get_def_use_mgr()->GetDef(16)));
957fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
958fd4e5da5Sopenharmony_ci        dominator_analysis->Dominates(context->get_def_use_mgr()->GetDef(15),
959fd4e5da5Sopenharmony_ci                                      context->get_def_use_mgr()->GetDef(21)));
960fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
961fd4e5da5Sopenharmony_ci        dominator_analysis->Dominates(context->get_def_use_mgr()->GetDef(15),
962fd4e5da5Sopenharmony_ci                                      context->get_def_use_mgr()->GetDef(18)));
963fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
964fd4e5da5Sopenharmony_ci        dominator_analysis->Dominates(context->get_def_use_mgr()->GetDef(15),
965fd4e5da5Sopenharmony_ci                                      context->get_def_use_mgr()->GetDef(22)));
966fd4e5da5Sopenharmony_ci    EXPECT_FALSE(
967fd4e5da5Sopenharmony_ci        dominator_analysis->Dominates(context->get_def_use_mgr()->GetDef(20),
968fd4e5da5Sopenharmony_ci                                      context->get_def_use_mgr()->GetDef(22)));
969fd4e5da5Sopenharmony_ci    EXPECT_FALSE(
970fd4e5da5Sopenharmony_ci        dominator_analysis->Dominates(context->get_def_use_mgr()->GetDef(21),
971fd4e5da5Sopenharmony_ci                                      context->get_def_use_mgr()->GetDef(22)));
972fd4e5da5Sopenharmony_ci    EXPECT_TRUE(
973fd4e5da5Sopenharmony_ci        dominator_analysis->Dominates(context->get_def_use_mgr()->GetDef(15),
974fd4e5da5Sopenharmony_ci                                      context->get_def_use_mgr()->GetDef(15)));
975fd4e5da5Sopenharmony_ci  }
976fd4e5da5Sopenharmony_ci  {
977fd4e5da5Sopenharmony_ci    const PostDominatorAnalysis* post_dominator_analysis =
978fd4e5da5Sopenharmony_ci        context->GetPostDominatorAnalysis(
979fd4e5da5Sopenharmony_ci            spvtest::GetFunction(context->module(), 4));
980fd4e5da5Sopenharmony_ci
981fd4e5da5Sopenharmony_ci    EXPECT_TRUE(post_dominator_analysis->Dominates(
982fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(15),
983fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(12)));
984fd4e5da5Sopenharmony_ci    EXPECT_FALSE(post_dominator_analysis->Dominates(
985fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(12),
986fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(15)));
987fd4e5da5Sopenharmony_ci    EXPECT_TRUE(post_dominator_analysis->Dominates(
988fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(12),
989fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(5)));
990fd4e5da5Sopenharmony_ci    EXPECT_FALSE(post_dominator_analysis->Dominates(
991fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(5),
992fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(12)));
993fd4e5da5Sopenharmony_ci    EXPECT_FALSE(post_dominator_analysis->Dominates(
994fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(16),
995fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(15)));
996fd4e5da5Sopenharmony_ci    EXPECT_FALSE(post_dominator_analysis->Dominates(
997fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(21),
998fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(15)));
999fd4e5da5Sopenharmony_ci    EXPECT_TRUE(post_dominator_analysis->Dominates(
1000fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(18),
1001fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(15)));
1002fd4e5da5Sopenharmony_ci    EXPECT_TRUE(post_dominator_analysis->Dominates(
1003fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(22),
1004fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(15)));
1005fd4e5da5Sopenharmony_ci    EXPECT_TRUE(post_dominator_analysis->Dominates(
1006fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(22),
1007fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(20)));
1008fd4e5da5Sopenharmony_ci    EXPECT_TRUE(post_dominator_analysis->Dominates(
1009fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(22),
1010fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(21)));
1011fd4e5da5Sopenharmony_ci    EXPECT_TRUE(post_dominator_analysis->Dominates(
1012fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(15),
1013fd4e5da5Sopenharmony_ci        context->get_def_use_mgr()->GetDef(15)));
1014fd4e5da5Sopenharmony_ci  }
1015fd4e5da5Sopenharmony_ci}
1016fd4e5da5Sopenharmony_ci
1017fd4e5da5Sopenharmony_ci}  // namespace
1018fd4e5da5Sopenharmony_ci}  // namespace opt
1019fd4e5da5Sopenharmony_ci}  // namespace spvtools
1020