• 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 #include "source/opt/function.h"
16 
17 #include <ostream>
18 #include <sstream>
19 
20 #include "function.h"
21 #include "ir_context.h"
22 #include "source/util/bit_vector.h"
23 
24 namespace spvtools {
25 namespace opt {
26 
Clone(IRContext * ctx) const27 Function* Function::Clone(IRContext* ctx) const {
28   Function* clone =
29       new Function(std::unique_ptr<Instruction>(DefInst().Clone(ctx)));
30   clone->params_.reserve(params_.size());
31   ForEachParam(
32       [clone, ctx](const Instruction* inst) {
33         clone->AddParameter(std::unique_ptr<Instruction>(inst->Clone(ctx)));
34       },
35       true);
36 
37   for (const auto& i : debug_insts_in_header_) {
38     clone->AddDebugInstructionInHeader(
39         std::unique_ptr<Instruction>(i.Clone(ctx)));
40   }
41 
42   clone->blocks_.reserve(blocks_.size());
43   for (const auto& b : blocks_) {
44     std::unique_ptr<BasicBlock> bb(b->Clone(ctx));
45     clone->AddBasicBlock(std::move(bb));
46   }
47 
48   clone->SetFunctionEnd(std::unique_ptr<Instruction>(EndInst()->Clone(ctx)));
49 
50   clone->non_semantic_.reserve(non_semantic_.size());
51   for (auto& non_semantic : non_semantic_) {
52     clone->AddNonSemanticInstruction(
53         std::unique_ptr<Instruction>(non_semantic->Clone(ctx)));
54   }
55   return clone;
56 }
57 
ForEachInst(const std::function<void (Instruction *)> & f,bool run_on_debug_line_insts,bool run_on_non_semantic_insts)58 void Function::ForEachInst(const std::function<void(Instruction*)>& f,
59                            bool run_on_debug_line_insts,
60                            bool run_on_non_semantic_insts) {
61   WhileEachInst(
62       [&f](Instruction* inst) {
63         f(inst);
64         return true;
65       },
66       run_on_debug_line_insts, run_on_non_semantic_insts);
67 }
68 
ForEachInst(const std::function<void (const Instruction *)> & f,bool run_on_debug_line_insts,bool run_on_non_semantic_insts) const69 void Function::ForEachInst(const std::function<void(const Instruction*)>& f,
70                            bool run_on_debug_line_insts,
71                            bool run_on_non_semantic_insts) const {
72   WhileEachInst(
73       [&f](const Instruction* inst) {
74         f(inst);
75         return true;
76       },
77       run_on_debug_line_insts, run_on_non_semantic_insts);
78 }
79 
WhileEachInst(const std::function<bool (Instruction *)> & f,bool run_on_debug_line_insts,bool run_on_non_semantic_insts)80 bool Function::WhileEachInst(const std::function<bool(Instruction*)>& f,
81                              bool run_on_debug_line_insts,
82                              bool run_on_non_semantic_insts) {
83   if (def_inst_) {
84     if (!def_inst_->WhileEachInst(f, run_on_debug_line_insts)) {
85       return false;
86     }
87   }
88 
89   for (auto& param : params_) {
90     if (!param->WhileEachInst(f, run_on_debug_line_insts)) {
91       return false;
92     }
93   }
94 
95   if (!debug_insts_in_header_.empty()) {
96     Instruction* di = &debug_insts_in_header_.front();
97     while (di != nullptr) {
98       Instruction* next_instruction = di->NextNode();
99       if (!di->WhileEachInst(f, run_on_debug_line_insts)) return false;
100       di = next_instruction;
101     }
102   }
103 
104   for (auto& bb : blocks_) {
105     if (!bb->WhileEachInst(f, run_on_debug_line_insts)) {
106       return false;
107     }
108   }
109 
110   if (end_inst_) {
111     if (!end_inst_->WhileEachInst(f, run_on_debug_line_insts)) {
112       return false;
113     }
114   }
115 
116   if (run_on_non_semantic_insts) {
117     for (auto& non_semantic : non_semantic_) {
118       if (!non_semantic->WhileEachInst(f, run_on_debug_line_insts)) {
119         return false;
120       }
121     }
122   }
123 
124   return true;
125 }
126 
WhileEachInst(const std::function<bool (const Instruction *)> & f,bool run_on_debug_line_insts,bool run_on_non_semantic_insts) const127 bool Function::WhileEachInst(const std::function<bool(const Instruction*)>& f,
128                              bool run_on_debug_line_insts,
129                              bool run_on_non_semantic_insts) const {
130   if (def_inst_) {
131     if (!static_cast<const Instruction*>(def_inst_.get())
132              ->WhileEachInst(f, run_on_debug_line_insts)) {
133       return false;
134     }
135   }
136 
137   for (const auto& param : params_) {
138     if (!static_cast<const Instruction*>(param.get())
139              ->WhileEachInst(f, run_on_debug_line_insts)) {
140       return false;
141     }
142   }
143 
144   for (const auto& di : debug_insts_in_header_) {
145     if (!static_cast<const Instruction*>(&di)->WhileEachInst(
146             f, run_on_debug_line_insts))
147       return false;
148   }
149 
150   for (const auto& bb : blocks_) {
151     if (!static_cast<const BasicBlock*>(bb.get())->WhileEachInst(
152             f, run_on_debug_line_insts)) {
153       return false;
154     }
155   }
156 
157   if (end_inst_) {
158     if (!static_cast<const Instruction*>(end_inst_.get())
159              ->WhileEachInst(f, run_on_debug_line_insts)) {
160       return false;
161     }
162   }
163 
164   if (run_on_non_semantic_insts) {
165     for (auto& non_semantic : non_semantic_) {
166       if (!static_cast<const Instruction*>(non_semantic.get())
167                ->WhileEachInst(f, run_on_debug_line_insts)) {
168         return false;
169       }
170     }
171   }
172 
173   return true;
174 }
175 
ForEachParam(const std::function<void (Instruction *)> & f,bool run_on_debug_line_insts)176 void Function::ForEachParam(const std::function<void(Instruction*)>& f,
177                             bool run_on_debug_line_insts) {
178   for (auto& param : params_)
179     static_cast<Instruction*>(param.get())
180         ->ForEachInst(f, run_on_debug_line_insts);
181 }
182 
ForEachParam(const std::function<void (const Instruction *)> & f,bool run_on_debug_line_insts) const183 void Function::ForEachParam(const std::function<void(const Instruction*)>& f,
184                             bool run_on_debug_line_insts) const {
185   for (const auto& param : params_)
186     static_cast<const Instruction*>(param.get())
187         ->ForEachInst(f, run_on_debug_line_insts);
188 }
189 
ForEachDebugInstructionsInHeader(const std::function<void (Instruction *)> & f)190 void Function::ForEachDebugInstructionsInHeader(
191     const std::function<void(Instruction*)>& f) {
192   if (debug_insts_in_header_.empty()) return;
193 
194   Instruction* di = &debug_insts_in_header_.front();
195   while (di != nullptr) {
196     Instruction* next_instruction = di->NextNode();
197     di->ForEachInst(f);
198     di = next_instruction;
199   }
200 }
201 
InsertBasicBlockAfter(std::unique_ptr<BasicBlock> && new_block,BasicBlock * position)202 BasicBlock* Function::InsertBasicBlockAfter(
203     std::unique_ptr<BasicBlock>&& new_block, BasicBlock* position) {
204   for (auto bb_iter = begin(); bb_iter != end(); ++bb_iter) {
205     if (&*bb_iter == position) {
206       new_block->SetParent(this);
207       ++bb_iter;
208       bb_iter = bb_iter.InsertBefore(std::move(new_block));
209       return &*bb_iter;
210     }
211   }
212   assert(false && "Could not find insertion point.");
213   return nullptr;
214 }
215 
InsertBasicBlockBefore(std::unique_ptr<BasicBlock> && new_block,BasicBlock * position)216 BasicBlock* Function::InsertBasicBlockBefore(
217     std::unique_ptr<BasicBlock>&& new_block, BasicBlock* position) {
218   for (auto bb_iter = begin(); bb_iter != end(); ++bb_iter) {
219     if (&*bb_iter == position) {
220       new_block->SetParent(this);
221       bb_iter = bb_iter.InsertBefore(std::move(new_block));
222       return &*bb_iter;
223     }
224   }
225   assert(false && "Could not find insertion point.");
226   return nullptr;
227 }
228 
HasEarlyReturn() const229 bool Function::HasEarlyReturn() const {
230   auto post_dominator_analysis =
231       blocks_.front()->GetLabel()->context()->GetPostDominatorAnalysis(this);
232   for (auto& block : blocks_) {
233     if (spvOpcodeIsReturn(block->tail()->opcode()) &&
234         !post_dominator_analysis->Dominates(block.get(), entry().get())) {
235       return true;
236     }
237   }
238   return false;
239 }
240 
IsRecursive() const241 bool Function::IsRecursive() const {
242   IRContext* ctx = blocks_.front()->GetLabel()->context();
243   IRContext::ProcessFunction mark_visited = [this](Function* fp) {
244     return fp == this;
245   };
246 
247   // Process the call tree from all of the function called by |this|.  If it get
248   // back to |this|, then we have a recursive function.
249   std::queue<uint32_t> roots;
250   ctx->AddCalls(this, &roots);
251   return ctx->ProcessCallTreeFromRoots(mark_visited, &roots);
252 }
253 
operator <<(std::ostream & str,const Function & func)254 std::ostream& operator<<(std::ostream& str, const Function& func) {
255   str << func.PrettyPrint();
256   return str;
257 }
258 
Dump() const259 void Function::Dump() const {
260   std::cerr << "Function #" << result_id() << "\n" << *this << "\n";
261 }
262 
PrettyPrint(uint32_t options) const263 std::string Function::PrettyPrint(uint32_t options) const {
264   std::ostringstream str;
265   ForEachInst([&str, options](const Instruction* inst) {
266     str << inst->PrettyPrint(options);
267     if (inst->opcode() != SpvOpFunctionEnd) {
268       str << std::endl;
269     }
270   });
271   return str.str();
272 }
273 
ReorderBasicBlocksInStructuredOrder()274 void Function::ReorderBasicBlocksInStructuredOrder() {
275   std::list<BasicBlock*> order;
276   IRContext* context = this->def_inst_->context();
277   context->cfg()->ComputeStructuredOrder(this, blocks_[0].get(), &order);
278   ReorderBasicBlocks(order.begin(), order.end());
279 }
280 
281 }  // namespace opt
282 }  // namespace spvtools
283