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