inline_pass.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. // Copyright (c) 2017 The Khronos Group Inc.
  2. // Copyright (c) 2017 Valve Corporation
  3. // Copyright (c) 2017 LunarG Inc.
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. #ifndef SOURCE_OPT_INLINE_PASS_H_
  17. #define SOURCE_OPT_INLINE_PASS_H_
  18. #include <algorithm>
  19. #include <list>
  20. #include <memory>
  21. #include <set>
  22. #include <unordered_map>
  23. #include <vector>
  24. #include "source/opt/debug_info_manager.h"
  25. #include "source/opt/decoration_manager.h"
  26. #include "source/opt/module.h"
  27. #include "source/opt/pass.h"
  28. namespace spvtools {
  29. namespace opt {
  30. // See optimizer.hpp for documentation.
  31. class InlinePass : public Pass {
  32. using cbb_ptr = const BasicBlock*;
  33. public:
  34. virtual ~InlinePass() override = default;
  35. protected:
  36. InlinePass();
  37. // Add pointer to type to module and return resultId. Returns 0 if the type
  38. // could not be created.
  39. uint32_t AddPointerToType(uint32_t type_id, spv::StorageClass storage_class);
  40. // Add unconditional branch to labelId to end of block block_ptr.
  41. void AddBranch(uint32_t labelId, std::unique_ptr<BasicBlock>* block_ptr);
  42. // Add conditional branch to end of block |block_ptr|.
  43. void AddBranchCond(uint32_t cond_id, uint32_t true_id, uint32_t false_id,
  44. std::unique_ptr<BasicBlock>* block_ptr);
  45. // Add unconditional branch to labelId to end of block block_ptr.
  46. void AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
  47. std::unique_ptr<BasicBlock>* block_ptr);
  48. // Add store of valId to ptrId to end of block block_ptr.
  49. void AddStore(uint32_t ptrId, uint32_t valId,
  50. std::unique_ptr<BasicBlock>* block_ptr,
  51. const Instruction* line_inst, const DebugScope& dbg_scope);
  52. // Add load of ptrId into resultId to end of block block_ptr.
  53. void AddLoad(uint32_t typeId, uint32_t resultId, uint32_t ptrId,
  54. std::unique_ptr<BasicBlock>* block_ptr,
  55. const Instruction* line_inst, const DebugScope& dbg_scope);
  56. // Return new label.
  57. std::unique_ptr<Instruction> NewLabel(uint32_t label_id);
  58. // Returns the id for the boolean false value. Looks in the module first
  59. // and creates it if not found. Remembers it for future calls. Returns 0 if
  60. // the value could not be created.
  61. uint32_t GetFalseId();
  62. // Map callee params to caller args
  63. void MapParams(Function* calleeFn, BasicBlock::iterator call_inst_itr,
  64. std::unordered_map<uint32_t, uint32_t>* callee2caller);
  65. // Clone and map callee locals. Return true if successful.
  66. bool CloneAndMapLocals(Function* calleeFn,
  67. std::vector<std::unique_ptr<Instruction>>* new_vars,
  68. std::unordered_map<uint32_t, uint32_t>* callee2caller,
  69. analysis::DebugInlinedAtContext* inlined_at_ctx);
  70. // Create return variable for callee clone code. The return type of
  71. // |calleeFn| must not be void. Returns the id of the return variable if
  72. // created. Returns 0 if the return variable could not be created.
  73. uint32_t CreateReturnVar(Function* calleeFn,
  74. std::vector<std::unique_ptr<Instruction>>* new_vars);
  75. // Return true if instruction must be in the same block that its result
  76. // is used.
  77. bool IsSameBlockOp(const Instruction* inst) const;
  78. // Clone operands which must be in same block as consumer instructions.
  79. // Look in preCallSB for instructions that need cloning. Look in
  80. // postCallSB for instructions already cloned. Add cloned instruction
  81. // to postCallSB.
  82. bool CloneSameBlockOps(std::unique_ptr<Instruction>* inst,
  83. std::unordered_map<uint32_t, uint32_t>* postCallSB,
  84. std::unordered_map<uint32_t, Instruction*>* preCallSB,
  85. std::unique_ptr<BasicBlock>* block_ptr);
  86. // Return in new_blocks the result of inlining the call at call_inst_itr
  87. // within its block at call_block_itr. The block at call_block_itr can
  88. // just be replaced with the blocks in new_blocks. Any additional branches
  89. // are avoided. Debug instructions are cloned along with their callee
  90. // instructions. Early returns are replaced by a store to a local return
  91. // variable and a branch to a (created) exit block where the local variable
  92. // is returned. Formal parameters are trivially mapped to their actual
  93. // parameters. Note that the first block in new_blocks retains the label
  94. // of the original calling block. Also note that if an exit block is
  95. // created, it is the last block of new_blocks.
  96. //
  97. // Also return in new_vars additional OpVariable instructions required by
  98. // and to be inserted into the caller function after the block at
  99. // call_block_itr is replaced with new_blocks.
  100. //
  101. // Returns true if successful.
  102. bool GenInlineCode(std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
  103. std::vector<std::unique_ptr<Instruction>>* new_vars,
  104. BasicBlock::iterator call_inst_itr,
  105. UptrVectorIterator<BasicBlock> call_block_itr);
  106. // Return true if |inst| is a function call that can be inlined.
  107. bool IsInlinableFunctionCall(const Instruction* inst);
  108. // Return true if |func| has no return in a loop. The current analysis
  109. // requires structured control flow, so return false if control flow not
  110. // structured ie. module is not a shader.
  111. bool HasNoReturnInLoop(Function* func);
  112. // Find all functions with multiple returns and no returns in loops
  113. void AnalyzeReturns(Function* func);
  114. // Return true if |func| is a function that can be inlined.
  115. bool IsInlinableFunction(Function* func);
  116. // Returns true if |func| contains an abort instruction that is not an
  117. // `OpUnreachable` instruction.
  118. bool ContainsAbortOtherThanUnreachable(Function* func) const;
  119. // Update phis in succeeding blocks to point to new last block
  120. void UpdateSucceedingPhis(
  121. std::vector<std::unique_ptr<BasicBlock>>& new_blocks);
  122. // Initialize state for optimization of |module|
  123. void InitializeInline();
  124. // Fixes invalid debug declare functions in `func` that were caused by
  125. // inlining. This function cannot be called while in the middle of inlining
  126. // because it needs to be able to find the instructions that define an
  127. // id.
  128. void FixDebugDeclares(Function* func);
  129. // Map from function's result id to function.
  130. std::unordered_map<uint32_t, Function*> id2function_;
  131. // Map from block's label id to block. TODO(dnovillo): This is superfluous wrt
  132. // CFG. It has functionality not present in CFG. Consolidate.
  133. std::unordered_map<uint32_t, BasicBlock*> id2block_;
  134. // Set of ids of functions with early return.
  135. std::set<uint32_t> early_return_funcs_;
  136. // Set of ids of functions with no returns in loop
  137. std::set<uint32_t> no_return_in_loop_;
  138. // Set of ids of inlinable functions
  139. std::set<uint32_t> inlinable_;
  140. // result id for OpConstantFalse
  141. uint32_t false_id_;
  142. // Set of functions that are originally called directly or indirectly from a
  143. // continue construct.
  144. std::unordered_set<uint32_t> funcs_called_from_continue_;
  145. private:
  146. // Moves instructions of the caller function up to the call instruction
  147. // to |new_blk_ptr|.
  148. void MoveInstsBeforeEntryBlock(
  149. std::unordered_map<uint32_t, Instruction*>* preCallSB,
  150. BasicBlock* new_blk_ptr, BasicBlock::iterator call_inst_itr,
  151. UptrVectorIterator<BasicBlock> call_block_itr);
  152. // Returns a new guard block after adding a branch to the end of
  153. // |new_blocks|.
  154. std::unique_ptr<BasicBlock> AddGuardBlock(
  155. std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
  156. std::unordered_map<uint32_t, uint32_t>* callee2caller,
  157. std::unique_ptr<BasicBlock> new_blk_ptr, uint32_t entry_blk_label_id);
  158. // Add store instructions for initializers of variables.
  159. InstructionList::iterator AddStoresForVariableInitializers(
  160. const std::unordered_map<uint32_t, uint32_t>& callee2caller,
  161. analysis::DebugInlinedAtContext* inlined_at_ctx,
  162. std::unique_ptr<BasicBlock>* new_blk_ptr,
  163. UptrVectorIterator<BasicBlock> callee_block_itr);
  164. // Inlines a single instruction of the callee function.
  165. bool InlineSingleInstruction(
  166. const std::unordered_map<uint32_t, uint32_t>& callee2caller,
  167. BasicBlock* new_blk_ptr, const Instruction* inst,
  168. uint32_t dbg_inlined_at);
  169. // Inlines the return instruction of the callee function.
  170. std::unique_ptr<BasicBlock> InlineReturn(
  171. const std::unordered_map<uint32_t, uint32_t>& callee2caller,
  172. std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
  173. std::unique_ptr<BasicBlock> new_blk_ptr,
  174. analysis::DebugInlinedAtContext* inlined_at_ctx, Function* calleeFn,
  175. const Instruction* inst, uint32_t returnVarId);
  176. // Inlines the entry block of the callee function.
  177. bool InlineEntryBlock(
  178. const std::unordered_map<uint32_t, uint32_t>& callee2caller,
  179. std::unique_ptr<BasicBlock>* new_blk_ptr,
  180. UptrVectorIterator<BasicBlock> callee_first_block,
  181. analysis::DebugInlinedAtContext* inlined_at_ctx);
  182. // Inlines basic blocks of the callee function other than the entry basic
  183. // block.
  184. std::unique_ptr<BasicBlock> InlineBasicBlocks(
  185. std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
  186. const std::unordered_map<uint32_t, uint32_t>& callee2caller,
  187. std::unique_ptr<BasicBlock> new_blk_ptr,
  188. analysis::DebugInlinedAtContext* inlined_at_ctx, Function* calleeFn);
  189. // Moves instructions of the caller function after the call instruction
  190. // to |new_blk_ptr|.
  191. bool MoveCallerInstsAfterFunctionCall(
  192. std::unordered_map<uint32_t, Instruction*>* preCallSB,
  193. std::unordered_map<uint32_t, uint32_t>* postCallSB,
  194. std::unique_ptr<BasicBlock>* new_blk_ptr,
  195. BasicBlock::iterator call_inst_itr, bool multiBlocks);
  196. // Move the OpLoopMerge from the last block back to the first.
  197. void MoveLoopMergeInstToFirstBlock(
  198. std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
  199. // Update the structure of single block loops so that the inlined code ends
  200. // up in the loop construct and a new continue target is added to satisfy
  201. // structural dominance.
  202. void UpdateSingleBlockLoopContinueTarget(
  203. uint32_t new_id, std::vector<std::unique_ptr<BasicBlock>>* new_blocks);
  204. // Replaces the `var` operand of `dbg_declare_inst` and updates the indexes
  205. // accordingly, if it is the id of an access chain in `access_chains`.
  206. void FixDebugDeclare(Instruction* dbg_declare_inst,
  207. const std::map<uint32_t, Instruction*>& access_chains);
  208. };
  209. } // namespace opt
  210. } // namespace spvtools
  211. #endif // SOURCE_OPT_INLINE_PASS_H_