function.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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 "source/opt/function.h"
  15. #include <ostream>
  16. #include "ir_context.h"
  17. #include "source/util/bit_vector.h"
  18. namespace spvtools {
  19. namespace opt {
  20. Function* Function::Clone(IRContext* ctx) const {
  21. Function* clone =
  22. new Function(std::unique_ptr<Instruction>(DefInst().Clone(ctx)));
  23. clone->params_.reserve(params_.size());
  24. ForEachParam(
  25. [clone, ctx](const Instruction* inst) {
  26. clone->AddParameter(std::unique_ptr<Instruction>(inst->Clone(ctx)));
  27. },
  28. true);
  29. for (const auto& i : debug_insts_in_header_) {
  30. clone->AddDebugInstructionInHeader(
  31. std::unique_ptr<Instruction>(i.Clone(ctx)));
  32. }
  33. clone->blocks_.reserve(blocks_.size());
  34. for (const auto& b : blocks_) {
  35. std::unique_ptr<BasicBlock> bb(b->Clone(ctx));
  36. if (!bb) {
  37. delete clone;
  38. return nullptr;
  39. }
  40. clone->AddBasicBlock(std::move(bb));
  41. }
  42. clone->SetFunctionEnd(std::unique_ptr<Instruction>(EndInst()->Clone(ctx)));
  43. clone->non_semantic_.reserve(non_semantic_.size());
  44. for (auto& non_semantic : non_semantic_) {
  45. clone->AddNonSemanticInstruction(
  46. std::unique_ptr<Instruction>(non_semantic->Clone(ctx)));
  47. }
  48. return clone;
  49. }
  50. void Function::ForEachInst(const std::function<void(Instruction*)>& f,
  51. bool run_on_debug_line_insts,
  52. bool run_on_non_semantic_insts) {
  53. WhileEachInst(
  54. [&f](Instruction* inst) {
  55. f(inst);
  56. return true;
  57. },
  58. run_on_debug_line_insts, run_on_non_semantic_insts);
  59. }
  60. void Function::ForEachInst(const std::function<void(const Instruction*)>& f,
  61. bool run_on_debug_line_insts,
  62. bool run_on_non_semantic_insts) const {
  63. WhileEachInst(
  64. [&f](const Instruction* inst) {
  65. f(inst);
  66. return true;
  67. },
  68. run_on_debug_line_insts, run_on_non_semantic_insts);
  69. }
  70. bool Function::WhileEachInst(const std::function<bool(Instruction*)>& f,
  71. bool run_on_debug_line_insts,
  72. bool run_on_non_semantic_insts) {
  73. if (def_inst_) {
  74. if (!def_inst_->WhileEachInst(f, run_on_debug_line_insts)) {
  75. return false;
  76. }
  77. }
  78. for (auto& param : params_) {
  79. if (!param->WhileEachInst(f, run_on_debug_line_insts)) {
  80. return false;
  81. }
  82. }
  83. if (!debug_insts_in_header_.empty()) {
  84. Instruction* di = &debug_insts_in_header_.front();
  85. while (di != nullptr) {
  86. Instruction* next_instruction = di->NextNode();
  87. if (!di->WhileEachInst(f, run_on_debug_line_insts)) return false;
  88. di = next_instruction;
  89. }
  90. }
  91. for (auto& bb : blocks_) {
  92. if (!bb->WhileEachInst(f, run_on_debug_line_insts)) {
  93. return false;
  94. }
  95. }
  96. if (end_inst_) {
  97. if (!end_inst_->WhileEachInst(f, run_on_debug_line_insts)) {
  98. return false;
  99. }
  100. }
  101. if (run_on_non_semantic_insts) {
  102. for (auto& non_semantic : non_semantic_) {
  103. if (!non_semantic->WhileEachInst(f, run_on_debug_line_insts)) {
  104. return false;
  105. }
  106. }
  107. }
  108. return true;
  109. }
  110. bool Function::WhileEachInst(const std::function<bool(const Instruction*)>& f,
  111. bool run_on_debug_line_insts,
  112. bool run_on_non_semantic_insts) const {
  113. if (def_inst_) {
  114. if (!static_cast<const Instruction*>(def_inst_.get())
  115. ->WhileEachInst(f, run_on_debug_line_insts)) {
  116. return false;
  117. }
  118. }
  119. for (const auto& param : params_) {
  120. if (!static_cast<const Instruction*>(param.get())
  121. ->WhileEachInst(f, run_on_debug_line_insts)) {
  122. return false;
  123. }
  124. }
  125. for (const auto& di : debug_insts_in_header_) {
  126. if (!static_cast<const Instruction*>(&di)->WhileEachInst(
  127. f, run_on_debug_line_insts))
  128. return false;
  129. }
  130. for (const auto& bb : blocks_) {
  131. if (!static_cast<const BasicBlock*>(bb.get())->WhileEachInst(
  132. f, run_on_debug_line_insts)) {
  133. return false;
  134. }
  135. }
  136. if (end_inst_) {
  137. if (!static_cast<const Instruction*>(end_inst_.get())
  138. ->WhileEachInst(f, run_on_debug_line_insts)) {
  139. return false;
  140. }
  141. }
  142. if (run_on_non_semantic_insts) {
  143. for (auto& non_semantic : non_semantic_) {
  144. if (!static_cast<const Instruction*>(non_semantic.get())
  145. ->WhileEachInst(f, run_on_debug_line_insts)) {
  146. return false;
  147. }
  148. }
  149. }
  150. return true;
  151. }
  152. void Function::ForEachParam(const std::function<void(Instruction*)>& f,
  153. bool run_on_debug_line_insts) {
  154. for (auto& param : params_)
  155. static_cast<Instruction*>(param.get())
  156. ->ForEachInst(f, run_on_debug_line_insts);
  157. }
  158. void Function::ForEachParam(const std::function<void(const Instruction*)>& f,
  159. bool run_on_debug_line_insts) const {
  160. for (const auto& param : params_)
  161. static_cast<const Instruction*>(param.get())
  162. ->ForEachInst(f, run_on_debug_line_insts);
  163. }
  164. void Function::ForEachDebugInstructionsInHeader(
  165. const std::function<void(Instruction*)>& f) {
  166. if (debug_insts_in_header_.empty()) return;
  167. Instruction* di = &debug_insts_in_header_.front();
  168. while (di != nullptr) {
  169. Instruction* next_instruction = di->NextNode();
  170. di->ForEachInst(f);
  171. di = next_instruction;
  172. }
  173. }
  174. BasicBlock* Function::InsertBasicBlockAfter(
  175. std::unique_ptr<BasicBlock>&& new_block, BasicBlock* position) {
  176. for (auto bb_iter = begin(); bb_iter != end(); ++bb_iter) {
  177. if (&*bb_iter == position) {
  178. new_block->SetParent(this);
  179. ++bb_iter;
  180. bb_iter = bb_iter.InsertBefore(std::move(new_block));
  181. return &*bb_iter;
  182. }
  183. }
  184. assert(false && "Could not find insertion point.");
  185. return nullptr;
  186. }
  187. BasicBlock* Function::InsertBasicBlockBefore(
  188. std::unique_ptr<BasicBlock>&& new_block, BasicBlock* position) {
  189. for (auto bb_iter = begin(); bb_iter != end(); ++bb_iter) {
  190. if (&*bb_iter == position) {
  191. new_block->SetParent(this);
  192. bb_iter = bb_iter.InsertBefore(std::move(new_block));
  193. return &*bb_iter;
  194. }
  195. }
  196. assert(false && "Could not find insertion point.");
  197. return nullptr;
  198. }
  199. bool Function::HasEarlyReturn() const {
  200. auto post_dominator_analysis =
  201. blocks_.front()->GetLabel()->context()->GetPostDominatorAnalysis(this);
  202. for (auto& block : blocks_) {
  203. if (spvOpcodeIsReturn(block->tail()->opcode()) &&
  204. !post_dominator_analysis->Dominates(block.get(), entry().get())) {
  205. return true;
  206. }
  207. }
  208. return false;
  209. }
  210. bool Function::IsRecursive() const {
  211. IRContext* ctx = blocks_.front()->GetLabel()->context();
  212. IRContext::ProcessFunction mark_visited = [this](Function* fp) {
  213. return fp == this;
  214. };
  215. // Process the call tree from all of the function called by |this|. If it get
  216. // back to |this|, then we have a recursive function.
  217. std::queue<uint32_t> roots;
  218. ctx->AddCalls(this, &roots);
  219. return ctx->ProcessCallTreeFromRoots(mark_visited, &roots);
  220. }
  221. std::ostream& operator<<(std::ostream& str, const Function& func) {
  222. str << func.PrettyPrint();
  223. return str;
  224. }
  225. void Function::Dump() const {
  226. std::cerr << "Function #" << result_id() << "\n" << *this << "\n";
  227. }
  228. std::string Function::PrettyPrint(uint32_t options) const {
  229. std::ostringstream str;
  230. ForEachInst([&str, options](const Instruction* inst) {
  231. str << inst->PrettyPrint(options);
  232. if (inst->opcode() != spv::Op::OpFunctionEnd) {
  233. str << std::endl;
  234. }
  235. });
  236. return str.str();
  237. }
  238. void Function::ReorderBasicBlocksInStructuredOrder() {
  239. std::list<BasicBlock*> order;
  240. IRContext* context = this->def_inst_->context();
  241. context->cfg()->ComputeStructuredOrder(this, blocks_[0].get(), &order);
  242. ReorderBasicBlocks(order.begin(), order.end());
  243. }
  244. } // namespace opt
  245. } // namespace spvtools