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