Analysis: infer when a refcount is required and add colors in DebugVisitor
[scilab.git] / scilab / modules / ast / src / cpp / analysis / FunctionBlock.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2014 - Scilab Enterprises - Calixte DENIZET
4  *
5  *  This file must be used under the terms of the CeCILL.
6  *  This source file is licensed as described in the file COPYING, which
7  *  you should have received as part of this distribution.  The terms
8  *  are also available at
9  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10  *
11  */
12
13 #include "debugvisitor.hxx"
14 #include "printvisitor.hxx"
15
16 #include "data/DataManager.hxx"
17 #include "data/FunctionBlock.hxx"
18 #include "data/CompleteMacroSignature.hxx"
19 #include "gvn/ConstraintManager.hxx"
20
21 namespace analysis
22 {
23
24 FunctionBlock::FunctionBlock(const unsigned int id, Block * parent, ast::Exp * exp) : Block(id, parent, exp), loopAnalyzer(exp), constraintManager(*this, dm->topFunction()), lhs(0), rhs(0), maxVarId(0)
25 {
26     gvn = &fgvn;
27     dm->pushFunction(this);
28     //std::wcerr << L"Loop analyze:" << loopAnalyzer << std::endl;
29 }
30
31 bool FunctionBlock::addIn(const TITypeSignatureTuple & tuple, const std::vector<GVN::Value *> & values)
32 {
33     std::vector<TITypeSignature>::const_iterator i = tuple.types.begin();
34     for (const auto & sym : in)
35     {
36         Info & info = addSym(sym, new Data(false, sym));
37         info.type = TIType(fgvn, i->type, i->scalar);
38         dm->registerData(info.data);//, __LINE__, __FILE__);
39         ++i;
40     }
41
42     for (const auto & sym : globals)
43     {
44         Info & info = addSym(sym, new Data(false, sym));
45         info.type = TIType(fgvn, i->type, i->scalar);
46         dm->registerData(info.data);//, __LINE__, __FILE__);
47         ++i;
48     }
49     inValues = values;
50     maxVarId = fgvn.getCurrentValue() - 1;
51
52     return true;
53 }
54
55 void FunctionBlock::addGlobal(const symbol::Symbol & sym)
56 {
57     //globals.emplace(sym);
58     Block::addGlobal(sym);
59 }
60
61 void FunctionBlock::setGlobals(const tools::SymbolOrdSet & v)
62 {
63     //globals = v; => bug on mac
64     std::copy(v.begin(), v.end(), std::inserter(globals, globals.begin()));
65 }
66
67 /*    TITypeSignatureTuple FunctionBlock::getGlobals(std::vector<symbol::Symbol> & v)
68     {
69         TITypeSignatureTuple tuple;
70         std::vector<TITypeSignature> & t = tuple.types;
71         t.reserve(globals.size());
72         v.reserve(globals.size());
73
74         for (const auto & sym : globals)
75         {
76             v.emplace_back(sym);
77             tools::SymbolMap<Info>::iterator it;
78             Block * block = parent->getDefBlock(sym, it);
79             if (block)
80             {
81                 t.emplace_back(it->second.type.type, it->second.type.isscalar());
82             }
83             else
84             {
85                 bool exists;
86                 TIType ty = DataManager::getSymInScilabContext(fgvn, sym, exists);
87                 t.emplace_back(ty.type, ty.isscalar());
88             }
89         }
90
91         return tuple;
92     }
93 */
94 MacroOut FunctionBlock::getOuts()
95 {
96     MacroOut mo;
97     mo.maxVarId = maxVarId;
98     std::vector<TIType> & v = mo.tuple.types;
99     v.reserve(lhs);
100     unsigned int i = 0;
101     for (std::vector<symbol::Symbol>::const_iterator s = out.begin(); i < lhs; ++i, ++s)
102     {
103         tools::SymbolMap<Info>::iterator it;
104         Block * block = getDefBlock(*s, it, false);
105         if (block == this)
106         {
107             v.emplace_back(it->second.type);
108         }
109         else
110         {
111             addGlobal(*s);
112             if (block)
113             {
114                 v.emplace_back(it->second.type);
115             }
116             else
117             {
118                 // TODO: if exists is false then it is an error
119                 bool exists;
120                 v.emplace_back(DataManager::getSymInScilabContext(fgvn, *s, exists));
121             }
122         }
123     }
124
125     return mo;
126 }
127
128 void FunctionBlock::finalize()
129 {
130     dm->popFunction();
131
132     for (unsigned int i = 0; i != lhs; ++i)
133     {
134         auto it = symMap.find(out[i]);
135         if (it != symMap.end())
136         {
137             const TIType & type = it->second.type;
138             if (type.isscalar())
139             {
140                 types_out.emplace_back(out[i], false, TypeLocal(type.type, 1, 1, false));
141             }
142             else
143             {
144                 types_out.emplace_back(out[i], false, TypeLocal(type.type, -1, -1, false));
145             }
146         }
147         else
148         {
149             types_out.emplace_back(out[i], false, TypeLocal(TIType::UNKNOWN, -1, -1, false));
150         }
151
152         auto jt = locals.find(out[i]);
153         if (jt != locals.end())
154         {
155             types_out.back().refcount = jt->second.refcount;
156             jt->second.set.erase(types_out.back().tl);
157             if (jt->second.set.empty())
158             {
159                 locals.erase(jt);
160             }
161         }
162     }
163 }
164
165 void FunctionBlock::addLocal(const symbol::Symbol & sym, const TIType & type, const bool isAnInt)
166 {
167     auto i = locals.find(sym);
168     if (i == locals.end())
169     {
170         i = locals.emplace(sym, LocalInfo()).first;
171     }
172
173     i->second.set.emplace(TypeLocal::get(type, isAnInt));
174 }
175
176 int FunctionBlock::getTmpId(const TIType & type, const bool isAnInt)
177 {
178     return tempManager.getTmp(type, isAnInt);
179 }
180
181 void FunctionBlock::releaseTmp(const int id, ast::Exp * exp)
182 {
183     tempManager.releaseTmp(id);
184     if (id != -1 && exp)
185     {
186         const TIType & ty = exp->getDecorator().getResult().getType();
187         // TODO: handle other complex types like mlist, struct, ...
188         if (!ty.isscalar() || ty.type == TIType::STRING || ty.type == TIType::POLYNOMIAL)
189         {
190             exp->getDecorator().deleteData = true;
191         }
192     }
193 }
194
195 void FunctionBlock::needRefCount(const tools::SymbolSet & set)
196 {
197     for (const auto & sym : set)
198     {
199         auto i = locals.find(sym);
200         if (i != locals.end())
201         {
202             i->second.refcount = true;
203         }
204     }
205 }
206
207 void FunctionBlock::setInOut(MacroDef * macrodef, const unsigned int rhs, const std::vector<TIType> & _in)
208 {
209     in = macrodef->getIn();
210     out = macrodef->getOut();
211
212     for (unsigned int i = 0; i != rhs; ++i)
213     {
214         if (_in[i].isscalar())
215         {
216             types_in.emplace_back(in[i], true, TypeLocal(_in[i].type, 1, 1, false));
217         }
218         else
219         {
220             types_in.emplace_back(in[i], true, TypeLocal(_in[i].type, -1, -1, false));
221         }
222     }
223 }
224
225 Block * FunctionBlock::getDefBlock(const symbol::Symbol & sym, tools::SymbolMap<Info>::iterator & it, const bool global)
226 {
227     it = symMap.find(sym);
228     if (it == symMap.end())
229     {
230         if (!global && globals.find(sym) == globals.end())
231         {
232             // we have looked for a symbol which is not in this function
233             // so we add it and give it an unknown type
234             it = symMap.emplace(sym, new Data(false, sym)).first;
235             Info & info = it->second;
236             info.local = Info::Local::INFO_UNKNOWN;
237             info.type = TIType(fgvn);
238             dm->registerData(info.data);
239         }
240         else
241         {
242             return parent->getDefBlock(sym, it, true);
243         }
244     }
245     return this;
246 }
247
248 std::wostream & operator<<(std::wostream & out, const FunctionBlock & fblock)
249 {
250     out << L"Function " << fblock.name << L'\n'
251         << L" -LHS: " << fblock.lhs << L'\n'
252         << L" -RHS: " << fblock.rhs << L'\n'
253         << L" -in:" << L'\n';
254     for (const auto & i : fblock.types_in)
255     {
256         out << L"   -" << i.sym << L" -> " << i.tl << L'\n';
257     }
258
259     out << L'\n'
260         << L" -out:" << L'\n';
261     for (const auto & i : fblock.types_out)
262     {
263         out << L"   -" << i.sym;
264         if (i.refcount)
265         {
266             out << L" (refcount)";
267         }
268         out << L" -> " << i.tl << L'\n';
269     }
270     out << L'\n';
271     if (fblock.locals.empty())
272     {
273         out << L" -locals: none" << L'\n';
274     }
275     else
276     {
277         out << L" -locals:" << L'\n';
278         for (const auto & p : fblock.locals)
279         {
280             out << L"   -" << p.first;
281             if (p.second.refcount)
282             {
283                 out << L" (refcount)";
284             }
285             out << L" -> ";
286             tools::printSet(p.second.set, out);
287             out << L'\n';
288         }
289     }
290
291     out << L'\n';
292     const std::map<TypeLocal, std::stack<int>> & temps = fblock.getTemp();
293     if (temps.empty())
294     {
295         out << L" -temps: none" << L'\n';
296     }
297     else
298     {
299         out << L" -temps:" << L'\n';
300         for (const auto & p : temps)
301         {
302             out << L"   -" << p.first << L" -> " << p.second.size() << L'\n';
303         }
304     }
305
306     //ast::PrintVisitor pv(out, true, false);
307     //fblock.exp->accept(pv);
308
309     ast::DebugVisitor dv(out, true, true);
310     fblock.exp->accept(dv);
311
312     return out;
313 }
314 }