Analysis: add info about $ and fix bug
[scilab.git] / scilab / modules / ast / includes / analysis / data / LoopAnalyzer.hxx
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2015 - 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 __LOOP_ANALYZER_HXX__
14 #define __LOOP_ANALYZER_HXX__
15
16 #include <iostream>
17 #include <string>
18 #include <sstream>
19 #include <stack>
20 #include <unordered_map>
21
22 #include "visitor.hxx"
23 #include "execvisitor.hxx"
24 #include "allexp.hxx"
25 #include "allvar.hxx"
26 #include "Chrono.hxx"
27 #include "tools.hxx"
28
29 namespace analysis
30 {
31
32 class LoopAnalyzer : public ast::Visitor, public Chrono
33 {
34
35     struct __Info
36     {
37         tools::SymbolSet assigned;
38         tools::SymbolSet inserted;
39         tools::SymbolSet shared;
40         tools::SymbolSet used;
41
42         __Info() { }
43     };
44
45     std::unordered_map<ast::Exp *, __Info> info;
46
47     std::stack<std::pair<ast::Exp *, __Info *>> loops;
48     ast::Exp * seq;
49
50 public:
51
52     LoopAnalyzer(ast::Exp * _seq) : seq(_seq)
53     {
54         //start_chrono();
55         static_cast<ast::SeqExp *>(seq)->accept(*this);
56         //stop_chrono();
57     }
58
59     virtual ~LoopAnalyzer()
60     {
61     }
62
63     virtual LoopAnalyzer* clone()
64     {
65         return new LoopAnalyzer(seq->clone());
66     }
67
68
69     inline bool isAssigned(ast::Exp * e, const symbol::Symbol & sym) const
70     {
71         if (e)
72         {
73             const auto i = info.find(e);
74             if (i != info.end())
75             {
76                 return i->second.assigned.find(sym) != i->second.assigned.end();
77             }
78         }
79         return false;
80     }
81
82     inline const tools::SymbolSet * getInserted(ast::Exp * e) const
83     {
84         if (e)
85         {
86             const auto i = info.find(e);
87             if (i != info.end())
88             {
89                 return &i->second.inserted;
90             }
91         }
92         return nullptr;
93     }
94
95     inline const tools::SymbolSet * getShared(ast::Exp * e) const
96     {
97         if (e)
98         {
99             const auto i = info.find(e);
100             if (i != info.end())
101             {
102                 return &i->second.shared;
103             }
104         }
105         return nullptr;
106     }
107
108     friend std::wostream & operator<<(std::wostream & out, const LoopAnalyzer & la)
109     {
110         if (!la.info.empty())
111         {
112             std::wostringstream wos_ass, wos_ins, wos_sh, wos_used;
113             for (const auto & p : la.info)
114             {
115                 wos_ass << L"  -Loop at " << p.first->getLocation().getLocationString() << L": ";
116                 tools::printSet(p.second.assigned, wos_ass);
117                 wos_ass << L"\n";
118
119                 wos_ins << L"  -Loop at " << p.first->getLocation().getLocationString() << L": ";
120                 tools::printSet(p.second.inserted, wos_ins);
121                 wos_ins << L"\n";
122
123                 wos_sh << L"  -Loop at " << p.first->getLocation().getLocationString() << L": ";
124                 tools::printSet(p.second.inserted, wos_sh);
125                 wos_sh << L"\n";
126
127                 wos_used << L"  -Loop at " << p.first->getLocation().getLocationString() << L": ";
128                 tools::printSet(p.second.inserted, wos_used);
129                 wos_used << L"\n";
130             }
131
132             std::wstring str = wos_ass.str();
133             if (!str.empty())
134             {
135                 out << L" Assigned:\n";
136                 out << str;
137             }
138             str = wos_ins.str();
139             if (!str.empty())
140             {
141                 out << L" Inserted:\n";
142                 out << str;
143             }
144             str = wos_sh.str();
145             if (!str.empty())
146             {
147                 out << L" Shared:\n";
148                 out << str;
149             }
150             str = wos_used.str();
151             if (!str.empty())
152             {
153                 out << L" Used:\n";
154                 out << str;
155             }
156         }
157
158         return out;
159     }
160
161     inline void print_info()
162     {
163         std::wcerr << L"Loop analyze: " << *static_cast<Chrono *>(this) << std::endl
164                    << *this << std::endl;
165     }
166
167 private:
168
169     inline void emplaceAssigned(const symbol::Symbol & sym)
170     {
171         loops.top().second->assigned.emplace(sym);
172     }
173
174     inline void emplaceInserted(const symbol::Symbol & sym)
175     {
176         loops.top().second->inserted.emplace(sym);
177     }
178
179     inline void emplaceShared(const symbol::Symbol & sym)
180     {
181         loops.top().second->shared.emplace(sym);
182     }
183
184     inline void emplaceUsed(const symbol::Symbol & sym)
185     {
186         loops.top().second->used.emplace(sym);
187     }
188
189     inline void push(ast::Exp & e)
190     {
191         __Info * i = &(info.emplace(&e, __Info()).first->second);
192         loops.push({ &e, i });
193     }
194
195     inline void pushAssigned()
196     {
197         std::pair<ast::Exp *, __Info *> last = loops.top();
198         loops.pop();
199
200         if (!loops.empty() && !last.second->assigned.empty())
201         {
202             std::pair<ast::Exp *, __Info *> & penult = loops.top();
203             penult.second->assigned.insert(last.second->assigned.begin(), last.second->assigned.end());
204         }
205     }
206
207     void visit(ast::SimpleVar & e)
208     {
209     }
210
211     void visit(ast::DollarVar & e)
212     {
213     }
214
215     void visit(ast::ColonVar & e)
216     {
217     }
218
219     void visit(ast::ArrayListVar & e)
220     {
221     }
222
223     void visit(ast::DoubleExp & e)
224     {
225     }
226
227     void visit(ast::BoolExp & e)
228     {
229     }
230
231     void visit(ast::StringExp & e)
232     {
233     }
234
235     void visit(ast::CommentExp & e)
236     {
237     }
238
239     void visit(ast::NilExp & e)
240     {
241     }
242
243     void visit(ast::CallExp & e)
244     {
245     }
246
247     void visit(ast::CellCallExp & e)
248     {
249     }
250
251     void visit(ast::OpExp & e)
252     {
253     }
254
255     void visit(ast::LogicalOpExp & e)
256     {
257     }
258
259     void visit(ast::AssignExp & e)
260     {
261         if (e.getLeftExp().isSimpleVar())
262         {
263             // A = ....
264             const symbol::Symbol & Lsym = static_cast<ast::SimpleVar &>(e.getLeftExp()).getSymbol();
265             emplaceAssigned(Lsym);
266             if (e.getRightExp().isSimpleVar())
267             {
268                 const symbol::Symbol & Rsym = static_cast<ast::SimpleVar &>(e.getRightExp()).getSymbol();
269                 emplaceShared(Lsym);
270                 emplaceShared(Rsym);
271                 emplaceUsed(Rsym);
272             }
273         }
274         else if (e.getLeftExp().isCallExp())
275         {
276             // A(...) = ...
277             ast::CallExp & ce = static_cast<ast::CallExp &>(e.getLeftExp());
278             if (ce.getName().isSimpleVar())
279             {
280                 const symbol::Symbol & Lsym = static_cast<ast::SimpleVar &>(ce.getName()).getSymbol();
281                 emplaceInserted(Lsym);
282                 emplaceAssigned(Lsym);
283             }
284         }
285         else if (e.getLeftExp().isAssignListExp())
286         {
287             // [A, ...] =
288             ast::AssignListExp & ale = static_cast<ast::AssignListExp &>(e.getLeftExp());
289             for (const auto re : ale.getExps())
290             {
291                 if (re->isSimpleVar())
292                 {
293                     const symbol::Symbol & Lsym = static_cast<const ast::SimpleVar *>(re)->getSymbol();
294                     emplaceAssigned(Lsym);
295                 }
296             }
297         }
298     }
299
300     void visit(ast::IfExp & e)
301     {
302         e.getThen().accept(*this);
303         if (e.hasElse())
304         {
305             e.getElse().accept(*this);
306         }
307     }
308
309     void visit(ast::WhileExp & e)
310     {
311         push(e);
312         e.getBody().accept(*this);
313
314         // pushAssigned pops loops
315         pushAssigned();
316     }
317
318     void visit(ast::ForExp & e)
319     {
320         push(e);
321         e.getVardec().accept(*this);
322         e.getBody().accept(*this);
323         pushAssigned();
324     }
325
326     void visit(ast::BreakExp & e)
327     {
328     }
329
330     void visit(ast::ContinueExp & e)
331     {
332     }
333
334     void visit(ast::TryCatchExp & e)
335     {
336         e.getTry().accept(*this);
337         e.getCatch().accept(*this);
338     }
339
340     void visit(ast::SelectExp & e)
341     {
342         e.getSelect()->accept(*this);
343         for (auto _e : e.getCases())
344         {
345             _e->accept(*this);
346         }
347         if (ast::Exp * def = e.getDefaultCase())
348         {
349             def->accept(*this);
350         }
351     }
352
353     void visit(ast::CaseExp & e)
354     {
355         e.getBody()->accept(*this);
356     }
357
358     void visit(ast::ReturnExp & e)
359     {
360     }
361
362     void visit(ast::FieldExp & e)
363     {
364     }
365
366     void visit(ast::NotExp & e)
367     {
368     }
369
370     void visit(ast::TransposeExp & e)
371     {
372     }
373
374     void visit(ast::MatrixExp & e)
375     {
376     }
377
378     void visit(ast::MatrixLineExp & e)
379     {
380     }
381
382     void visit(ast::CellExp & e)
383     {
384     }
385
386     void visit(ast::SeqExp & e)
387     {
388         if (loops.empty())
389         {
390             for (auto _e : e.getExps())
391             {
392                 if (_e->isForExp() || _e->isWhileExp())
393                 {
394                     _e->accept(*this);
395                 }
396             }
397         }
398         else
399         {
400             for (auto _e : e.getExps())
401             {
402                 _e->accept(*this);
403             }
404         }
405     }
406
407     void visit(ast::ArrayListExp & e)
408     {
409     }
410
411     void visit(ast::AssignListExp & e)
412     {
413     }
414
415     void visit(ast::VarDec & e)
416     {
417         emplaceAssigned(e.getSymbol());
418     }
419
420     void visit(ast::FunctionDec & e)
421     {
422     }
423
424     void visit(ast::ListExp & e)
425     {
426     }
427
428     void visit(ast::OptimizedExp & e)
429     {
430     }
431
432     void visit(ast::MemfillExp & e)
433     {
434     }
435
436     void visit(ast::DAXPYExp & e)
437     {
438     }
439
440     void visit(ast::IntSelectExp & e)
441     {
442         visit(static_cast<ast::SelectExp &>(e));
443     }
444
445     void visit(ast::StringSelectExp & e)
446     {
447         visit(static_cast<ast::SelectExp &>(e));
448     }
449 };
450
451 } // namespace analysis
452
453 #endif // __LOOP_ANALYZER_HXX__
454