def_use_test.cpp 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720
  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