• 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   clone->blocks_.reserve(blocks_.size());
38   for (const auto& b : blocks_) {
39     std::unique_ptr<BasicBlock> bb(b->Clone(ctx));
40     bb->SetParent(clone);
41     clone->AddBasicBlock(std::move(bb));
42   }
43 
44   clone->SetFunctionEnd(std::unique_ptr<Instruction>(EndInst()->Clone(ctx)));
45   return clone;
46 }
47 
ForEachInst(const std::function<void (Instruction *)> & f,bool run_on_debug_line_insts)48 void Function::ForEachInst(const std::function<void(Instruction*)>& f,
49                            bool run_on_debug_line_insts) {
50   WhileEachInst(
51       [&f](Instruction* inst) {
52         f(inst);
53         return true;
54       },
55       run_on_debug_line_insts);
56 }
57 
ForEachInst(const std::function<void (const Instruction *)> & f,bool run_on_debug_line_insts) const58 void Function::ForEachInst(const std::function<void(const Instruction*)>& f,
59                            bool run_on_debug_line_insts) const {
60   WhileEachInst(
61       [&f](const Instruction* inst) {
62         f(inst);
63         return true;
64       },
65       run_on_debug_line_insts);
66 }
67 
WhileEachInst(const std::function<bool (Instruction *)> & f,bool run_on_debug_line_insts)68 bool Function::WhileEachInst(const std::function<bool(Instruction*)>& f,
69                              bool run_on_debug_line_insts) {
70   if (def_inst_) {
71     if (!def_inst_->WhileEachInst(f, run_on_debug_line_insts)) {
72       return false;
73     }
74   }
75 
76   for (auto& param : params_) {
77     if (!param->WhileEachInst(f, run_on_debug_line_insts)) {
78       return false;
79     }
80   }
81 
82   for (auto& bb : blocks_) {
83     if (!bb->WhileEachInst(f, run_on_debug_line_insts)) {
84       return false;
85     }
86   }
87 
88   if (end_inst_) return end_inst_->WhileEachInst(f, run_on_debug_line_insts);
89 
90   return true;
91 }
92 
WhileEachInst(const std::function<bool (const Instruction *)> & f,bool run_on_debug_line_insts) const93 bool Function::WhileEachInst(const std::function<bool(const Instruction*)>& f,
94                              bool run_on_debug_line_insts) const {
95   if (def_inst_) {
96     if (!static_cast<const Instruction*>(def_inst_.get())
97              ->WhileEachInst(f, run_on_debug_line_insts)) {
98       return false;
99     }
100   }
101 
102   for (const auto& param : params_) {
103     if (!static_cast<const Instruction*>(param.get())
104              ->WhileEachInst(f, run_on_debug_line_insts)) {
105       return false;
106     }
107   }
108 
109   for (const auto& bb : blocks_) {
110     if (!static_cast<const BasicBlock*>(bb.get())->WhileEachInst(
111             f, run_on_debug_line_insts)) {
112       return false;
113     }
114   }
115 
116   if (end_inst_)
117     return static_cast<const Instruction*>(end_inst_.get())
118         ->WhileEachInst(f, run_on_debug_line_insts);
119 
120   return true;
121 }
122 
ForEachParam(const std::function<void (Instruction *)> & f,bool run_on_debug_line_insts)123 void Function::ForEachParam(const std::function<void(Instruction*)>& f,
124                             bool run_on_debug_line_insts) {
125   for (auto& param : params_)
126     static_cast<Instruction*>(param.get())
127         ->ForEachInst(f, run_on_debug_line_insts);
128 }
129 
ForEachParam(const std::function<void (const Instruction *)> & f,bool run_on_debug_line_insts) const130 void Function::ForEachParam(const std::function<void(const Instruction*)>& f,
131                             bool run_on_debug_line_insts) const {
132   for (const auto& param : params_)
133     static_cast<const Instruction*>(param.get())
134         ->ForEachInst(f, run_on_debug_line_insts);
135 }
136 
InsertBasicBlockAfter(std::unique_ptr<BasicBlock> && new_block,BasicBlock * position)137 BasicBlock* Function::InsertBasicBlockAfter(
138     std::unique_ptr<BasicBlock>&& new_block, BasicBlock* position) {
139   for (auto bb_iter = begin(); bb_iter != end(); ++bb_iter) {
140     if (&*bb_iter == position) {
141       new_block->SetParent(this);
142       ++bb_iter;
143       bb_iter = bb_iter.InsertBefore(std::move(new_block));
144       return &*bb_iter;
145     }
146   }
147   assert(false && "Could not find insertion point.");
148   return nullptr;
149 }
150 
InsertBasicBlockBefore(std::unique_ptr<BasicBlock> && new_block,BasicBlock * position)151 BasicBlock* Function::InsertBasicBlockBefore(
152     std::unique_ptr<BasicBlock>&& new_block, BasicBlock* position) {
153   for (auto bb_iter = begin(); bb_iter != end(); ++bb_iter) {
154     if (&*bb_iter == position) {
155       new_block->SetParent(this);
156       bb_iter = bb_iter.InsertBefore(std::move(new_block));
157       return &*bb_iter;
158     }
159   }
160   assert(false && "Could not find insertion point.");
161   return nullptr;
162 }
163 
IsRecursive() const164 bool Function::IsRecursive() const {
165   IRContext* ctx = blocks_.front()->GetLabel()->context();
166   IRContext::ProcessFunction mark_visited = [this](Function* fp) {
167     return fp == this;
168   };
169 
170   // Process the call tree from all of the function called by |this|.  If it get
171   // back to |this|, then we have a recursive function.
172   std::queue<uint32_t> roots;
173   ctx->AddCalls(this, &roots);
174   return ctx->ProcessCallTreeFromRoots(mark_visited, &roots);
175 }
176 
operator <<(std::ostream & str,const Function & func)177 std::ostream& operator<<(std::ostream& str, const Function& func) {
178   str << func.PrettyPrint();
179   return str;
180 }
181 
Dump() const182 void Function::Dump() const {
183   std::cerr << "Function #" << result_id() << "\n" << *this << "\n";
184 }
185 
PrettyPrint(uint32_t options) const186 std::string Function::PrettyPrint(uint32_t options) const {
187   std::ostringstream str;
188   ForEachInst([&str, options](const Instruction* inst) {
189     str << inst->PrettyPrint(options);
190     if (inst->opcode() != SpvOpFunctionEnd) {
191       str << std::endl;
192     }
193   });
194   return str.str();
195 }
196 }  // namespace opt
197 }  // namespace spvtools
198