def_use_test.cpp 51 KB

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