• 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 #include "function.h"
17 #include "ir_context.h"
18 
19 #include <source/util/bit_vector.h>
20 #include <ostream>
21 #include <sstream>
22 
23 namespace spvtools {
24 namespace opt {
25 
Clone(IRContext * ctx) const26 Function* Function::Clone(IRContext* ctx) const {
27   Function* clone =
28       new Function(std::unique_ptr<Instruction>(DefInst().Clone(ctx)));
29   clone->params_.reserve(params_.size());
30   ForEachParam(
31       [clone, ctx](const Instruction* inst) {
32         clone->AddParameter(std::unique_ptr<Instruction>(inst->Clone(ctx)));
33       },
34       true);
35 
36   clone->blocks_.reserve(blocks_.size());
37   for (const auto& b : blocks_) {
38     std::unique_ptr<BasicBlock> bb(b->Clone(ctx));
39     bb->SetParent(clone);
40     clone->AddBasicBlock(std::move(bb));
41   }
42 
43   clone->SetFunctionEnd(std::unique_ptr<Instruction>(EndInst()->Clone(ctx)));
44   return clone;
45 }
46 
ForEachInst(const std::function<void (Instruction *)> & f,bool run_on_debug_line_insts)47 void Function::ForEachInst(const std::function<void(Instruction*)>& f,
48                            bool run_on_debug_line_insts) {
49   WhileEachInst(
50       [&f](Instruction* inst) {
51         f(inst);
52         return true;
53       },
54       run_on_debug_line_insts);
55 }
56 
ForEachInst(const std::function<void (const Instruction *)> & f,bool run_on_debug_line_insts) const57 void Function::ForEachInst(const std::function<void(const Instruction*)>& f,
58                            bool run_on_debug_line_insts) const {
59   WhileEachInst(
60       [&f](const Instruction* inst) {
61         f(inst);
62         return true;
63       },
64       run_on_debug_line_insts);
65 }
66 
WhileEachInst(const std::function<bool (Instruction *)> & f,bool run_on_debug_line_insts)67 bool Function::WhileEachInst(const std::function<bool(Instruction*)>& f,
68                              bool run_on_debug_line_insts) {
69   if (def_inst_) {
70     if (!def_inst_->WhileEachInst(f, run_on_debug_line_insts)) {
71       return false;
72     }
73   }
74 
75   for (auto& param : params_) {
76     if (!param->WhileEachInst(f, run_on_debug_line_insts)) {
77       return false;
78     }
79   }
80 
81   for (auto& bb : blocks_) {
82     if (!bb->WhileEachInst(f, run_on_debug_line_insts)) {
83       return false;
84     }
85   }
86 
87   if (end_inst_) return end_inst_->WhileEachInst(f, run_on_debug_line_insts);
88 
89   return true;
90 }
91 
WhileEachInst(const std::function<bool (const Instruction *)> & f,bool run_on_debug_line_insts) const92 bool Function::WhileEachInst(const std::function<bool(const Instruction*)>& f,
93                              bool run_on_debug_line_insts) const {
94   if (def_inst_) {
95     if (!static_cast<const Instruction*>(def_inst_.get())
96              ->WhileEachInst(f, run_on_debug_line_insts)) {
97       return false;
98     }
99   }
100 
101   for (const auto& param : params_) {
102     if (!static_cast<const Instruction*>(param.get())
103              ->WhileEachInst(f, run_on_debug_line_insts)) {
104       return false;
105     }
106   }
107 
108   for (const auto& bb : blocks_) {
109     if (!static_cast<const BasicBlock*>(bb.get())->WhileEachInst(
110             f, run_on_debug_line_insts)) {
111       return false;
112     }
113   }
114 
115   if (end_inst_)
116     return static_cast<const Instruction*>(end_inst_.get())
117         ->WhileEachInst(f, run_on_debug_line_insts);
118 
119   return true;
120 }
121 
ForEachParam(const std::function<void (Instruction *)> & f,bool run_on_debug_line_insts)122 void Function::ForEachParam(const std::function<void(Instruction*)>& f,
123                             bool run_on_debug_line_insts) {
124   for (auto& param : params_)
125     static_cast<Instruction*>(param.get())
126         ->ForEachInst(f, run_on_debug_line_insts);
127 }
128 
ForEachParam(const std::function<void (const Instruction *)> & f,bool run_on_debug_line_insts) const129 void Function::ForEachParam(const std::function<void(const Instruction*)>& f,
130                             bool run_on_debug_line_insts) const {
131   for (const auto& param : params_)
132     static_cast<const Instruction*>(param.get())
133         ->ForEachInst(f, run_on_debug_line_insts);
134 }
135 
InsertBasicBlockAfter(std::unique_ptr<BasicBlock> && new_block,BasicBlock * position)136 BasicBlock* Function::InsertBasicBlockAfter(
137     std::unique_ptr<BasicBlock>&& new_block, BasicBlock* position) {
138   for (auto bb_iter = begin(); bb_iter != end(); ++bb_iter) {
139     if (&*bb_iter == position) {
140       new_block->SetParent(this);
141       ++bb_iter;
142       bb_iter = bb_iter.InsertBefore(std::move(new_block));
143       return &*bb_iter;
144     }
145   }
146   assert(false && "Could not find insertion point.");
147   return nullptr;
148 }
149 
IsRecursive() const150 bool Function::IsRecursive() const {
151   IRContext* ctx = blocks_.front()->GetLabel()->context();
152   IRContext::ProcessFunction mark_visited = [this](Function* fp) {
153     return fp == this;
154   };
155 
156   // Process the call tree from all of the function called by |this|.  If it get
157   // back to |this|, then we have a recursive function.
158   std::queue<uint32_t> roots;
159   ctx->AddCalls(this, &roots);
160   return ctx->ProcessCallTreeFromRoots(mark_visited, &roots);
161 }
162 
operator <<(std::ostream & str,const Function & func)163 std::ostream& operator<<(std::ostream& str, const Function& func) {
164   str << func.PrettyPrint();
165   return str;
166 }
167 
Dump() const168 void Function::Dump() const {
169   std::cerr << "Function #" << result_id() << "\n" << *this << "\n";
170 }
171 
PrettyPrint(uint32_t options) const172 std::string Function::PrettyPrint(uint32_t options) const {
173   std::ostringstream str;
174   ForEachInst([&str, options](const Instruction* inst) {
175     str << inst->PrettyPrint(options);
176     if (inst->opcode() != SpvOpFunctionEnd) {
177       str << std::endl;
178     }
179   });
180   return str.str();
181 }
182 }  // namespace opt
183 }  // namespace spvtools
184