propagator.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // Copyright (c) 2017 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 "source/opt/propagator.h"
  15. namespace spvtools {
  16. namespace opt {
  17. void SSAPropagator::AddControlEdge(const Edge& edge) {
  18. BasicBlock* dest_bb = edge.dest;
  19. // Refuse to add the exit block to the work list.
  20. if (dest_bb == ctx_->cfg()->pseudo_exit_block()) {
  21. return;
  22. }
  23. // Try to mark the edge executable. If it was already in the set of
  24. // executable edges, do nothing.
  25. if (!MarkEdgeExecutable(edge)) {
  26. return;
  27. }
  28. // If the edge had not already been marked executable, add the destination
  29. // basic block to the work list.
  30. blocks_.push(dest_bb);
  31. }
  32. void SSAPropagator::AddSSAEdges(Instruction* instr) {
  33. // Ignore instructions that produce no result.
  34. if (instr->result_id() == 0) {
  35. return;
  36. }
  37. get_def_use_mgr()->ForEachUser(
  38. instr->result_id(), [this](Instruction* use_instr) {
  39. // If the basic block for |use_instr| has not been simulated yet, do
  40. // nothing. The instruction |use_instr| will be simulated next time the
  41. // block is scheduled.
  42. if (!BlockHasBeenSimulated(ctx_->get_instr_block(use_instr))) {
  43. return;
  44. }
  45. if (ShouldSimulateAgain(use_instr)) {
  46. ssa_edge_uses_.push(use_instr);
  47. }
  48. });
  49. }
  50. bool SSAPropagator::IsPhiArgExecutable(Instruction* phi, uint32_t i) const {
  51. BasicBlock* phi_bb = ctx_->get_instr_block(phi);
  52. uint32_t in_label_id = phi->GetSingleWordOperand(i + 1);
  53. Instruction* in_label_instr = get_def_use_mgr()->GetDef(in_label_id);
  54. BasicBlock* in_bb = ctx_->get_instr_block(in_label_instr);
  55. return IsEdgeExecutable(Edge(in_bb, phi_bb));
  56. }
  57. bool SSAPropagator::SetStatus(Instruction* inst, PropStatus status) {
  58. bool has_old_status = false;
  59. PropStatus old_status = kVarying;
  60. if (HasStatus(inst)) {
  61. has_old_status = true;
  62. old_status = Status(inst);
  63. }
  64. assert((!has_old_status || old_status <= status) &&
  65. "Invalid lattice transition");
  66. bool status_changed = !has_old_status || (old_status != status);
  67. if (status_changed) statuses_[inst] = status;
  68. return status_changed;
  69. }
  70. bool SSAPropagator::Simulate(Instruction* instr) {
  71. bool changed = false;
  72. // Don't bother visiting instructions that should not be simulated again.
  73. if (!ShouldSimulateAgain(instr)) {
  74. return changed;
  75. }
  76. BasicBlock* dest_bb = nullptr;
  77. PropStatus status = visit_fn_(instr, &dest_bb);
  78. bool status_changed = SetStatus(instr, status);
  79. if (status == kVarying) {
  80. // The statement produces a varying result, add it to the list of statements
  81. // not to simulate anymore and add its SSA def-use edges for simulation.
  82. DontSimulateAgain(instr);
  83. if (status_changed) {
  84. AddSSAEdges(instr);
  85. }
  86. // If |instr| is a block terminator, add all the control edges out of its
  87. // block.
  88. if (instr->IsBlockTerminator()) {
  89. BasicBlock* block = ctx_->get_instr_block(instr);
  90. for (const auto& e : bb_succs_.at(block)) {
  91. AddControlEdge(e);
  92. }
  93. }
  94. return false;
  95. } else if (status == kInteresting) {
  96. // Add the SSA edges coming out of this instruction if the propagation
  97. // status has changed.
  98. if (status_changed) {
  99. AddSSAEdges(instr);
  100. }
  101. // If there are multiple outgoing control flow edges and we know which one
  102. // will be taken, add the destination block to the CFG work list.
  103. if (dest_bb) {
  104. AddControlEdge(Edge(ctx_->get_instr_block(instr), dest_bb));
  105. }
  106. changed = true;
  107. }
  108. // At this point, we are dealing with instructions that are in status
  109. // kInteresting or kNotInteresting. To decide whether this instruction should
  110. // be simulated again, we examine its operands. If at least one operand O is
  111. // defined at an instruction D that should be simulated again, then the output
  112. // of D might affect |instr|, so we should simulate |instr| again.
  113. bool has_operands_to_simulate = false;
  114. if (instr->opcode() == spv::Op::OpPhi) {
  115. // For Phi instructions, an operand causes the Phi to be simulated again if
  116. // the operand comes from an edge that has not yet been traversed or if its
  117. // definition should be simulated again.
  118. for (uint32_t i = 2; i < instr->NumOperands(); i += 2) {
  119. // Phi arguments come in pairs. Index 'i' contains the
  120. // variable id, index 'i + 1' is the originating block id.
  121. assert(i % 2 == 0 && i < instr->NumOperands() - 1 &&
  122. "malformed Phi arguments");
  123. uint32_t arg_id = instr->GetSingleWordOperand(i);
  124. Instruction* arg_def_instr = get_def_use_mgr()->GetDef(arg_id);
  125. if (!IsPhiArgExecutable(instr, i) || ShouldSimulateAgain(arg_def_instr)) {
  126. has_operands_to_simulate = true;
  127. break;
  128. }
  129. }
  130. } else {
  131. // For regular instructions, check if the defining instruction of each
  132. // operand needs to be simulated again. If so, then this instruction should
  133. // also be simulated again.
  134. has_operands_to_simulate =
  135. !instr->WhileEachInId([this](const uint32_t* use) {
  136. Instruction* def_instr = get_def_use_mgr()->GetDef(*use);
  137. if (ShouldSimulateAgain(def_instr)) {
  138. return false;
  139. }
  140. return true;
  141. });
  142. }
  143. if (!has_operands_to_simulate) {
  144. DontSimulateAgain(instr);
  145. }
  146. return changed;
  147. }
  148. bool SSAPropagator::Simulate(BasicBlock* block) {
  149. if (block == ctx_->cfg()->pseudo_exit_block()) {
  150. return false;
  151. }
  152. // Always simulate Phi instructions, even if we have simulated this block
  153. // before. We do this because Phi instructions receive their inputs from
  154. // incoming edges. When those edges are marked executable, the corresponding
  155. // operand can be simulated.
  156. bool changed = false;
  157. block->ForEachPhiInst(
  158. [&changed, this](Instruction* instr) { changed |= Simulate(instr); });
  159. // If this is the first time this block is being simulated, simulate every
  160. // statement in it.
  161. if (!BlockHasBeenSimulated(block)) {
  162. block->ForEachInst([this, &changed](Instruction* instr) {
  163. if (instr->opcode() != spv::Op::OpPhi) {
  164. changed |= Simulate(instr);
  165. }
  166. });
  167. MarkBlockSimulated(block);
  168. // If this block has exactly one successor, mark the edge to its successor
  169. // as executable.
  170. if (bb_succs_.at(block).size() == 1) {
  171. AddControlEdge(bb_succs_.at(block).at(0));
  172. }
  173. }
  174. return changed;
  175. }
  176. void SSAPropagator::Initialize(Function* fn) {
  177. // Compute predecessor and successor blocks for every block in |fn|'s CFG.
  178. // TODO(dnovillo): Move this to CFG and always build them. Alternately,
  179. // move it to IRContext and build CFG preds/succs on-demand.
  180. bb_succs_[ctx_->cfg()->pseudo_entry_block()].push_back(
  181. Edge(ctx_->cfg()->pseudo_entry_block(), fn->entry().get()));
  182. for (auto& block : *fn) {
  183. const auto& const_block = block;
  184. const_block.ForEachSuccessorLabel([this, &block](const uint32_t label_id) {
  185. BasicBlock* succ_bb =
  186. ctx_->get_instr_block(get_def_use_mgr()->GetDef(label_id));
  187. bb_succs_[&block].push_back(Edge(&block, succ_bb));
  188. bb_preds_[succ_bb].push_back(Edge(succ_bb, &block));
  189. });
  190. if (block.IsReturnOrAbort()) {
  191. bb_succs_[&block].push_back(
  192. Edge(&block, ctx_->cfg()->pseudo_exit_block()));
  193. bb_preds_[ctx_->cfg()->pseudo_exit_block()].push_back(
  194. Edge(ctx_->cfg()->pseudo_exit_block(), &block));
  195. }
  196. }
  197. // Add the edges out of the entry block to seed the propagator.
  198. const auto& entry_succs = bb_succs_[ctx_->cfg()->pseudo_entry_block()];
  199. for (const auto& e : entry_succs) {
  200. AddControlEdge(e);
  201. }
  202. }
  203. bool SSAPropagator::Run(Function* fn) {
  204. Initialize(fn);
  205. bool changed = false;
  206. while (!blocks_.empty() || !ssa_edge_uses_.empty()) {
  207. // Simulate all blocks first. Simulating blocks will add SSA edges to
  208. // follow after all the blocks have been simulated.
  209. if (!blocks_.empty()) {
  210. auto block = blocks_.front();
  211. changed |= Simulate(block);
  212. blocks_.pop();
  213. continue;
  214. }
  215. // Simulate edges from the SSA queue.
  216. if (!ssa_edge_uses_.empty()) {
  217. Instruction* instr = ssa_edge_uses_.front();
  218. changed |= Simulate(instr);
  219. ssa_edge_uses_.pop();
  220. }
  221. }
  222. #ifndef NDEBUG
  223. // Verify all visited values have settled. No value that has been simulated
  224. // should end on not interesting.
  225. fn->ForEachInst([this](Instruction* inst) {
  226. assert(
  227. (!HasStatus(inst) || Status(inst) != SSAPropagator::kNotInteresting) &&
  228. "Unsettled value");
  229. });
  230. #endif
  231. return changed;
  232. }
  233. std::ostream& operator<<(std::ostream& str,
  234. const SSAPropagator::PropStatus& status) {
  235. switch (status) {
  236. case SSAPropagator::kVarying:
  237. str << "Varying";
  238. break;
  239. case SSAPropagator::kInteresting:
  240. str << "Interesting";
  241. break;
  242. default:
  243. str << "Not interesting";
  244. break;
  245. }
  246. return str;
  247. }
  248. } // namespace opt
  249. } // namespace spvtools