• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
DefInst()54   Instruction& DefInst() { return *def_inst_; }
DefInst()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 debug instruction in function header to this function.
60   inline void AddDebugInstructionInHeader(std::unique_ptr<Instruction> p);
61   // Appends a basic block to this function.
62   inline void AddBasicBlock(std::unique_ptr<BasicBlock> b);
63   // Appends a basic block to this function at the position |ip|.
64   inline void AddBasicBlock(std::unique_ptr<BasicBlock> b, iterator ip);
65   template <typename T>
66   inline void AddBasicBlocks(T begin, T end, iterator ip);
67 
68   // Move basic block with |id| to the position after |ip|. Both have to be
69   // contained in this function.
70   inline void MoveBasicBlockToAfter(uint32_t id, BasicBlock* ip);
71 
72   // Delete all basic blocks that contain no instructions.
73   inline void RemoveEmptyBlocks();
74 
75   // Removes a parameter from the function with result id equal to |id|.
76   // Does nothing if the function doesn't have such a parameter.
77   inline void RemoveParameter(uint32_t id);
78 
79   // Saves the given function end instruction.
80   inline void SetFunctionEnd(std::unique_ptr<Instruction> end_inst);
81 
82   // Add a non-semantic instruction that succeeds this function in the module.
83   // These instructions are maintained in the order they are added.
84   inline void AddNonSemanticInstruction(
85       std::unique_ptr<Instruction> non_semantic);
86 
87   // Returns the given function end instruction.
EndInst()88   inline Instruction* EndInst() { return end_inst_.get(); }
EndInst()89   inline const Instruction* EndInst() const { return end_inst_.get(); }
90 
91   // Returns function's id
result_id()92   inline uint32_t result_id() const { return def_inst_->result_id(); }
93 
94   // Returns function's return type id
type_id()95   inline uint32_t type_id() const { return def_inst_->type_id(); }
96 
97   // Returns the function's control mask
control_mask()98   inline uint32_t control_mask() const { return def_inst_->GetSingleWordInOperand(0); }
99 
100   // Returns the entry basic block for this function.
entry()101   const std::unique_ptr<BasicBlock>& entry() const { return blocks_.front(); }
102 
103   // Returns the last basic block in this function.
tail()104   BasicBlock* tail() { return blocks_.back().get(); }
tail()105   const BasicBlock* tail() const { return blocks_.back().get(); }
106 
begin()107   iterator begin() { return iterator(&blocks_, blocks_.begin()); }
end()108   iterator end() { return iterator(&blocks_, blocks_.end()); }
begin()109   const_iterator begin() const { return cbegin(); }
end()110   const_iterator end() const { return cend(); }
cbegin()111   const_iterator cbegin() const {
112     return const_iterator(&blocks_, blocks_.cbegin());
113   }
cend()114   const_iterator cend() const {
115     return const_iterator(&blocks_, blocks_.cend());
116   }
117 
118   // Returns an iterator to the basic block |id|.
FindBlock(uint32_t bb_id)119   iterator FindBlock(uint32_t bb_id) {
120     return std::find_if(begin(), end(), [bb_id](const BasicBlock& it_bb) {
121       return bb_id == it_bb.id();
122     });
123   }
124 
125   // Runs the given function |f| on instructions in this function, in order,
126   // and optionally on debug line instructions that might precede them and
127   // non-semantic instructions that succceed the function.
128   void ForEachInst(const std::function<void(Instruction*)>& f,
129                    bool run_on_debug_line_insts = false,
130                    bool run_on_non_semantic_insts = false);
131   void ForEachInst(const std::function<void(const Instruction*)>& f,
132                    bool run_on_debug_line_insts = false,
133                    bool run_on_non_semantic_insts = false) const;
134   // Runs the given function |f| on instructions in this function, in order,
135   // and optionally on debug line instructions that might precede them and
136   // non-semantic instructions that succeed the function.  If |f| returns
137   // false, iteration is terminated and this function returns false.
138   bool WhileEachInst(const std::function<bool(Instruction*)>& f,
139                      bool run_on_debug_line_insts = false,
140                      bool run_on_non_semantic_insts = false);
141   bool WhileEachInst(const std::function<bool(const Instruction*)>& f,
142                      bool run_on_debug_line_insts = false,
143                      bool run_on_non_semantic_insts = false) const;
144 
145   // Runs the given function |f| on each parameter instruction in this function,
146   // in order, and optionally on debug line instructions that might precede
147   // them.
148   void ForEachParam(const std::function<void(const Instruction*)>& f,
149                     bool run_on_debug_line_insts = false) const;
150   void ForEachParam(const std::function<void(Instruction*)>& f,
151                     bool run_on_debug_line_insts = false);
152 
153   // Runs the given function |f| on each debug instruction in this function's
154   // header in order.
155   void ForEachDebugInstructionsInHeader(
156       const std::function<void(Instruction*)>& f);
157 
158   BasicBlock* InsertBasicBlockAfter(std::unique_ptr<BasicBlock>&& new_block,
159                                     BasicBlock* position);
160 
161   BasicBlock* InsertBasicBlockBefore(std::unique_ptr<BasicBlock>&& new_block,
162                                      BasicBlock* position);
163 
164   // Returns true if the function has a return block other than the exit block.
165   bool HasEarlyReturn() const;
166 
167   // Returns true if the function calls itself either directly or indirectly.
168   bool IsRecursive() const;
169 
170   // Pretty-prints all the basic blocks in this function into a std::string.
171   //
172   // |options| are the disassembly options. SPV_BINARY_TO_TEXT_OPTION_NO_HEADER
173   // is always added to |options|.
174   std::string PrettyPrint(uint32_t options = 0u) const;
175 
176   // Dump this function on stderr.  Useful when running interactive
177   // debuggers.
178   void Dump() const;
179 
180   // Returns true is a function declaration and not a function definition.
IsDeclaration()181   bool IsDeclaration() { return begin() == end(); }
182 
183  private:
184   // The OpFunction instruction that begins the definition of this function.
185   std::unique_ptr<Instruction> def_inst_;
186   // All parameters to this function.
187   std::vector<std::unique_ptr<Instruction>> params_;
188   // All debug instructions in this function's header.
189   InstructionList debug_insts_in_header_;
190   // All basic blocks inside this function in specification order
191   std::vector<std::unique_ptr<BasicBlock>> blocks_;
192   // The OpFunctionEnd instruction.
193   std::unique_ptr<Instruction> end_inst_;
194   // Non-semantic instructions succeeded by this function.
195   std::vector<std::unique_ptr<Instruction>> non_semantic_;
196 };
197 
198 // Pretty-prints |func| to |str|. Returns |str|.
199 std::ostream& operator<<(std::ostream& str, const Function& func);
200 
Function(std::unique_ptr<Instruction> def_inst)201 inline Function::Function(std::unique_ptr<Instruction> def_inst)
202     : def_inst_(std::move(def_inst)), end_inst_() {}
203 
AddParameter(std::unique_ptr<Instruction> p)204 inline void Function::AddParameter(std::unique_ptr<Instruction> p) {
205   params_.emplace_back(std::move(p));
206 }
207 
AddDebugInstructionInHeader(std::unique_ptr<Instruction> p)208 inline void Function::AddDebugInstructionInHeader(
209     std::unique_ptr<Instruction> p) {
210   debug_insts_in_header_.push_back(std::move(p));
211 }
212 
AddBasicBlock(std::unique_ptr<BasicBlock> b)213 inline void Function::AddBasicBlock(std::unique_ptr<BasicBlock> b) {
214   AddBasicBlock(std::move(b), end());
215 }
216 
AddBasicBlock(std::unique_ptr<BasicBlock> b,iterator ip)217 inline void Function::AddBasicBlock(std::unique_ptr<BasicBlock> b,
218                                     iterator ip) {
219   b->SetParent(this);
220   ip.InsertBefore(std::move(b));
221 }
222 
223 template <typename T>
AddBasicBlocks(T src_begin,T src_end,iterator ip)224 inline void Function::AddBasicBlocks(T src_begin, T src_end, iterator ip) {
225   blocks_.insert(ip.Get(), std::make_move_iterator(src_begin),
226                  std::make_move_iterator(src_end));
227 }
228 
MoveBasicBlockToAfter(uint32_t id,BasicBlock * ip)229 inline void Function::MoveBasicBlockToAfter(uint32_t id, BasicBlock* ip) {
230   std::unique_ptr<BasicBlock> block_to_move = std::move(*FindBlock(id).Get());
231   blocks_.erase(std::find(std::begin(blocks_), std::end(blocks_), nullptr));
232 
233   assert(block_to_move->GetParent() == ip->GetParent() &&
234          "Both blocks have to be in the same function.");
235 
236   InsertBasicBlockAfter(std::move(block_to_move), ip);
237 }
238 
RemoveEmptyBlocks()239 inline void Function::RemoveEmptyBlocks() {
240   auto first_empty =
241       std::remove_if(std::begin(blocks_), std::end(blocks_),
242                      [](const std::unique_ptr<BasicBlock>& bb) -> bool {
243                        return bb->GetLabelInst()->opcode() == SpvOpNop;
244                      });
245   blocks_.erase(first_empty, std::end(blocks_));
246 }
247 
RemoveParameter(uint32_t id)248 inline void Function::RemoveParameter(uint32_t id) {
249   params_.erase(std::remove_if(params_.begin(), params_.end(),
250                                [id](const std::unique_ptr<Instruction>& param) {
251                                  return param->result_id() == id;
252                                }),
253                 params_.end());
254 }
255 
SetFunctionEnd(std::unique_ptr<Instruction> end_inst)256 inline void Function::SetFunctionEnd(std::unique_ptr<Instruction> end_inst) {
257   end_inst_ = std::move(end_inst);
258 }
259 
AddNonSemanticInstruction(std::unique_ptr<Instruction> non_semantic)260 inline void Function::AddNonSemanticInstruction(
261     std::unique_ptr<Instruction> non_semantic) {
262   non_semantic_.emplace_back(std::move(non_semantic));
263 }
264 
265 }  // namespace opt
266 }  // namespace spvtools
267 
268 #endif  // SOURCE_OPT_FUNCTION_H_
269