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