Improve performance for loop and insertion
[scilab.git] / scilab / modules / ast / includes / analysis / data / DataManager.hxx
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 #ifndef __DATA_MANAGER_HXX__
14 #define __DATA_MANAGER_HXX__
15
16 #include <iostream>
17 #include <stack>
18 #include <string>
19 #include <vector>
20
21 //#define DEBUG_DATAMANAGER
22
23 #include "allexp.hxx"
24 #include "allvar.hxx"
25 #include "alldec.hxx"
26 #include "tools.hxx"
27 #include "Block.hxx"
28 #include "FunctionBlock.hxx"
29 #include "XBlock.hxx"
30 #include "LoopBlock.hxx"
31 #include "symbol.hxx"
32 #include "TIType.hxx"
33 #include "gvn/GVN.hxx"
34
35 namespace analysis
36 {
37
38 class FunctionBlock;
39
40 class DataManager
41 {
42     friend class Block;
43
44     Block * root;
45     Block * current;
46     std::vector<Data *> data;
47     unsigned int id;
48     std::set<symbol::Symbol> globals;
49     std::stack<FunctionBlock *> callStack;
50     GVN gvn;
51
52 public:
53
54     DataManager() : id(0)
55     {
56         current = root = new Block(this);
57     }
58
59     ~DataManager()
60     {
61         //std::cerr << "delete DataManager: begin" << std::endl;
62         for (const auto d : data)
63         {
64             //std::cout << "ptr delete=" << d << std::endl;
65             delete d;
66         }
67         delete root;
68         //std::cerr << "delete DataManager: end" << std::endl;
69     }
70
71     inline GVN & getGVN()
72     {
73         return current->getGVN();
74     }
75
76     inline GVN & getDefaultGVN()
77     {
78         return gvn;
79     }
80
81     inline void addGlobal(const symbol::Symbol & sym)
82     {
83         globals.emplace(sym);
84     }
85
86     inline void registerData(Data * _data, int line, char * file)
87     {
88         if (_data)
89         {
90             /*              bool ok = true;
91                         for (const auto d : data)
92                         {
93                         if (d == _data)
94                         {
95                         ok =  false;
96                         break;
97                         }
98                         }
99
100                         std::cout << "ptr added=" << _data << " line:" << line << " file:" << file << " doubloon:" << ok << std::endl;
101                         */
102             data.push_back(_data);
103         }
104     }
105
106     inline Info & read(const symbol::Symbol & sym, ast::Exp * exp)
107     {
108         return current->addRead(sym, exp);
109     }
110
111     inline Info & write(const symbol::Symbol & sym, const TIType & Rtype, ast::Exp * exp)
112     {
113         return current->addWrite(sym, Rtype, exp);
114     }
115
116     inline Info & define(const symbol::Symbol & sym, const TIType & Rtype, ast::Exp * exp)
117     {
118         return current->addDefine(sym, Rtype, exp);
119     }
120
121     inline Info & share(const symbol::Symbol & Lsym, const symbol::Symbol & Rsym, const TIType & Rtype, ast::Exp * exp)
122     {
123         return current->addShare(Lsym, Rsym, Rtype, exp);
124     }
125
126     inline Info & clear(const symbol::Symbol & sym, ast::Exp * exp)
127     {
128         return current->addClear(sym, exp);
129     }
130
131     inline Info & macrodef(ast::Exp * exp)
132     {
133         return current->addMacroDef(static_cast<ast::FunctionDec *>(exp));
134     }
135
136     inline std::vector<TIType> call(AnalysisVisitor & visitor, const unsigned int lhs, const symbol::Symbol & sym, std::vector<TIType> & in, ast::CallExp * callexp)
137     {
138         return current->addCall(visitor, lhs, sym, in, callexp);
139     }
140
141     inline void addBlock(Block::BlockKind kind, ast::Exp * exp)
142     {
143         current = current->addBlock(++id, kind, exp);
144     }
145
146     inline Block * getCurrent()
147     {
148         return current;
149     }
150
151     inline void finalizeBlock()
152     {
153 #ifndef DEBUG_DATAMANAGER
154         current->finalize();
155 #endif
156         current = current->parent;
157     }
158
159     inline bool requiresAnotherTrip()
160     {
161         return current->requiresAnotherTrip();
162     }
163
164     inline void pushFunction(FunctionBlock * fblock)
165     {
166         callStack.push(fblock);
167     }
168
169     inline FunctionBlock * poptopFunction()
170     {
171         FunctionBlock * fblock = callStack.top();
172         callStack.pop();
173         return fblock;
174     }
175
176     inline FunctionBlock * topFunction()
177     {
178         if (callStack.empty())
179         {
180             return nullptr;
181         }
182         return callStack.top();
183     }
184
185     inline void popFunction()
186     {
187         callStack.pop();
188     }
189
190     inline static TIType getSymInScilabContext(GVN & gvn, const symbol::Symbol & sym, bool & exists)
191     {
192         types::InternalType * pIT;
193         return getSymInScilabContext(gvn, sym, exists, pIT);
194     }
195
196     inline static TIType getSymInScilabContext(GVN & gvn, const symbol::Symbol & sym, bool & exists, types::InternalType *& pIT)
197     {
198         pIT = symbol::Context::getInstance()->get(sym);
199         if (pIT)
200         {
201             exists = true;
202             if (pIT->isGenericType())
203             {
204                 types::GenericType * pGT = static_cast<types::GenericType *>(pIT);
205                 switch (pIT->getType())
206                 {
207                     case types::InternalType::ScilabInt8:
208                         return TIType(gvn, TIType::Type::INT8, pGT->getRows(), pGT->getCols());
209                     case types::InternalType::ScilabUInt8:
210                         return TIType(gvn, TIType::Type::UINT8, pGT->getRows(), pGT->getCols());
211                     case types::InternalType::ScilabInt16:
212                         return TIType(gvn, TIType::Type::INT16, pGT->getRows(), pGT->getCols());
213                     case types::InternalType::ScilabUInt16:
214                         return TIType(gvn, TIType::Type::UINT16, pGT->getRows(), pGT->getCols());
215                     case types::InternalType::ScilabInt32:
216                         return TIType(gvn, TIType::Type::INT32, pGT->getRows(), pGT->getCols());
217                     case types::InternalType::ScilabUInt32:
218                         return TIType(gvn, TIType::Type::UINT32, pGT->getRows(), pGT->getCols());
219                     case types::InternalType::ScilabInt64:
220                         return TIType(gvn, TIType::Type::INT64, pGT->getRows(), pGT->getCols());
221                     case types::InternalType::ScilabUInt64:
222                         return TIType(gvn, TIType::Type::UINT64, pGT->getRows(), pGT->getCols());
223                     case types::InternalType::ScilabString:
224                         return TIType(gvn, TIType::Type::STRING, pGT->getRows(), pGT->getCols());
225                     case types::InternalType::ScilabDouble:
226                     {
227                         types::Double * pDbl = static_cast<types::Double *>(pGT);
228                         if (pDbl->isEmpty())
229                         {
230                             return TIType(gvn, TIType::Type::EMPTY, 0, 0);
231                         }
232                         else if (pDbl->isComplex())
233                         {
234                             return TIType(gvn, TIType::Type::COMPLEX, pGT->getRows(), pGT->getCols());
235                         }
236                         else
237                         {
238                             return TIType(gvn, TIType::Type::DOUBLE, pGT->getRows(), pGT->getCols());
239                         }
240                     }
241                     case types::InternalType::ScilabBool:
242                         return TIType(gvn, TIType::Type::BOOLEAN, pGT->getRows(), pGT->getCols());
243                     case types::InternalType::ScilabPolynom:
244                         return TIType(gvn, TIType::Type::POLYNOMIAL, pGT->getRows(), pGT->getCols());
245                     case types::InternalType::ScilabSparse:
246                         return TIType(gvn, TIType::Type::SPARSE, pGT->getRows(), pGT->getCols());
247                     default:
248                         return TIType(gvn, TIType::Type::UNKNOWN, pGT->getRows(), pGT->getCols());
249                 }
250             }
251             else if (pIT->isCallable())
252             {
253                 switch (pIT->getType())
254                 {
255                     case types::InternalType::ScilabFunction:
256                         return TIType(gvn, TIType::Type::FUNCTION);
257                     case types::InternalType::ScilabMacro:
258                         return TIType(gvn, TIType::Type::MACRO);
259                     case types::InternalType::ScilabMacroFile:
260                         return TIType(gvn, TIType::Type::MACROFILE);
261                     case types::InternalType::ScilabLibrary:
262                         return TIType(gvn, TIType::Type::LIBRARY);
263                 }
264             }
265         }
266
267         exists = false;
268         return TIType(gvn);
269     }
270
271     template<typename T>
272     inline bool getTypes(std::vector<TIType> & out, const T & syms)
273     {
274         Block * parent = getCurrent();
275         for (const auto & sym : syms)
276         {
277             std::map<symbol::Symbol, Info>::iterator it;
278             Block * block = parent->getDefBlock(sym, it);
279             if (block)
280             {
281                 Info & i = it->second;
282                 out.emplace_back(i.type.type, i.type.isscalar());
283             }
284             else
285             {
286                 // TODO: get type in Scilab context
287                 return false;
288             }
289         }
290
291         return true;
292     }
293
294     inline TIType getType(const symbol::Symbol & sym)
295     {
296         Block * parent = getCurrent();
297         std::map<symbol::Symbol, Info>::iterator it;
298         Block * block = parent->getDefBlock(sym, it);
299         if (block)
300         {
301             return it->second.type;
302         }
303         else
304         {
305             bool exists;
306             return DataManager::getSymInScilabContext(getGVN(), sym, exists);
307         }
308     }
309
310     inline Info & getInfo(const symbol::Symbol & sym)
311     {
312         std::map<symbol::Symbol, Info>::iterator it;
313         Block * block = current->getDefBlock(sym, it);
314         if (block)
315         {
316             return it->second;
317         }
318
319         // The sym is not in this DataManager... try in the Scilab's context
320         return current->setDefaultData(sym);
321     }
322
323     friend std::wostream & operator<<(std::wostream & out, const DataManager & dm)
324     {
325         out << L"DataManager:" << std::endl
326             << L"Globals: ";
327
328         tools::printSet(dm.globals, out);
329         out << std::endl << *dm.root;
330
331         return out;
332     }
333 };
334 }
335
336 #endif // __DATA_MANAGER_HXX__