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