9cc319febf6ed8c13b9c32d1264e62a2389dcbc6
[scilab.git] / scilab / modules / ast / includes / analysis / AnalysisVisitor.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 __ANALYSIS_VISITOR_HXX__
14 #define __ANALYSIS_VISITOR_HXX__
15
16 #include <algorithm>
17 #include <limits>
18 #include <map>
19 #include <memory>
20 #include <stack>
21 #include <vector>
22
23 #include "visitor.hxx"
24 #include "debugvisitor.hxx"
25 #include "execvisitor.hxx"
26 #include "printvisitor.hxx"
27 #include "allexp.hxx"
28 #include "allvar.hxx"
29 #include "analyzers/CallAnalyzer.hxx"
30 #include "checkers/Checkers.hxx"
31 #include "Chrono.hxx"
32 #include "ForList.hxx"
33 #include "Result.hxx"
34 #include "TIType.hxx"
35 #include "ConstantVisitor.hxx"
36 #include "gvn/SymbolicList.hxx"
37 #include "FBlockEmittedListener.hxx"
38 #include "data/DataManager.hxx"
39 #include "data/PolymorphicMacroCache.hxx"
40 #include "gvn/ConstraintManager.hxx"
41 #include "logging/Logger.hxx"
42 #include "dynlib_ast.h"
43
44 namespace analysis
45 {
46
47 class EXTERN_AST AnalysisVisitor : public ast::Visitor, public Chrono
48 {
49
50 public:
51
52     typedef unordered_map<std::wstring, std::shared_ptr<CallAnalyzer>> MapSymCall;
53     typedef std::vector<Call *> Calls;
54
55 private:
56
57     Result _result;
58     Calls allCalls;
59     DataManager dm;
60     PolymorphicMacroCache pmc;
61     ConstraintManager cm;
62     ConstantVisitor cv;
63     ast::DebugVisitor dv;
64     ast::PrintVisitor pv;
65     std::vector<Result> multipleLHS;
66     logging::Logger logger;
67     std::vector<FBlockEmittedListener *> fblockListeners;
68     std::stack<ast::Exp *> loops;
69
70     static MapSymCall symscall;
71     static MapSymCall initCalls();
72
73 public:
74
75     static bool asDouble(ast::Exp & e, double & out);
76     static bool asDouble(types::InternalType * pIT, double & out);
77     static bool isDoubleConstant(const ast::Exp & e);
78     static bool asDoubleMatrix(ast::Exp & e, types::Double *& data);
79     static void analyze(ast::SelectExp & e);
80
81     AnalysisVisitor() : cv(*this), pv(std::wcerr, true, false), logger("/tmp/analysis.log")
82     {
83         start_chrono();
84     }
85
86     virtual ~AnalysisVisitor()
87     {
88         //std::cerr << "delete AnalysisVisitor" << std::endl;
89     }
90
91     inline CallAnalyzer * getAnalyzer(const symbol::Symbol & sym)
92     {
93         MapSymCall::iterator it = symscall.find(sym.getName());
94         if (it == symscall.end())
95         {
96             return nullptr;
97         }
98         else
99         {
100             return it->second.get();
101         }
102     }
103
104     inline DataManager & getDM()
105     {
106         return dm;
107     }
108
109     inline GVN & getGVN()
110     {
111         return dm.getGVN();
112     }
113
114     inline PolymorphicMacroCache & getPMC()
115     {
116         return pmc;
117     }
118
119     inline ConstantVisitor & getCV()
120     {
121         return cv;
122     }
123
124     inline ast::PrintVisitor & getPV()
125     {
126         return pv;
127     }
128
129     inline ast::DebugVisitor & getDV()
130     {
131         return dv;
132     }
133
134     inline ast::ExecVisitor & getExec()
135     {
136         return cv.getExec();
137     }
138
139     inline void finalize()
140     {
141         //dm.finalize(nullptr);
142     }
143
144     inline void setResult(Result & val)
145     {
146         _result = val;
147     }
148
149     inline void setResult(Result && val)
150     {
151         _result = val;
152     }
153
154     inline Result & getResult()
155     {
156         return _result;
157     }
158
159     inline const Calls & getCalls() const
160     {
161         return allCalls;
162     }
163
164     inline std::vector<Result> & getLHSContainer()
165     {
166         return multipleLHS;
167     }
168
169     inline ConstraintManager & getCM()
170     {
171         if (FunctionBlock * fblock = getDM().topFunction())
172         {
173             return fblock->getConstraintManager();
174         }
175         else
176         {
177             return cm;
178         }
179     }
180
181     inline ast::Exp * getCurrentLoop() const
182     {
183         if (!loops.empty())
184         {
185             return loops.top();
186         }
187
188         return nullptr;
189     }
190
191     inline void registerFBlockEmittedListener(FBlockEmittedListener * listener)
192     {
193         if (listener)
194         {
195             fblockListeners.push_back(listener);
196         }
197     }
198
199     inline void emitFunctionBlock(FunctionBlock & fblock)
200     {
201         for (auto listener : fblockListeners)
202         {
203             listener->action(fblock);
204         }
205     }
206
207     inline Info & getSymInfo(const symbol::Symbol & sym)
208     {
209         return dm.getInfo(sym);
210     }
211
212     bool analyzeIndices(TIType & type, ast::CallExp & ce);
213
214     // Only for debug use
215     void print_info();
216     logging::Logger & getLogger();
217
218 private:
219
220     bool getDimension(SymbolicDimension & dim, ast::Exp & arg, bool & safe, SymbolicDimension & out);
221
222     inline void pushCall(Call * c)
223     {
224         if (c)
225         {
226             allCalls.push_back(c);
227         }
228     }
229
230     /*
231        Workaround for a C++11 bug with Intel compiler
232        https://software.intel.com/fr-fr/forums/topic/514793
233     */
234     inline static TIType _check_plus(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
235     {
236         return Checkers::check_____add____(gvn, Ltype, Rtype);
237     }
238
239     inline static TIType _check_minus(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
240     {
241         return Checkers::check_____sub____(gvn, Ltype, Rtype);
242     }
243
244     inline static TIType _check_dottimes(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
245     {
246         return Checkers::check_____dottimes____(gvn, Ltype, Rtype);
247     }
248
249     inline static TIType _check_dotrdiv(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
250     {
251         return Checkers::check_____dotrdiv____(gvn, Ltype, Rtype);
252     }
253
254     inline static TIType _check_dotpower(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
255     {
256         return Checkers::check_____dotpower____(gvn, Ltype, Rtype);
257     }
258
259     inline static TIType _check_eq(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
260     {
261         return Checkers::check_____eq____(gvn, Ltype, Rtype);
262     }
263
264     inline static TIType _check_neq(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
265     {
266         return Checkers::check_____neq____(gvn, Ltype, Rtype);
267     }
268
269     inline static TIType _check_lt(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
270     {
271         return Checkers::check_____lt____(gvn, Ltype, Rtype);
272     }
273
274     inline static TIType _check_le(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
275     {
276         return Checkers::check_____le____(gvn, Ltype, Rtype);
277     }
278
279     inline static TIType _check_gt(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
280     {
281         return Checkers::check_____gt____(gvn, Ltype, Rtype);
282     }
283
284     inline static TIType _check_ge(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
285     {
286         return Checkers::check_____ge____(gvn, Ltype, Rtype);
287     }
288
289     inline static TIType _check_and(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
290     {
291         return Checkers::check_____and____(gvn, Ltype, Rtype);
292     }
293
294     inline static TIType _check_or(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
295     {
296         return Checkers::check_____or____(gvn, Ltype, Rtype);
297     }
298
299     inline static TIType _check_andand(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
300     {
301         return Checkers::check_____and____(gvn, Ltype, Rtype);
302     }
303
304     inline static TIType _check_oror(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
305     {
306         return Checkers::check_____or____(gvn, Ltype, Rtype);
307     }
308
309     template<TIType (F)(GVN &, const TIType &, const TIType &)>
310     inline TIType checkEWBinOp(TIType & LT, TIType & RT, const Result & LR, const Result & RR, bool & safe, int & tempId)
311     {
312         TIType resT = F(getGVN(), LT, RT);
313         if (resT.hasInvalidDims())
314         {
315             const bool ret = getCM().check(ConstraintManager::SAMEDIMS, LT.rows.getValue(), LT.cols.getValue(), RT.rows.getValue(), RT.cols.getValue());
316
317             if (ret)
318             {
319                 resT = F(getGVN(), LT, RT);
320                 safe = true;
321             }
322             else
323             {
324                 resT = resT.asUnknownMatrix();
325             }
326         }
327         else
328         {
329             safe = true;
330         }
331
332         tempId = getTmpIdForEWOp(resT, LR, RR);
333
334         if (resT.isscalar())
335         {
336         }
337
338         return resT;
339     }
340
341     bool operGVNValues(ast::OpExp & oe);
342     bool operSymbolicRange(ast::OpExp & oe);
343
344     // get temp id for an element-wise operation
345     // A + (B + 1) => B+1 is a temp, A is not and we can reuse the temp to put the result of A + (B+1)
346     int getTmpIdForEWOp(const TIType & resT, const Result & LR, const Result & RR);
347     void visitArguments(const std::wstring & name, const unsigned int lhs, const TIType & calltype, ast::CallExp & e, const ast::exps_t & args);
348
349     void visit(ast::SelectExp & e);
350     void visit(ast::ListExp & e);
351     void visit(ast::MatrixExp & e);
352     void visit(ast::OpExp & e);
353     void visit(ast::NotExp & e);
354     void visit(ast::TransposeExp & e);
355     void visit(ast::AssignExp & e);
356     void visit(ast::IfExp & e);
357     void visit(ast::ForExp & e);
358     void visit(ast::CallExp & e);
359     void visit(ast::CallExp & e, const unsigned int lhs);
360     void visit(ast::SeqExp & e);
361     void visit(ast::DoubleExp & e);
362     void visit(ast::BoolExp & e);
363     void visit(ast::StringExp & e);
364     void visit(ast::SimpleVar & e);
365     void visit(ast::DollarVar & e);
366     void visit(ast::VarDec & e);
367
368     void visit(ast::MatrixLineExp & e)
369     {
370         /* treated in MatrixExp */
371     }
372     void visit(ast::OptimizedExp & e) { }
373     void visit(ast::MemfillExp & e) { }
374     void visit(ast::DAXPYExp & e) { }
375     void visit(ast::IntSelectExp & e) { }
376     void visit(ast::StringSelectExp & e) { }
377     void visit(ast::CommentExp & e) { }
378     void visit(ast::NilExp & e) { }
379     void visit(ast::ColonVar & e) { }
380
381     void visit(ast::ArrayListVar & e)
382     {
383         logger.log(L"ArrayListVar", e.getLocation());
384         const ast::exps_t & vars = e.getVars();
385         for (auto var : vars)
386         {
387             var->accept(*this);
388         }
389     }
390
391     void visit(ast::CellCallExp & e)
392     {
393         logger.log(L"CellCallExp", e.getLocation());
394         visit(static_cast<ast::CallExp &>(e));
395     }
396
397     void visit(ast::LogicalOpExp & e)
398     {
399         logger.log(L"LogicalOpExp", e.getLocation());
400         visit(static_cast<ast::OpExp &>(e));
401     }
402
403     void visit(ast::WhileExp & e)
404     {
405         logger.log(L"WhileExp", e.getLocation());
406         loops.push(&e);
407         e.getTest().accept(*this);
408         dm.releaseTmp(getResult().getTempId());
409         e.getBody().accept(*this);
410         loops.pop();
411     }
412
413     void visit(ast::BreakExp & e)
414     {
415         logger.log(L"BreakExp", e.getLocation());
416         // nothing to do
417     }
418
419     void visit(ast::ContinueExp & e)
420     {
421         logger.log(L"ContinueExp", e.getLocation());
422         // nothing to do
423     }
424
425     void visit(ast::TryCatchExp & e)
426     {
427         logger.log(L"TryCatchExp", e.getLocation());
428         e.getTry().accept(*this);
429         e.getCatch().accept(*this);
430     }
431
432     void visit(ast::CaseExp & e)
433     {
434         logger.log(L"CaseExp", e.getLocation());
435         e.getTest()->accept(*this);
436         e.getBody()->accept(*this);
437     }
438
439     void visit(ast::ReturnExp & e)
440     {
441         logger.log(L"ReturnExp", e.getLocation());
442         getDM().getCurrent()->setReturn(true);
443         // Bug with return;
444         //e.exp_get().accept(*this);
445
446     }
447
448     void visit(ast::FieldExp & e)
449     {
450         logger.log(L"FieldExp", e.getLocation());
451         // a.b.c <=> (a.b).c where a.b is the head and c is the tail
452
453         //e.head_get()->accept(*this);
454         //e.tail_get()->accept(*this);
455     }
456
457     void visit(ast::CellExp & e)
458     {
459         logger.log(L"CellExp", e.getLocation());
460         visit(static_cast<ast::MatrixExp &>(e));
461     }
462
463     void visit(ast::ArrayListExp & e)
464     {
465         logger.log(L"ArrayListExp", e.getLocation());
466         const ast::exps_t & exps = e.getExps();
467         for (const auto exp : e.getExps())
468         {
469             exp->accept(*this);
470         }
471     }
472
473     void visit(ast::AssignListExp & e)
474     {
475         logger.log(L"AssignListExp", e.getLocation());
476         visit(static_cast<ast::ArrayListExp &>(e));
477     }
478
479     void visit(ast::FunctionDec & e)
480     {
481         /*e.args_get().accept(*this);
482           e.returns_get().accept(*this);
483           e.body_get().accept(*this);*/
484         logger.log(L"FunctionDec", e.getLocation());
485         dm.macrodef(&e);
486     }
487 };
488
489 } // namespace analysis
490
491 #endif // __ANALYSIS_VISITOR_HXX__