Linux compilation fixed
[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     // Only for debug use
140     inline void print_info()
141     {
142         stop_chrono();
143
144         //std::wcout << getGVN() << std::endl << std::endl; function z=foo(x,y);z=argn(2);endfunction;jit("x=123;y=456;t=foo(x,y)")
145         std::wcerr << L"Analysis: " << *static_cast<Chrono *>(this) << std::endl;
146         //std::wcout << temp << std::endl;
147
148         std::wcerr << dm << std::endl;
149
150         std::wcerr << std::endl;
151     }
152
153     inline void finalize()
154     {
155         //dm.finalize(nullptr);
156     }
157
158     inline void setResult(Result & val)
159     {
160         _result = val;
161     }
162
163     inline void setResult(Result && val)
164     {
165         _result = val;
166     }
167
168     inline Result & getResult()
169     {
170         return _result;
171     }
172
173     inline const Calls & getCalls() const
174     {
175         return allCalls;
176     }
177
178     inline std::vector<Result> & getLHSContainer()
179     {
180         return multipleLHS;
181     }
182
183     inline ConstraintManager & getCM()
184     {
185         if (FunctionBlock * fblock = getDM().topFunction())
186         {
187             return fblock->getConstraintManager();
188         }
189         else
190         {
191             return cm;
192         }
193     }
194
195     inline ast::Exp * getCurrentLoop() const
196     {
197         if (!loops.empty())
198         {
199             return loops.top();
200         }
201
202         return nullptr;
203     }
204
205     inline void registerFBlockEmittedListener(FBlockEmittedListener * listener)
206     {
207         if (listener)
208         {
209             fblockListeners.push_back(listener);
210         }
211     }
212
213     inline void emitFunctionBlock(FunctionBlock & fblock)
214     {
215         for (auto listener : fblockListeners)
216         {
217             listener->action(fblock);
218         }
219     }
220
221     inline Info & getSymInfo(const symbol::Symbol & sym)
222     {
223         return dm.getInfo(sym);
224     }
225
226     inline logging::Logger & getLogger()
227     {
228         return logger;
229     }
230
231     bool analyzeIndices(TIType & type, ast::CallExp & ce);
232
233 private:
234
235     bool getDimension(SymbolicDimension & dim, ast::Exp & arg, bool & safe, SymbolicDimension & out);
236
237     inline void pushCall(Call * c)
238     {
239         if (c)
240         {
241             allCalls.push_back(c);
242         }
243     }
244
245     /*
246        Workaround for a C++11 bug with Intel compiler
247        https://software.intel.com/fr-fr/forums/topic/514793
248     */
249     inline static TIType _check_plus(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
250     {
251         return Checkers::check_____add____(gvn, Ltype, Rtype);
252     }
253
254     inline static TIType _check_minus(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
255     {
256         return Checkers::check_____sub____(gvn, Ltype, Rtype);
257     }
258
259     inline static TIType _check_dottimes(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
260     {
261         return Checkers::check_____dottimes____(gvn, Ltype, Rtype);
262     }
263
264     inline static TIType _check_dotrdiv(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
265     {
266         return Checkers::check_____dotrdiv____(gvn, Ltype, Rtype);
267     }
268
269     inline static TIType _check_dotpower(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
270     {
271         return Checkers::check_____dotpower____(gvn, Ltype, Rtype);
272     }
273
274     inline static TIType _check_eq(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
275     {
276         return Checkers::check_____eq____(gvn, Ltype, Rtype);
277     }
278
279     inline static TIType _check_neq(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
280     {
281         return Checkers::check_____neq____(gvn, Ltype, Rtype);
282     }
283
284     inline static TIType _check_lt(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
285     {
286         return Checkers::check_____lt____(gvn, Ltype, Rtype);
287     }
288
289     inline static TIType _check_le(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
290     {
291         return Checkers::check_____le____(gvn, Ltype, Rtype);
292     }
293
294     inline static TIType _check_gt(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
295     {
296         return Checkers::check_____gt____(gvn, Ltype, Rtype);
297     }
298
299     inline static TIType _check_ge(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
300     {
301         return Checkers::check_____ge____(gvn, Ltype, Rtype);
302     }
303
304     inline static TIType _check_and(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
305     {
306         return Checkers::check_____and____(gvn, Ltype, Rtype);
307     }
308
309     inline static TIType _check_or(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
310     {
311         return Checkers::check_____or____(gvn, Ltype, Rtype);
312     }
313
314     inline static TIType _check_andand(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
315     {
316         return Checkers::check_____and____(gvn, Ltype, Rtype);
317     }
318
319     inline static TIType _check_oror(GVN & gvn, const TIType & Ltype, const TIType & Rtype)
320     {
321         return Checkers::check_____or____(gvn, Ltype, Rtype);
322     }
323
324     template<TIType (F)(GVN &, const TIType &, const TIType &)>
325     inline TIType checkEWBinOp(TIType & LT, TIType & RT, const Result & LR, const Result & RR, bool & safe, int & tempId)
326     {
327         TIType resT = F(getGVN(), LT, RT);
328         if (resT.hasInvalidDims())
329         {
330             const bool ret = getCM().check(ConstraintManager::SAMEDIMS, LT.rows.getValue(), LT.cols.getValue(), RT.rows.getValue(), RT.cols.getValue());
331
332             if (ret)
333             {
334                 resT = F(getGVN(), LT, RT);
335                 safe = true;
336             }
337             else
338             {
339                 resT = resT.asUnknownMatrix();
340             }
341         }
342         else
343         {
344             safe = true;
345         }
346
347         tempId = getTmpIdForEWOp(resT, LR, RR);
348
349         if (resT.isscalar())
350         {
351         }
352
353         return resT;
354     }
355
356
357     bool operGVNValues(ast::OpExp & oe);
358     bool operSymbolicRange(ast::OpExp & oe);
359
360     // get temp id for an element-wise operation
361     // 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)
362     int getTmpIdForEWOp(const TIType & resT, const Result & LR, const Result & RR);
363     void visitArguments(const std::wstring & name, const unsigned int lhs, const TIType & calltype, ast::CallExp & e, const ast::exps_t & args);
364
365
366
367     void visit(ast::SelectExp & e);
368     void visit(ast::ListExp & e);
369     void visit(ast::MatrixExp & e);
370     void visit(ast::OpExp & e);
371     void visit(ast::NotExp & e);
372     void visit(ast::TransposeExp & e);
373     void visit(ast::AssignExp & e);
374     void visit(ast::IfExp & e);
375
376     void visit(ast::MatrixLineExp & e)
377     {
378         /* treated in MatrixExp */
379     }
380     void visit(ast::OptimizedExp & e) { }
381     void visit(ast::MemfillExp & e) { }
382     void visit(ast::DAXPYExp & e) { }
383     void visit(ast::IntSelectExp & e) { }
384     void visit(ast::StringSelectExp & e) { }
385     void visit(ast::CommentExp & e) { }
386     void visit(ast::NilExp & e) { }
387     void visit(ast::ColonVar & e) { }
388
389     void visit(ast::SimpleVar & e)
390     {
391         logger.log(L"SimpleVar", e.getSymbol().getName(), e.getLocation());
392         symbol::Symbol & sym = e.getSymbol();
393         Info & info = dm.read(sym, &e);
394         Result & res = e.getDecorator().setResult(info.type);
395         res.setConstant(info.getConstant());
396         res.setRange(info.getRange());
397         res.setMaxIndex(info.getMaxIndex());
398         setResult(res);
399     }
400
401     void visit(ast::DollarVar & e)
402     {
403         logger.log(L"DollarVar", e.getLocation());
404         Result & res = e.getDecorator().setResult(TIType(dm.getGVN(), TIType::POLYNOMIAL, 1, 1));
405         res.getConstant() = getGVN().getValue(symbol::Symbol(L"$"));
406         setResult(res);
407     }
408
409     void visit(ast::ArrayListVar & e)
410     {
411         logger.log(L"ArrayListVar", e.getLocation());
412         const ast::exps_t & vars = e.getVars();
413         for (auto var : vars)
414         {
415             var->accept(*this);
416         }
417     }
418
419     void visit(ast::DoubleExp & e)
420     {
421         logger.log(L"DoubleExp", e.getLocation());
422         if (!e.getConstant())
423         {
424             e.accept(cv.getExec());
425             cv.getExec().setResult(nullptr);
426         }
427         types::Double * pDbl = static_cast<types::Double *>(e.getConstant());
428         if (pDbl->isComplex())
429         {
430             Result & res = e.getDecorator().setResult(TIType(dm.getGVN(), TIType::COMPLEX, pDbl->getRows(), pDbl->getCols()));
431             res.getConstant() = e.getConstant();
432             setResult(res);
433         }
434         else
435         {
436             Result & res = e.getDecorator().setResult(TIType(dm.getGVN(), TIType::DOUBLE, pDbl->getRows(), pDbl->getCols()));
437             res.getConstant() = e.getConstant();
438             setResult(res);
439         }
440     }
441
442     void visit(ast::BoolExp & e)
443     {
444         logger.log(L"BoolExp", e.getLocation());
445         if (!e.getConstant())
446         {
447             e.accept(cv.getExec());
448             cv.getExec().setResult(nullptr);
449         }
450         types::Bool * pBool = static_cast<types::Bool *>(e.getConstant());
451         Result & res = e.getDecorator().setResult(TIType(dm.getGVN(), TIType::BOOLEAN, pBool->getRows(), pBool->getCols()));
452         res.getConstant() = e.getConstant();
453         setResult(res);
454     }
455
456     void visit(ast::StringExp & e)
457     {
458         logger.log(L"StringExp", e.getLocation());
459         if (!e.getConstant())
460         {
461             e.accept(cv.getExec());
462             cv.getExec().setResult(nullptr);
463         }
464         types::String * pStr = static_cast<types::String *>(e.getConstant());
465         Result & res = e.getDecorator().setResult(TIType(dm.getGVN(), TIType::STRING, pStr->getRows(), pStr->getCols()));
466         res.getConstant() = e.getConstant();
467         setResult(res);
468     }
469
470     void visit(ast::CallExp & e, const unsigned int lhs)
471     {
472         // TODO: e.getName() is not always a simple var: foo(a)(b)
473         if (e.getName().isSimpleVar())
474         {
475             const ast::SimpleVar & var = static_cast<ast::SimpleVar &>(e.getName());
476             const symbol::Symbol & sym = var.getSymbol();
477             const std::wstring & name = sym.getName();
478             Info & info = getSymInfo(sym); // that put the sym in the current block !
479             Result & res = e.getName().getDecorator().setResult(info.type);
480             res.setConstant(info.getConstant());
481             res.setRange(info.getRange());
482             res.setMaxIndex(info.getMaxIndex());
483
484             logger.log(L"CallExp", e.getLocation(), name);
485
486             if (info.type.type == TIType::MACRO || info.type.type == TIType::MACROFILE || info.type.type == TIType::FUNCTION)
487             {
488                 if (name == L"error")
489                 {
490                     getDM().getCurrent()->setReturn(true);
491                 }
492
493                 // Special analysis cases: size, zeros, ones, ...
494                 MapSymCall::iterator it = symscall.find(name);
495                 if (it != symscall.end())
496                 {
497                     if (getCM().checkGlobalConstant(sym) && it->second.get()->analyze(*this, lhs, e))
498                     {
499                         pushCall(e.getDecorator().getCall());
500                         return;
501                     }
502                 }
503
504                 visitArguments(name, lhs, info.type, e, e.getArgs());
505                 pushCall(e.getDecorator().getCall());
506             }
507             else
508             {
509                 analyzeIndices(info.type, e);
510             }
511         }
512     }
513
514     void visit(ast::CallExp & e)
515     {
516         visit(e, 1);
517     }
518
519     void visit(ast::CellCallExp & e)
520     {
521         logger.log(L"CellCallExp", e.getLocation());
522         visit(static_cast<ast::CallExp &>(e));
523     }
524
525     void visit(ast::LogicalOpExp & e)
526     {
527         logger.log(L"LogicalOpExp", e.getLocation());
528         visit(static_cast<ast::OpExp &>(e));
529     }
530
531     void visit(ast::WhileExp & e)
532     {
533         logger.log(L"WhileExp", e.getLocation());
534         loops.push(&e);
535         e.getTest().accept(*this);
536         dm.releaseTmp(getResult().getTempId());
537         e.getBody().accept(*this);
538         loops.pop();
539     }
540
541     void visit(ast::ForExp & e)
542     {
543         logger.log(L"ForExp", e.getLocation());
544         loops.push(&e);
545
546         dm.addBlock(Block::LOOP, &e);
547         e.getVardec().accept(*this);
548         dm.addBlock(Block::NORMAL, &e.getBody());
549         e.getBody().accept(*this);
550
551         if (dm.requiresAnotherTrip())
552         {
553             std::wcerr << "Invalid forexp: types or refcount are not the same before and after the loop" << std::endl;
554
555             dm.finalizeBlock();
556             dm.addBlock(Block::NORMAL, &e.getBody());
557             e.getBody().accept(*this);
558
559             if (dm.requiresAnotherTrip())
560             {
561                 std::wcerr << "Invalid forexp: types or refcount are not the same before and after the loop" << std::endl;
562             }
563         }
564
565         dm.finalizeBlock();
566         dm.finalizeBlock();
567
568         loops.pop();
569     }
570
571     void visit(ast::BreakExp & e)
572     {
573         logger.log(L"BreakExp", e.getLocation());
574         // nothing to do
575     }
576
577     void visit(ast::ContinueExp & e)
578     {
579         logger.log(L"ContinueExp", e.getLocation());
580         // nothing to do
581     }
582
583     void visit(ast::TryCatchExp & e)
584     {
585         logger.log(L"TryCatchExp", e.getLocation());
586         e.getTry().accept(*this);
587         e.getCatch().accept(*this);
588     }
589
590     void visit(ast::CaseExp & e)
591     {
592         logger.log(L"CaseExp", e.getLocation());
593         e.getTest()->accept(*this);
594         e.getBody()->accept(*this);
595     }
596
597     void visit(ast::ReturnExp & e)
598     {
599         logger.log(L"ReturnExp", e.getLocation());
600         getDM().getCurrent()->setReturn(true);
601         // Bug with return;
602         //e.exp_get().accept(*this);
603
604     }
605
606     void visit(ast::FieldExp & e)
607     {
608         logger.log(L"FieldExp", e.getLocation());
609         // a.b.c <=> (a.b).c where a.b is the head and c is the tail
610
611         //e.head_get()->accept(*this);
612         //e.tail_get()->accept(*this);
613     }
614
615     void visit(ast::CellExp & e)
616     {
617         logger.log(L"CellExp", e.getLocation());
618         visit(static_cast<ast::MatrixExp &>(e));
619     }
620
621     void visit(ast::SeqExp & e)
622     {
623         logger.log(L"SeqExp", e.getLocation());
624         ast::exps_t::iterator i = e.getExps().begin();
625         ast::exps_t::iterator itEnd = e.getExps().end();
626         for (; i != itEnd; ++i)
627         {
628             ast::Exp* exp = *i;
629             if (exp->isCallExp())
630             {
631                 visit(*static_cast<ast::CallExp *>(exp), /* LHS */ 0);
632             }
633             else if (exp->isBreakExp() || exp->isContinueExp())
634             {
635                 exp->accept(*this);
636                 if (loops.empty())
637                 {
638                     // We are not in a loop so this break is useless.
639                     exp->replace(new ast::CommentExp(exp->getLocation(), new std::wstring(L"useless break or continue")));
640                 }
641                 else
642                 {
643                     // We are in a loop: all the code after the break in this SeqExp is useless
644                     break;
645                 }
646             }
647             else
648             {
649                 exp->accept(*this);
650             }
651         }
652
653         if (i != itEnd)
654         {
655             ++i;
656             if (i != itEnd)
657             {
658                 e.getExps().erase(i, itEnd);
659             }
660         }
661     }
662
663     void visit(ast::ArrayListExp & e)
664     {
665         logger.log(L"ArrayListExp", e.getLocation());
666         const ast::exps_t & exps = e.getExps();
667         for (const auto exp : e.getExps())
668         {
669             exp->accept(*this);
670         }
671     }
672
673     void visit(ast::AssignListExp & e)
674     {
675         logger.log(L"AssignListExp", e.getLocation());
676         visit(static_cast<ast::ArrayListExp &>(e));
677     }
678
679     void visit(ast::VarDec & e)
680     {
681         // VarDec is only used in For loop for iterator declaration
682         logger.log(L"VarDec", e.getLocation());
683         const symbol::Symbol & sym = e.getSymbol();
684         if (e.getInit().isListExp())
685         {
686             ast::ListExp & le = static_cast<ast::ListExp &>(e.getInit());
687             //e.setListInfo(ForList64());
688             le.accept(*this);
689             Result & res = getResult();
690             Info & info = dm.define(sym, res.getType(), res.isAnInt(), &e);
691             info.setRange(res.getRange());
692         }
693     }
694
695     void visit(ast::FunctionDec & e)
696     {
697         /*e.args_get().accept(*this);
698           e.returns_get().accept(*this);
699           e.body_get().accept(*this);*/
700         logger.log(L"FunctionDec", e.getLocation());
701         dm.macrodef(&e);
702     }
703 };
704
705 } // namespace analysis
706
707 #endif // __ANALYSIS_VISITOR_HXX__