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