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