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 #include "AnalysisVisitor.hxx"
17 #include "tools.hxx"
18 
19 namespace analysis
20 {
21 
visit(ast::ListExp & e)22 void AnalysisVisitor::visit(ast::ListExp & e)
23 {
24     logger.log(L"ListExp", e.getLocation());
25     if (e.getParent()->isVarDec())
26     {
27         visitInVarDecCtxt(e);
28         return;
29     }
30 
31     e.getStart().accept(*this);
32     Result & Rstart = e.getStart().getDecorator().getResult();
33     e.getEnd().accept(*this);
34     Result & Rend = e.getEnd().getDecorator().getResult();
35     e.getStep().accept(*this);
36     Result & Rstep = e.getStep().getDecorator().getResult();
37 
38     double start = 1;
39     double step = 1;
40     double end = 1;
41     if (Rstart.getConstant().getDblValue(start) && Rstep.getConstant().getDblValue(step) && Rend.getConstant().getDblValue(end))
42     {
43         // Start, Step & End are constant !
44         double out;
45         int type = ForList64::checkList(start, end, step, out);
46 
47         switch (type)
48         {
49             case 0:
50                 e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::EMPTY), -1));
51                 break;
52             case 1:
53                 e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::DOUBLE), -1));
54                 break;
55             case 2:
56             {
57                 const uint64_t N = ForList64::size(start, end, step);
58                 TIType T(dm.getGVN(), TIType::DOUBLE, 1, N);
59                 if (N == 1)
60                 {
61                     out = start;
62                 }
63                 e.getDecorator().setResult(Result(T, dm.getTmpId(T, false)));
64                 break;
65             }
66             default:
67                 break;
68         }
69         e.setValues(start, step, end, out);
70         setResult(e.getDecorator().res);
71 
72         return;
73     }
74 
75     if (step == 0 || tools::isNaN(step) || !tools::isFinite(step)
76             || tools::isNaN(start) || !tools::isFinite(start)
77             ||  tools::isNaN(end) || !tools::isFinite(end))
78     {
79         e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::EMPTY), -1));
80         return;
81     }
82 
83     if (!Rstep.getConstant().getDblValue(step) || (step != -1 && step != 1))
84     {
85         Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
86         setResult(res);
87         return;
88     }
89 
90     if (!Rstart.getType().isscalar() || !Rend.getType().isscalar())
91     {
92         Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
93         setResult(res);
94         return;
95     }
96 
97     GVN::Value * gvnStart;
98     if (Rstart.getConstant().getDblValue(start))
99     {
100         if (tools::getIntType(start) == tools::NOTANINT)
101         {
102             gvnStart = getGVN().getValue((double)tools::cast<int>(start + step));
103         }
104         else
105         {
106             gvnStart = getGVN().getValue((double)tools::cast<int>(start));
107         }
108     }
109     else
110     {
111         gvnStart = Rstart.getConstant().getGVNValue();
112         if (!gvnStart)
113         {
114             Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
115             setResult(res);
116             return;
117         }
118     }
119 
120     GVN::Value * gvnEnd;
121 
122     if (Rend.getConstant().getDblValue(end))
123     {
124         if (tools::getIntType(end) == tools::NOTANINT)
125         {
126             gvnEnd = getGVN().getValue((double)tools::cast<int>(end - step));
127         }
128         else
129         {
130             gvnEnd = getGVN().getValue((double)tools::cast<int>(end));
131         }
132     }
133     else
134     {
135         gvnEnd = Rend.getConstant().getGVNValue();
136         if (!gvnEnd)
137         {
138             Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
139             setResult(res);
140             return;
141         }
142     }
143 
144     GVN::Value * ONEValue = getGVN().getValue(int64_t(1));
145     SymbolicDimension ONE(getGVN(), ONEValue);
146     GVN::Value * v;
147 
148     if (gvnStart->value == gvnEnd->value)
149     {
150         Result & res = e.getDecorator().setResult(Result(TIType(getGVN(), TIType::DOUBLE, ONE, ONE)));
151         setResult(res);
152         return;
153     }
154 
155     if (step == 1)
156     {
157         v = getGVN().getValue(OpValue::Kind::MINUS, *gvnEnd, *gvnStart);
158     }
159     else
160     {
161         v = getGVN().getValue(OpValue::Kind::MINUS, *gvnStart, *gvnEnd);
162     }
163     v = getGVN().getValue(OpValue::Kind::PLUS, *v, *ONEValue);
164 
165     if (v->poly->constant < 0 && v->poly->isCoeffNegative(false))
166     {
167         TIType type(getGVN(), TIType::EMPTY);
168         e.getDecorator().res = Result(type);
169     }
170     else
171     {
172         bool res = getCM().check(ConstraintManager::POSITIVE, v);
173         if (res)
174         {
175             TIType type(getGVN(), TIType::DOUBLE, ONE, SymbolicDimension(getGVN(), v));
176             e.getDecorator().setResult(type);
177         }
178         else
179         {
180             Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), Rstart.getType().type, false), -1));
181             setResult(res);
182             return;
183         }
184     }
185 
186     setResult(e.getDecorator().res);
187 }
188 
visitInVarDecCtxt(ast::ListExp & e)189 void AnalysisVisitor::visitInVarDecCtxt(ast::ListExp & e)
190 {
191     e.getStart().accept(*this);
192     Result & Rstart = e.getStart().getDecorator().getResult();
193     e.getEnd().accept(*this);
194     Result & Rend = e.getEnd().getDecorator().getResult();
195     e.getStep().accept(*this);
196     Result & Rstep = e.getStep().getDecorator().getResult();
197 
198     double start = 1;
199     double step = 1;
200     double end = 1;
201     if ((Rstart.getConstant().getDblValue(start) || Rstep.getConstant().getDblValue(step)
202             || Rend.getConstant().getDblValue(end)) &&
203             (step == 0 || tools::isNaN(step) || !tools::isFinite(step)
204              || tools::isNaN(start) || !tools::isFinite(start)
205              ||  tools::isNaN(end) || !tools::isFinite(end)))
206     {
207         // We have an invalid list
208         e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::EMPTY), -1));
209         return;
210     }
211 
212     ast::VarDec & vd = *static_cast<ast::VarDec *>(e.getParent());
213     const symbol::Symbol & sym = vd.getSymbol();
214     GVN::Value * startRange = nullptr;
215     GVN::Value * endRange = nullptr;
216     Result & res = e.getDecorator().setResult(Result(TIType(dm.getGVN(), TIType::DOUBLE), -1));
217 
218     if (Rstart.getConstant().getGVNValue(getGVN(), startRange) && Rend.getConstant().getGVNValue(getGVN(), endRange))
219     {
220         // Start & End are GVN values
221         res.setRange(SymbolicRange(getGVN(), startRange, endRange));
222     }
223     else
224     {
225         SymbolicRange & rangeStart = Rstart.getRange();
226         if (rangeStart.isValid())
227         {
228             // Start is an iterator: for i=1:N, for j=i:N, ... in the second for "i" in "i:n" is an iterator
229             if (endRange || Rend.getConstant().getGVNValue(getGVN(), endRange))
230             {
231                 // Start is an iterator and End is GVN value
232                 res.setRange(SymbolicRange(getGVN(), rangeStart.getStart(), endRange));
233             }
234             else
235             {
236                 SymbolicRange & rangeEnd = Rend.getRange();
237                 if (rangeEnd.isValid())
238                 {
239                     // Start & End are iterators
240                     res.setRange(SymbolicRange(getGVN(), rangeStart.getStart(), rangeEnd.getEnd()));
241                 }
242             }
243         }
244         else if (startRange || Rstart.getConstant().getGVNValue(getGVN(), startRange))
245         {
246             // Start is a GVN value
247             SymbolicRange & rangeEnd = Rend.getRange();
248             if (rangeEnd.isValid())
249             {
250                 // Start is a GVN value and End is an iterator
251                 res.setRange(SymbolicRange(getGVN(), startRange, rangeEnd.getEnd()));
252             }
253         }
254     }
255 
256     setResult(res);
257 }
258 }
259