• 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   if (def_inst_) def_inst_->ForEachInst(f, run_on_debug_line_insts);
50   for (auto& param : params_) param->ForEachInst(f, run_on_debug_line_insts);
51   for (auto& bb : blocks_) bb->ForEachInst(f, run_on_debug_line_insts);
52   if (end_inst_) end_inst_->ForEachInst(f, run_on_debug_line_insts);
53 }
54 
ForEachInst(const std::function<void (const Instruction *)> & f,bool run_on_debug_line_insts) const55 void Function::ForEachInst(const std::function<void(const Instruction*)>& f,
56                            bool run_on_debug_line_insts) const {
57   if (def_inst_)
58     static_cast<const Instruction*>(def_inst_.get())
59         ->ForEachInst(f, run_on_debug_line_insts);
60 
61   for (const auto& param : params_)
62     static_cast<const Instruction*>(param.get())
63         ->ForEachInst(f, run_on_debug_line_insts);
64 
65   for (const auto& bb : blocks_)
66     static_cast<const BasicBlock*>(bb.get())->ForEachInst(
67         f, run_on_debug_line_insts);
68 
69   if (end_inst_)
70     static_cast<const Instruction*>(end_inst_.get())
71         ->ForEachInst(f, run_on_debug_line_insts);
72 }
73 
ForEachParam(const std::function<void (Instruction *)> & f,bool run_on_debug_line_insts)74 void Function::ForEachParam(const std::function<void(Instruction*)>& f,
75                             bool run_on_debug_line_insts) {
76   for (auto& param : params_)
77     static_cast<Instruction*>(param.get())
78         ->ForEachInst(f, run_on_debug_line_insts);
79 }
80 
ForEachParam(const std::function<void (const Instruction *)> & f,bool run_on_debug_line_insts) const81 void Function::ForEachParam(const std::function<void(const Instruction*)>& f,
82                             bool run_on_debug_line_insts) const {
83   for (const auto& param : params_)
84     static_cast<const Instruction*>(param.get())
85         ->ForEachInst(f, run_on_debug_line_insts);
86 }
87 
InsertBasicBlockAfter(std::unique_ptr<BasicBlock> && new_block,BasicBlock * position)88 BasicBlock* Function::InsertBasicBlockAfter(
89     std::unique_ptr<BasicBlock>&& new_block, BasicBlock* position) {
90   for (auto bb_iter = begin(); bb_iter != end(); ++bb_iter) {
91     if (&*bb_iter == position) {
92       new_block->SetParent(this);
93       ++bb_iter;
94       bb_iter = bb_iter.InsertBefore(std::move(new_block));
95       return &*bb_iter;
96     }
97   }
98   assert(false && "Could not find insertion point.");
99   return nullptr;
100 }
101 
IsRecursive() const102 bool Function::IsRecursive() const {
103   IRContext* ctx = blocks_.front()->GetLabel()->context();
104   IRContext::ProcessFunction mark_visited = [this](Function* fp) {
105     return fp == this;
106   };
107 
108   // Process the call tree from all of the function called by |this|.  If it get
109   // back to |this|, then we have a recursive function.
110   std::queue<uint32_t> roots;
111   ctx->AddCalls(this, &roots);
112   return ctx->ProcessCallTreeFromRoots(mark_visited, &roots);
113 }
114 
operator <<(std::ostream & str,const Function & func)115 std::ostream& operator<<(std::ostream& str, const Function& func) {
116   str << func.PrettyPrint();
117   return str;
118 }
119 
Dump() const120 void Function::Dump() const {
121   std::cerr << "Function #" << result_id() << "\n" << *this << "\n";
122 }
123 
PrettyPrint(uint32_t options) const124 std::string Function::PrettyPrint(uint32_t options) const {
125   std::ostringstream str;
126   ForEachInst([&str, options](const Instruction* inst) {
127     str << inst->PrettyPrint(options);
128     if (inst->opcode() != SpvOpFunctionEnd) {
129       str << std::endl;
130     }
131   });
132   return str.str();
133 }
134 }  // namespace opt
135 }  // namespace spvtools
136