register_pressure.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. // Copyright (c) 2018 Google LLC.
  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 "source/opt/register_pressure.h"
  15. #include <algorithm>
  16. #include <iterator>
  17. #include "source/opt/cfg.h"
  18. #include "source/opt/def_use_manager.h"
  19. #include "source/opt/dominator_tree.h"
  20. #include "source/opt/function.h"
  21. #include "source/opt/ir_context.h"
  22. #include "source/opt/iterator.h"
  23. namespace spvtools {
  24. namespace opt {
  25. namespace {
  26. // Predicate for the FilterIterator to only consider instructions that are not
  27. // phi instructions defined in the basic block |bb|.
  28. class ExcludePhiDefinedInBlock {
  29. public:
  30. ExcludePhiDefinedInBlock(IRContext* context, const BasicBlock* bb)
  31. : context_(context), bb_(bb) {}
  32. bool operator()(Instruction* insn) const {
  33. return !(insn->opcode() == spv::Op::OpPhi &&
  34. context_->get_instr_block(insn) == bb_);
  35. }
  36. private:
  37. IRContext* context_;
  38. const BasicBlock* bb_;
  39. };
  40. // Returns true if |insn| generates a SSA register that is likely to require a
  41. // physical register.
  42. bool CreatesRegisterUsage(Instruction* insn) {
  43. if (!insn->HasResultId()) return false;
  44. if (insn->opcode() == spv::Op::OpUndef) return false;
  45. if (IsConstantInst(insn->opcode())) return false;
  46. if (insn->opcode() == spv::Op::OpLabel) return false;
  47. return true;
  48. }
  49. // Compute the register liveness for each basic block of a function. This also
  50. // fill-up some information about the pick register usage and a break down of
  51. // register usage. This implements: "A non-iterative data-flow algorithm for
  52. // computing liveness sets in strict ssa programs" from Boissinot et al.
  53. class ComputeRegisterLiveness {
  54. public:
  55. ComputeRegisterLiveness(RegisterLiveness* reg_pressure, Function* f)
  56. : reg_pressure_(reg_pressure),
  57. context_(reg_pressure->GetContext()),
  58. function_(f),
  59. cfg_(*reg_pressure->GetContext()->cfg()),
  60. def_use_manager_(*reg_pressure->GetContext()->get_def_use_mgr()),
  61. dom_tree_(
  62. reg_pressure->GetContext()->GetDominatorAnalysis(f)->GetDomTree()),
  63. loop_desc_(*reg_pressure->GetContext()->GetLoopDescriptor(f)) {}
  64. // Computes the register liveness for |function_| and then estimate the
  65. // register usage. The liveness algorithm works in 2 steps:
  66. // - First, compute the liveness for each basic blocks, but will ignore any
  67. // back-edge;
  68. // - Second, walk loop forest to propagate registers crossing back-edges
  69. // (add iterative values into the liveness set).
  70. void Compute() {
  71. for (BasicBlock& start_bb : *function_) {
  72. if (reg_pressure_->Get(start_bb.id()) != nullptr) {
  73. continue;
  74. }
  75. cfg_.ForEachBlockInPostOrder(&start_bb, [this](BasicBlock* bb) {
  76. if (reg_pressure_->Get(bb->id()) == nullptr) {
  77. ComputePartialLiveness(bb);
  78. }
  79. });
  80. }
  81. DoLoopLivenessUnification();
  82. EvaluateRegisterRequirements();
  83. }
  84. private:
  85. // Registers all SSA register used by successors of |bb| in their phi
  86. // instructions.
  87. void ComputePhiUses(const BasicBlock& bb,
  88. RegisterLiveness::RegionRegisterLiveness::LiveSet* live) {
  89. uint32_t bb_id = bb.id();
  90. bb.ForEachSuccessorLabel([live, bb_id, this](uint32_t sid) {
  91. BasicBlock* succ_bb = cfg_.block(sid);
  92. succ_bb->ForEachPhiInst([live, bb_id, this](const Instruction* phi) {
  93. for (uint32_t i = 0; i < phi->NumInOperands(); i += 2) {
  94. if (phi->GetSingleWordInOperand(i + 1) == bb_id) {
  95. Instruction* insn_op =
  96. def_use_manager_.GetDef(phi->GetSingleWordInOperand(i));
  97. if (CreatesRegisterUsage(insn_op)) {
  98. live->insert(insn_op);
  99. break;
  100. }
  101. }
  102. }
  103. });
  104. });
  105. }
  106. // Computes register liveness for each basic blocks but ignores all
  107. // back-edges.
  108. void ComputePartialLiveness(BasicBlock* bb) {
  109. assert(reg_pressure_->Get(bb) == nullptr &&
  110. "Basic block already processed");
  111. RegisterLiveness::RegionRegisterLiveness* live_inout =
  112. reg_pressure_->GetOrInsert(bb->id());
  113. ComputePhiUses(*bb, &live_inout->live_out_);
  114. const BasicBlock* cbb = bb;
  115. cbb->ForEachSuccessorLabel([&live_inout, bb, this](uint32_t sid) {
  116. // Skip back edges.
  117. if (dom_tree_.Dominates(sid, bb->id())) {
  118. return;
  119. }
  120. BasicBlock* succ_bb = cfg_.block(sid);
  121. RegisterLiveness::RegionRegisterLiveness* succ_live_inout =
  122. reg_pressure_->Get(succ_bb);
  123. assert(succ_live_inout &&
  124. "Successor liveness analysis was not performed");
  125. ExcludePhiDefinedInBlock predicate(context_, succ_bb);
  126. auto filter =
  127. MakeFilterIteratorRange(succ_live_inout->live_in_.begin(),
  128. succ_live_inout->live_in_.end(), predicate);
  129. live_inout->live_out_.insert(filter.begin(), filter.end());
  130. });
  131. live_inout->live_in_ = live_inout->live_out_;
  132. for (Instruction& insn : make_range(bb->rbegin(), bb->rend())) {
  133. if (insn.opcode() == spv::Op::OpPhi) {
  134. live_inout->live_in_.insert(&insn);
  135. break;
  136. }
  137. live_inout->live_in_.erase(&insn);
  138. insn.ForEachInId([live_inout, this](uint32_t* id) {
  139. Instruction* insn_op = def_use_manager_.GetDef(*id);
  140. if (CreatesRegisterUsage(insn_op)) {
  141. live_inout->live_in_.insert(insn_op);
  142. }
  143. });
  144. }
  145. }
  146. // Propagates the register liveness information of each loop iterators.
  147. void DoLoopLivenessUnification() {
  148. for (const Loop* loop : *loop_desc_.GetPlaceholderRootLoop()) {
  149. DoLoopLivenessUnification(*loop);
  150. }
  151. }
  152. // Propagates the register liveness information of loop iterators trough-out
  153. // the loop body.
  154. void DoLoopLivenessUnification(const Loop& loop) {
  155. auto blocks_in_loop = MakeFilterIteratorRange(
  156. loop.GetBlocks().begin(), loop.GetBlocks().end(),
  157. [&loop, this](uint32_t bb_id) {
  158. return bb_id != loop.GetHeaderBlock()->id() &&
  159. loop_desc_[bb_id] == &loop;
  160. });
  161. RegisterLiveness::RegionRegisterLiveness* header_live_inout =
  162. reg_pressure_->Get(loop.GetHeaderBlock());
  163. assert(header_live_inout &&
  164. "Liveness analysis was not performed for the current block");
  165. ExcludePhiDefinedInBlock predicate(context_, loop.GetHeaderBlock());
  166. auto live_loop =
  167. MakeFilterIteratorRange(header_live_inout->live_in_.begin(),
  168. header_live_inout->live_in_.end(), predicate);
  169. for (uint32_t bb_id : blocks_in_loop) {
  170. BasicBlock* bb = cfg_.block(bb_id);
  171. RegisterLiveness::RegionRegisterLiveness* live_inout =
  172. reg_pressure_->Get(bb);
  173. live_inout->live_in_.insert(live_loop.begin(), live_loop.end());
  174. live_inout->live_out_.insert(live_loop.begin(), live_loop.end());
  175. }
  176. for (const Loop* inner_loop : loop) {
  177. RegisterLiveness::RegionRegisterLiveness* live_inout =
  178. reg_pressure_->Get(inner_loop->GetHeaderBlock());
  179. live_inout->live_in_.insert(live_loop.begin(), live_loop.end());
  180. live_inout->live_out_.insert(live_loop.begin(), live_loop.end());
  181. DoLoopLivenessUnification(*inner_loop);
  182. }
  183. }
  184. // Get the number of required registers for this each basic block.
  185. void EvaluateRegisterRequirements() {
  186. for (BasicBlock& bb : *function_) {
  187. RegisterLiveness::RegionRegisterLiveness* live_inout =
  188. reg_pressure_->Get(bb.id());
  189. assert(live_inout != nullptr && "Basic block not processed");
  190. size_t reg_count = live_inout->live_out_.size();
  191. for (Instruction* insn : live_inout->live_out_) {
  192. live_inout->AddRegisterClass(insn);
  193. }
  194. live_inout->used_registers_ = reg_count;
  195. std::unordered_set<uint32_t> die_in_block;
  196. for (Instruction& insn : make_range(bb.rbegin(), bb.rend())) {
  197. // If it is a phi instruction, the register pressure will not change
  198. // anymore.
  199. if (insn.opcode() == spv::Op::OpPhi) {
  200. break;
  201. }
  202. insn.ForEachInId(
  203. [live_inout, &die_in_block, &reg_count, this](uint32_t* id) {
  204. Instruction* op_insn = def_use_manager_.GetDef(*id);
  205. if (!CreatesRegisterUsage(op_insn) ||
  206. live_inout->live_out_.count(op_insn)) {
  207. // already taken into account.
  208. return;
  209. }
  210. if (!die_in_block.count(*id)) {
  211. live_inout->AddRegisterClass(def_use_manager_.GetDef(*id));
  212. reg_count++;
  213. die_in_block.insert(*id);
  214. }
  215. });
  216. live_inout->used_registers_ =
  217. std::max(live_inout->used_registers_, reg_count);
  218. if (CreatesRegisterUsage(&insn)) {
  219. reg_count--;
  220. }
  221. }
  222. }
  223. }
  224. RegisterLiveness* reg_pressure_;
  225. IRContext* context_;
  226. Function* function_;
  227. CFG& cfg_;
  228. analysis::DefUseManager& def_use_manager_;
  229. DominatorTree& dom_tree_;
  230. LoopDescriptor& loop_desc_;
  231. };
  232. } // namespace
  233. // Get the number of required registers for each basic block.
  234. void RegisterLiveness::RegionRegisterLiveness::AddRegisterClass(
  235. Instruction* insn) {
  236. assert(CreatesRegisterUsage(insn) && "Instruction does not use a register");
  237. analysis::Type* type =
  238. insn->context()->get_type_mgr()->GetType(insn->type_id());
  239. RegisterLiveness::RegisterClass reg_class{type, false};
  240. insn->context()->get_decoration_mgr()->WhileEachDecoration(
  241. insn->result_id(), uint32_t(spv::Decoration::Uniform),
  242. [&reg_class](const Instruction&) {
  243. reg_class.is_uniform_ = true;
  244. return false;
  245. });
  246. AddRegisterClass(reg_class);
  247. }
  248. void RegisterLiveness::Analyze(Function* f) {
  249. block_pressure_.clear();
  250. ComputeRegisterLiveness(this, f).Compute();
  251. }
  252. void RegisterLiveness::ComputeLoopRegisterPressure(
  253. const Loop& loop, RegionRegisterLiveness* loop_reg_pressure) const {
  254. loop_reg_pressure->Clear();
  255. const RegionRegisterLiveness* header_live_inout = Get(loop.GetHeaderBlock());
  256. loop_reg_pressure->live_in_ = header_live_inout->live_in_;
  257. std::unordered_set<uint32_t> exit_blocks;
  258. loop.GetExitBlocks(&exit_blocks);
  259. for (uint32_t bb_id : exit_blocks) {
  260. const RegionRegisterLiveness* live_inout = Get(bb_id);
  261. loop_reg_pressure->live_out_.insert(live_inout->live_in_.begin(),
  262. live_inout->live_in_.end());
  263. }
  264. std::unordered_set<uint32_t> seen_insn;
  265. for (Instruction* insn : loop_reg_pressure->live_out_) {
  266. loop_reg_pressure->AddRegisterClass(insn);
  267. seen_insn.insert(insn->result_id());
  268. }
  269. for (Instruction* insn : loop_reg_pressure->live_in_) {
  270. if (!seen_insn.count(insn->result_id())) {
  271. continue;
  272. }
  273. loop_reg_pressure->AddRegisterClass(insn);
  274. seen_insn.insert(insn->result_id());
  275. }
  276. loop_reg_pressure->used_registers_ = 0;
  277. for (uint32_t bb_id : loop.GetBlocks()) {
  278. BasicBlock* bb = context_->cfg()->block(bb_id);
  279. const RegionRegisterLiveness* live_inout = Get(bb_id);
  280. assert(live_inout != nullptr && "Basic block not processed");
  281. loop_reg_pressure->used_registers_ = std::max(
  282. loop_reg_pressure->used_registers_, live_inout->used_registers_);
  283. for (Instruction& insn : *bb) {
  284. if (insn.opcode() == spv::Op::OpPhi || !CreatesRegisterUsage(&insn) ||
  285. seen_insn.count(insn.result_id())) {
  286. continue;
  287. }
  288. loop_reg_pressure->AddRegisterClass(&insn);
  289. }
  290. }
  291. }
  292. void RegisterLiveness::SimulateFusion(
  293. const Loop& l1, const Loop& l2, RegionRegisterLiveness* sim_result) const {
  294. sim_result->Clear();
  295. // Compute the live-in state:
  296. // sim_result.live_in = l1.live_in U l2.live_in
  297. // This assumes that |l1| does not generated register that is live-out for
  298. // |l1|.
  299. const RegionRegisterLiveness* l1_header_live_inout = Get(l1.GetHeaderBlock());
  300. sim_result->live_in_ = l1_header_live_inout->live_in_;
  301. const RegionRegisterLiveness* l2_header_live_inout = Get(l2.GetHeaderBlock());
  302. sim_result->live_in_.insert(l2_header_live_inout->live_in_.begin(),
  303. l2_header_live_inout->live_in_.end());
  304. // The live-out set of the fused loop is the l2 live-out set.
  305. std::unordered_set<uint32_t> exit_blocks;
  306. l2.GetExitBlocks(&exit_blocks);
  307. for (uint32_t bb_id : exit_blocks) {
  308. const RegionRegisterLiveness* live_inout = Get(bb_id);
  309. sim_result->live_out_.insert(live_inout->live_in_.begin(),
  310. live_inout->live_in_.end());
  311. }
  312. // Compute the register usage information.
  313. std::unordered_set<uint32_t> seen_insn;
  314. for (Instruction* insn : sim_result->live_out_) {
  315. sim_result->AddRegisterClass(insn);
  316. seen_insn.insert(insn->result_id());
  317. }
  318. for (Instruction* insn : sim_result->live_in_) {
  319. if (!seen_insn.count(insn->result_id())) {
  320. continue;
  321. }
  322. sim_result->AddRegisterClass(insn);
  323. seen_insn.insert(insn->result_id());
  324. }
  325. sim_result->used_registers_ = 0;
  326. // The loop fusion is injecting the l1 before the l2, the latch of l1 will be
  327. // connected to the header of l2.
  328. // To compute the register usage, we inject the loop live-in (union of l1 and
  329. // l2 live-in header blocks) into the live in/out of each basic block of
  330. // l1 to get the peak register usage. We then repeat the operation to for l2
  331. // basic blocks but in this case we inject the live-out of the latch of l1.
  332. auto live_loop = MakeFilterIteratorRange(
  333. sim_result->live_in_.begin(), sim_result->live_in_.end(),
  334. [&l1, &l2](Instruction* insn) {
  335. BasicBlock* bb = insn->context()->get_instr_block(insn);
  336. return insn->HasResultId() &&
  337. !(insn->opcode() == spv::Op::OpPhi &&
  338. (bb == l1.GetHeaderBlock() || bb == l2.GetHeaderBlock()));
  339. });
  340. for (uint32_t bb_id : l1.GetBlocks()) {
  341. BasicBlock* bb = context_->cfg()->block(bb_id);
  342. const RegionRegisterLiveness* live_inout_info = Get(bb_id);
  343. assert(live_inout_info != nullptr && "Basic block not processed");
  344. RegionRegisterLiveness::LiveSet live_out = live_inout_info->live_out_;
  345. live_out.insert(live_loop.begin(), live_loop.end());
  346. sim_result->used_registers_ =
  347. std::max(sim_result->used_registers_,
  348. live_inout_info->used_registers_ + live_out.size() -
  349. live_inout_info->live_out_.size());
  350. for (Instruction& insn : *bb) {
  351. if (insn.opcode() == spv::Op::OpPhi || !CreatesRegisterUsage(&insn) ||
  352. seen_insn.count(insn.result_id())) {
  353. continue;
  354. }
  355. sim_result->AddRegisterClass(&insn);
  356. }
  357. }
  358. const RegionRegisterLiveness* l1_latch_live_inout_info =
  359. Get(l1.GetLatchBlock()->id());
  360. assert(l1_latch_live_inout_info != nullptr && "Basic block not processed");
  361. RegionRegisterLiveness::LiveSet l1_latch_live_out =
  362. l1_latch_live_inout_info->live_out_;
  363. l1_latch_live_out.insert(live_loop.begin(), live_loop.end());
  364. auto live_loop_l2 =
  365. make_range(l1_latch_live_out.begin(), l1_latch_live_out.end());
  366. for (uint32_t bb_id : l2.GetBlocks()) {
  367. BasicBlock* bb = context_->cfg()->block(bb_id);
  368. const RegionRegisterLiveness* live_inout_info = Get(bb_id);
  369. assert(live_inout_info != nullptr && "Basic block not processed");
  370. RegionRegisterLiveness::LiveSet live_out = live_inout_info->live_out_;
  371. live_out.insert(live_loop_l2.begin(), live_loop_l2.end());
  372. sim_result->used_registers_ =
  373. std::max(sim_result->used_registers_,
  374. live_inout_info->used_registers_ + live_out.size() -
  375. live_inout_info->live_out_.size());
  376. for (Instruction& insn : *bb) {
  377. if (insn.opcode() == spv::Op::OpPhi || !CreatesRegisterUsage(&insn) ||
  378. seen_insn.count(insn.result_id())) {
  379. continue;
  380. }
  381. sim_result->AddRegisterClass(&insn);
  382. }
  383. }
  384. }
  385. void RegisterLiveness::SimulateFission(
  386. const Loop& loop, const std::unordered_set<Instruction*>& moved_inst,
  387. const std::unordered_set<Instruction*>& copied_inst,
  388. RegionRegisterLiveness* l1_sim_result,
  389. RegionRegisterLiveness* l2_sim_result) const {
  390. l1_sim_result->Clear();
  391. l2_sim_result->Clear();
  392. // Filter predicates: consider instructions that only belong to the first and
  393. // second loop.
  394. auto belong_to_loop1 = [&moved_inst, &copied_inst, &loop](Instruction* insn) {
  395. return moved_inst.count(insn) || copied_inst.count(insn) ||
  396. !loop.IsInsideLoop(insn);
  397. };
  398. auto belong_to_loop2 = [&moved_inst](Instruction* insn) {
  399. return !moved_inst.count(insn);
  400. };
  401. const RegionRegisterLiveness* header_live_inout = Get(loop.GetHeaderBlock());
  402. // l1 live-in
  403. {
  404. auto live_loop = MakeFilterIteratorRange(
  405. header_live_inout->live_in_.begin(), header_live_inout->live_in_.end(),
  406. belong_to_loop1);
  407. l1_sim_result->live_in_.insert(live_loop.begin(), live_loop.end());
  408. }
  409. // l2 live-in
  410. {
  411. auto live_loop = MakeFilterIteratorRange(
  412. header_live_inout->live_in_.begin(), header_live_inout->live_in_.end(),
  413. belong_to_loop2);
  414. l2_sim_result->live_in_.insert(live_loop.begin(), live_loop.end());
  415. }
  416. std::unordered_set<uint32_t> exit_blocks;
  417. loop.GetExitBlocks(&exit_blocks);
  418. // l2 live-out.
  419. for (uint32_t bb_id : exit_blocks) {
  420. const RegionRegisterLiveness* live_inout = Get(bb_id);
  421. l2_sim_result->live_out_.insert(live_inout->live_in_.begin(),
  422. live_inout->live_in_.end());
  423. }
  424. // l1 live-out.
  425. {
  426. auto live_out = MakeFilterIteratorRange(l2_sim_result->live_out_.begin(),
  427. l2_sim_result->live_out_.end(),
  428. belong_to_loop1);
  429. l1_sim_result->live_out_.insert(live_out.begin(), live_out.end());
  430. }
  431. {
  432. auto live_out =
  433. MakeFilterIteratorRange(l2_sim_result->live_in_.begin(),
  434. l2_sim_result->live_in_.end(), belong_to_loop1);
  435. l1_sim_result->live_out_.insert(live_out.begin(), live_out.end());
  436. }
  437. // Lives out of l1 are live out of l2 so are live in of l2 as well.
  438. l2_sim_result->live_in_.insert(l1_sim_result->live_out_.begin(),
  439. l1_sim_result->live_out_.end());
  440. for (Instruction* insn : l1_sim_result->live_in_) {
  441. l1_sim_result->AddRegisterClass(insn);
  442. }
  443. for (Instruction* insn : l2_sim_result->live_in_) {
  444. l2_sim_result->AddRegisterClass(insn);
  445. }
  446. l1_sim_result->used_registers_ = 0;
  447. l2_sim_result->used_registers_ = 0;
  448. for (uint32_t bb_id : loop.GetBlocks()) {
  449. BasicBlock* bb = context_->cfg()->block(bb_id);
  450. const RegisterLiveness::RegionRegisterLiveness* live_inout = Get(bb_id);
  451. assert(live_inout != nullptr && "Basic block not processed");
  452. auto l1_block_live_out =
  453. MakeFilterIteratorRange(live_inout->live_out_.begin(),
  454. live_inout->live_out_.end(), belong_to_loop1);
  455. auto l2_block_live_out =
  456. MakeFilterIteratorRange(live_inout->live_out_.begin(),
  457. live_inout->live_out_.end(), belong_to_loop2);
  458. size_t l1_reg_count =
  459. std::distance(l1_block_live_out.begin(), l1_block_live_out.end());
  460. size_t l2_reg_count =
  461. std::distance(l2_block_live_out.begin(), l2_block_live_out.end());
  462. std::unordered_set<uint32_t> die_in_block;
  463. for (Instruction& insn : make_range(bb->rbegin(), bb->rend())) {
  464. if (insn.opcode() == spv::Op::OpPhi) {
  465. break;
  466. }
  467. bool does_belong_to_loop1 = belong_to_loop1(&insn);
  468. bool does_belong_to_loop2 = belong_to_loop2(&insn);
  469. insn.ForEachInId([live_inout, &die_in_block, &l1_reg_count, &l2_reg_count,
  470. does_belong_to_loop1, does_belong_to_loop2,
  471. this](uint32_t* id) {
  472. Instruction* op_insn = context_->get_def_use_mgr()->GetDef(*id);
  473. if (!CreatesRegisterUsage(op_insn) ||
  474. live_inout->live_out_.count(op_insn)) {
  475. // already taken into account.
  476. return;
  477. }
  478. if (!die_in_block.count(*id)) {
  479. if (does_belong_to_loop1) {
  480. l1_reg_count++;
  481. }
  482. if (does_belong_to_loop2) {
  483. l2_reg_count++;
  484. }
  485. die_in_block.insert(*id);
  486. }
  487. });
  488. l1_sim_result->used_registers_ =
  489. std::max(l1_sim_result->used_registers_, l1_reg_count);
  490. l2_sim_result->used_registers_ =
  491. std::max(l2_sim_result->used_registers_, l2_reg_count);
  492. if (CreatesRegisterUsage(&insn)) {
  493. if (does_belong_to_loop1) {
  494. if (!l1_sim_result->live_in_.count(&insn)) {
  495. l1_sim_result->AddRegisterClass(&insn);
  496. }
  497. l1_reg_count--;
  498. }
  499. if (does_belong_to_loop2) {
  500. if (!l2_sim_result->live_in_.count(&insn)) {
  501. l2_sim_result->AddRegisterClass(&insn);
  502. }
  503. l2_reg_count--;
  504. }
  505. }
  506. }
  507. }
  508. }
  509. } // namespace opt
  510. } // namespace spvtools