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 } // namespace opt
274 } // namespace spvtools
275