def_use_test.cpp 51 KB

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