inline_pass.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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/decoration_manager.h"
  25. #include "source/opt/module.h"
  26. #include "source/opt/pass.h"
  27. namespace spvtools {
  28. namespace opt {
  29. // See optimizer.hpp for documentation.
  30. class InlinePass : public Pass {
  31. using cbb_ptr = const BasicBlock*;
  32. public:
  33. virtual ~InlinePass() = default;
  34. protected:
  35. InlinePass();
  36. // Add pointer to type to module and return resultId. Returns 0 if the type
  37. // could not be created.
  38. uint32_t AddPointerToType(uint32_t type_id, SpvStorageClass storage_class);
  39. // Add unconditional branch to labelId to end of block block_ptr.
  40. void AddBranch(uint32_t labelId, std::unique_ptr<BasicBlock>* block_ptr);
  41. // Add conditional branch to end of block |block_ptr|.
  42. void AddBranchCond(uint32_t cond_id, uint32_t true_id, uint32_t false_id,
  43. std::unique_ptr<BasicBlock>* block_ptr);
  44. // Add unconditional branch to labelId to end of block block_ptr.
  45. void AddLoopMerge(uint32_t merge_id, uint32_t continue_id,
  46. std::unique_ptr<BasicBlock>* block_ptr);
  47. // Add store of valId to ptrId to end of block block_ptr.
  48. void AddStore(uint32_t ptrId, uint32_t valId,
  49. std::unique_ptr<BasicBlock>* block_ptr);
  50. // Add load of ptrId into resultId to end of block block_ptr.
  51. void AddLoad(uint32_t typeId, uint32_t resultId, uint32_t ptrId,
  52. std::unique_ptr<BasicBlock>* block_ptr);
  53. // Return new label.
  54. std::unique_ptr<Instruction> NewLabel(uint32_t label_id);
  55. // Returns the id for the boolean false value. Looks in the module first
  56. // and creates it if not found. Remembers it for future calls. Returns 0 if
  57. // the value could not be created.
  58. uint32_t GetFalseId();
  59. // Map callee params to caller args
  60. void MapParams(Function* calleeFn, BasicBlock::iterator call_inst_itr,
  61. std::unordered_map<uint32_t, uint32_t>* callee2caller);
  62. // Clone and map callee locals. Return true if successful.
  63. bool CloneAndMapLocals(Function* calleeFn,
  64. std::vector<std::unique_ptr<Instruction>>* new_vars,
  65. std::unordered_map<uint32_t, uint32_t>* callee2caller);
  66. // Create return variable for callee clone code. The return type of
  67. // |calleeFn| must not be void. Returns the id of the return variable if
  68. // created. Returns 0 if the return variable could not be created.
  69. uint32_t CreateReturnVar(Function* calleeFn,
  70. std::vector<std::unique_ptr<Instruction>>* new_vars);
  71. // Return true if instruction must be in the same block that its result
  72. // is used.
  73. bool IsSameBlockOp(const Instruction* inst) const;
  74. // Clone operands which must be in same block as consumer instructions.
  75. // Look in preCallSB for instructions that need cloning. Look in
  76. // postCallSB for instructions already cloned. Add cloned instruction
  77. // to postCallSB.
  78. bool CloneSameBlockOps(std::unique_ptr<Instruction>* inst,
  79. std::unordered_map<uint32_t, uint32_t>* postCallSB,
  80. std::unordered_map<uint32_t, Instruction*>* preCallSB,
  81. std::unique_ptr<BasicBlock>* block_ptr);
  82. // Return in new_blocks the result of inlining the call at call_inst_itr
  83. // within its block at call_block_itr. The block at call_block_itr can
  84. // just be replaced with the blocks in new_blocks. Any additional branches
  85. // are avoided. Debug instructions are cloned along with their callee
  86. // instructions. Early returns are replaced by a store to a local return
  87. // variable and a branch to a (created) exit block where the local variable
  88. // is returned. Formal parameters are trivially mapped to their actual
  89. // parameters. Note that the first block in new_blocks retains the label
  90. // of the original calling block. Also note that if an exit block is
  91. // created, it is the last block of new_blocks.
  92. //
  93. // Also return in new_vars additional OpVariable instructions required by
  94. // and to be inserted into the caller function after the block at
  95. // call_block_itr is replaced with new_blocks.
  96. //
  97. // Returns true if successful.
  98. bool GenInlineCode(std::vector<std::unique_ptr<BasicBlock>>* new_blocks,
  99. std::vector<std::unique_ptr<Instruction>>* new_vars,
  100. BasicBlock::iterator call_inst_itr,
  101. UptrVectorIterator<BasicBlock> call_block_itr);
  102. // Return true if |inst| is a function call that can be inlined.
  103. bool IsInlinableFunctionCall(const Instruction* inst);
  104. // Return true if |func| does not have a return that is
  105. // nested in a structured if, switch or loop.
  106. bool HasNoReturnInStructuredConstruct(Function* func);
  107. // Return true if |func| has no return in a loop. The current analysis
  108. // requires structured control flow, so return false if control flow not
  109. // structured ie. module is not a shader.
  110. bool HasNoReturnInLoop(Function* func);
  111. // Find all functions with multiple returns and no returns in loops
  112. void AnalyzeReturns(Function* func);
  113. // Return true if |func| is a function that can be inlined.
  114. bool IsInlinableFunction(Function* func);
  115. // Returns true if |func| contains an OpKill instruction.
  116. bool ContainsKill(Function* func) const;
  117. // Update phis in succeeding blocks to point to new last block
  118. void UpdateSucceedingPhis(
  119. std::vector<std::unique_ptr<BasicBlock>>& new_blocks);
  120. // Initialize state for optimization of |module|
  121. void InitializeInline();
  122. // Map from function's result id to function.
  123. std::unordered_map<uint32_t, Function*> id2function_;
  124. // Map from block's label id to block. TODO(dnovillo): This is superfluous wrt
  125. // CFG. It has functionality not present in CFG. Consolidate.
  126. std::unordered_map<uint32_t, BasicBlock*> id2block_;
  127. // Set of ids of functions with early return.
  128. std::set<uint32_t> early_return_funcs_;
  129. // Set of ids of functions with no returns in loop
  130. std::set<uint32_t> no_return_in_loop_;
  131. // Set of ids of inlinable functions
  132. std::set<uint32_t> inlinable_;
  133. // result id for OpConstantFalse
  134. uint32_t false_id_;
  135. // Set of functions that are originally called directly or indirectly from a
  136. // continue construct.
  137. std::unordered_set<uint32_t> funcs_called_from_continue_;
  138. };
  139. } // namespace opt
  140. } // namespace spvtools
  141. #endif // SOURCE_OPT_INLINE_PASS_H_