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 15 #ifndef SOURCE_OPT_FUNCTION_H_ 16 #define SOURCE_OPT_FUNCTION_H_ 17 18 #include <algorithm> 19 #include <functional> 20 #include <memory> 21 #include <string> 22 #include <utility> 23 #include <vector> 24 25 #include "source/opt/basic_block.h" 26 #include "source/opt/instruction.h" 27 #include "source/opt/iterator.h" 28 29 namespace spvtools { 30 namespace opt { 31 32 class CFG; 33 class IRContext; 34 class Module; 35 36 // A SPIR-V function. 37 class Function { 38 public: 39 using iterator = UptrVectorIterator<BasicBlock>; 40 using const_iterator = UptrVectorIterator<BasicBlock, true>; 41 42 // Creates a function instance declared by the given OpFunction instruction 43 // |def_inst|. 44 inline explicit Function(std::unique_ptr<Instruction> def_inst); 45 46 explicit Function(const Function& f) = delete; 47 48 // Creates a clone of the instruction in the given |context| 49 // 50 // The parent module will default to null and needs to be explicitly set by 51 // the user. 52 Function* Clone(IRContext*) const; 53 // The OpFunction instruction that begins the definition of this function. 54 Instruction& DefInst() { return *def_inst_; } 55 const Instruction& DefInst() const { return *def_inst_; } 56 57 // Appends a parameter to this function. 58 inline void AddParameter(std::unique_ptr<Instruction> p); 59 // Appends a basic block to this function. 60 inline void AddBasicBlock(std::unique_ptr<BasicBlock> b); 61 // Appends a basic block to this function at the position |ip|. 62 inline void AddBasicBlock(std::unique_ptr<BasicBlock> b, iterator ip); 63 template <typename T> 64 inline void AddBasicBlocks(T begin, T end, iterator ip); 65 66 // Move basic block with |id| to the position after |ip|. Both have to be 67 // contained in this function. 68 inline void MoveBasicBlockToAfter(uint32_t id, BasicBlock* ip); 69 70 // Delete all basic blocks that contain no instructions. 71 inline void RemoveEmptyBlocks(); 72 73 // Saves the given function end instruction. 74 inline void SetFunctionEnd(std::unique_ptr<Instruction> end_inst); 75 76 // Returns the given function end instruction. 77 inline Instruction* EndInst() { return end_inst_.get(); } 78 inline const Instruction* EndInst() const { return end_inst_.get(); } 79 80 // Returns function's id 81 inline uint32_t result_id() const { return def_inst_->result_id(); } 82 83 // Returns function's return type id 84 inline uint32_t type_id() const { return def_inst_->type_id(); } 85 86 // Returns the entry basic block for this function. 87 const std::unique_ptr<BasicBlock>& entry() const { return blocks_.front(); } 88 89 iterator begin() { return iterator(&blocks_, blocks_.begin()); } 90 iterator end() { return iterator(&blocks_, blocks_.end()); } 91 const_iterator begin() const { return cbegin(); } 92 const_iterator end() const { return cend(); } 93 const_iterator cbegin() const { 94 return const_iterator(&blocks_, blocks_.cbegin()); 95 } 96 const_iterator cend() const { 97 return const_iterator(&blocks_, blocks_.cend()); 98 } 99 100 // Returns an iterator to the basic block |id|. 101 iterator FindBlock(uint32_t bb_id) { 102 return std::find_if(begin(), end(), [bb_id](const BasicBlock& it_bb) { 103 return bb_id == it_bb.id(); 104 }); 105 } 106 107 // Runs the given function |f| on each instruction in this function, and 108 // optionally on debug line instructions that might precede them. 109 void ForEachInst(const std::function<void(Instruction*)>& f, 110 bool run_on_debug_line_insts = false); 111 void ForEachInst(const std::function<void(const Instruction*)>& f, 112 bool run_on_debug_line_insts = false) const; 113 114 // Runs the given function |f| on each parameter instruction in this function, 115 // and optionally on debug line instructions that might precede them. 116 void ForEachParam(const std::function<void(const Instruction*)>& f, 117 bool run_on_debug_line_insts = false) const; 118 void ForEachParam(const std::function<void(Instruction*)>& f, 119 bool run_on_debug_line_insts = false); 120 121 BasicBlock* InsertBasicBlockAfter(std::unique_ptr<BasicBlock>&& new_block, 122 BasicBlock* position); 123 124 // Return true if the function calls itself either directly or indirectly. 125 bool IsRecursive() const; 126 127 // Pretty-prints all the basic blocks in this function into a std::string. 128 // 129 // |options| are the disassembly options. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER 130 // is always added to |options|. 131 std::string PrettyPrint(uint32_t options = 0u) const; 132 133 // Dump this function on stderr. Useful when running interactive 134 // debuggers. 135 void Dump() const; 136 137 private: 138 // The OpFunction instruction that begins the definition of this function. 139 std::unique_ptr<Instruction> def_inst_; 140 // All parameters to this function. 141 std::vector<std::unique_ptr<Instruction>> params_; 142 // All basic blocks inside this function in specification order 143 std::vector<std::unique_ptr<BasicBlock>> blocks_; 144 // The OpFunctionEnd instruction. 145 std::unique_ptr<Instruction> end_inst_; 146 }; 147 148 // Pretty-prints |func| to |str|. Returns |str|. 149 std::ostream& operator<<(std::ostream& str, const Function& func); 150 151 inline Function::Function(std::unique_ptr<Instruction> def_inst) 152 : def_inst_(std::move(def_inst)), end_inst_() {} 153 154 inline void Function::AddParameter(std::unique_ptr<Instruction> p) { 155 params_.emplace_back(std::move(p)); 156 } 157 158 inline void Function::AddBasicBlock(std::unique_ptr<BasicBlock> b) { 159 AddBasicBlock(std::move(b), end()); 160 } 161 162 inline void Function::AddBasicBlock(std::unique_ptr<BasicBlock> b, 163 iterator ip) { 164 ip.InsertBefore(std::move(b)); 165 } 166 167 template <typename T> 168 inline void Function::AddBasicBlocks(T src_begin, T src_end, iterator ip) { 169 blocks_.insert(ip.Get(), std::make_move_iterator(src_begin), 170 std::make_move_iterator(src_end)); 171 } 172 173 inline void Function::MoveBasicBlockToAfter(uint32_t id, BasicBlock* ip) { 174 auto block_to_move = std::move(*FindBlock(id).Get()); 175 176 assert(block_to_move->GetParent() == ip->GetParent() && 177 "Both blocks have to be in the same function."); 178 179 InsertBasicBlockAfter(std::move(block_to_move), ip); 180 blocks_.erase(std::find(std::begin(blocks_), std::end(blocks_), nullptr)); 181 } 182 183 inline void Function::RemoveEmptyBlocks() { 184 auto first_empty = 185 std::remove_if(std::begin(blocks_), std::end(blocks_), 186 [](const std::unique_ptr<BasicBlock>& bb) -> bool { 187 return bb->GetLabelInst()->opcode() == SpvOpNop; 188 }); 189 blocks_.erase(first_empty, std::end(blocks_)); 190 } 191 192 inline void Function::SetFunctionEnd(std::unique_ptr<Instruction> end_inst) { 193 end_inst_ = std::move(end_inst); 194 } 195 196 } // namespace opt 197 } // namespace spvtools 198 199 #endif // SOURCE_OPT_FUNCTION_H_ 200