1fd4e5da5Sopenharmony_ci// Copyright (c) 2016 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 <unordered_map>
17fd4e5da5Sopenharmony_ci#include <unordered_set>
18fd4e5da5Sopenharmony_ci#include <utility>
19fd4e5da5Sopenharmony_ci#include <vector>
20fd4e5da5Sopenharmony_ci
21fd4e5da5Sopenharmony_ci#include "gmock/gmock.h"
22fd4e5da5Sopenharmony_ci#include "gtest/gtest.h"
23fd4e5da5Sopenharmony_ci#include "source/opt/build_module.h"
24fd4e5da5Sopenharmony_ci#include "source/opt/def_use_manager.h"
25fd4e5da5Sopenharmony_ci#include "source/opt/ir_context.h"
26fd4e5da5Sopenharmony_ci#include "source/opt/module.h"
27fd4e5da5Sopenharmony_ci#include "spirv-tools/libspirv.hpp"
28fd4e5da5Sopenharmony_ci#include "test/opt/pass_fixture.h"
29fd4e5da5Sopenharmony_ci#include "test/opt/pass_utils.h"
30fd4e5da5Sopenharmony_ci
31fd4e5da5Sopenharmony_cinamespace spvtools {
32fd4e5da5Sopenharmony_cinamespace opt {
33fd4e5da5Sopenharmony_cinamespace analysis {
34fd4e5da5Sopenharmony_cinamespace {
35fd4e5da5Sopenharmony_ci
36fd4e5da5Sopenharmony_ciusing ::testing::Contains;
37fd4e5da5Sopenharmony_ciusing ::testing::UnorderedElementsAre;
38fd4e5da5Sopenharmony_ciusing ::testing::UnorderedElementsAreArray;
39fd4e5da5Sopenharmony_ci
40fd4e5da5Sopenharmony_ci// Returns the number of uses of |id|.
41fd4e5da5Sopenharmony_ciuint32_t NumUses(const std::unique_ptr<IRContext>& context, uint32_t id) {
42fd4e5da5Sopenharmony_ci  uint32_t count = 0;
43fd4e5da5Sopenharmony_ci  context->get_def_use_mgr()->ForEachUse(
44fd4e5da5Sopenharmony_ci      id, [&count](Instruction*, uint32_t) { ++count; });
45fd4e5da5Sopenharmony_ci  return count;
46fd4e5da5Sopenharmony_ci}
47fd4e5da5Sopenharmony_ci
48fd4e5da5Sopenharmony_ci// Returns the opcode of each use of |id|.
49fd4e5da5Sopenharmony_ci//
50fd4e5da5Sopenharmony_ci// If |id| is used multiple times in a single instruction, that instruction's
51fd4e5da5Sopenharmony_ci// opcode will appear a corresponding number of times.
52fd4e5da5Sopenharmony_cistd::vector<spv::Op> GetUseOpcodes(const std::unique_ptr<IRContext>& context,
53fd4e5da5Sopenharmony_ci                                   uint32_t id) {
54fd4e5da5Sopenharmony_ci  std::vector<spv::Op> opcodes;
55fd4e5da5Sopenharmony_ci  context->get_def_use_mgr()->ForEachUse(
56fd4e5da5Sopenharmony_ci      id, [&opcodes](Instruction* user, uint32_t) {
57fd4e5da5Sopenharmony_ci        opcodes.push_back(user->opcode());
58fd4e5da5Sopenharmony_ci      });
59fd4e5da5Sopenharmony_ci  return opcodes;
60fd4e5da5Sopenharmony_ci}
61fd4e5da5Sopenharmony_ci
62fd4e5da5Sopenharmony_ci// Disassembles the given |inst| and returns the disassembly.
63fd4e5da5Sopenharmony_cistd::string DisassembleInst(Instruction* inst) {
64fd4e5da5Sopenharmony_ci  SpirvTools tools(SPV_ENV_UNIVERSAL_1_1);
65fd4e5da5Sopenharmony_ci
66fd4e5da5Sopenharmony_ci  std::vector<uint32_t> binary;
67fd4e5da5Sopenharmony_ci  // We need this to generate the necessary header in the binary.
68fd4e5da5Sopenharmony_ci  tools.Assemble("", &binary);
69fd4e5da5Sopenharmony_ci  inst->ToBinaryWithoutAttachedDebugInsts(&binary);
70fd4e5da5Sopenharmony_ci
71fd4e5da5Sopenharmony_ci  std::string text;
72fd4e5da5Sopenharmony_ci  // We'll need to check the underlying id numbers.
73fd4e5da5Sopenharmony_ci  // So turn off friendly names for ids.
74fd4e5da5Sopenharmony_ci  tools.Disassemble(binary, &text, SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
75fd4e5da5Sopenharmony_ci  while (!text.empty() && text.back() == '\n') text.pop_back();
76fd4e5da5Sopenharmony_ci  return text;
77fd4e5da5Sopenharmony_ci}
78fd4e5da5Sopenharmony_ci
79fd4e5da5Sopenharmony_ci// A struct for holding expected id defs and uses.
80fd4e5da5Sopenharmony_cistruct InstDefUse {
81fd4e5da5Sopenharmony_ci  using IdInstPair = std::pair<uint32_t, std::string>;
82fd4e5da5Sopenharmony_ci  using IdInstsPair = std::pair<uint32_t, std::vector<std::string>>;
83fd4e5da5Sopenharmony_ci
84fd4e5da5Sopenharmony_ci  // Ids and their corresponding def instructions.
85fd4e5da5Sopenharmony_ci  std::vector<IdInstPair> defs;
86fd4e5da5Sopenharmony_ci  // Ids and their corresponding use instructions.
87fd4e5da5Sopenharmony_ci  std::vector<IdInstsPair> uses;
88fd4e5da5Sopenharmony_ci};
89fd4e5da5Sopenharmony_ci
90fd4e5da5Sopenharmony_ci// Checks that the |actual_defs| and |actual_uses| are in accord with
91fd4e5da5Sopenharmony_ci// |expected_defs_uses|.
92fd4e5da5Sopenharmony_civoid CheckDef(const InstDefUse& expected_defs_uses,
93fd4e5da5Sopenharmony_ci              const DefUseManager::IdToDefMap& actual_defs) {
94fd4e5da5Sopenharmony_ci  // Check defs.
95fd4e5da5Sopenharmony_ci  ASSERT_EQ(expected_defs_uses.defs.size(), actual_defs.size());
96fd4e5da5Sopenharmony_ci  for (uint32_t i = 0; i < expected_defs_uses.defs.size(); ++i) {
97fd4e5da5Sopenharmony_ci    const auto id = expected_defs_uses.defs[i].first;
98fd4e5da5Sopenharmony_ci    const auto expected_def = expected_defs_uses.defs[i].second;
99fd4e5da5Sopenharmony_ci    ASSERT_EQ(1u, actual_defs.count(id)) << "expected to def id [" << id << "]";
100fd4e5da5Sopenharmony_ci    auto def = actual_defs.at(id);
101fd4e5da5Sopenharmony_ci    if (def->opcode() != spv::Op::OpConstant) {
102fd4e5da5Sopenharmony_ci      // Constants don't disassemble properly without a full context.
103fd4e5da5Sopenharmony_ci      EXPECT_EQ(expected_def, DisassembleInst(actual_defs.at(id)));
104fd4e5da5Sopenharmony_ci    }
105fd4e5da5Sopenharmony_ci  }
106fd4e5da5Sopenharmony_ci}
107fd4e5da5Sopenharmony_ci
108fd4e5da5Sopenharmony_ciusing UserMap = std::unordered_map<uint32_t, std::vector<Instruction*>>;
109fd4e5da5Sopenharmony_ci
110fd4e5da5Sopenharmony_ci// Creates a mapping of all definitions to their users (except OpConstant).
111fd4e5da5Sopenharmony_ci//
112fd4e5da5Sopenharmony_ci// OpConstants are skipped because they cannot be disassembled in isolation.
113fd4e5da5Sopenharmony_ciUserMap BuildAllUsers(const DefUseManager* mgr, uint32_t idBound) {
114fd4e5da5Sopenharmony_ci  UserMap userMap;
115fd4e5da5Sopenharmony_ci  for (uint32_t id = 0; id != idBound; ++id) {
116fd4e5da5Sopenharmony_ci    if (mgr->GetDef(id)) {
117fd4e5da5Sopenharmony_ci      mgr->ForEachUser(id, [id, &userMap](Instruction* user) {
118fd4e5da5Sopenharmony_ci        if (user->opcode() != spv::Op::OpConstant) {
119fd4e5da5Sopenharmony_ci          userMap[id].push_back(user);
120fd4e5da5Sopenharmony_ci        }
121fd4e5da5Sopenharmony_ci      });
122fd4e5da5Sopenharmony_ci    }
123fd4e5da5Sopenharmony_ci  }
124fd4e5da5Sopenharmony_ci  return userMap;
125fd4e5da5Sopenharmony_ci}
126fd4e5da5Sopenharmony_ci
127fd4e5da5Sopenharmony_ci// Constants don't disassemble properly without a full context, so skip them as
128fd4e5da5Sopenharmony_ci// checks.
129fd4e5da5Sopenharmony_civoid CheckUse(const InstDefUse& expected_defs_uses, const DefUseManager* mgr,
130fd4e5da5Sopenharmony_ci              uint32_t idBound) {
131fd4e5da5Sopenharmony_ci  UserMap actual_uses = BuildAllUsers(mgr, idBound);
132fd4e5da5Sopenharmony_ci  // Check uses.
133fd4e5da5Sopenharmony_ci  ASSERT_EQ(expected_defs_uses.uses.size(), actual_uses.size());
134fd4e5da5Sopenharmony_ci  for (uint32_t i = 0; i < expected_defs_uses.uses.size(); ++i) {
135fd4e5da5Sopenharmony_ci    const auto id = expected_defs_uses.uses[i].first;
136fd4e5da5Sopenharmony_ci    const auto& expected_uses = expected_defs_uses.uses[i].second;
137fd4e5da5Sopenharmony_ci
138fd4e5da5Sopenharmony_ci    ASSERT_EQ(1u, actual_uses.count(id)) << "expected to use id [" << id << "]";
139fd4e5da5Sopenharmony_ci    const auto& uses = actual_uses.at(id);
140fd4e5da5Sopenharmony_ci
141fd4e5da5Sopenharmony_ci    ASSERT_EQ(expected_uses.size(), uses.size())
142fd4e5da5Sopenharmony_ci        << "id [" << id << "] # uses: expected: " << expected_uses.size()
143fd4e5da5Sopenharmony_ci        << " actual: " << uses.size();
144fd4e5da5Sopenharmony_ci
145fd4e5da5Sopenharmony_ci    std::vector<std::string> actual_uses_disassembled;
146fd4e5da5Sopenharmony_ci    for (const auto actual_use : uses) {
147fd4e5da5Sopenharmony_ci      actual_uses_disassembled.emplace_back(DisassembleInst(actual_use));
148fd4e5da5Sopenharmony_ci    }
149fd4e5da5Sopenharmony_ci    EXPECT_THAT(actual_uses_disassembled,
150fd4e5da5Sopenharmony_ci                UnorderedElementsAreArray(expected_uses));
151fd4e5da5Sopenharmony_ci  }
152fd4e5da5Sopenharmony_ci}
153fd4e5da5Sopenharmony_ci
154fd4e5da5Sopenharmony_ci// The following test case mimics how LLVM handles induction variables.
155fd4e5da5Sopenharmony_ci// But, yeah, it's not very readable. However, we only care about the id
156fd4e5da5Sopenharmony_ci// defs and uses. So, no need to make sure this is valid OpPhi construct.
157fd4e5da5Sopenharmony_ciconst char kOpPhiTestFunction[] =
158fd4e5da5Sopenharmony_ci    " %1 = OpTypeVoid "
159fd4e5da5Sopenharmony_ci    " %6 = OpTypeInt 32 0 "
160fd4e5da5Sopenharmony_ci    "%10 = OpTypeFloat 32 "
161fd4e5da5Sopenharmony_ci    "%16 = OpTypeBool "
162fd4e5da5Sopenharmony_ci    " %3 = OpTypeFunction %1 "
163fd4e5da5Sopenharmony_ci    " %8 = OpConstant %6 0 "
164fd4e5da5Sopenharmony_ci    "%18 = OpConstant %6 1 "
165fd4e5da5Sopenharmony_ci    "%12 = OpConstant %10 1.0 "
166fd4e5da5Sopenharmony_ci    " %2 = OpFunction %1 None %3 "
167fd4e5da5Sopenharmony_ci    " %4 = OpLabel "
168fd4e5da5Sopenharmony_ci    "      OpBranch %5 "
169fd4e5da5Sopenharmony_ci
170fd4e5da5Sopenharmony_ci    " %5 = OpLabel "
171fd4e5da5Sopenharmony_ci    " %7 = OpPhi %6 %8 %4 %9 %5 "
172fd4e5da5Sopenharmony_ci    "%11 = OpPhi %10 %12 %4 %13 %5 "
173fd4e5da5Sopenharmony_ci    " %9 = OpIAdd %6 %7 %8 "
174fd4e5da5Sopenharmony_ci    "%13 = OpFAdd %10 %11 %12 "
175fd4e5da5Sopenharmony_ci    "%17 = OpSLessThan %16 %7 %18 "
176fd4e5da5Sopenharmony_ci    "      OpLoopMerge %19 %5 None "
177fd4e5da5Sopenharmony_ci    "      OpBranchConditional %17 %5 %19 "
178fd4e5da5Sopenharmony_ci
179fd4e5da5Sopenharmony_ci    "%19 = OpLabel "
180fd4e5da5Sopenharmony_ci    "      OpReturn "
181fd4e5da5Sopenharmony_ci    "      OpFunctionEnd";
182fd4e5da5Sopenharmony_ci
183fd4e5da5Sopenharmony_cistruct ParseDefUseCase {
184fd4e5da5Sopenharmony_ci  const char* text;
185fd4e5da5Sopenharmony_ci  InstDefUse du;
186fd4e5da5Sopenharmony_ci};
187fd4e5da5Sopenharmony_ci
188fd4e5da5Sopenharmony_ciusing ParseDefUseTest = ::testing::TestWithParam<ParseDefUseCase>;
189fd4e5da5Sopenharmony_ci
190fd4e5da5Sopenharmony_ciTEST_P(ParseDefUseTest, Case) {
191fd4e5da5Sopenharmony_ci  const auto& tc = GetParam();
192fd4e5da5Sopenharmony_ci
193fd4e5da5Sopenharmony_ci  // Build module.
194fd4e5da5Sopenharmony_ci  const std::vector<const char*> text = {tc.text};
195fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
196fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, JoinAllInsts(text),
197fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
198fd4e5da5Sopenharmony_ci  ASSERT_NE(nullptr, context);
199fd4e5da5Sopenharmony_ci
200fd4e5da5Sopenharmony_ci  // Analyze def and use.
201fd4e5da5Sopenharmony_ci  DefUseManager manager(context->module());
202fd4e5da5Sopenharmony_ci
203fd4e5da5Sopenharmony_ci  CheckDef(tc.du, manager.id_to_defs());
204fd4e5da5Sopenharmony_ci  CheckUse(tc.du, &manager, context->module()->IdBound());
205fd4e5da5Sopenharmony_ci}
206fd4e5da5Sopenharmony_ci
207fd4e5da5Sopenharmony_ci// clang-format off
208fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(
209fd4e5da5Sopenharmony_ci    TestCase, ParseDefUseTest,
210fd4e5da5Sopenharmony_ci    ::testing::ValuesIn(std::vector<ParseDefUseCase>{
211fd4e5da5Sopenharmony_ci        {"", {{}, {}}},                              // no instruction
212fd4e5da5Sopenharmony_ci        {"OpMemoryModel Logical GLSL450", {{}, {}}}, // no def and use
213fd4e5da5Sopenharmony_ci        { // single def, no use
214fd4e5da5Sopenharmony_ci          "%1 = OpString \"wow\"",
215fd4e5da5Sopenharmony_ci          {
216fd4e5da5Sopenharmony_ci            {{1, "%1 = OpString \"wow\""}}, // defs
217fd4e5da5Sopenharmony_ci            {}                              // uses
218fd4e5da5Sopenharmony_ci          }
219fd4e5da5Sopenharmony_ci        },
220fd4e5da5Sopenharmony_ci        { // multiple def, no use
221fd4e5da5Sopenharmony_ci          "%1 = OpString \"hello\" "
222fd4e5da5Sopenharmony_ci          "%2 = OpString \"world\" "
223fd4e5da5Sopenharmony_ci          "%3 = OpTypeVoid",
224fd4e5da5Sopenharmony_ci          {
225fd4e5da5Sopenharmony_ci            {  // defs
226fd4e5da5Sopenharmony_ci              {1, "%1 = OpString \"hello\""},
227fd4e5da5Sopenharmony_ci              {2, "%2 = OpString \"world\""},
228fd4e5da5Sopenharmony_ci              {3, "%3 = OpTypeVoid"},
229fd4e5da5Sopenharmony_ci            },
230fd4e5da5Sopenharmony_ci            {} // uses
231fd4e5da5Sopenharmony_ci          }
232fd4e5da5Sopenharmony_ci        },
233fd4e5da5Sopenharmony_ci        { // multiple def, multiple use
234fd4e5da5Sopenharmony_ci          "%1 = OpTypeBool "
235fd4e5da5Sopenharmony_ci          "%2 = OpTypeVector %1 3 "
236fd4e5da5Sopenharmony_ci          "%3 = OpTypeMatrix %2 3",
237fd4e5da5Sopenharmony_ci          {
238fd4e5da5Sopenharmony_ci            { // defs
239fd4e5da5Sopenharmony_ci              {1, "%1 = OpTypeBool"},
240fd4e5da5Sopenharmony_ci              {2, "%2 = OpTypeVector %1 3"},
241fd4e5da5Sopenharmony_ci              {3, "%3 = OpTypeMatrix %2 3"},
242fd4e5da5Sopenharmony_ci            },
243fd4e5da5Sopenharmony_ci            { // uses
244fd4e5da5Sopenharmony_ci              {1, {"%2 = OpTypeVector %1 3"}},
245fd4e5da5Sopenharmony_ci              {2, {"%3 = OpTypeMatrix %2 3"}},
246fd4e5da5Sopenharmony_ci            }
247fd4e5da5Sopenharmony_ci          }
248fd4e5da5Sopenharmony_ci        },
249fd4e5da5Sopenharmony_ci        { // multiple use of the same id
250fd4e5da5Sopenharmony_ci          "%1 = OpTypeBool "
251fd4e5da5Sopenharmony_ci          "%2 = OpTypeVector %1 2 "
252fd4e5da5Sopenharmony_ci          "%3 = OpTypeVector %1 3 "
253fd4e5da5Sopenharmony_ci          "%4 = OpTypeVector %1 4",
254fd4e5da5Sopenharmony_ci          {
255fd4e5da5Sopenharmony_ci            { // defs
256fd4e5da5Sopenharmony_ci              {1, "%1 = OpTypeBool"},
257fd4e5da5Sopenharmony_ci              {2, "%2 = OpTypeVector %1 2"},
258fd4e5da5Sopenharmony_ci              {3, "%3 = OpTypeVector %1 3"},
259fd4e5da5Sopenharmony_ci              {4, "%4 = OpTypeVector %1 4"},
260fd4e5da5Sopenharmony_ci            },
261fd4e5da5Sopenharmony_ci            { // uses
262fd4e5da5Sopenharmony_ci              {1,
263fd4e5da5Sopenharmony_ci                {
264fd4e5da5Sopenharmony_ci                  "%2 = OpTypeVector %1 2",
265fd4e5da5Sopenharmony_ci                  "%3 = OpTypeVector %1 3",
266fd4e5da5Sopenharmony_ci                  "%4 = OpTypeVector %1 4",
267fd4e5da5Sopenharmony_ci                }
268fd4e5da5Sopenharmony_ci              },
269fd4e5da5Sopenharmony_ci            }
270fd4e5da5Sopenharmony_ci          }
271fd4e5da5Sopenharmony_ci        },
272fd4e5da5Sopenharmony_ci        { // labels
273fd4e5da5Sopenharmony_ci          "%1 = OpTypeVoid "
274fd4e5da5Sopenharmony_ci          "%2 = OpTypeBool "
275fd4e5da5Sopenharmony_ci          "%3 = OpTypeFunction %1 "
276fd4e5da5Sopenharmony_ci          "%4 = OpConstantTrue %2 "
277fd4e5da5Sopenharmony_ci          "%5 = OpFunction %1 None %3 "
278fd4e5da5Sopenharmony_ci
279fd4e5da5Sopenharmony_ci          "%6 = OpLabel "
280fd4e5da5Sopenharmony_ci          "OpBranchConditional %4 %7 %8 "
281fd4e5da5Sopenharmony_ci
282fd4e5da5Sopenharmony_ci          "%7 = OpLabel "
283fd4e5da5Sopenharmony_ci          "OpBranch %7 "
284fd4e5da5Sopenharmony_ci
285fd4e5da5Sopenharmony_ci          "%8 = OpLabel "
286fd4e5da5Sopenharmony_ci          "OpReturn "
287fd4e5da5Sopenharmony_ci
288fd4e5da5Sopenharmony_ci          "OpFunctionEnd",
289fd4e5da5Sopenharmony_ci          {
290fd4e5da5Sopenharmony_ci            { // defs
291fd4e5da5Sopenharmony_ci              {1, "%1 = OpTypeVoid"},
292fd4e5da5Sopenharmony_ci              {2, "%2 = OpTypeBool"},
293fd4e5da5Sopenharmony_ci              {3, "%3 = OpTypeFunction %1"},
294fd4e5da5Sopenharmony_ci              {4, "%4 = OpConstantTrue %2"},
295fd4e5da5Sopenharmony_ci              {5, "%5 = OpFunction %1 None %3"},
296fd4e5da5Sopenharmony_ci              {6, "%6 = OpLabel"},
297fd4e5da5Sopenharmony_ci              {7, "%7 = OpLabel"},
298fd4e5da5Sopenharmony_ci              {8, "%8 = OpLabel"},
299fd4e5da5Sopenharmony_ci            },
300fd4e5da5Sopenharmony_ci            { // uses
301fd4e5da5Sopenharmony_ci              {1, {
302fd4e5da5Sopenharmony_ci                    "%3 = OpTypeFunction %1",
303fd4e5da5Sopenharmony_ci                    "%5 = OpFunction %1 None %3",
304fd4e5da5Sopenharmony_ci                  }
305fd4e5da5Sopenharmony_ci              },
306fd4e5da5Sopenharmony_ci              {2, {"%4 = OpConstantTrue %2"}},
307fd4e5da5Sopenharmony_ci              {3, {"%5 = OpFunction %1 None %3"}},
308fd4e5da5Sopenharmony_ci              {4, {"OpBranchConditional %4 %7 %8"}},
309fd4e5da5Sopenharmony_ci              {7,
310fd4e5da5Sopenharmony_ci                {
311fd4e5da5Sopenharmony_ci                  "OpBranchConditional %4 %7 %8",
312fd4e5da5Sopenharmony_ci                  "OpBranch %7",
313fd4e5da5Sopenharmony_ci                }
314fd4e5da5Sopenharmony_ci              },
315fd4e5da5Sopenharmony_ci              {8, {"OpBranchConditional %4 %7 %8"}},
316fd4e5da5Sopenharmony_ci            }
317fd4e5da5Sopenharmony_ci          }
318fd4e5da5Sopenharmony_ci        },
319fd4e5da5Sopenharmony_ci        { // cross function
320fd4e5da5Sopenharmony_ci          "%1 = OpTypeBool "
321fd4e5da5Sopenharmony_ci          "%3 = OpTypeFunction %1 "
322fd4e5da5Sopenharmony_ci          "%2 = OpFunction %1 None %3 "
323fd4e5da5Sopenharmony_ci
324fd4e5da5Sopenharmony_ci          "%4 = OpLabel "
325fd4e5da5Sopenharmony_ci          "%5 = OpVariable %1 Function "
326fd4e5da5Sopenharmony_ci          "%6 = OpFunctionCall %1 %2 %5 "
327fd4e5da5Sopenharmony_ci          "OpReturnValue %6 "
328fd4e5da5Sopenharmony_ci
329fd4e5da5Sopenharmony_ci          "OpFunctionEnd",
330fd4e5da5Sopenharmony_ci          {
331fd4e5da5Sopenharmony_ci            { // defs
332fd4e5da5Sopenharmony_ci              {1, "%1 = OpTypeBool"},
333fd4e5da5Sopenharmony_ci              {2, "%2 = OpFunction %1 None %3"},
334fd4e5da5Sopenharmony_ci              {3, "%3 = OpTypeFunction %1"},
335fd4e5da5Sopenharmony_ci              {4, "%4 = OpLabel"},
336fd4e5da5Sopenharmony_ci              {5, "%5 = OpVariable %1 Function"},
337fd4e5da5Sopenharmony_ci              {6, "%6 = OpFunctionCall %1 %2 %5"},
338fd4e5da5Sopenharmony_ci            },
339fd4e5da5Sopenharmony_ci            { // uses
340fd4e5da5Sopenharmony_ci              {1,
341fd4e5da5Sopenharmony_ci                {
342fd4e5da5Sopenharmony_ci                  "%2 = OpFunction %1 None %3",
343fd4e5da5Sopenharmony_ci                  "%3 = OpTypeFunction %1",
344fd4e5da5Sopenharmony_ci                  "%5 = OpVariable %1 Function",
345fd4e5da5Sopenharmony_ci                  "%6 = OpFunctionCall %1 %2 %5",
346fd4e5da5Sopenharmony_ci                }
347fd4e5da5Sopenharmony_ci              },
348fd4e5da5Sopenharmony_ci              {2, {"%6 = OpFunctionCall %1 %2 %5"}},
349fd4e5da5Sopenharmony_ci              {3, {"%2 = OpFunction %1 None %3"}},
350fd4e5da5Sopenharmony_ci              {5, {"%6 = OpFunctionCall %1 %2 %5"}},
351fd4e5da5Sopenharmony_ci              {6, {"OpReturnValue %6"}},
352fd4e5da5Sopenharmony_ci            }
353fd4e5da5Sopenharmony_ci          }
354fd4e5da5Sopenharmony_ci        },
355fd4e5da5Sopenharmony_ci        { // selection merge and loop merge
356fd4e5da5Sopenharmony_ci          "%1 = OpTypeVoid "
357fd4e5da5Sopenharmony_ci          "%3 = OpTypeFunction %1 "
358fd4e5da5Sopenharmony_ci          "%10 = OpTypeBool "
359fd4e5da5Sopenharmony_ci          "%8 = OpConstantTrue %10 "
360fd4e5da5Sopenharmony_ci          "%2 = OpFunction %1 None %3 "
361fd4e5da5Sopenharmony_ci
362fd4e5da5Sopenharmony_ci          "%4 = OpLabel "
363fd4e5da5Sopenharmony_ci          "OpLoopMerge %5 %4 None "
364fd4e5da5Sopenharmony_ci          "OpBranch %6 "
365fd4e5da5Sopenharmony_ci
366fd4e5da5Sopenharmony_ci          "%5 = OpLabel "
367fd4e5da5Sopenharmony_ci          "OpReturn "
368fd4e5da5Sopenharmony_ci
369fd4e5da5Sopenharmony_ci          "%6 = OpLabel "
370fd4e5da5Sopenharmony_ci          "OpSelectionMerge %7 None "
371fd4e5da5Sopenharmony_ci          "OpBranchConditional %8 %9 %7 "
372fd4e5da5Sopenharmony_ci
373fd4e5da5Sopenharmony_ci          "%7 = OpLabel "
374fd4e5da5Sopenharmony_ci          "OpReturn "
375fd4e5da5Sopenharmony_ci
376fd4e5da5Sopenharmony_ci          "%9 = OpLabel "
377fd4e5da5Sopenharmony_ci          "OpReturn "
378fd4e5da5Sopenharmony_ci
379fd4e5da5Sopenharmony_ci          "OpFunctionEnd",
380fd4e5da5Sopenharmony_ci          {
381fd4e5da5Sopenharmony_ci            { // defs
382fd4e5da5Sopenharmony_ci              {1, "%1 = OpTypeVoid"},
383fd4e5da5Sopenharmony_ci              {2, "%2 = OpFunction %1 None %3"},
384fd4e5da5Sopenharmony_ci              {3, "%3 = OpTypeFunction %1"},
385fd4e5da5Sopenharmony_ci              {4, "%4 = OpLabel"},
386fd4e5da5Sopenharmony_ci              {5, "%5 = OpLabel"},
387fd4e5da5Sopenharmony_ci              {6, "%6 = OpLabel"},
388fd4e5da5Sopenharmony_ci              {7, "%7 = OpLabel"},
389fd4e5da5Sopenharmony_ci              {8, "%8 = OpConstantTrue %10"},
390fd4e5da5Sopenharmony_ci              {9, "%9 = OpLabel"},
391fd4e5da5Sopenharmony_ci              {10, "%10 = OpTypeBool"},
392fd4e5da5Sopenharmony_ci            },
393fd4e5da5Sopenharmony_ci            { // uses
394fd4e5da5Sopenharmony_ci              {1,
395fd4e5da5Sopenharmony_ci                {
396fd4e5da5Sopenharmony_ci                  "%2 = OpFunction %1 None %3",
397fd4e5da5Sopenharmony_ci                  "%3 = OpTypeFunction %1",
398fd4e5da5Sopenharmony_ci                }
399fd4e5da5Sopenharmony_ci              },
400fd4e5da5Sopenharmony_ci              {3, {"%2 = OpFunction %1 None %3"}},
401fd4e5da5Sopenharmony_ci              {4, {"OpLoopMerge %5 %4 None"}},
402fd4e5da5Sopenharmony_ci              {5, {"OpLoopMerge %5 %4 None"}},
403fd4e5da5Sopenharmony_ci              {6, {"OpBranch %6"}},
404fd4e5da5Sopenharmony_ci              {7,
405fd4e5da5Sopenharmony_ci                {
406fd4e5da5Sopenharmony_ci                  "OpSelectionMerge %7 None",
407fd4e5da5Sopenharmony_ci                  "OpBranchConditional %8 %9 %7",
408fd4e5da5Sopenharmony_ci                }
409fd4e5da5Sopenharmony_ci              },
410fd4e5da5Sopenharmony_ci              {8, {"OpBranchConditional %8 %9 %7"}},
411fd4e5da5Sopenharmony_ci              {9, {"OpBranchConditional %8 %9 %7"}},
412fd4e5da5Sopenharmony_ci              {10, {"%8 = OpConstantTrue %10"}},
413fd4e5da5Sopenharmony_ci            }
414fd4e5da5Sopenharmony_ci          }
415fd4e5da5Sopenharmony_ci        },
416fd4e5da5Sopenharmony_ci        { // Forward reference
417fd4e5da5Sopenharmony_ci          "OpDecorate %1 Block "
418fd4e5da5Sopenharmony_ci          "OpTypeForwardPointer %2 Input "
419fd4e5da5Sopenharmony_ci          "%3 = OpTypeInt 32 0 "
420fd4e5da5Sopenharmony_ci          "%1 = OpTypeStruct %3 "
421fd4e5da5Sopenharmony_ci          "%2 = OpTypePointer Input %3",
422fd4e5da5Sopenharmony_ci          {
423fd4e5da5Sopenharmony_ci            { // defs
424fd4e5da5Sopenharmony_ci              {1, "%1 = OpTypeStruct %3"},
425fd4e5da5Sopenharmony_ci              {2, "%2 = OpTypePointer Input %3"},
426fd4e5da5Sopenharmony_ci              {3, "%3 = OpTypeInt 32 0"},
427fd4e5da5Sopenharmony_ci            },
428fd4e5da5Sopenharmony_ci            { // uses
429fd4e5da5Sopenharmony_ci              {1, {"OpDecorate %1 Block"}},
430fd4e5da5Sopenharmony_ci              {2, {"OpTypeForwardPointer %2 Input"}},
431fd4e5da5Sopenharmony_ci              {3,
432fd4e5da5Sopenharmony_ci                {
433fd4e5da5Sopenharmony_ci                  "%1 = OpTypeStruct %3",
434fd4e5da5Sopenharmony_ci                  "%2 = OpTypePointer Input %3",
435fd4e5da5Sopenharmony_ci                }
436fd4e5da5Sopenharmony_ci              }
437fd4e5da5Sopenharmony_ci            },
438fd4e5da5Sopenharmony_ci          },
439fd4e5da5Sopenharmony_ci        },
440fd4e5da5Sopenharmony_ci        { // OpPhi
441fd4e5da5Sopenharmony_ci          kOpPhiTestFunction,
442fd4e5da5Sopenharmony_ci          {
443fd4e5da5Sopenharmony_ci            { // defs
444fd4e5da5Sopenharmony_ci              {1, "%1 = OpTypeVoid"},
445fd4e5da5Sopenharmony_ci              {2, "%2 = OpFunction %1 None %3"},
446fd4e5da5Sopenharmony_ci              {3, "%3 = OpTypeFunction %1"},
447fd4e5da5Sopenharmony_ci              {4, "%4 = OpLabel"},
448fd4e5da5Sopenharmony_ci              {5, "%5 = OpLabel"},
449fd4e5da5Sopenharmony_ci              {6, "%6 = OpTypeInt 32 0"},
450fd4e5da5Sopenharmony_ci              {7, "%7 = OpPhi %6 %8 %4 %9 %5"},
451fd4e5da5Sopenharmony_ci              {8, "%8 = OpConstant %6 0"},
452fd4e5da5Sopenharmony_ci              {9, "%9 = OpIAdd %6 %7 %8"},
453fd4e5da5Sopenharmony_ci              {10, "%10 = OpTypeFloat 32"},
454fd4e5da5Sopenharmony_ci              {11, "%11 = OpPhi %10 %12 %4 %13 %5"},
455fd4e5da5Sopenharmony_ci              {12, "%12 = OpConstant %10 1.0"},
456fd4e5da5Sopenharmony_ci              {13, "%13 = OpFAdd %10 %11 %12"},
457fd4e5da5Sopenharmony_ci              {16, "%16 = OpTypeBool"},
458fd4e5da5Sopenharmony_ci              {17, "%17 = OpSLessThan %16 %7 %18"},
459fd4e5da5Sopenharmony_ci              {18, "%18 = OpConstant %6 1"},
460fd4e5da5Sopenharmony_ci              {19, "%19 = OpLabel"},
461fd4e5da5Sopenharmony_ci            },
462fd4e5da5Sopenharmony_ci            { // uses
463fd4e5da5Sopenharmony_ci              {1,
464fd4e5da5Sopenharmony_ci                {
465fd4e5da5Sopenharmony_ci                  "%2 = OpFunction %1 None %3",
466fd4e5da5Sopenharmony_ci                  "%3 = OpTypeFunction %1",
467fd4e5da5Sopenharmony_ci                }
468fd4e5da5Sopenharmony_ci              },
469fd4e5da5Sopenharmony_ci              {3, {"%2 = OpFunction %1 None %3"}},
470fd4e5da5Sopenharmony_ci              {4,
471fd4e5da5Sopenharmony_ci                {
472fd4e5da5Sopenharmony_ci                  "%7 = OpPhi %6 %8 %4 %9 %5",
473fd4e5da5Sopenharmony_ci                  "%11 = OpPhi %10 %12 %4 %13 %5",
474fd4e5da5Sopenharmony_ci                }
475fd4e5da5Sopenharmony_ci              },
476fd4e5da5Sopenharmony_ci              {5,
477fd4e5da5Sopenharmony_ci                {
478fd4e5da5Sopenharmony_ci                  "OpBranch %5",
479fd4e5da5Sopenharmony_ci                  "%7 = OpPhi %6 %8 %4 %9 %5",
480fd4e5da5Sopenharmony_ci                  "%11 = OpPhi %10 %12 %4 %13 %5",
481fd4e5da5Sopenharmony_ci                  "OpLoopMerge %19 %5 None",
482fd4e5da5Sopenharmony_ci                  "OpBranchConditional %17 %5 %19",
483fd4e5da5Sopenharmony_ci                }
484fd4e5da5Sopenharmony_ci              },
485fd4e5da5Sopenharmony_ci              {6,
486fd4e5da5Sopenharmony_ci                {
487fd4e5da5Sopenharmony_ci                  // Can't check constants properly
488fd4e5da5Sopenharmony_ci                  // "%8 = OpConstant %6 0",
489fd4e5da5Sopenharmony_ci                  // "%18 = OpConstant %6 1",
490fd4e5da5Sopenharmony_ci                  "%7 = OpPhi %6 %8 %4 %9 %5",
491fd4e5da5Sopenharmony_ci                  "%9 = OpIAdd %6 %7 %8",
492fd4e5da5Sopenharmony_ci                }
493fd4e5da5Sopenharmony_ci              },
494fd4e5da5Sopenharmony_ci              {7,
495fd4e5da5Sopenharmony_ci                {
496fd4e5da5Sopenharmony_ci                  "%9 = OpIAdd %6 %7 %8",
497fd4e5da5Sopenharmony_ci                  "%17 = OpSLessThan %16 %7 %18",
498fd4e5da5Sopenharmony_ci                }
499fd4e5da5Sopenharmony_ci              },
500fd4e5da5Sopenharmony_ci              {8,
501fd4e5da5Sopenharmony_ci                {
502fd4e5da5Sopenharmony_ci                  "%7 = OpPhi %6 %8 %4 %9 %5",
503fd4e5da5Sopenharmony_ci                  "%9 = OpIAdd %6 %7 %8",
504fd4e5da5Sopenharmony_ci                }
505fd4e5da5Sopenharmony_ci              },
506fd4e5da5Sopenharmony_ci              {9, {"%7 = OpPhi %6 %8 %4 %9 %5"}},
507fd4e5da5Sopenharmony_ci              {10,
508fd4e5da5Sopenharmony_ci                {
509fd4e5da5Sopenharmony_ci                  // "%12 = OpConstant %10 1.0",
510fd4e5da5Sopenharmony_ci                  "%11 = OpPhi %10 %12 %4 %13 %5",
511fd4e5da5Sopenharmony_ci                  "%13 = OpFAdd %10 %11 %12",
512fd4e5da5Sopenharmony_ci                }
513fd4e5da5Sopenharmony_ci              },
514fd4e5da5Sopenharmony_ci              {11, {"%13 = OpFAdd %10 %11 %12"}},
515fd4e5da5Sopenharmony_ci              {12,
516fd4e5da5Sopenharmony_ci                {
517fd4e5da5Sopenharmony_ci                  "%11 = OpPhi %10 %12 %4 %13 %5",
518fd4e5da5Sopenharmony_ci                  "%13 = OpFAdd %10 %11 %12",
519fd4e5da5Sopenharmony_ci                }
520fd4e5da5Sopenharmony_ci              },
521fd4e5da5Sopenharmony_ci              {13, {"%11 = OpPhi %10 %12 %4 %13 %5"}},
522fd4e5da5Sopenharmony_ci              {16, {"%17 = OpSLessThan %16 %7 %18"}},
523fd4e5da5Sopenharmony_ci              {17, {"OpBranchConditional %17 %5 %19"}},
524fd4e5da5Sopenharmony_ci              {18, {"%17 = OpSLessThan %16 %7 %18"}},
525fd4e5da5Sopenharmony_ci              {19,
526fd4e5da5Sopenharmony_ci                {
527fd4e5da5Sopenharmony_ci                  "OpLoopMerge %19 %5 None",
528fd4e5da5Sopenharmony_ci                  "OpBranchConditional %17 %5 %19",
529fd4e5da5Sopenharmony_ci                }
530fd4e5da5Sopenharmony_ci              },
531fd4e5da5Sopenharmony_ci            },
532fd4e5da5Sopenharmony_ci          },
533fd4e5da5Sopenharmony_ci        },
534fd4e5da5Sopenharmony_ci        { // OpPhi defining and referencing the same id.
535fd4e5da5Sopenharmony_ci          "%1 = OpTypeBool "
536fd4e5da5Sopenharmony_ci          "%3 = OpTypeFunction %1 "
537fd4e5da5Sopenharmony_ci          "%2 = OpConstantTrue %1 "
538fd4e5da5Sopenharmony_ci          "%4 = OpFunction %1 None %3 "
539fd4e5da5Sopenharmony_ci          "%6 = OpLabel "
540fd4e5da5Sopenharmony_ci          "     OpBranch %7 "
541fd4e5da5Sopenharmony_ci          "%7 = OpLabel "
542fd4e5da5Sopenharmony_ci          "%8 = OpPhi %1   %8 %7   %2 %6 " // both defines and uses %8
543fd4e5da5Sopenharmony_ci          "     OpBranch %7 "
544fd4e5da5Sopenharmony_ci          "     OpFunctionEnd",
545fd4e5da5Sopenharmony_ci          {
546fd4e5da5Sopenharmony_ci            { // defs
547fd4e5da5Sopenharmony_ci              {1, "%1 = OpTypeBool"},
548fd4e5da5Sopenharmony_ci              {2, "%2 = OpConstantTrue %1"},
549fd4e5da5Sopenharmony_ci              {3, "%3 = OpTypeFunction %1"},
550fd4e5da5Sopenharmony_ci              {4, "%4 = OpFunction %1 None %3"},
551fd4e5da5Sopenharmony_ci              {6, "%6 = OpLabel"},
552fd4e5da5Sopenharmony_ci              {7, "%7 = OpLabel"},
553fd4e5da5Sopenharmony_ci              {8, "%8 = OpPhi %1 %8 %7 %2 %6"},
554fd4e5da5Sopenharmony_ci            },
555fd4e5da5Sopenharmony_ci            { // uses
556fd4e5da5Sopenharmony_ci              {1,
557fd4e5da5Sopenharmony_ci                {
558fd4e5da5Sopenharmony_ci                  "%2 = OpConstantTrue %1",
559fd4e5da5Sopenharmony_ci                  "%3 = OpTypeFunction %1",
560fd4e5da5Sopenharmony_ci                  "%4 = OpFunction %1 None %3",
561fd4e5da5Sopenharmony_ci                  "%8 = OpPhi %1 %8 %7 %2 %6",
562fd4e5da5Sopenharmony_ci                }
563fd4e5da5Sopenharmony_ci              },
564fd4e5da5Sopenharmony_ci              {2, {"%8 = OpPhi %1 %8 %7 %2 %6"}},
565fd4e5da5Sopenharmony_ci              {3, {"%4 = OpFunction %1 None %3"}},
566fd4e5da5Sopenharmony_ci              {6, {"%8 = OpPhi %1 %8 %7 %2 %6"}},
567fd4e5da5Sopenharmony_ci              {7,
568fd4e5da5Sopenharmony_ci                {
569fd4e5da5Sopenharmony_ci                  "OpBranch %7",
570fd4e5da5Sopenharmony_ci                  "%8 = OpPhi %1 %8 %7 %2 %6",
571fd4e5da5Sopenharmony_ci                  "OpBranch %7",
572fd4e5da5Sopenharmony_ci                }
573fd4e5da5Sopenharmony_ci              },
574fd4e5da5Sopenharmony_ci              {8, {"%8 = OpPhi %1 %8 %7 %2 %6"}},
575fd4e5da5Sopenharmony_ci            },
576fd4e5da5Sopenharmony_ci          },
577fd4e5da5Sopenharmony_ci        },
578fd4e5da5Sopenharmony_ci    })
579fd4e5da5Sopenharmony_ci);
580fd4e5da5Sopenharmony_ci// clang-format on
581fd4e5da5Sopenharmony_ci
582fd4e5da5Sopenharmony_cistruct ReplaceUseCase {
583fd4e5da5Sopenharmony_ci  const char* before;
584fd4e5da5Sopenharmony_ci  std::vector<std::pair<uint32_t, uint32_t>> candidates;
585fd4e5da5Sopenharmony_ci  const char* after;
586fd4e5da5Sopenharmony_ci  InstDefUse du;
587fd4e5da5Sopenharmony_ci};
588fd4e5da5Sopenharmony_ci
589fd4e5da5Sopenharmony_ciusing ReplaceUseTest = ::testing::TestWithParam<ReplaceUseCase>;
590fd4e5da5Sopenharmony_ci
591fd4e5da5Sopenharmony_ci// Disassembles the given |module| and returns the disassembly.
592fd4e5da5Sopenharmony_cistd::string DisassembleModule(Module* module) {
593fd4e5da5Sopenharmony_ci  SpirvTools tools(SPV_ENV_UNIVERSAL_1_1);
594fd4e5da5Sopenharmony_ci
595fd4e5da5Sopenharmony_ci  std::vector<uint32_t> binary;
596fd4e5da5Sopenharmony_ci  module->ToBinary(&binary, /* skip_nop = */ false);
597fd4e5da5Sopenharmony_ci
598fd4e5da5Sopenharmony_ci  std::string text;
599fd4e5da5Sopenharmony_ci  // We'll need to check the underlying id numbers.
600fd4e5da5Sopenharmony_ci  // So turn off friendly names for ids.
601fd4e5da5Sopenharmony_ci  tools.Disassemble(binary, &text, SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
602fd4e5da5Sopenharmony_ci  while (!text.empty() && text.back() == '\n') text.pop_back();
603fd4e5da5Sopenharmony_ci  return text;
604fd4e5da5Sopenharmony_ci}
605fd4e5da5Sopenharmony_ci
606fd4e5da5Sopenharmony_ciTEST_P(ReplaceUseTest, Case) {
607fd4e5da5Sopenharmony_ci  const auto& tc = GetParam();
608fd4e5da5Sopenharmony_ci
609fd4e5da5Sopenharmony_ci  // Build module.
610fd4e5da5Sopenharmony_ci  const std::vector<const char*> text = {tc.before};
611fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
612fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, JoinAllInsts(text),
613fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
614fd4e5da5Sopenharmony_ci  ASSERT_NE(nullptr, context);
615fd4e5da5Sopenharmony_ci
616fd4e5da5Sopenharmony_ci  // Force a re-build of def-use manager.
617fd4e5da5Sopenharmony_ci  context->InvalidateAnalyses(IRContext::Analysis::kAnalysisDefUse);
618fd4e5da5Sopenharmony_ci  (void)context->get_def_use_mgr();
619fd4e5da5Sopenharmony_ci
620fd4e5da5Sopenharmony_ci  // Do the substitution.
621fd4e5da5Sopenharmony_ci  for (const auto& candidate : tc.candidates) {
622fd4e5da5Sopenharmony_ci    context->ReplaceAllUsesWith(candidate.first, candidate.second);
623fd4e5da5Sopenharmony_ci  }
624fd4e5da5Sopenharmony_ci
625fd4e5da5Sopenharmony_ci  EXPECT_EQ(tc.after, DisassembleModule(context->module()));
626fd4e5da5Sopenharmony_ci  CheckDef(tc.du, context->get_def_use_mgr()->id_to_defs());
627fd4e5da5Sopenharmony_ci  CheckUse(tc.du, context->get_def_use_mgr(), context->module()->IdBound());
628fd4e5da5Sopenharmony_ci}
629fd4e5da5Sopenharmony_ci
630fd4e5da5Sopenharmony_ci// clang-format off
631fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(
632fd4e5da5Sopenharmony_ci    TestCase, ReplaceUseTest,
633fd4e5da5Sopenharmony_ci    ::testing::ValuesIn(std::vector<ReplaceUseCase>{
634fd4e5da5Sopenharmony_ci      { // no use, no replace request
635fd4e5da5Sopenharmony_ci        "", {}, "", {},
636fd4e5da5Sopenharmony_ci      },
637fd4e5da5Sopenharmony_ci      { // replace one use
638fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool "
639fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %1 3 "
640fd4e5da5Sopenharmony_ci        "%3 = OpTypeInt 32 0 ",
641fd4e5da5Sopenharmony_ci        {{1, 3}},
642fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool\n"
643fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %3 3\n"
644fd4e5da5Sopenharmony_ci        "%3 = OpTypeInt 32 0",
645fd4e5da5Sopenharmony_ci        {
646fd4e5da5Sopenharmony_ci          { // defs
647fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeBool"},
648fd4e5da5Sopenharmony_ci            {2, "%2 = OpTypeVector %3 3"},
649fd4e5da5Sopenharmony_ci            {3, "%3 = OpTypeInt 32 0"},
650fd4e5da5Sopenharmony_ci          },
651fd4e5da5Sopenharmony_ci          { // uses
652fd4e5da5Sopenharmony_ci            {3, {"%2 = OpTypeVector %3 3"}},
653fd4e5da5Sopenharmony_ci          },
654fd4e5da5Sopenharmony_ci        },
655fd4e5da5Sopenharmony_ci      },
656fd4e5da5Sopenharmony_ci      { // replace and then replace back
657fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool "
658fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %1 3 "
659fd4e5da5Sopenharmony_ci        "%3 = OpTypeInt 32 0",
660fd4e5da5Sopenharmony_ci        {{1, 3}, {3, 1}},
661fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool\n"
662fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %1 3\n"
663fd4e5da5Sopenharmony_ci        "%3 = OpTypeInt 32 0",
664fd4e5da5Sopenharmony_ci        {
665fd4e5da5Sopenharmony_ci          { // defs
666fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeBool"},
667fd4e5da5Sopenharmony_ci            {2, "%2 = OpTypeVector %1 3"},
668fd4e5da5Sopenharmony_ci            {3, "%3 = OpTypeInt 32 0"},
669fd4e5da5Sopenharmony_ci          },
670fd4e5da5Sopenharmony_ci          { // uses
671fd4e5da5Sopenharmony_ci            {1, {"%2 = OpTypeVector %1 3"}},
672fd4e5da5Sopenharmony_ci          },
673fd4e5da5Sopenharmony_ci        },
674fd4e5da5Sopenharmony_ci      },
675fd4e5da5Sopenharmony_ci      { // replace with the same id
676fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool "
677fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %1 3",
678fd4e5da5Sopenharmony_ci        {{1, 1}, {2, 2}, {3, 3}},
679fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool\n"
680fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %1 3",
681fd4e5da5Sopenharmony_ci        {
682fd4e5da5Sopenharmony_ci          { // defs
683fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeBool"},
684fd4e5da5Sopenharmony_ci            {2, "%2 = OpTypeVector %1 3"},
685fd4e5da5Sopenharmony_ci          },
686fd4e5da5Sopenharmony_ci          { // uses
687fd4e5da5Sopenharmony_ci            {1, {"%2 = OpTypeVector %1 3"}},
688fd4e5da5Sopenharmony_ci          },
689fd4e5da5Sopenharmony_ci        },
690fd4e5da5Sopenharmony_ci      },
691fd4e5da5Sopenharmony_ci      { // replace in sequence
692fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool "
693fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %1 3 "
694fd4e5da5Sopenharmony_ci        "%3 = OpTypeInt 32 0 "
695fd4e5da5Sopenharmony_ci        "%4 = OpTypeInt 32 1 ",
696fd4e5da5Sopenharmony_ci        {{1, 3}, {3, 4}},
697fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool\n"
698fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %4 3\n"
699fd4e5da5Sopenharmony_ci        "%3 = OpTypeInt 32 0\n"
700fd4e5da5Sopenharmony_ci        "%4 = OpTypeInt 32 1",
701fd4e5da5Sopenharmony_ci        {
702fd4e5da5Sopenharmony_ci          { // defs
703fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeBool"},
704fd4e5da5Sopenharmony_ci            {2, "%2 = OpTypeVector %4 3"},
705fd4e5da5Sopenharmony_ci            {3, "%3 = OpTypeInt 32 0"},
706fd4e5da5Sopenharmony_ci            {4, "%4 = OpTypeInt 32 1"},
707fd4e5da5Sopenharmony_ci          },
708fd4e5da5Sopenharmony_ci          { // uses
709fd4e5da5Sopenharmony_ci            {4, {"%2 = OpTypeVector %4 3"}},
710fd4e5da5Sopenharmony_ci          },
711fd4e5da5Sopenharmony_ci        },
712fd4e5da5Sopenharmony_ci      },
713fd4e5da5Sopenharmony_ci      { // replace multiple uses
714fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool "
715fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %1 2 "
716fd4e5da5Sopenharmony_ci        "%3 = OpTypeVector %1 3 "
717fd4e5da5Sopenharmony_ci        "%4 = OpTypeVector %1 4 "
718fd4e5da5Sopenharmony_ci        "%5 = OpTypeMatrix %2 2 "
719fd4e5da5Sopenharmony_ci        "%6 = OpTypeMatrix %3 3 "
720fd4e5da5Sopenharmony_ci        "%7 = OpTypeMatrix %4 4 "
721fd4e5da5Sopenharmony_ci        "%8 = OpTypeInt 32 0 "
722fd4e5da5Sopenharmony_ci        "%9 = OpTypeInt 32 1 "
723fd4e5da5Sopenharmony_ci        "%10 = OpTypeInt 64 0",
724fd4e5da5Sopenharmony_ci        {{1, 8}, {2, 9}, {4, 10}},
725fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool\n"
726fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %8 2\n"
727fd4e5da5Sopenharmony_ci        "%3 = OpTypeVector %8 3\n"
728fd4e5da5Sopenharmony_ci        "%4 = OpTypeVector %8 4\n"
729fd4e5da5Sopenharmony_ci        "%5 = OpTypeMatrix %9 2\n"
730fd4e5da5Sopenharmony_ci        "%6 = OpTypeMatrix %3 3\n"
731fd4e5da5Sopenharmony_ci        "%7 = OpTypeMatrix %10 4\n"
732fd4e5da5Sopenharmony_ci        "%8 = OpTypeInt 32 0\n"
733fd4e5da5Sopenharmony_ci        "%9 = OpTypeInt 32 1\n"
734fd4e5da5Sopenharmony_ci        "%10 = OpTypeInt 64 0",
735fd4e5da5Sopenharmony_ci        {
736fd4e5da5Sopenharmony_ci          { // defs
737fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeBool"},
738fd4e5da5Sopenharmony_ci            {2, "%2 = OpTypeVector %8 2"},
739fd4e5da5Sopenharmony_ci            {3, "%3 = OpTypeVector %8 3"},
740fd4e5da5Sopenharmony_ci            {4, "%4 = OpTypeVector %8 4"},
741fd4e5da5Sopenharmony_ci            {5, "%5 = OpTypeMatrix %9 2"},
742fd4e5da5Sopenharmony_ci            {6, "%6 = OpTypeMatrix %3 3"},
743fd4e5da5Sopenharmony_ci            {7, "%7 = OpTypeMatrix %10 4"},
744fd4e5da5Sopenharmony_ci            {8, "%8 = OpTypeInt 32 0"},
745fd4e5da5Sopenharmony_ci            {9, "%9 = OpTypeInt 32 1"},
746fd4e5da5Sopenharmony_ci            {10, "%10 = OpTypeInt 64 0"},
747fd4e5da5Sopenharmony_ci          },
748fd4e5da5Sopenharmony_ci          { // uses
749fd4e5da5Sopenharmony_ci            {8,
750fd4e5da5Sopenharmony_ci              {
751fd4e5da5Sopenharmony_ci                "%2 = OpTypeVector %8 2",
752fd4e5da5Sopenharmony_ci                "%3 = OpTypeVector %8 3",
753fd4e5da5Sopenharmony_ci                "%4 = OpTypeVector %8 4",
754fd4e5da5Sopenharmony_ci              }
755fd4e5da5Sopenharmony_ci            },
756fd4e5da5Sopenharmony_ci            {9, {"%5 = OpTypeMatrix %9 2"}},
757fd4e5da5Sopenharmony_ci            {3, {"%6 = OpTypeMatrix %3 3"}},
758fd4e5da5Sopenharmony_ci            {10, {"%7 = OpTypeMatrix %10 4"}},
759fd4e5da5Sopenharmony_ci          },
760fd4e5da5Sopenharmony_ci        },
761fd4e5da5Sopenharmony_ci      },
762fd4e5da5Sopenharmony_ci      { // OpPhi.
763fd4e5da5Sopenharmony_ci        kOpPhiTestFunction,
764fd4e5da5Sopenharmony_ci        // replace one id used by OpPhi, replace one id generated by OpPhi
765fd4e5da5Sopenharmony_ci        {{9, 13}, {11, 9}},
766fd4e5da5Sopenharmony_ci         "%1 = OpTypeVoid\n"
767fd4e5da5Sopenharmony_ci         "%6 = OpTypeInt 32 0\n"
768fd4e5da5Sopenharmony_ci         "%10 = OpTypeFloat 32\n"
769fd4e5da5Sopenharmony_ci         "%16 = OpTypeBool\n"
770fd4e5da5Sopenharmony_ci         "%3 = OpTypeFunction %1\n"
771fd4e5da5Sopenharmony_ci         "%8 = OpConstant %6 0\n"
772fd4e5da5Sopenharmony_ci         "%18 = OpConstant %6 1\n"
773fd4e5da5Sopenharmony_ci         "%12 = OpConstant %10 1\n"
774fd4e5da5Sopenharmony_ci         "%2 = OpFunction %1 None %3\n"
775fd4e5da5Sopenharmony_ci         "%4 = OpLabel\n"
776fd4e5da5Sopenharmony_ci               "OpBranch %5\n"
777fd4e5da5Sopenharmony_ci
778fd4e5da5Sopenharmony_ci         "%5 = OpLabel\n"
779fd4e5da5Sopenharmony_ci         "%7 = OpPhi %6 %8 %4 %13 %5\n" // %9 -> %13
780fd4e5da5Sopenharmony_ci        "%11 = OpPhi %10 %12 %4 %13 %5\n"
781fd4e5da5Sopenharmony_ci         "%9 = OpIAdd %6 %7 %8\n"
782fd4e5da5Sopenharmony_ci        "%13 = OpFAdd %10 %9 %12\n"       // %11 -> %9
783fd4e5da5Sopenharmony_ci        "%17 = OpSLessThan %16 %7 %18\n"
784fd4e5da5Sopenharmony_ci              "OpLoopMerge %19 %5 None\n"
785fd4e5da5Sopenharmony_ci              "OpBranchConditional %17 %5 %19\n"
786fd4e5da5Sopenharmony_ci
787fd4e5da5Sopenharmony_ci        "%19 = OpLabel\n"
788fd4e5da5Sopenharmony_ci              "OpReturn\n"
789fd4e5da5Sopenharmony_ci              "OpFunctionEnd",
790fd4e5da5Sopenharmony_ci        {
791fd4e5da5Sopenharmony_ci          { // defs.
792fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeVoid"},
793fd4e5da5Sopenharmony_ci            {2, "%2 = OpFunction %1 None %3"},
794fd4e5da5Sopenharmony_ci            {3, "%3 = OpTypeFunction %1"},
795fd4e5da5Sopenharmony_ci            {4, "%4 = OpLabel"},
796fd4e5da5Sopenharmony_ci            {5, "%5 = OpLabel"},
797fd4e5da5Sopenharmony_ci            {6, "%6 = OpTypeInt 32 0"},
798fd4e5da5Sopenharmony_ci            {7, "%7 = OpPhi %6 %8 %4 %13 %5"},
799fd4e5da5Sopenharmony_ci            {8, "%8 = OpConstant %6 0"},
800fd4e5da5Sopenharmony_ci            {9, "%9 = OpIAdd %6 %7 %8"},
801fd4e5da5Sopenharmony_ci            {10, "%10 = OpTypeFloat 32"},
802fd4e5da5Sopenharmony_ci            {11, "%11 = OpPhi %10 %12 %4 %13 %5"},
803fd4e5da5Sopenharmony_ci            {12, "%12 = OpConstant %10 1.0"},
804fd4e5da5Sopenharmony_ci            {13, "%13 = OpFAdd %10 %9 %12"},
805fd4e5da5Sopenharmony_ci            {16, "%16 = OpTypeBool"},
806fd4e5da5Sopenharmony_ci            {17, "%17 = OpSLessThan %16 %7 %18"},
807fd4e5da5Sopenharmony_ci            {18, "%18 = OpConstant %6 1"},
808fd4e5da5Sopenharmony_ci            {19, "%19 = OpLabel"},
809fd4e5da5Sopenharmony_ci          },
810fd4e5da5Sopenharmony_ci          { // uses
811fd4e5da5Sopenharmony_ci            {1,
812fd4e5da5Sopenharmony_ci              {
813fd4e5da5Sopenharmony_ci                "%2 = OpFunction %1 None %3",
814fd4e5da5Sopenharmony_ci                "%3 = OpTypeFunction %1",
815fd4e5da5Sopenharmony_ci              }
816fd4e5da5Sopenharmony_ci            },
817fd4e5da5Sopenharmony_ci            {3, {"%2 = OpFunction %1 None %3"}},
818fd4e5da5Sopenharmony_ci            {4,
819fd4e5da5Sopenharmony_ci              {
820fd4e5da5Sopenharmony_ci                "%7 = OpPhi %6 %8 %4 %13 %5",
821fd4e5da5Sopenharmony_ci                "%11 = OpPhi %10 %12 %4 %13 %5",
822fd4e5da5Sopenharmony_ci              }
823fd4e5da5Sopenharmony_ci            },
824fd4e5da5Sopenharmony_ci            {5,
825fd4e5da5Sopenharmony_ci              {
826fd4e5da5Sopenharmony_ci                "OpBranch %5",
827fd4e5da5Sopenharmony_ci                "%7 = OpPhi %6 %8 %4 %13 %5",
828fd4e5da5Sopenharmony_ci                "%11 = OpPhi %10 %12 %4 %13 %5",
829fd4e5da5Sopenharmony_ci                "OpLoopMerge %19 %5 None",
830fd4e5da5Sopenharmony_ci                "OpBranchConditional %17 %5 %19",
831fd4e5da5Sopenharmony_ci              }
832fd4e5da5Sopenharmony_ci            },
833fd4e5da5Sopenharmony_ci            {6,
834fd4e5da5Sopenharmony_ci              {
835fd4e5da5Sopenharmony_ci                // Can't properly check constants
836fd4e5da5Sopenharmony_ci                // "%8 = OpConstant %6 0",
837fd4e5da5Sopenharmony_ci                // "%18 = OpConstant %6 1",
838fd4e5da5Sopenharmony_ci                "%7 = OpPhi %6 %8 %4 %13 %5",
839fd4e5da5Sopenharmony_ci                "%9 = OpIAdd %6 %7 %8"
840fd4e5da5Sopenharmony_ci              }
841fd4e5da5Sopenharmony_ci            },
842fd4e5da5Sopenharmony_ci            {7,
843fd4e5da5Sopenharmony_ci              {
844fd4e5da5Sopenharmony_ci                "%9 = OpIAdd %6 %7 %8",
845fd4e5da5Sopenharmony_ci                "%17 = OpSLessThan %16 %7 %18",
846fd4e5da5Sopenharmony_ci              }
847fd4e5da5Sopenharmony_ci            },
848fd4e5da5Sopenharmony_ci            {8,
849fd4e5da5Sopenharmony_ci              {
850fd4e5da5Sopenharmony_ci                "%7 = OpPhi %6 %8 %4 %13 %5",
851fd4e5da5Sopenharmony_ci                "%9 = OpIAdd %6 %7 %8",
852fd4e5da5Sopenharmony_ci              }
853fd4e5da5Sopenharmony_ci            },
854fd4e5da5Sopenharmony_ci            {9, {"%13 = OpFAdd %10 %9 %12"}}, // uses of %9 changed from %7 to %13
855fd4e5da5Sopenharmony_ci            {10,
856fd4e5da5Sopenharmony_ci              {
857fd4e5da5Sopenharmony_ci                "%11 = OpPhi %10 %12 %4 %13 %5",
858fd4e5da5Sopenharmony_ci                // "%12 = OpConstant %10 1",
859fd4e5da5Sopenharmony_ci                "%13 = OpFAdd %10 %9 %12"
860fd4e5da5Sopenharmony_ci              }
861fd4e5da5Sopenharmony_ci            },
862fd4e5da5Sopenharmony_ci            // no more uses of %11
863fd4e5da5Sopenharmony_ci            {12,
864fd4e5da5Sopenharmony_ci              {
865fd4e5da5Sopenharmony_ci                "%11 = OpPhi %10 %12 %4 %13 %5",
866fd4e5da5Sopenharmony_ci                "%13 = OpFAdd %10 %9 %12"
867fd4e5da5Sopenharmony_ci              }
868fd4e5da5Sopenharmony_ci            },
869fd4e5da5Sopenharmony_ci            {13, {
870fd4e5da5Sopenharmony_ci                   "%7 = OpPhi %6 %8 %4 %13 %5",
871fd4e5da5Sopenharmony_ci                   "%11 = OpPhi %10 %12 %4 %13 %5",
872fd4e5da5Sopenharmony_ci                 }
873fd4e5da5Sopenharmony_ci            },
874fd4e5da5Sopenharmony_ci            {16, {"%17 = OpSLessThan %16 %7 %18"}},
875fd4e5da5Sopenharmony_ci            {17, {"OpBranchConditional %17 %5 %19"}},
876fd4e5da5Sopenharmony_ci            {18, {"%17 = OpSLessThan %16 %7 %18"}},
877fd4e5da5Sopenharmony_ci            {19,
878fd4e5da5Sopenharmony_ci              {
879fd4e5da5Sopenharmony_ci                "OpLoopMerge %19 %5 None",
880fd4e5da5Sopenharmony_ci                "OpBranchConditional %17 %5 %19",
881fd4e5da5Sopenharmony_ci              }
882fd4e5da5Sopenharmony_ci            },
883fd4e5da5Sopenharmony_ci          },
884fd4e5da5Sopenharmony_ci        },
885fd4e5da5Sopenharmony_ci      },
886fd4e5da5Sopenharmony_ci      { // OpPhi defining and referencing the same id.
887fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool "
888fd4e5da5Sopenharmony_ci        "%3 = OpTypeFunction %1 "
889fd4e5da5Sopenharmony_ci        "%2 = OpConstantTrue %1 "
890fd4e5da5Sopenharmony_ci
891fd4e5da5Sopenharmony_ci        "%4 = OpFunction %3 None %1 "
892fd4e5da5Sopenharmony_ci        "%6 = OpLabel "
893fd4e5da5Sopenharmony_ci        "     OpBranch %7 "
894fd4e5da5Sopenharmony_ci        "%7 = OpLabel "
895fd4e5da5Sopenharmony_ci        "%8 = OpPhi %1   %8 %7   %2 %6 " // both defines and uses %8
896fd4e5da5Sopenharmony_ci        "     OpBranch %7 "
897fd4e5da5Sopenharmony_ci        "     OpFunctionEnd",
898fd4e5da5Sopenharmony_ci        {{8, 2}},
899fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool\n"
900fd4e5da5Sopenharmony_ci        "%3 = OpTypeFunction %1\n"
901fd4e5da5Sopenharmony_ci        "%2 = OpConstantTrue %1\n"
902fd4e5da5Sopenharmony_ci
903fd4e5da5Sopenharmony_ci        "%4 = OpFunction %3 None %1\n"
904fd4e5da5Sopenharmony_ci        "%6 = OpLabel\n"
905fd4e5da5Sopenharmony_ci             "OpBranch %7\n"
906fd4e5da5Sopenharmony_ci        "%7 = OpLabel\n"
907fd4e5da5Sopenharmony_ci        "%8 = OpPhi %1 %2 %7 %2 %6\n" // use of %8 changed to %2
908fd4e5da5Sopenharmony_ci             "OpBranch %7\n"
909fd4e5da5Sopenharmony_ci             "OpFunctionEnd",
910fd4e5da5Sopenharmony_ci        {
911fd4e5da5Sopenharmony_ci          { // defs
912fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeBool"},
913fd4e5da5Sopenharmony_ci            {2, "%2 = OpConstantTrue %1"},
914fd4e5da5Sopenharmony_ci            {3, "%3 = OpTypeFunction %1"},
915fd4e5da5Sopenharmony_ci            {4, "%4 = OpFunction %3 None %1"},
916fd4e5da5Sopenharmony_ci            {6, "%6 = OpLabel"},
917fd4e5da5Sopenharmony_ci            {7, "%7 = OpLabel"},
918fd4e5da5Sopenharmony_ci            {8, "%8 = OpPhi %1 %2 %7 %2 %6"},
919fd4e5da5Sopenharmony_ci          },
920fd4e5da5Sopenharmony_ci          { // uses
921fd4e5da5Sopenharmony_ci            {1,
922fd4e5da5Sopenharmony_ci              {
923fd4e5da5Sopenharmony_ci                "%2 = OpConstantTrue %1",
924fd4e5da5Sopenharmony_ci                "%3 = OpTypeFunction %1",
925fd4e5da5Sopenharmony_ci                "%4 = OpFunction %3 None %1",
926fd4e5da5Sopenharmony_ci                "%8 = OpPhi %1 %2 %7 %2 %6",
927fd4e5da5Sopenharmony_ci              }
928fd4e5da5Sopenharmony_ci            },
929fd4e5da5Sopenharmony_ci            {2,
930fd4e5da5Sopenharmony_ci              {
931fd4e5da5Sopenharmony_ci                // Only checking users
932fd4e5da5Sopenharmony_ci                "%8 = OpPhi %1 %2 %7 %2 %6",
933fd4e5da5Sopenharmony_ci              }
934fd4e5da5Sopenharmony_ci            },
935fd4e5da5Sopenharmony_ci            {3, {"%4 = OpFunction %3 None %1"}},
936fd4e5da5Sopenharmony_ci            {6, {"%8 = OpPhi %1 %2 %7 %2 %6"}},
937fd4e5da5Sopenharmony_ci            {7,
938fd4e5da5Sopenharmony_ci              {
939fd4e5da5Sopenharmony_ci                "OpBranch %7",
940fd4e5da5Sopenharmony_ci                "%8 = OpPhi %1 %2 %7 %2 %6",
941fd4e5da5Sopenharmony_ci                "OpBranch %7",
942fd4e5da5Sopenharmony_ci              }
943fd4e5da5Sopenharmony_ci            },
944fd4e5da5Sopenharmony_ci            // {8, {"%8 = OpPhi %1 %8 %7 %2 %6"}},
945fd4e5da5Sopenharmony_ci          },
946fd4e5da5Sopenharmony_ci        },
947fd4e5da5Sopenharmony_ci      },
948fd4e5da5Sopenharmony_ci    })
949fd4e5da5Sopenharmony_ci);
950fd4e5da5Sopenharmony_ci// clang-format on
951fd4e5da5Sopenharmony_ci
952fd4e5da5Sopenharmony_cistruct KillDefCase {
953fd4e5da5Sopenharmony_ci  const char* before;
954fd4e5da5Sopenharmony_ci  std::vector<uint32_t> ids_to_kill;
955fd4e5da5Sopenharmony_ci  const char* after;
956fd4e5da5Sopenharmony_ci  InstDefUse du;
957fd4e5da5Sopenharmony_ci};
958fd4e5da5Sopenharmony_ci
959fd4e5da5Sopenharmony_ciusing KillDefTest = ::testing::TestWithParam<KillDefCase>;
960fd4e5da5Sopenharmony_ci
961fd4e5da5Sopenharmony_ciTEST_P(KillDefTest, Case) {
962fd4e5da5Sopenharmony_ci  const auto& tc = GetParam();
963fd4e5da5Sopenharmony_ci
964fd4e5da5Sopenharmony_ci  // Build module.
965fd4e5da5Sopenharmony_ci  const std::vector<const char*> text = {tc.before};
966fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
967fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, JoinAllInsts(text),
968fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
969fd4e5da5Sopenharmony_ci  ASSERT_NE(nullptr, context);
970fd4e5da5Sopenharmony_ci
971fd4e5da5Sopenharmony_ci  // Analyze def and use.
972fd4e5da5Sopenharmony_ci  DefUseManager manager(context->module());
973fd4e5da5Sopenharmony_ci
974fd4e5da5Sopenharmony_ci  // Do the substitution.
975fd4e5da5Sopenharmony_ci  for (const auto id : tc.ids_to_kill) context->KillDef(id);
976fd4e5da5Sopenharmony_ci
977fd4e5da5Sopenharmony_ci  EXPECT_EQ(tc.after, DisassembleModule(context->module()));
978fd4e5da5Sopenharmony_ci  CheckDef(tc.du, context->get_def_use_mgr()->id_to_defs());
979fd4e5da5Sopenharmony_ci  CheckUse(tc.du, context->get_def_use_mgr(), context->module()->IdBound());
980fd4e5da5Sopenharmony_ci}
981fd4e5da5Sopenharmony_ci
982fd4e5da5Sopenharmony_ci// clang-format off
983fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(
984fd4e5da5Sopenharmony_ci    TestCase, KillDefTest,
985fd4e5da5Sopenharmony_ci    ::testing::ValuesIn(std::vector<KillDefCase>{
986fd4e5da5Sopenharmony_ci      { // no def, no use, no kill
987fd4e5da5Sopenharmony_ci        "", {}, "", {}
988fd4e5da5Sopenharmony_ci      },
989fd4e5da5Sopenharmony_ci      { // kill nothing
990fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool "
991fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %1 2 "
992fd4e5da5Sopenharmony_ci        "%3 = OpTypeVector %1 3 ",
993fd4e5da5Sopenharmony_ci        {},
994fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool\n"
995fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %1 2\n"
996fd4e5da5Sopenharmony_ci        "%3 = OpTypeVector %1 3",
997fd4e5da5Sopenharmony_ci        {
998fd4e5da5Sopenharmony_ci          { // defs
999fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeBool"},
1000fd4e5da5Sopenharmony_ci            {2, "%2 = OpTypeVector %1 2"},
1001fd4e5da5Sopenharmony_ci            {3, "%3 = OpTypeVector %1 3"},
1002fd4e5da5Sopenharmony_ci          },
1003fd4e5da5Sopenharmony_ci          { // uses
1004fd4e5da5Sopenharmony_ci            {1,
1005fd4e5da5Sopenharmony_ci              {
1006fd4e5da5Sopenharmony_ci                "%2 = OpTypeVector %1 2",
1007fd4e5da5Sopenharmony_ci                "%3 = OpTypeVector %1 3",
1008fd4e5da5Sopenharmony_ci              }
1009fd4e5da5Sopenharmony_ci            },
1010fd4e5da5Sopenharmony_ci          },
1011fd4e5da5Sopenharmony_ci        },
1012fd4e5da5Sopenharmony_ci      },
1013fd4e5da5Sopenharmony_ci      { // kill id used, kill id not used, kill id not defined
1014fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool "
1015fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %1 2 "
1016fd4e5da5Sopenharmony_ci        "%3 = OpTypeVector %1 3 "
1017fd4e5da5Sopenharmony_ci        "%4 = OpTypeVector %1 4 "
1018fd4e5da5Sopenharmony_ci        "%5 = OpTypeMatrix %3 3 "
1019fd4e5da5Sopenharmony_ci        "%6 = OpTypeMatrix %2 3",
1020fd4e5da5Sopenharmony_ci        {1, 3, 5, 10}, // ids to kill
1021fd4e5da5Sopenharmony_ci        "%2 = OpTypeVector %1 2\n"
1022fd4e5da5Sopenharmony_ci        "%4 = OpTypeVector %1 4\n"
1023fd4e5da5Sopenharmony_ci        "%6 = OpTypeMatrix %2 3",
1024fd4e5da5Sopenharmony_ci        {
1025fd4e5da5Sopenharmony_ci          { // defs
1026fd4e5da5Sopenharmony_ci            {2, "%2 = OpTypeVector %1 2"},
1027fd4e5da5Sopenharmony_ci            {4, "%4 = OpTypeVector %1 4"},
1028fd4e5da5Sopenharmony_ci            {6, "%6 = OpTypeMatrix %2 3"},
1029fd4e5da5Sopenharmony_ci          },
1030fd4e5da5Sopenharmony_ci          { // uses. %1 and %3 are both killed, so no uses
1031fd4e5da5Sopenharmony_ci            // recorded for them anymore.
1032fd4e5da5Sopenharmony_ci            {2, {"%6 = OpTypeMatrix %2 3"}},
1033fd4e5da5Sopenharmony_ci          }
1034fd4e5da5Sopenharmony_ci        },
1035fd4e5da5Sopenharmony_ci      },
1036fd4e5da5Sopenharmony_ci      { // OpPhi.
1037fd4e5da5Sopenharmony_ci        kOpPhiTestFunction,
1038fd4e5da5Sopenharmony_ci        {9, 11}, // kill one id used by OpPhi, kill one id generated by OpPhi
1039fd4e5da5Sopenharmony_ci         "%1 = OpTypeVoid\n"
1040fd4e5da5Sopenharmony_ci         "%6 = OpTypeInt 32 0\n"
1041fd4e5da5Sopenharmony_ci         "%10 = OpTypeFloat 32\n"
1042fd4e5da5Sopenharmony_ci         "%16 = OpTypeBool\n"
1043fd4e5da5Sopenharmony_ci         "%3 = OpTypeFunction %1\n"
1044fd4e5da5Sopenharmony_ci         "%8 = OpConstant %6 0\n"
1045fd4e5da5Sopenharmony_ci         "%18 = OpConstant %6 1\n"
1046fd4e5da5Sopenharmony_ci         "%12 = OpConstant %10 1\n"
1047fd4e5da5Sopenharmony_ci         "%2 = OpFunction %1 None %3\n"
1048fd4e5da5Sopenharmony_ci         "%4 = OpLabel\n"
1049fd4e5da5Sopenharmony_ci               "OpBranch %5\n"
1050fd4e5da5Sopenharmony_ci
1051fd4e5da5Sopenharmony_ci         "%5 = OpLabel\n"
1052fd4e5da5Sopenharmony_ci         "%7 = OpPhi %6 %8 %4 %9 %5\n"
1053fd4e5da5Sopenharmony_ci        "%13 = OpFAdd %10 %11 %12\n"
1054fd4e5da5Sopenharmony_ci        "%17 = OpSLessThan %16 %7 %18\n"
1055fd4e5da5Sopenharmony_ci              "OpLoopMerge %19 %5 None\n"
1056fd4e5da5Sopenharmony_ci              "OpBranchConditional %17 %5 %19\n"
1057fd4e5da5Sopenharmony_ci
1058fd4e5da5Sopenharmony_ci        "%19 = OpLabel\n"
1059fd4e5da5Sopenharmony_ci              "OpReturn\n"
1060fd4e5da5Sopenharmony_ci              "OpFunctionEnd",
1061fd4e5da5Sopenharmony_ci        {
1062fd4e5da5Sopenharmony_ci          { // defs. %9 & %11 are killed.
1063fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeVoid"},
1064fd4e5da5Sopenharmony_ci            {2, "%2 = OpFunction %1 None %3"},
1065fd4e5da5Sopenharmony_ci            {3, "%3 = OpTypeFunction %1"},
1066fd4e5da5Sopenharmony_ci            {4, "%4 = OpLabel"},
1067fd4e5da5Sopenharmony_ci            {5, "%5 = OpLabel"},
1068fd4e5da5Sopenharmony_ci            {6, "%6 = OpTypeInt 32 0"},
1069fd4e5da5Sopenharmony_ci            {7, "%7 = OpPhi %6 %8 %4 %9 %5"},
1070fd4e5da5Sopenharmony_ci            {8, "%8 = OpConstant %6 0"},
1071fd4e5da5Sopenharmony_ci            {10, "%10 = OpTypeFloat 32"},
1072fd4e5da5Sopenharmony_ci            {12, "%12 = OpConstant %10 1.0"},
1073fd4e5da5Sopenharmony_ci            {13, "%13 = OpFAdd %10 %11 %12"},
1074fd4e5da5Sopenharmony_ci            {16, "%16 = OpTypeBool"},
1075fd4e5da5Sopenharmony_ci            {17, "%17 = OpSLessThan %16 %7 %18"},
1076fd4e5da5Sopenharmony_ci            {18, "%18 = OpConstant %6 1"},
1077fd4e5da5Sopenharmony_ci            {19, "%19 = OpLabel"},
1078fd4e5da5Sopenharmony_ci          },
1079fd4e5da5Sopenharmony_ci          { // uses
1080fd4e5da5Sopenharmony_ci            {1,
1081fd4e5da5Sopenharmony_ci              {
1082fd4e5da5Sopenharmony_ci                "%2 = OpFunction %1 None %3",
1083fd4e5da5Sopenharmony_ci                "%3 = OpTypeFunction %1",
1084fd4e5da5Sopenharmony_ci              }
1085fd4e5da5Sopenharmony_ci            },
1086fd4e5da5Sopenharmony_ci            {3, {"%2 = OpFunction %1 None %3"}},
1087fd4e5da5Sopenharmony_ci            {4,
1088fd4e5da5Sopenharmony_ci              {
1089fd4e5da5Sopenharmony_ci                "%7 = OpPhi %6 %8 %4 %9 %5",
1090fd4e5da5Sopenharmony_ci                // "%11 = OpPhi %10 %12 %4 %13 %5",
1091fd4e5da5Sopenharmony_ci              }
1092fd4e5da5Sopenharmony_ci            },
1093fd4e5da5Sopenharmony_ci            {5,
1094fd4e5da5Sopenharmony_ci              {
1095fd4e5da5Sopenharmony_ci                "OpBranch %5",
1096fd4e5da5Sopenharmony_ci                "%7 = OpPhi %6 %8 %4 %9 %5",
1097fd4e5da5Sopenharmony_ci                // "%11 = OpPhi %10 %12 %4 %13 %5",
1098fd4e5da5Sopenharmony_ci                "OpLoopMerge %19 %5 None",
1099fd4e5da5Sopenharmony_ci                "OpBranchConditional %17 %5 %19",
1100fd4e5da5Sopenharmony_ci              }
1101fd4e5da5Sopenharmony_ci            },
1102fd4e5da5Sopenharmony_ci            {6,
1103fd4e5da5Sopenharmony_ci              {
1104fd4e5da5Sopenharmony_ci                // Can't properly check constants
1105fd4e5da5Sopenharmony_ci                // "%8 = OpConstant %6 0",
1106fd4e5da5Sopenharmony_ci                // "%18 = OpConstant %6 1",
1107fd4e5da5Sopenharmony_ci                "%7 = OpPhi %6 %8 %4 %9 %5",
1108fd4e5da5Sopenharmony_ci                // "%9 = OpIAdd %6 %7 %8"
1109fd4e5da5Sopenharmony_ci              }
1110fd4e5da5Sopenharmony_ci            },
1111fd4e5da5Sopenharmony_ci            {7, {"%17 = OpSLessThan %16 %7 %18"}},
1112fd4e5da5Sopenharmony_ci            {8,
1113fd4e5da5Sopenharmony_ci              {
1114fd4e5da5Sopenharmony_ci                "%7 = OpPhi %6 %8 %4 %9 %5",
1115fd4e5da5Sopenharmony_ci                // "%9 = OpIAdd %6 %7 %8",
1116fd4e5da5Sopenharmony_ci              }
1117fd4e5da5Sopenharmony_ci            },
1118fd4e5da5Sopenharmony_ci            // {9, {"%7 = OpPhi %6 %8 %4 %13 %5"}},
1119fd4e5da5Sopenharmony_ci            {10,
1120fd4e5da5Sopenharmony_ci              {
1121fd4e5da5Sopenharmony_ci                // "%11 = OpPhi %10 %12 %4 %13 %5",
1122fd4e5da5Sopenharmony_ci                // "%12 = OpConstant %10 1",
1123fd4e5da5Sopenharmony_ci                "%13 = OpFAdd %10 %11 %12"
1124fd4e5da5Sopenharmony_ci              }
1125fd4e5da5Sopenharmony_ci            },
1126fd4e5da5Sopenharmony_ci            // {11, {"%13 = OpFAdd %10 %11 %12"}},
1127fd4e5da5Sopenharmony_ci            {12,
1128fd4e5da5Sopenharmony_ci              {
1129fd4e5da5Sopenharmony_ci                // "%11 = OpPhi %10 %12 %4 %13 %5",
1130fd4e5da5Sopenharmony_ci                "%13 = OpFAdd %10 %11 %12"
1131fd4e5da5Sopenharmony_ci              }
1132fd4e5da5Sopenharmony_ci            },
1133fd4e5da5Sopenharmony_ci            // {13, {"%11 = OpPhi %10 %12 %4 %13 %5"}},
1134fd4e5da5Sopenharmony_ci            {16, {"%17 = OpSLessThan %16 %7 %18"}},
1135fd4e5da5Sopenharmony_ci            {17, {"OpBranchConditional %17 %5 %19"}},
1136fd4e5da5Sopenharmony_ci            {18, {"%17 = OpSLessThan %16 %7 %18"}},
1137fd4e5da5Sopenharmony_ci            {19,
1138fd4e5da5Sopenharmony_ci              {
1139fd4e5da5Sopenharmony_ci                "OpLoopMerge %19 %5 None",
1140fd4e5da5Sopenharmony_ci                "OpBranchConditional %17 %5 %19",
1141fd4e5da5Sopenharmony_ci              }
1142fd4e5da5Sopenharmony_ci            },
1143fd4e5da5Sopenharmony_ci          },
1144fd4e5da5Sopenharmony_ci        },
1145fd4e5da5Sopenharmony_ci      },
1146fd4e5da5Sopenharmony_ci      { // OpPhi defining and referencing the same id.
1147fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool "
1148fd4e5da5Sopenharmony_ci        "%3 = OpTypeFunction %1 "
1149fd4e5da5Sopenharmony_ci        "%2 = OpConstantTrue %1 "
1150fd4e5da5Sopenharmony_ci        "%4 = OpFunction %3 None %1 "
1151fd4e5da5Sopenharmony_ci        "%6 = OpLabel "
1152fd4e5da5Sopenharmony_ci        "     OpBranch %7 "
1153fd4e5da5Sopenharmony_ci        "%7 = OpLabel "
1154fd4e5da5Sopenharmony_ci        "%8 = OpPhi %1   %8 %7   %2 %6 " // both defines and uses %8
1155fd4e5da5Sopenharmony_ci        "     OpBranch %7 "
1156fd4e5da5Sopenharmony_ci        "     OpFunctionEnd",
1157fd4e5da5Sopenharmony_ci        {8},
1158fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool\n"
1159fd4e5da5Sopenharmony_ci        "%3 = OpTypeFunction %1\n"
1160fd4e5da5Sopenharmony_ci        "%2 = OpConstantTrue %1\n"
1161fd4e5da5Sopenharmony_ci
1162fd4e5da5Sopenharmony_ci        "%4 = OpFunction %3 None %1\n"
1163fd4e5da5Sopenharmony_ci        "%6 = OpLabel\n"
1164fd4e5da5Sopenharmony_ci             "OpBranch %7\n"
1165fd4e5da5Sopenharmony_ci        "%7 = OpLabel\n"
1166fd4e5da5Sopenharmony_ci             "OpBranch %7\n"
1167fd4e5da5Sopenharmony_ci             "OpFunctionEnd",
1168fd4e5da5Sopenharmony_ci        {
1169fd4e5da5Sopenharmony_ci          { // defs
1170fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeBool"},
1171fd4e5da5Sopenharmony_ci            {2, "%2 = OpConstantTrue %1"},
1172fd4e5da5Sopenharmony_ci            {3, "%3 = OpTypeFunction %1"},
1173fd4e5da5Sopenharmony_ci            {4, "%4 = OpFunction %3 None %1"},
1174fd4e5da5Sopenharmony_ci            {6, "%6 = OpLabel"},
1175fd4e5da5Sopenharmony_ci            {7, "%7 = OpLabel"},
1176fd4e5da5Sopenharmony_ci            // {8, "%8 = OpPhi %1 %8 %7 %2 %6"},
1177fd4e5da5Sopenharmony_ci          },
1178fd4e5da5Sopenharmony_ci          { // uses
1179fd4e5da5Sopenharmony_ci            {1,
1180fd4e5da5Sopenharmony_ci              {
1181fd4e5da5Sopenharmony_ci                "%2 = OpConstantTrue %1",
1182fd4e5da5Sopenharmony_ci                "%3 = OpTypeFunction %1",
1183fd4e5da5Sopenharmony_ci                "%4 = OpFunction %3 None %1",
1184fd4e5da5Sopenharmony_ci                // "%8 = OpPhi %1 %8 %7 %2 %6",
1185fd4e5da5Sopenharmony_ci              }
1186fd4e5da5Sopenharmony_ci            },
1187fd4e5da5Sopenharmony_ci            // {2, {"%8 = OpPhi %1 %8 %7 %2 %6"}},
1188fd4e5da5Sopenharmony_ci            {3, {"%4 = OpFunction %3 None %1"}},
1189fd4e5da5Sopenharmony_ci            // {6, {"%8 = OpPhi %1 %8 %7 %2 %6"}},
1190fd4e5da5Sopenharmony_ci            {7,
1191fd4e5da5Sopenharmony_ci              {
1192fd4e5da5Sopenharmony_ci                "OpBranch %7",
1193fd4e5da5Sopenharmony_ci                // "%8 = OpPhi %1 %8 %7 %2 %6",
1194fd4e5da5Sopenharmony_ci                "OpBranch %7",
1195fd4e5da5Sopenharmony_ci              }
1196fd4e5da5Sopenharmony_ci            },
1197fd4e5da5Sopenharmony_ci            // {8, {"%8 = OpPhi %1 %8 %7 %2 %6"}},
1198fd4e5da5Sopenharmony_ci          },
1199fd4e5da5Sopenharmony_ci        },
1200fd4e5da5Sopenharmony_ci      },
1201fd4e5da5Sopenharmony_ci    })
1202fd4e5da5Sopenharmony_ci);
1203fd4e5da5Sopenharmony_ci// clang-format on
1204fd4e5da5Sopenharmony_ci
1205fd4e5da5Sopenharmony_ciTEST(DefUseTest, OpSwitch) {
1206fd4e5da5Sopenharmony_ci  // Because disassembler has basic type check for OpSwitch's selector, we
1207fd4e5da5Sopenharmony_ci  // cannot use the DisassembleInst() in the above. Thus, this special spotcheck
1208fd4e5da5Sopenharmony_ci  // test case.
1209fd4e5da5Sopenharmony_ci
1210fd4e5da5Sopenharmony_ci  const char original_text[] =
1211fd4e5da5Sopenharmony_ci      // int64 f(int64 v) {
1212fd4e5da5Sopenharmony_ci      //   switch (v) {
1213fd4e5da5Sopenharmony_ci      //     case 1:                   break;
1214fd4e5da5Sopenharmony_ci      //     case -4294967296:         break;
1215fd4e5da5Sopenharmony_ci      //     case 9223372036854775807: break;
1216fd4e5da5Sopenharmony_ci      //     default:                  break;
1217fd4e5da5Sopenharmony_ci      //   }
1218fd4e5da5Sopenharmony_ci      //   return v;
1219fd4e5da5Sopenharmony_ci      // }
1220fd4e5da5Sopenharmony_ci      " %1 = OpTypeInt 64 1 "
1221fd4e5da5Sopenharmony_ci      " %3 = OpTypePointer Input %1 "
1222fd4e5da5Sopenharmony_ci      " %2 = OpFunction %1 None %3 "  // %3 is int64(int64)*
1223fd4e5da5Sopenharmony_ci      " %4 = OpFunctionParameter %1 "
1224fd4e5da5Sopenharmony_ci      " %5 = OpLabel "
1225fd4e5da5Sopenharmony_ci      " %6 = OpLoad %1 %4 "  // selector value
1226fd4e5da5Sopenharmony_ci      "      OpSelectionMerge %7 None "
1227fd4e5da5Sopenharmony_ci      "      OpSwitch %6 %8 "
1228fd4e5da5Sopenharmony_ci      "                  1                    %9 "  // 1
1229fd4e5da5Sopenharmony_ci      "                  -4294967296         %10 "  // -2^32
1230fd4e5da5Sopenharmony_ci      "                  9223372036854775807 %11 "  // 2^63-1
1231fd4e5da5Sopenharmony_ci      " %8 = OpLabel "                              // default
1232fd4e5da5Sopenharmony_ci      "      OpBranch %7 "
1233fd4e5da5Sopenharmony_ci      " %9 = OpLabel "
1234fd4e5da5Sopenharmony_ci      "      OpBranch %7 "
1235fd4e5da5Sopenharmony_ci      "%10 = OpLabel "
1236fd4e5da5Sopenharmony_ci      "      OpBranch %7 "
1237fd4e5da5Sopenharmony_ci      "%11 = OpLabel "
1238fd4e5da5Sopenharmony_ci      "      OpBranch %7 "
1239fd4e5da5Sopenharmony_ci      " %7 = OpLabel "
1240fd4e5da5Sopenharmony_ci      "      OpReturnValue %6 "
1241fd4e5da5Sopenharmony_ci      "      OpFunctionEnd";
1242fd4e5da5Sopenharmony_ci
1243fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
1244fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, original_text,
1245fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1246fd4e5da5Sopenharmony_ci  ASSERT_NE(nullptr, context);
1247fd4e5da5Sopenharmony_ci
1248fd4e5da5Sopenharmony_ci  // Force a re-build of def-use manager.
1249fd4e5da5Sopenharmony_ci  context->InvalidateAnalyses(IRContext::Analysis::kAnalysisDefUse);
1250fd4e5da5Sopenharmony_ci  (void)context->get_def_use_mgr();
1251fd4e5da5Sopenharmony_ci
1252fd4e5da5Sopenharmony_ci  // Do a bunch replacements.
1253fd4e5da5Sopenharmony_ci  context->ReplaceAllUsesWith(11, 7);   // to existing id
1254fd4e5da5Sopenharmony_ci  context->ReplaceAllUsesWith(10, 11);  // to existing id
1255fd4e5da5Sopenharmony_ci  context->ReplaceAllUsesWith(9, 10);   // to existing id
1256fd4e5da5Sopenharmony_ci
1257fd4e5da5Sopenharmony_ci  // clang-format off
1258fd4e5da5Sopenharmony_ci  const char modified_text[] =
1259fd4e5da5Sopenharmony_ci       "%1 = OpTypeInt 64 1\n"
1260fd4e5da5Sopenharmony_ci       "%3 = OpTypePointer Input %1\n"
1261fd4e5da5Sopenharmony_ci       "%2 = OpFunction %1 None %3\n" // %3 is int64(int64)*
1262fd4e5da5Sopenharmony_ci       "%4 = OpFunctionParameter %1\n"
1263fd4e5da5Sopenharmony_ci       "%5 = OpLabel\n"
1264fd4e5da5Sopenharmony_ci       "%6 = OpLoad %1 %4\n" // selector value
1265fd4e5da5Sopenharmony_ci            "OpSelectionMerge %7 None\n"
1266fd4e5da5Sopenharmony_ci            "OpSwitch %6 %8 1 %10 -4294967296 %11 9223372036854775807 %7\n" // changed!
1267fd4e5da5Sopenharmony_ci       "%8 = OpLabel\n"      // default
1268fd4e5da5Sopenharmony_ci            "OpBranch %7\n"
1269fd4e5da5Sopenharmony_ci       "%9 = OpLabel\n"
1270fd4e5da5Sopenharmony_ci            "OpBranch %7\n"
1271fd4e5da5Sopenharmony_ci      "%10 = OpLabel\n"
1272fd4e5da5Sopenharmony_ci            "OpBranch %7\n"
1273fd4e5da5Sopenharmony_ci      "%11 = OpLabel\n"
1274fd4e5da5Sopenharmony_ci            "OpBranch %7\n"
1275fd4e5da5Sopenharmony_ci       "%7 = OpLabel\n"
1276fd4e5da5Sopenharmony_ci            "OpReturnValue %6\n"
1277fd4e5da5Sopenharmony_ci            "OpFunctionEnd";
1278fd4e5da5Sopenharmony_ci  // clang-format on
1279fd4e5da5Sopenharmony_ci
1280fd4e5da5Sopenharmony_ci  EXPECT_EQ(modified_text, DisassembleModule(context->module()));
1281fd4e5da5Sopenharmony_ci
1282fd4e5da5Sopenharmony_ci  InstDefUse def_uses = {};
1283fd4e5da5Sopenharmony_ci  def_uses.defs = {
1284fd4e5da5Sopenharmony_ci      {1, "%1 = OpTypeInt 64 1"},
1285fd4e5da5Sopenharmony_ci      {2, "%2 = OpFunction %1 None %3"},
1286fd4e5da5Sopenharmony_ci      {3, "%3 = OpTypePointer Input %1"},
1287fd4e5da5Sopenharmony_ci      {4, "%4 = OpFunctionParameter %1"},
1288fd4e5da5Sopenharmony_ci      {5, "%5 = OpLabel"},
1289fd4e5da5Sopenharmony_ci      {6, "%6 = OpLoad %1 %4"},
1290fd4e5da5Sopenharmony_ci      {7, "%7 = OpLabel"},
1291fd4e5da5Sopenharmony_ci      {8, "%8 = OpLabel"},
1292fd4e5da5Sopenharmony_ci      {9, "%9 = OpLabel"},
1293fd4e5da5Sopenharmony_ci      {10, "%10 = OpLabel"},
1294fd4e5da5Sopenharmony_ci      {11, "%11 = OpLabel"},
1295fd4e5da5Sopenharmony_ci  };
1296fd4e5da5Sopenharmony_ci  CheckDef(def_uses, context->get_def_use_mgr()->id_to_defs());
1297fd4e5da5Sopenharmony_ci
1298fd4e5da5Sopenharmony_ci  {
1299fd4e5da5Sopenharmony_ci    EXPECT_EQ(2u, NumUses(context, 6));
1300fd4e5da5Sopenharmony_ci    std::vector<spv::Op> opcodes = GetUseOpcodes(context, 6u);
1301fd4e5da5Sopenharmony_ci    EXPECT_THAT(opcodes, UnorderedElementsAre(spv::Op::OpSwitch,
1302fd4e5da5Sopenharmony_ci                                              spv::Op::OpReturnValue));
1303fd4e5da5Sopenharmony_ci  }
1304fd4e5da5Sopenharmony_ci  {
1305fd4e5da5Sopenharmony_ci    EXPECT_EQ(6u, NumUses(context, 7));
1306fd4e5da5Sopenharmony_ci    std::vector<spv::Op> opcodes = GetUseOpcodes(context, 7u);
1307fd4e5da5Sopenharmony_ci    // OpSwitch is now a user of %7.
1308fd4e5da5Sopenharmony_ci    EXPECT_THAT(opcodes, UnorderedElementsAre(
1309fd4e5da5Sopenharmony_ci                             spv::Op::OpSelectionMerge, spv::Op::OpBranch,
1310fd4e5da5Sopenharmony_ci                             spv::Op::OpBranch, spv::Op::OpBranch,
1311fd4e5da5Sopenharmony_ci                             spv::Op::OpBranch, spv::Op::OpSwitch));
1312fd4e5da5Sopenharmony_ci  }
1313fd4e5da5Sopenharmony_ci  // Check all ids only used by OpSwitch after replacement.
1314fd4e5da5Sopenharmony_ci  for (const auto id : {8u, 10u, 11u}) {
1315fd4e5da5Sopenharmony_ci    EXPECT_EQ(1u, NumUses(context, id));
1316fd4e5da5Sopenharmony_ci    EXPECT_EQ(spv::Op::OpSwitch, GetUseOpcodes(context, id).back());
1317fd4e5da5Sopenharmony_ci  }
1318fd4e5da5Sopenharmony_ci}
1319fd4e5da5Sopenharmony_ci
1320fd4e5da5Sopenharmony_ci// Test case for analyzing individual instructions.
1321fd4e5da5Sopenharmony_cistruct AnalyzeInstDefUseTestCase {
1322fd4e5da5Sopenharmony_ci  const char* module_text;
1323fd4e5da5Sopenharmony_ci  InstDefUse expected_define_use;
1324fd4e5da5Sopenharmony_ci};
1325fd4e5da5Sopenharmony_ci
1326fd4e5da5Sopenharmony_ciusing AnalyzeInstDefUseTest =
1327fd4e5da5Sopenharmony_ci    ::testing::TestWithParam<AnalyzeInstDefUseTestCase>;
1328fd4e5da5Sopenharmony_ci
1329fd4e5da5Sopenharmony_ci// Test the analyzing result for individual instructions.
1330fd4e5da5Sopenharmony_ciTEST_P(AnalyzeInstDefUseTest, Case) {
1331fd4e5da5Sopenharmony_ci  auto tc = GetParam();
1332fd4e5da5Sopenharmony_ci
1333fd4e5da5Sopenharmony_ci  // Build module.
1334fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
1335fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.module_text);
1336fd4e5da5Sopenharmony_ci  ASSERT_NE(nullptr, context);
1337fd4e5da5Sopenharmony_ci
1338fd4e5da5Sopenharmony_ci  // Analyze the instructions.
1339fd4e5da5Sopenharmony_ci  DefUseManager manager(context->module());
1340fd4e5da5Sopenharmony_ci
1341fd4e5da5Sopenharmony_ci  CheckDef(tc.expected_define_use, manager.id_to_defs());
1342fd4e5da5Sopenharmony_ci  CheckUse(tc.expected_define_use, &manager, context->module()->IdBound());
1343fd4e5da5Sopenharmony_ci  // CheckUse(tc.expected_define_use, manager.id_to_uses());
1344fd4e5da5Sopenharmony_ci}
1345fd4e5da5Sopenharmony_ci
1346fd4e5da5Sopenharmony_ci// clang-format off
1347fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(
1348fd4e5da5Sopenharmony_ci    TestCase, AnalyzeInstDefUseTest,
1349fd4e5da5Sopenharmony_ci    ::testing::ValuesIn(std::vector<AnalyzeInstDefUseTestCase>{
1350fd4e5da5Sopenharmony_ci      { // A type declaring instruction.
1351fd4e5da5Sopenharmony_ci        "%1 = OpTypeInt 32 1",
1352fd4e5da5Sopenharmony_ci        {
1353fd4e5da5Sopenharmony_ci          // defs
1354fd4e5da5Sopenharmony_ci          {{1, "%1 = OpTypeInt 32 1"}},
1355fd4e5da5Sopenharmony_ci          {}, // no uses
1356fd4e5da5Sopenharmony_ci        },
1357fd4e5da5Sopenharmony_ci      },
1358fd4e5da5Sopenharmony_ci      { // A type declaring instruction and a constant value.
1359fd4e5da5Sopenharmony_ci        "%1 = OpTypeBool "
1360fd4e5da5Sopenharmony_ci        "%2 = OpConstantTrue %1",
1361fd4e5da5Sopenharmony_ci        {
1362fd4e5da5Sopenharmony_ci          { // defs
1363fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeBool"},
1364fd4e5da5Sopenharmony_ci            {2, "%2 = OpConstantTrue %1"},
1365fd4e5da5Sopenharmony_ci          },
1366fd4e5da5Sopenharmony_ci          { // uses
1367fd4e5da5Sopenharmony_ci            {1, {"%2 = OpConstantTrue %1"}},
1368fd4e5da5Sopenharmony_ci          },
1369fd4e5da5Sopenharmony_ci        },
1370fd4e5da5Sopenharmony_ci      },
1371fd4e5da5Sopenharmony_ci      }));
1372fd4e5da5Sopenharmony_ci// clang-format on
1373fd4e5da5Sopenharmony_ci
1374fd4e5da5Sopenharmony_ciusing AnalyzeInstDefUse = ::testing::Test;
1375fd4e5da5Sopenharmony_ci
1376fd4e5da5Sopenharmony_ciTEST(AnalyzeInstDefUse, UseWithNoResultId) {
1377fd4e5da5Sopenharmony_ci  IRContext context(SPV_ENV_UNIVERSAL_1_2, nullptr);
1378fd4e5da5Sopenharmony_ci
1379fd4e5da5Sopenharmony_ci  // Analyze the instructions.
1380fd4e5da5Sopenharmony_ci  DefUseManager manager(context.module());
1381fd4e5da5Sopenharmony_ci
1382fd4e5da5Sopenharmony_ci  Instruction label(&context, spv::Op::OpLabel, 0, 2, {});
1383fd4e5da5Sopenharmony_ci  manager.AnalyzeInstDefUse(&label);
1384fd4e5da5Sopenharmony_ci
1385fd4e5da5Sopenharmony_ci  Instruction branch(&context, spv::Op::OpBranch, 0, 0,
1386fd4e5da5Sopenharmony_ci                     {{SPV_OPERAND_TYPE_ID, {2}}});
1387fd4e5da5Sopenharmony_ci  manager.AnalyzeInstDefUse(&branch);
1388fd4e5da5Sopenharmony_ci  context.module()->SetIdBound(3);
1389fd4e5da5Sopenharmony_ci
1390fd4e5da5Sopenharmony_ci  InstDefUse expected = {
1391fd4e5da5Sopenharmony_ci      // defs
1392fd4e5da5Sopenharmony_ci      {
1393fd4e5da5Sopenharmony_ci          {2, "%2 = OpLabel"},
1394fd4e5da5Sopenharmony_ci      },
1395fd4e5da5Sopenharmony_ci      // uses
1396fd4e5da5Sopenharmony_ci      {{2, {"OpBranch %2"}}},
1397fd4e5da5Sopenharmony_ci  };
1398fd4e5da5Sopenharmony_ci
1399fd4e5da5Sopenharmony_ci  CheckDef(expected, manager.id_to_defs());
1400fd4e5da5Sopenharmony_ci  CheckUse(expected, &manager, context.module()->IdBound());
1401fd4e5da5Sopenharmony_ci}
1402fd4e5da5Sopenharmony_ci
1403fd4e5da5Sopenharmony_ciTEST(AnalyzeInstDefUse, AddNewInstruction) {
1404fd4e5da5Sopenharmony_ci  const std::string input = "%1 = OpTypeBool";
1405fd4e5da5Sopenharmony_ci
1406fd4e5da5Sopenharmony_ci  // Build module.
1407fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
1408fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, input);
1409fd4e5da5Sopenharmony_ci  ASSERT_NE(nullptr, context);
1410fd4e5da5Sopenharmony_ci
1411fd4e5da5Sopenharmony_ci  // Analyze the instructions.
1412fd4e5da5Sopenharmony_ci  DefUseManager manager(context->module());
1413fd4e5da5Sopenharmony_ci
1414fd4e5da5Sopenharmony_ci  Instruction newInst(context.get(), spv::Op::OpConstantTrue, 1, 2, {});
1415fd4e5da5Sopenharmony_ci  manager.AnalyzeInstDefUse(&newInst);
1416fd4e5da5Sopenharmony_ci
1417fd4e5da5Sopenharmony_ci  InstDefUse expected = {
1418fd4e5da5Sopenharmony_ci      {
1419fd4e5da5Sopenharmony_ci          // defs
1420fd4e5da5Sopenharmony_ci          {1, "%1 = OpTypeBool"},
1421fd4e5da5Sopenharmony_ci          {2, "%2 = OpConstantTrue %1"},
1422fd4e5da5Sopenharmony_ci      },
1423fd4e5da5Sopenharmony_ci      {
1424fd4e5da5Sopenharmony_ci          // uses
1425fd4e5da5Sopenharmony_ci          {1, {"%2 = OpConstantTrue %1"}},
1426fd4e5da5Sopenharmony_ci      },
1427fd4e5da5Sopenharmony_ci  };
1428fd4e5da5Sopenharmony_ci
1429fd4e5da5Sopenharmony_ci  CheckDef(expected, manager.id_to_defs());
1430fd4e5da5Sopenharmony_ci  CheckUse(expected, &manager, context->module()->IdBound());
1431fd4e5da5Sopenharmony_ci}
1432fd4e5da5Sopenharmony_ci
1433fd4e5da5Sopenharmony_cistruct KillInstTestCase {
1434fd4e5da5Sopenharmony_ci  const char* before;
1435fd4e5da5Sopenharmony_ci  std::unordered_set<uint32_t> indices_for_inst_to_kill;
1436fd4e5da5Sopenharmony_ci  const char* after;
1437fd4e5da5Sopenharmony_ci  InstDefUse expected_define_use;
1438fd4e5da5Sopenharmony_ci};
1439fd4e5da5Sopenharmony_ci
1440fd4e5da5Sopenharmony_ciusing KillInstTest = ::testing::TestWithParam<KillInstTestCase>;
1441fd4e5da5Sopenharmony_ci
1442fd4e5da5Sopenharmony_ciTEST_P(KillInstTest, Case) {
1443fd4e5da5Sopenharmony_ci  auto tc = GetParam();
1444fd4e5da5Sopenharmony_ci
1445fd4e5da5Sopenharmony_ci  // Build module.
1446fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
1447fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.before,
1448fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1449fd4e5da5Sopenharmony_ci  ASSERT_NE(nullptr, context);
1450fd4e5da5Sopenharmony_ci
1451fd4e5da5Sopenharmony_ci  // Force a re-build of the def-use manager.
1452fd4e5da5Sopenharmony_ci  context->InvalidateAnalyses(IRContext::Analysis::kAnalysisDefUse);
1453fd4e5da5Sopenharmony_ci  (void)context->get_def_use_mgr();
1454fd4e5da5Sopenharmony_ci
1455fd4e5da5Sopenharmony_ci  // KillInst
1456fd4e5da5Sopenharmony_ci  context->module()->ForEachInst([&tc, &context](Instruction* inst) {
1457fd4e5da5Sopenharmony_ci    if (tc.indices_for_inst_to_kill.count(inst->result_id())) {
1458fd4e5da5Sopenharmony_ci      context->KillInst(inst);
1459fd4e5da5Sopenharmony_ci    }
1460fd4e5da5Sopenharmony_ci  });
1461fd4e5da5Sopenharmony_ci
1462fd4e5da5Sopenharmony_ci  EXPECT_EQ(tc.after, DisassembleModule(context->module()));
1463fd4e5da5Sopenharmony_ci  CheckDef(tc.expected_define_use, context->get_def_use_mgr()->id_to_defs());
1464fd4e5da5Sopenharmony_ci  CheckUse(tc.expected_define_use, context->get_def_use_mgr(),
1465fd4e5da5Sopenharmony_ci           context->module()->IdBound());
1466fd4e5da5Sopenharmony_ci}
1467fd4e5da5Sopenharmony_ci
1468fd4e5da5Sopenharmony_ci// clang-format off
1469fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(
1470fd4e5da5Sopenharmony_ci    TestCase, KillInstTest,
1471fd4e5da5Sopenharmony_ci    ::testing::ValuesIn(std::vector<KillInstTestCase>{
1472fd4e5da5Sopenharmony_ci      // Kill id defining instructions.
1473fd4e5da5Sopenharmony_ci      {
1474fd4e5da5Sopenharmony_ci        "%3 = OpTypeVoid "
1475fd4e5da5Sopenharmony_ci        "%1 = OpTypeFunction %3 "
1476fd4e5da5Sopenharmony_ci        "%2 = OpFunction %1 None %3 "
1477fd4e5da5Sopenharmony_ci        "%4 = OpLabel "
1478fd4e5da5Sopenharmony_ci        "     OpBranch %5 "
1479fd4e5da5Sopenharmony_ci        "%5 = OpLabel "
1480fd4e5da5Sopenharmony_ci        "     OpBranch %6 "
1481fd4e5da5Sopenharmony_ci        "%6 = OpLabel "
1482fd4e5da5Sopenharmony_ci        "     OpBranch %4 "
1483fd4e5da5Sopenharmony_ci        "%7 = OpLabel "
1484fd4e5da5Sopenharmony_ci        "     OpReturn "
1485fd4e5da5Sopenharmony_ci        "     OpFunctionEnd",
1486fd4e5da5Sopenharmony_ci        {3, 5, 7},
1487fd4e5da5Sopenharmony_ci        "%1 = OpTypeFunction %3\n"
1488fd4e5da5Sopenharmony_ci        "%2 = OpFunction %1 None %3\n"
1489fd4e5da5Sopenharmony_ci        "%4 = OpLabel\n"
1490fd4e5da5Sopenharmony_ci        "OpBranch %5\n"
1491fd4e5da5Sopenharmony_ci        "OpNop\n"
1492fd4e5da5Sopenharmony_ci        "OpBranch %6\n"
1493fd4e5da5Sopenharmony_ci        "%6 = OpLabel\n"
1494fd4e5da5Sopenharmony_ci        "OpBranch %4\n"
1495fd4e5da5Sopenharmony_ci        "OpNop\n"
1496fd4e5da5Sopenharmony_ci        "OpReturn\n"
1497fd4e5da5Sopenharmony_ci        "OpFunctionEnd",
1498fd4e5da5Sopenharmony_ci        {
1499fd4e5da5Sopenharmony_ci          // defs
1500fd4e5da5Sopenharmony_ci          {
1501fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeFunction %3"},
1502fd4e5da5Sopenharmony_ci            {2, "%2 = OpFunction %1 None %3"},
1503fd4e5da5Sopenharmony_ci            {4, "%4 = OpLabel"},
1504fd4e5da5Sopenharmony_ci            {6, "%6 = OpLabel"},
1505fd4e5da5Sopenharmony_ci          },
1506fd4e5da5Sopenharmony_ci          // uses
1507fd4e5da5Sopenharmony_ci          {
1508fd4e5da5Sopenharmony_ci            {1, {"%2 = OpFunction %1 None %3"}},
1509fd4e5da5Sopenharmony_ci            {4, {"OpBranch %4"}},
1510fd4e5da5Sopenharmony_ci            {6, {"OpBranch %6"}},
1511fd4e5da5Sopenharmony_ci          }
1512fd4e5da5Sopenharmony_ci        }
1513fd4e5da5Sopenharmony_ci      },
1514fd4e5da5Sopenharmony_ci      // Kill instructions that do not have result ids.
1515fd4e5da5Sopenharmony_ci      {
1516fd4e5da5Sopenharmony_ci        "%3 = OpTypeVoid "
1517fd4e5da5Sopenharmony_ci        "%1 = OpTypeFunction %3 "
1518fd4e5da5Sopenharmony_ci        "%2 = OpFunction %1 None %3 "
1519fd4e5da5Sopenharmony_ci        "%4 = OpLabel "
1520fd4e5da5Sopenharmony_ci        "     OpBranch %5 "
1521fd4e5da5Sopenharmony_ci        "%5 = OpLabel "
1522fd4e5da5Sopenharmony_ci        "     OpBranch %6 "
1523fd4e5da5Sopenharmony_ci        "%6 = OpLabel "
1524fd4e5da5Sopenharmony_ci        "     OpBranch %4 "
1525fd4e5da5Sopenharmony_ci        "%7 = OpLabel "
1526fd4e5da5Sopenharmony_ci        "     OpReturn "
1527fd4e5da5Sopenharmony_ci        "     OpFunctionEnd",
1528fd4e5da5Sopenharmony_ci        {2, 4},
1529fd4e5da5Sopenharmony_ci        "%3 = OpTypeVoid\n"
1530fd4e5da5Sopenharmony_ci        "%1 = OpTypeFunction %3\n"
1531fd4e5da5Sopenharmony_ci             "OpNop\n"
1532fd4e5da5Sopenharmony_ci             "OpNop\n"
1533fd4e5da5Sopenharmony_ci             "OpBranch %5\n"
1534fd4e5da5Sopenharmony_ci        "%5 = OpLabel\n"
1535fd4e5da5Sopenharmony_ci             "OpBranch %6\n"
1536fd4e5da5Sopenharmony_ci        "%6 = OpLabel\n"
1537fd4e5da5Sopenharmony_ci             "OpBranch %4\n"
1538fd4e5da5Sopenharmony_ci        "%7 = OpLabel\n"
1539fd4e5da5Sopenharmony_ci             "OpReturn\n"
1540fd4e5da5Sopenharmony_ci             "OpFunctionEnd",
1541fd4e5da5Sopenharmony_ci        {
1542fd4e5da5Sopenharmony_ci          // defs
1543fd4e5da5Sopenharmony_ci          {
1544fd4e5da5Sopenharmony_ci            {1, "%1 = OpTypeFunction %3"},
1545fd4e5da5Sopenharmony_ci            {3, "%3 = OpTypeVoid"},
1546fd4e5da5Sopenharmony_ci            {5, "%5 = OpLabel"},
1547fd4e5da5Sopenharmony_ci            {6, "%6 = OpLabel"},
1548fd4e5da5Sopenharmony_ci            {7, "%7 = OpLabel"},
1549fd4e5da5Sopenharmony_ci          },
1550fd4e5da5Sopenharmony_ci          // uses
1551fd4e5da5Sopenharmony_ci          {
1552fd4e5da5Sopenharmony_ci            {3, {"%1 = OpTypeFunction %3"}},
1553fd4e5da5Sopenharmony_ci            {5, {"OpBranch %5"}},
1554fd4e5da5Sopenharmony_ci            {6, {"OpBranch %6"}},
1555fd4e5da5Sopenharmony_ci          }
1556fd4e5da5Sopenharmony_ci        }
1557fd4e5da5Sopenharmony_ci      },
1558fd4e5da5Sopenharmony_ci      }));
1559fd4e5da5Sopenharmony_ci// clang-format on
1560fd4e5da5Sopenharmony_ci
1561fd4e5da5Sopenharmony_cistruct GetAnnotationsTestCase {
1562fd4e5da5Sopenharmony_ci  const char* code;
1563fd4e5da5Sopenharmony_ci  uint32_t id;
1564fd4e5da5Sopenharmony_ci  std::vector<std::string> annotations;
1565fd4e5da5Sopenharmony_ci};
1566fd4e5da5Sopenharmony_ci
1567fd4e5da5Sopenharmony_ciusing GetAnnotationsTest = ::testing::TestWithParam<GetAnnotationsTestCase>;
1568fd4e5da5Sopenharmony_ci
1569fd4e5da5Sopenharmony_ciTEST_P(GetAnnotationsTest, Case) {
1570fd4e5da5Sopenharmony_ci  const GetAnnotationsTestCase& tc = GetParam();
1571fd4e5da5Sopenharmony_ci
1572fd4e5da5Sopenharmony_ci  // Build module.
1573fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
1574fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, tc.code);
1575fd4e5da5Sopenharmony_ci  ASSERT_NE(nullptr, context);
1576fd4e5da5Sopenharmony_ci
1577fd4e5da5Sopenharmony_ci  // Get annotations
1578fd4e5da5Sopenharmony_ci  DefUseManager manager(context->module());
1579fd4e5da5Sopenharmony_ci  auto insts = manager.GetAnnotations(tc.id);
1580fd4e5da5Sopenharmony_ci
1581fd4e5da5Sopenharmony_ci  // Check
1582fd4e5da5Sopenharmony_ci  ASSERT_EQ(tc.annotations.size(), insts.size())
1583fd4e5da5Sopenharmony_ci      << "wrong number of annotation instructions";
1584fd4e5da5Sopenharmony_ci  auto inst_iter = insts.begin();
1585fd4e5da5Sopenharmony_ci  for (const std::string& expected_anno_inst : tc.annotations) {
1586fd4e5da5Sopenharmony_ci    EXPECT_EQ(expected_anno_inst, DisassembleInst(*inst_iter))
1587fd4e5da5Sopenharmony_ci        << "annotation instruction mismatch";
1588fd4e5da5Sopenharmony_ci    inst_iter++;
1589fd4e5da5Sopenharmony_ci  }
1590fd4e5da5Sopenharmony_ci}
1591fd4e5da5Sopenharmony_ci
1592fd4e5da5Sopenharmony_ci// clang-format off
1593fd4e5da5Sopenharmony_ciINSTANTIATE_TEST_SUITE_P(
1594fd4e5da5Sopenharmony_ci    TestCase, GetAnnotationsTest,
1595fd4e5da5Sopenharmony_ci    ::testing::ValuesIn(std::vector<GetAnnotationsTestCase>{
1596fd4e5da5Sopenharmony_ci      // empty
1597fd4e5da5Sopenharmony_ci      {"", 0, {}},
1598fd4e5da5Sopenharmony_ci      // basic
1599fd4e5da5Sopenharmony_ci      {
1600fd4e5da5Sopenharmony_ci        // code
1601fd4e5da5Sopenharmony_ci        "OpDecorate %1 Block "
1602fd4e5da5Sopenharmony_ci        "OpDecorate %1 RelaxedPrecision "
1603fd4e5da5Sopenharmony_ci        "%3 = OpTypeInt 32 0 "
1604fd4e5da5Sopenharmony_ci        "%1 = OpTypeStruct %3",
1605fd4e5da5Sopenharmony_ci        // id
1606fd4e5da5Sopenharmony_ci        1,
1607fd4e5da5Sopenharmony_ci        // annotations
1608fd4e5da5Sopenharmony_ci        {
1609fd4e5da5Sopenharmony_ci          "OpDecorate %1 Block",
1610fd4e5da5Sopenharmony_ci          "OpDecorate %1 RelaxedPrecision",
1611fd4e5da5Sopenharmony_ci        },
1612fd4e5da5Sopenharmony_ci      },
1613fd4e5da5Sopenharmony_ci      // with debug instructions
1614fd4e5da5Sopenharmony_ci      {
1615fd4e5da5Sopenharmony_ci        // code
1616fd4e5da5Sopenharmony_ci        "OpName %1 \"struct_type\" "
1617fd4e5da5Sopenharmony_ci        "OpName %3 \"int_type\" "
1618fd4e5da5Sopenharmony_ci        "OpDecorate %1 Block "
1619fd4e5da5Sopenharmony_ci        "OpDecorate %1 RelaxedPrecision "
1620fd4e5da5Sopenharmony_ci        "%3 = OpTypeInt 32 0 "
1621fd4e5da5Sopenharmony_ci        "%1 = OpTypeStruct %3",
1622fd4e5da5Sopenharmony_ci        // id
1623fd4e5da5Sopenharmony_ci        1,
1624fd4e5da5Sopenharmony_ci        // annotations
1625fd4e5da5Sopenharmony_ci        {
1626fd4e5da5Sopenharmony_ci          "OpDecorate %1 Block",
1627fd4e5da5Sopenharmony_ci          "OpDecorate %1 RelaxedPrecision",
1628fd4e5da5Sopenharmony_ci        },
1629fd4e5da5Sopenharmony_ci      },
1630fd4e5da5Sopenharmony_ci      // no annotations
1631fd4e5da5Sopenharmony_ci      {
1632fd4e5da5Sopenharmony_ci        // code
1633fd4e5da5Sopenharmony_ci        "OpName %1 \"struct_type\" "
1634fd4e5da5Sopenharmony_ci        "OpName %3 \"int_type\" "
1635fd4e5da5Sopenharmony_ci        "OpDecorate %1 Block "
1636fd4e5da5Sopenharmony_ci        "OpDecorate %1 RelaxedPrecision "
1637fd4e5da5Sopenharmony_ci        "%3 = OpTypeInt 32 0 "
1638fd4e5da5Sopenharmony_ci        "%1 = OpTypeStruct %3",
1639fd4e5da5Sopenharmony_ci        // id
1640fd4e5da5Sopenharmony_ci        3,
1641fd4e5da5Sopenharmony_ci        // annotations
1642fd4e5da5Sopenharmony_ci        {},
1643fd4e5da5Sopenharmony_ci      },
1644fd4e5da5Sopenharmony_ci      // decoration group
1645fd4e5da5Sopenharmony_ci      {
1646fd4e5da5Sopenharmony_ci        // code
1647fd4e5da5Sopenharmony_ci        "OpDecorate %1 Block "
1648fd4e5da5Sopenharmony_ci        "OpDecorate %1 RelaxedPrecision "
1649fd4e5da5Sopenharmony_ci        "%1 = OpDecorationGroup "
1650fd4e5da5Sopenharmony_ci        "OpGroupDecorate %1 %2 %3 "
1651fd4e5da5Sopenharmony_ci        "%4 = OpTypeInt 32 0 "
1652fd4e5da5Sopenharmony_ci        "%2 = OpTypeStruct %4 "
1653fd4e5da5Sopenharmony_ci        "%3 = OpTypeStruct %4 %4",
1654fd4e5da5Sopenharmony_ci        // id
1655fd4e5da5Sopenharmony_ci        3,
1656fd4e5da5Sopenharmony_ci        // annotations
1657fd4e5da5Sopenharmony_ci        {
1658fd4e5da5Sopenharmony_ci          "OpGroupDecorate %1 %2 %3",
1659fd4e5da5Sopenharmony_ci        },
1660fd4e5da5Sopenharmony_ci      },
1661fd4e5da5Sopenharmony_ci      // member decorate
1662fd4e5da5Sopenharmony_ci      {
1663fd4e5da5Sopenharmony_ci        // code
1664fd4e5da5Sopenharmony_ci        "OpMemberDecorate %1 0 RelaxedPrecision "
1665fd4e5da5Sopenharmony_ci        "%2 = OpTypeInt 32 0 "
1666fd4e5da5Sopenharmony_ci        "%1 = OpTypeStruct %2 %2",
1667fd4e5da5Sopenharmony_ci        // id
1668fd4e5da5Sopenharmony_ci        1,
1669fd4e5da5Sopenharmony_ci        // annotations
1670fd4e5da5Sopenharmony_ci        {
1671fd4e5da5Sopenharmony_ci          "OpMemberDecorate %1 0 RelaxedPrecision",
1672fd4e5da5Sopenharmony_ci        },
1673fd4e5da5Sopenharmony_ci      },
1674fd4e5da5Sopenharmony_ci      }));
1675fd4e5da5Sopenharmony_ci
1676fd4e5da5Sopenharmony_ciusing UpdateUsesTest = PassTest<::testing::Test>;
1677fd4e5da5Sopenharmony_ci
1678fd4e5da5Sopenharmony_ciTEST_F(UpdateUsesTest, KeepOldUses) {
1679fd4e5da5Sopenharmony_ci  const std::vector<const char*> text = {
1680fd4e5da5Sopenharmony_ci      // clang-format off
1681fd4e5da5Sopenharmony_ci      "OpCapability Shader",
1682fd4e5da5Sopenharmony_ci      "%1 = OpExtInstImport \"GLSL.std.450\"",
1683fd4e5da5Sopenharmony_ci      "OpMemoryModel Logical GLSL450",
1684fd4e5da5Sopenharmony_ci      "OpEntryPoint Vertex %main \"main\"",
1685fd4e5da5Sopenharmony_ci      "OpName %main \"main\"",
1686fd4e5da5Sopenharmony_ci      "%void = OpTypeVoid",
1687fd4e5da5Sopenharmony_ci      "%4 = OpTypeFunction %void",
1688fd4e5da5Sopenharmony_ci      "%uint = OpTypeInt 32 0",
1689fd4e5da5Sopenharmony_ci      "%uint_5 = OpConstant %uint 5",
1690fd4e5da5Sopenharmony_ci      "%25 = OpConstant %uint 25",
1691fd4e5da5Sopenharmony_ci      "%main = OpFunction %void None %4",
1692fd4e5da5Sopenharmony_ci      "%8 = OpLabel",
1693fd4e5da5Sopenharmony_ci      "%9 = OpIMul %uint %uint_5 %uint_5",
1694fd4e5da5Sopenharmony_ci      "%10 = OpIMul %uint %9 %uint_5",
1695fd4e5da5Sopenharmony_ci      "OpReturn",
1696fd4e5da5Sopenharmony_ci      "OpFunctionEnd"
1697fd4e5da5Sopenharmony_ci      // clang-format on
1698fd4e5da5Sopenharmony_ci  };
1699fd4e5da5Sopenharmony_ci
1700fd4e5da5Sopenharmony_ci  std::unique_ptr<IRContext> context =
1701fd4e5da5Sopenharmony_ci      BuildModule(SPV_ENV_UNIVERSAL_1_1, nullptr, JoinAllInsts(text),
1702fd4e5da5Sopenharmony_ci                  SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
1703fd4e5da5Sopenharmony_ci  ASSERT_NE(nullptr, context);
1704fd4e5da5Sopenharmony_ci
1705fd4e5da5Sopenharmony_ci  DefUseManager* def_use_mgr = context->get_def_use_mgr();
1706fd4e5da5Sopenharmony_ci  Instruction* def = def_use_mgr->GetDef(9);
1707fd4e5da5Sopenharmony_ci  Instruction* use = def_use_mgr->GetDef(10);
1708fd4e5da5Sopenharmony_ci  def->SetOpcode(spv::Op::OpCopyObject);
1709fd4e5da5Sopenharmony_ci  def->SetInOperands({{SPV_OPERAND_TYPE_ID, {25}}});
1710fd4e5da5Sopenharmony_ci  context->UpdateDefUse(def);
1711fd4e5da5Sopenharmony_ci
1712fd4e5da5Sopenharmony_ci  auto scanUser = [&](Instruction* user) { return user != use; };
1713fd4e5da5Sopenharmony_ci  bool userFound = !def_use_mgr->WhileEachUser(def, scanUser);
1714fd4e5da5Sopenharmony_ci
1715fd4e5da5Sopenharmony_ci  EXPECT_TRUE(userFound);
1716fd4e5da5Sopenharmony_ci}
1717fd4e5da5Sopenharmony_ci// clang-format on
1718fd4e5da5Sopenharmony_ci
1719fd4e5da5Sopenharmony_ci}  // namespace
1720fd4e5da5Sopenharmony_ci}  // namespace analysis
1721fd4e5da5Sopenharmony_ci}  // namespace opt
1722fd4e5da5Sopenharmony_ci}  // namespace spvtools
1723