source: branches/dev-jk-2597/Compiler/ModelicaMiddleEnd/src/jastadd/scalarization/Scalarization.jrag @ 13822

Last change on this file since 13822 was 13822, checked in by Jonathan Kämpe, 8 weeks ago

#5862 Now printing empty array subscripts in order to detect them in tests. Fixed a couple of occurences.

File size: 73.8 KB
Line 
1/*
2    Copyright (C) 2009 Modelon AB
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, version 3 of the License.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program.  If not, see <http://www.gnu.org/licenses/>.
15*/
16
17import java.util.ArrayList;
18import java.util.Arrays;
19import java.util.Iterator;
20import java.util.HashMap;
21import java.util.Map;
22import java.util.Collections;
23
24aspect Scalarization {
25
26    public abstract class Scalarizer {
27       
28        private List vars;
29        private List clauses;
30        private ForNames forNames;
31        private TypePrefixVariability variability;
32       
33        public Scalarizer(List vars, List clauses, ForNames forNames, TypePrefixVariability variability) {
34            this.vars = vars;
35            this.clauses = clauses;
36            this.forNames = forNames;
37            this.variability = variability;
38        }
39       
40        public void add(ASTNode clause) {
41            clauses.add(clause);
42        }
43       
44        public abstract void add(List<FFunctionCallLeft> lefts, FAbstractFunctionCall call);
45       
46        public void add(FAbstractVariable fv) {
47            vars.add(fv);
48        }
49       
50        public List getVars() {
51            return vars;
52        }
53       
54        public List getClauses() {
55            return clauses;
56        }
57       
58        public ForNames getNames() {
59            return forNames;
60        }
61       
62        public void createForLoops(List<FStatement> inner, FExp exp) {
63            createForLoops(inner, exp.size());
64        }
65       
66        public void createForLoops(List<FStatement> inner, Size size) {
67            forNames.createForLoops(this, clauses, inner, size);
68        }
69       
70        public void createForLoops(FAssignableExp left, FExp right, FExp exp) {
71            List<FStatement> l = new List<FStatement>();
72            l.add(new FAssignStmt(left, right));
73            createForLoops(l, exp.size());
74        }
75       
76        public FExp scalarizeAccessExp(FAccessExp accessExp) {
77            FExp res = accessExp.myFV().scalarizeIterIndex(this);
78            if (res == null) {
79                res = accessExp.createNode(accessExp.getFAccess().scalarize(this, accessExp.indexNames));
80            }
81            return accessExp.setLocationOf(res);
82        }
83       
84        public abstract void add(FExp left, FExp right);
85       
86        public void add(List v) {
87            vars.addAll(v);
88        }
89       
90        public void addTempVar(FType type, String name, boolean addVar, boolean init) {
91            if (addVar) {
92                type.createTempFVariables(getVars(), new FAccessString(name), variability);
93            }
94        }
95       
96        public void addTempVar(FExp source, boolean init) {
97            addTempVar(source.type(), source.tempVarName(), !source.useTempVar, init);
98        }
99       
100        public abstract<T extends Scalarizer> T block(List clauses);
101        public abstract<T extends Scalarizer> T block(List vars, List clauses);
102       
103        public TypePrefixVariability getVariability() {
104            return variability;
105        }
106       
107        public boolean inFunction() {
108            return false;
109        }
110       
111        public boolean unroll() {
112            return true;
113        }
114       
115        public static class Variable {
116           
117            public List vars;
118            public Scalarizer.Equation si;
119            public Scalarizer.Equation sp;
120            public Scalarizer.Equation sc;
121           
122            public Variable(List vars) {
123                this.vars = vars;
124                si = new Scalarizer.Equation(vars, new List<FAbstractEquation>(), Variability.INITIALPARAMETER);
125                sp = new Scalarizer.Equation(vars, new List<FAbstractEquation>(), Variability.FIXEDPARAMETER);
126                sc = new Scalarizer.Equation(vars, new List<FAbstractEquation>(), Variability.CONTINUOUS);
127            }
128           
129            public Scalarizer.Equation select(TypePrefixVariability variability) {
130                if (variability.fixedParameterOrLess()) {
131                    return sp;
132                } else if (variability.parameterOrLess()) {
133                    return si;
134                } else {
135                    return sc;
136                }
137            }
138        }
139       
140        public static class Equation extends Scalarizer {
141           
142            public Equation(List vars, List equs, TypePrefixVariability variability) {
143                this(vars, equs, new ForNames(), variability);
144            }
145           
146            public Equation(List vars, List equs, ForNames forNames, TypePrefixVariability variability) {
147                super(vars, equs, forNames, variability);
148            }
149           
150            public Scalarizer.Equation block(List clauses) {
151                return block(getVars(), clauses);
152            }
153           
154            public Scalarizer.Equation block(List vars, List clauses) {
155                return new Equation(vars, clauses, getNames(), getVariability());
156            }
157           
158            public void add(FExp left, FExp right) {
159                                // TODO: Not 100% correct, should be equation.setLocationOf(...)
160                add(left.setLocationOf(new FEquation(left, right)));
161            }
162           
163            @Override
164            public void add(List<FFunctionCallLeft> lefts, FAbstractFunctionCall call) {
165                add(new FFunctionCallEquation(lefts, call));
166            }
167           
168            @Override
169            public void addTempVar(FExp source, boolean init) {
170                if (!source.useTempVar) {
171                    super.addTempVar(source, init);
172                    source.notifyIfWhenEquationsOfTemporaryVar();
173                }
174            }
175        }
176       
177        public Scalarizer.Algorithm algorithm(List<FStatement> stmts) {
178            return new Algorithm(getVars(), stmts, getNames(), false, true, variability);
179        }
180       
181        public static Scalarizer.Algorithm function(List<FFunctionVariable> vars, List<FStatement> stmts, boolean unroll) {
182            return new Algorithm(vars, stmts, new ForNames(), true, unroll, Variability.DISCRETE);
183        }
184       
185        public static class Algorithm extends Scalarizer {
186            private boolean func;
187            private boolean unroll;
188           
189            public Algorithm(List vars, List clauses, ForNames forNames, boolean func, boolean unroll, TypePrefixVariability variability) {
190                super(vars, clauses, forNames, variability);
191                this.func = func;
192                this.unroll = !func || unroll;
193            }
194           
195            public Scalarizer.Algorithm block(List clauses) {
196                return block(getVars(), clauses);
197            }
198           
199            public Scalarizer.Algorithm block(List vars, List clauses) {
200                return new Algorithm(vars, clauses, getNames(), func, unroll, getVariability());
201            }
202           
203            public void add(FExp left, FExp right) {
204                add(new FAssignStmt((FAssignableExp)left, right));
205            }
206           
207            @Override
208            public void add(List<FFunctionCallLeft> lefts, FAbstractFunctionCall call) {
209                add(new FFunctionCallStmt(lefts, call));
210            }
211           
212            @Override
213            public void addTempVar(FType type, String name, boolean addVar, boolean init) {
214                if (func) {
215                    if (addVar) {
216                        type = type.treeCopy();
217                        add(new FFunctionVariable(VisibilityType.TEMPORARY, type, name));
218                    }
219                    if (init && type.isArray()) {
220                        FInitArrayStmt stmt = new FInitArrayStmt(new FAccessExp(name), true, type.size().scalarizedSizeExpressions(this));
221                        add(stmt);
222                    }
223                } else {
224                    super.addTempVar(type, name, addVar, init);
225                }
226            }
227           
228            public void addTempVar(FAssignStmt source, boolean init) {
229                FType type = source.getLeft().size().isUnknown() ? source.getLeft().type() : source.getRight().type();
230                addTempVar(type, source.tempVarName(), true, init);
231            }
232           
233            @Override
234            public boolean inFunction() {
235                return func;
236            }
237           
238            @Override
239            public boolean unroll() {
240                return unroll;
241            }
242        }
243    }
244   
245    public List<FAbstractEquation> TypePrefixVariability.selectEquations(List<FAbstractEquation> iEqus,
246            List<FAbstractEquation> pEqus, List<FAbstractEquation> equs) { return equs; }
247    public List<FAbstractEquation> Parameter.selectEquations(List<FAbstractEquation> iEqus,
248            List<FAbstractEquation> pEqus, List<FAbstractEquation> equs) { return pEqus; }
249    public List<FAbstractEquation> InitialParameter.selectEquations(List<FAbstractEquation> iEqus,
250            List<FAbstractEquation> pEqus, List<FAbstractEquation> equs) { return iEqus; }
251   
252        /**
253         * Flag indicating if a variable is scalarized.
254         */
255        boolean FAccess.scalarized = false;
256
257        /**
258         * Flag indicating if a flat class is scalarized.
259         */
260        boolean FClass.scalarized = false;
261       
262        syn boolean FVariable.isScalarized() = getFAccess().isScalarized();
263        syn boolean FAccess.isScalarized() = scalarized;
264
265    public class FClass {
266        /**
267         * Scalarize all variables and equations in the flat model.
268         */
269        public class scalarize extends Transformation {
270            public void perform() {
271                List<FVariable> vars = new List<FVariable>();
272                Scalarizer.Variable sv = new Scalarizer.Variable(vars);
273                scalarizeVars(sv);
274                setFVariableList(vars);
275                scalarizeFuncs();
276                scalarizeTypes();
277                scalarizeAttributes(sv.sp);
278                getConnectionSetManager().scalarize();
279                scalarized = true;
280                scalarizationCleanup();
281                scalarizationErrorCheck();
282            }
283        }
284    }
285   
286    /**
287     * Scalarize variable declarations and equations.
288     */
289    protected void FClass.scalarizeVars(Scalarizer.Variable sv) {
290       
291        FAbstractEquation.scalarizeList(sv.sc, getFAbstractEquations());
292        FAbstractEquation.scalarizeList(sv.si, getFInitialEquations());
293        FAbstractEquation.scalarizeList(sv.sp, getParameterEquations());
294       
295        for (FVariable fv : getFVariables()) {
296            fv.scalarize(sv);
297        }
298       
299        setFAbstractEquationList(sv.sc.getClauses());
300        setFInitialEquationList(sv.si.getClauses());
301        setParameterEquationList(sv.sp.getClauses());
302    }
303   
304    protected void FClass.scalarizeFuncs() {
305        boolean unroll = myOptions().getBooleanOption("unroll_functions");
306        for (FFunctionDecl f : getFFunctionDecls()) {
307            f.scalarize(unroll);
308        }
309    }
310   
311    /**
312     * Handles scalarization of the FAttributes that are declared in the FClass
313     */
314    private void FClass.scalarizeAttributes(Scalarizer s) {
315        List<FAttribute> attrs = new List<FAttribute>();
316        for (FAttribute a : getFAttributes())
317            a.scalarize(attrs, Index.NULL, s);
318        setFAttributeList(attrs);
319    }
320       
321        /**
322         * Scalarize type declarations by removing array-valued attributes.
323         * They have been copied to the variables when the variables were scalarized.
324         */
325        protected void FClass.scalarizeTypes() {
326                for (FDerivedType t : getFDerivedTypes())
327                        t.removeArrayValuedAttributes();
328        }
329       
330        /**
331         * Removing all array-valued attributes.
332         */
333        public void FDerivedType.removeArrayValuedAttributes() {
334                List<FAttribute> list = new List<FAttribute>();
335                for (FAttribute a : getFAttributes())
336                        if (!a.removeArrayValuedAttributes())
337                                list.add(a);
338                setFAttributeList(list);
339        }
340       
341        /**
342         * Removing all array-valued attributes.
343         *
344         * @return  true if the attribute should be removed
345         */
346        public boolean FAttribute.removeArrayValuedAttributes() {
347                boolean keep = false;
348                List<FAttribute> list = null;
349                if (getNumFAttribute() > 0) {
350                        list = new List<FAttribute>();
351                        for (FAttribute a : getFAttributes())
352                                if (!a.removeArrayValuedAttributes())
353                                        list.add(a);
354                        keep = list.getNumChild() > 0;
355                }
356                if (hasValue()) {
357                        if (getValue().isArray()) {
358                                if (keep)
359                                        setValueOpt(new Opt());
360                        } else {
361                                keep = true;
362                        }
363                }
364                if (keep && list != null)
365                        setFAttributeList(list);
366                return !keep;
367        }
368
369    protected void FClass.scalarizationCleanup() {
370        flush();  // Must flush before traversing
371    }
372   
373    public static void FAbstractEquation.scalarizeList(Scalarizer.Equation s, List<FAbstractEquation> fromList) {
374        for (FAbstractEquation ae : fromList) {
375            ae.scalarize(s);
376        }
377    }
378   
379    /**
380     * Scalarize the FVariable and put all scalarized variables in the
381     * list vars.
382     */
383    public void FVariable.scalarize(Scalarizer.Variable s) {
384        try {
385            if (size().isZero())
386                return;
387            createArrayTemporaries(s);
388            doScalarize(s);
389        } catch (ModelicaException e) {
390            throw e;
391        } catch (Exception e) {
392            throw new org.jmodelica.util.exceptions.InternalCompilerError("Exception caught while scalarizing component'" + name() + "'", e);
393        }
394    }
395   
396    public void FVariable.doScalarize(Scalarizer.Variable s) {
397        for (Index i : indices()) {
398            createScalarFVariable(s, i);
399        }
400    }
401   
402    @Override
403    public void FRecordVariable.doScalarize(Scalarizer.Variable s) {
404        scalarRecordFVariables(s, new ScalarizingVariableInstance(s, this));
405    }
406   
407    public void FVariable.createArrayTemporaries(Scalarizer.Variable s) {
408        if (hasBindingExp()) {
409            getBindingExp().createArrayTemporaries(s.select(variability()));
410        }
411        for (FAttribute fab : getFAttributes()) {
412            fab.createArrayTemporaries(s, variability(), type());
413        }
414    }
415   
416    public void FAttribute.createArrayTemporaries(Scalarizer.Variable s, TypePrefixVariability variability, FType type) {
417        type = type.componentType(name());
418        if (type.isUnknown()) {
419            variability = Variability.FIXEDPARAMETER;
420        } else {
421            variability = variability.component(name());
422        }
423        if (hasValue()) {
424            getValue().createArrayTemporaries(s.select(variability));
425        }
426        for (FAttribute fab : getFAttributes()) {
427            fab.createArrayTemporaries(s, variability, type);
428        }
429    }
430       
431        /**
432         * Create a scalar FVariable for a single cell or an already scalar FVariable.
433         *
434         * @param i  the Index of the cell to create an FVariable for. Should be Index.NULL for
435         *           already scalar FVariables.
436         */
437    protected FVariable FVariable.createScalarFVariable(Scalarizer.Variable s, Index i) {
438                // Create new variable and copy fields that should be same
439                FVariable fv = createEmptyNode();
440                fv.setVisibilityType(getVisibilityType());
441                fv.setTypePrefixVariability(getTypePrefixVariability());
442                fv.setCausalityConnectorPrefix(getCausalityConnectorPrefix());
443                if (hasFStringComment())
444                        fv.setFStringComment(getFStringComment().fullCopy());
445
446        fv.setFAccess(scalarizeVariableName(i));
447
448        // Scalarize binding expressions
449        if (hasBindingExp()) {
450            FExp bexp = getBindingExp().cell(i).scalarize(s.select(variability()));
451            if (keepBExp(variability(), getBindingExp())) {
452                fv.setBindingExp(bexp);
453            } else {
454                s.select(variability()).add(setLocationOf(new FAccessExp(scalarizeVariableUse(i))), bexp);
455            }
456        }
457
458                // Iterate over all attributes and scalarize.
459        List<FAttribute> attrs = new List<FAttribute>();
460        attrs.addAll(fv.getFAttributes());
461        for (FAttribute a : getFAttributes()) {
462            a.scalarize(attrs, i, s.sp);
463        }
464        fv.setFAttributeList(attrs);
465                fv.setDerivedType(getDerivedType());
466        fv.addArrayAttributesFromType(s, i, myFDerivedType());
467
468                fv.setLocation(this);
469               
470        s.select(variability()).add(fv);
471        return fv;
472        }
473
474    /**
475     * Create an FAccess for the scalarized variable.
476     * Separate method for extensibility.
477     */
478    protected FAccess FVariable.scalarizeVariableName(Index i) {
479        String name = getFAccess().name();
480        if (i.ndims() > 0) {
481            name = name + i;
482        }
483        return new FAccessString(name);
484    }
485
486    /**
487     * Create an FAccess for the scalarized binding equation.
488     * Separate method for extensibility.
489     */
490    protected FAccess FVariable.scalarizeVariableUse(Index i) {
491        return scalarizeVariableName(i);
492    }
493
494    @Override
495    protected FExternalObjectVariable FExternalObjectVariable.createScalarFVariable(Scalarizer.Variable s, Index i) {
496        FExternalObjectVariable fex = (FExternalObjectVariable) super.createScalarFVariable(s, i);
497                fex.setConstructor(getConstructor().fullCopy());
498                return fex;
499        }
500       
501    @Override
502    protected FEnumVariable FEnumVariable.createScalarFVariable(Scalarizer.Variable s, Index i) {
503        FEnumVariable fv = (FEnumVariable) super.createScalarFVariable(s, i);
504                fv.setEnum(getEnum().fullCopy());
505                return fv;
506        }
507       
508        /**
509         * Copy any attributes with array values from type, selecting the scalar value corresponding
510         * to the given index.
511         */
512    protected void FVariable.addArrayAttributesFromType(Scalarizer.Variable s, Index i, FDerivedType t) {
513        if (t != null && i != Index.NULL) {
514            for (FAttribute a : t.getFAttributes()) {
515                List<FAttribute> attrs = new List<FAttribute>();
516                attrs.addAll(getFAttributes());
517                a.addArrayAttributesTo(s, i, attrs);
518                setFAttributeList(attrs);
519            }
520        }
521        }
522       
523        /**
524         * Copy any attributes with array values to the given list, selecting the scalar value corresponding
525         * to the given index.
526         *
527         * @return  true if any attribute was added to the list
528         */
529    protected boolean FAttribute.addArrayAttributesTo(Scalarizer.Variable s, Index i, List<FAttribute> list) {
530                FAttribute match = findMatching(list, getName().name());
531                if (match != null) {
532                        list = match.getFAttributes();
533                        for (FAttribute a : getFAttributes())
534                                a.addArrayAttributesTo(s, i, list);
535                        return false;
536                }
537               
538                boolean isArray = hasValue() && getValue().isArray();
539                boolean add = isArray;
540                List<FAttribute> subList = null;
541                if (add || getNumFAttribute() > 0) {
542                        subList = new List<FAttribute>();
543                        for (FAttribute a : getFAttributes())
544                                add = a.addArrayAttributesTo(s, i, subList) || add;
545                }
546                if (add) {
547                        FAttribute res = new FAttribute(getType().fullCopy(), getName().fullCopy(), new Opt(), 
548                                        getAttributeSet(), getLevel(), getFEachOpt().fullCopy(), getFFinalOpt().fullCopy(), subList);
549                        if (hasValue()) {
550                                FExp val = getValue();
551                                if (isArray) {
552                                        if (val.ndims() < i.ndims())
553                                                i = i.subIndex(i.ndims() - val.ndims());
554                                        val = val.getArray().get(i);
555                                }
556                res.setValue(val.scalarize(s.sp));
557                        }
558                        list.add(res);
559                }
560                return add;
561        }
562       
563    /**
564     * Generate scalar FVariables for this record or record component.
565     *
566     * @param s Scalarization visitor
567     * @param bes        Instance representation of this variable
568     */
569    public void FVariable.scalarRecordFVariables(Scalarizer.Variable s, ScalarizingVariableInstance bes) {
570        try {
571            for (Index i : bes.indices(this)) {
572                scalarRecordCellFVariables(s, bes.create(s, i));
573            }
574        } catch (ModelicaException e) {
575            throw e;
576        } catch (Exception e) {
577            throw new org.jmodelica.util.exceptions.InternalCompilerError("Exception caught while scalarizing component'" + bes.name() + "'", e);
578        }
579    }
580   
581    public String ScalarizingVariableInstance.name() {
582        return name.toString();
583    }
584   
585    /**
586     * Generate scalar FVariables for a single array cell of this record or record component.
587     *
588     * @param s Scalarization visitor
589     * @param bes        Instance representation of this variable
590     * @param i          the index of this scalar variable in an array, or Index.NULL for scalar components
591     */
592    public void FVariable.scalarRecordCellFVariables(Scalarizer.Variable s, ScalarizingVariableInstance bes) {
593        bes.createScalarized(s, this);
594    }
595   
596    public void FRecordVariable.scalarRecordCellFVariables(Scalarizer.Variable s, ScalarizingVariableInstance bes) {
597        for (FVariable comp : myFRecordDecl().getFVariables()) {
598            comp.scalarRecordFVariables(s, bes.create(s, comp));
599        }
600    }
601   
602    /**
603     * Check if this FExp is in an binding exp that will still be a binding exp after scalarization
604     */
605    inh boolean FExp.inKeptBExp();
606    eq Root.getChild().inKeptBExp() = false;
607    eq FVariable.getBindingExp().inKeptBExp() = keepBExp(variability(), getBindingExp());
608   
609    /**
610     * Check if this FVariable should have a binding exp after scalarization
611     */
612    syn boolean FVariable.keepBExp(TypePrefixVariability variability, FExp bexp) =
613            variability.knownParameterOrLess() ||
614            (variability.parameterVariability() && bexp.isIndependentParameterExp());
615   
616    /**
617     * Lightweight representation of an FVariable used to scalarize record variables.
618     */
619    public class ScalarizingVariableInstance {
620       
621        private TypePrefixVariability variability; 
622       
623        private VisibilityType visibility;
624       
625        // Binding expression
626        private FExp bExp;
627       
628        // (Mapped) attributes of this variable
629        private Map<String, FAttribute> mattrs; 
630       
631        // Full name of this variable
632        private String name;
633       
634        // input/output prefix of top-level variable
635        private CausalityConnectorPrefix inputOutput;
636       
637        private Index index;
638       
639        private ScalarizingVariableInstance(String name, Map<String, FAttribute> mattrs, FExp be,
640                TypePrefixVariability variability, VisibilityType visibility, CausalityConnectorPrefix inputOutput, Index i)  {
641            bExp = be;
642            this.name = name;
643            index = i;
644            this.mattrs = mattrs;
645            this.variability = variability;
646            this.visibility = visibility;
647            this.inputOutput = inputOutput;
648        }
649       
650        private ScalarizingVariableInstance(String name, List<FAttribute> attrs, FExp be,
651                TypePrefixVariability variability, VisibilityType visibility, CausalityConnectorPrefix inputOutput, Index i)  {
652            this(name, ScalarizingVariableInstance.mapped(attrs), be, variability, visibility, inputOutput, i);
653        }
654       
655        public ScalarizingVariableInstance(Scalarizer.Variable s, FVariable fv) {
656            this(fv.name(), fv.getFAttributes(),
657                    fv.hasBindingExp() ? fv.getBindingExp().dynamicFExp(fv.getBindingExp().scalarize(s.select(fv.variability()))) : null,
658                    fv.variability(), fv.getVisibilityType(), fv.getCausalityConnectorPrefix(), Index.NULL);
659        }
660       
661        private static Map<String, FAttribute> mapped(List<FAttribute> as) {
662            Map<String, FAttribute> m;
663            if (as != null && as.getNumChild() > 0) {
664                m = new LinkedHashMap<String, FAttribute>();
665                for (FAttribute a : as) {
666                    m.put(a.name(), a);
667                }
668            } else {
669                m = Collections.<String, FAttribute>emptyMap();
670            }
671            return m;
672        }
673       
674        public Indices indices(FVariable comp) {
675            FAttribute sa = mattrs.get(FAttribute.SIZE);
676            if (sa != null && sa.hasValue()) {
677                return Indices.create(new MutableSize(sa.getValue().splitArrayExp(index)));
678            } else {
679                return comp.indices();
680            }
681        }
682       
683        public ScalarizingVariableInstance create(Scalarizer.Variable s, Index i) {
684            FExp nbexp = bExp;
685            Index ti = index.expand(i);
686            if (nbexp != null && nbexp.isArray()) {
687                Index ni = ti.subIndex(ti.ndims() - nbexp.ndims());
688                nbexp = nbexp.fArrayCell(ni, 0);
689            }
690            return new ScalarizingVariableInstance(i.ndims() > 0 ? name + i : name, mattrs, nbexp, variability,
691                    visibility, inputOutput, ti);
692        }
693       
694        public ScalarizingVariableInstance create(Scalarizer.Variable s, FVariable comp) {
695            String cName = comp.name();
696           
697            TypePrefixVariability nv = variability.component(cName);
698           
699            List<FAttribute> attrs = null;
700            FAttribute a = mattrs.get(cName);
701            if (a != null) {
702                attrs = a.getFAttributes();
703            }
704           
705            FExp nbexp = bExp;
706            if (nbexp == null) {
707                if (a != null) {
708                    nbexp = a.getValue();
709                }
710                if (nbexp != null) {
711                    nbexp = nbexp.dynamicFExp(nbexp.scalarize(s.select(nv)));
712                }
713            } else {
714                nbexp = nbexp.component(cName);
715            }
716           
717            return new ScalarizingVariableInstance(name + "." + cName, attrs, nbexp, nv, visibility, inputOutput, index);
718        }
719       
720        public void createScalarized(Scalarizer.Variable s, FVariable comp) {
721            Scalarizer.Equation se = s.select(variability);
722            Index cell = index.subIndex(index.ndims() - comp.ndims());
723            FVariable fv = comp.copyForName(s, name, cell);
724            fv.setVisibilityType(VisibilityType.mostRestrictive(fv.getVisibilityType(), visibility));
725            if (bExp != null) {
726                bExp.resetOriginalReferences(); /* Workaround for test RecordArray12 */
727                if (comp.keepBExp(variability, bExp)) {
728                    fv.setBindingExp(bExp);
729                } else {
730                    se.add(new FAccessExp(name), bExp);
731                    fv.setBindingExpOpt(new Opt());
732                }
733            } else {
734                fv.setBindingExpOpt(new Opt());
735            }
736            fv.setTypePrefixVariability(variability);
737            fv.setCausalityConnectorPrefix(inputOutput);
738            List<FAttribute> attrs = new List<FAttribute>();
739            for (FAttribute attr : mattrs.values()) {
740                attr.scalarize(attrs, index, s.sp);
741            }
742            fv.setFAttributeList(attrs);
743            fv.addArrayAttributesFromType(s, cell, comp.myFDerivedType());
744            if (!comp.isAbsoluteValue()) {
745                fv.annotation("absoluteValue").setValue(new FBooleanLitExpFalse());
746            }
747            se.add(fv);
748        }
749    }
750   
751        /**
752         * Create a copy of the variable with a specific name.
753         *
754         * The new variable is marked as scalarized, and if it refers to a specific cell in an array,
755         * then attributes are updated accordingly.
756         */
757    public FVariable FVariable.copyForName(Scalarizer.Variable s, String name, Index cell) {
758                FVariable fv = createEmptyNode();
759        fv.setFAccess(new FAccessString(name));
760                fv.getFAccess().scalarized = true;
761                fv.setVisibilityType(getVisibilityType());
762                fv.setTypePrefixVariability(getTypePrefixVariability());
763                fv.setCausalityConnectorPrefix(getCausalityConnectorPrefix());
764                fv.setDerivedType(getDerivedType());
765                if (hasBindingExp())
766                        fv.setBindingExp(getBindingExp().fullCopy());
767                if (hasFStringComment())
768                        fv.setFStringComment(getFStringComment().fullCopy());
769               
770                for (FAttribute a : getFAttributes())
771                        if (!a.isInternal())
772                fv.addFAttribute(a.copyForCell(s, cell));
773                return fv;
774        }
775
776    public FEnumVariable FEnumVariable.copyForName(Scalarizer.Variable s, String name, Index cell) {
777        FEnumVariable fv = (FEnumVariable) super.copyForName(s, name, cell);
778                fv.setEnum(getEnum().fullCopy());
779                return fv;
780        }
781   
782    public FExternalObjectVariable FExternalObjectVariable.copyForName(Scalarizer.Variable s, String name, Index cell) {
783        FExternalObjectVariable fv = (FExternalObjectVariable) super.copyForName(s, name, cell);
784        fv.setConstructor(getConstructor().fullCopy());
785        return fv;
786    }
787   
788        /**
789         * Create a copy of the attibute with dimensions removed from all array expressions according
790         * to an index.
791         */
792    public FAttribute FAttribute.copyForCell(Scalarizer.Variable s, Index i) {
793        if (i == Index.NULL)
794                        return fullCopy();
795                FAttribute res = createEmptyNode();
796                res.setType(getType().fullCopy());
797                res.setName(getName().fullCopy());
798        res.setLevel(getLevel());
799                if (hasValue()) {
800                        FExp val = getValue();
801                        if (val.ndims() < i.ndims() || isInternal())
802                val = val.scalarize(s.sp);
803                        else
804                                val = val.dynamicFExp(val.splitArrayExp(i).unboundCopy()).scalarize(s.sp);
805                        res.setValue(val);
806                }
807                res.setAttributeSet(getAttributeSet());
808                if (hasFEach())
809                        res.setFEach(getFEach().fullCopy());
810                if (hasFFinal())
811                        res.setFFinal(getFFinal().fullCopy());
812                for (FAttribute a : getFAttributes())
813            res.addFAttribute(a.copyForCell(s, i));
814                return res;
815        }
816       
817    public void FAttribute.scalarize(List<FAttribute> attrs, Index i, Scalarizer s) {
818        if (!name().equals(FAttribute.SIZE)) {
819            scalarizeInternal(attrs, i, s);
820        }
821    }
822    /**
823     * Scalarize the attribute, picking out the specific element from an array
824     *        expression or removing "each".
825     */
826    public FAttribute FAttribute.scalarizeInternal(List<FAttribute> attrs, Index i, Scalarizer s) {
827        FAttribute attr = createEmptyNode();
828        List<FAttribute> l = new List<FAttribute>();
829        for (FAttribute a : getFAttributes()) {
830            a.scalarize(l, i, s);
831        }
832        attr.setFAttributeList(l);
833        attr.setType(getType().fullCopy());
834        attr.setName(getName().fullCopy());
835        attr.setAttributeSet(getAttributeSet());
836        attr.setLevel(getLevel());
837        attr.setFFinalOpt(getFFinalOpt().fullCopy());
838        if (hasValue()) 
839            attr.setValue(scalarizeValue(i, s));
840        attrs.add(attr);
841        return attr;
842    }
843       
844    @Override
845    public void FAnnotationAttribute.scalarize(List<FAttribute> attrs, Index i, Scalarizer s) {
846        if (i.ndims() == 0)
847            scalarize(attrs, s);
848        else
849            scalarizeInternal(attrs, i, s);
850    }
851    /**
852     * Scalarize the attribute and create multiple instances for non-scalar
853     * attributes.
854     * An attribute is scalarized if it has no value and all its child
855     * attributes have value and are of the same size.
856     */
857    public void FAttribute.scalarize(List<FAttribute> attrs, Scalarizer s) {
858        if (hasValue()) {
859            scalarizeInternal(attrs, Index.NULL, s);
860        } else {
861            Size size = null;
862            boolean keepScalar = false;
863            for (FAttribute attr : getFAttributes()) {
864                if (!attr.hasValue())
865                    keepScalar = true;
866                else if (size == null)
867                    size = attr.getValue().size();
868                else if (!attr.hasFEach() && !attr.getValue().size().equals(size))
869                    keepScalar = true;
870            }
871            if (size == null || keepScalar)
872                size = Size.SCALAR;
873            for (Index i : Indices.create(size)) {
874                scalarizeInternal(attrs, i, s);
875            }
876        }
877    }
878
879    /**
880     * Scalarize the value of this attribute, picking out the specific element from an array
881     * expression.
882     *
883     * Returns null if attribute has no value.
884     */
885    public FExp FAttribute.scalarizeValue(Index i, Scalarizer s) {
886        if (!hasValue()) 
887            return null;
888        if (i.ndims() > getValue().ndims()) {
889            i = i.subIndex(i.ndims() - getValue().ndims());
890        }
891        return getValue().cell(i).scalarize(s);
892    }
893
894    /*
895     * Attributes for creating FTempIdExps and function temps.
896     */
897    syn FTempAccessExp FExp.tempExp() = tempExp(indexNames);
898    syn FTempAccessExp FExp.tempExp(String name)          = tempExp(name, (FArraySubscripts)null);
899    syn FTempAccessExp FExp.tempExp(Index i)              = tempExp(tempVarName(), i);
900    syn FTempAccessExp FExp.tempExp(FArraySubscripts fas) = tempExp(tempVarName(), fas);
901    syn FTempAccessExp FExp.tempExp(FExp[] subs) {
902        FArraySubscripts fas = null;
903        if (subs != null && subs.length > 0) {
904            List<FSubscript> l = new List<FSubscript>();
905            for (FExp e : subs) {
906                l.add(e.treeCopy().createFSubscript());
907            }
908            fas = new FArrayExpSubscripts(l);
909        }
910        return tempExp(tempVarName(), fas);
911    }
912
913    public FTempAccessExp FExp.tempExp(String name, Index i) {
914        FTempAccessExp res;
915        if (inFunction()) {
916            res = new FTempAccessExp(new FAccessFull(name, i.createFArraySubscripts()));
917        } else {
918            res = new FTempAccessExp(new FAccessString(name + i));
919        }
920        return (FTempAccessExp) dynamicFExp(res);
921    }
922
923    public FTempAccessExp FExp.tempExp(String name, FArraySubscripts fas) {
924        FTempAccessExp res;
925        if (inFunction()) {
926            if (fas == null) {
927                res = new FTempAccessExp(new FAccessFull(name));
928            } else {
929                res = new FTempAccessExp(new FAccessFull(name, fas));
930            }
931        } else {
932            if (fas == null) {
933                res = new FTempAccessExp(new FAccessString(name));
934            } else {
935                res = new FTempAccessExp(new FAccessString(name + fas));
936            }
937        }
938        return (FTempAccessExp) dynamicFExp(res);
939    }
940
941    /**
942     * Stores FSubscripts to be uses by <code>scalarize()</code>
943     */
944    public FExp[] FExp.indexNames = null;
945    public FExp FColonSubscript.indexName = null;
946   
947    public CommonAccessExp CommonAccessExp.createUseFas(String name) {
948        if (indexNames != null && indexNames.length > 0) {
949            return new FAccessExp(name, createIndexNameFas());
950        } else {
951            return new FAccessExp(name);
952        }
953    }
954   
955    public FArraySubscripts CommonAccessExp.createIndexNameFas() {
956        List<FSubscript> l = new List<FSubscript>();
957        for (FExp e : indexNames) {
958            l.add(e.treeCopy().createFSubscript());
959        }
960        return new FArrayExpSubscripts(l);
961    }
962   
963    public List<FAttribute> FAbstractEquation.scalarizeAttributeList(Index i, Scalarizer s) {
964        List<FAttribute> scalarized = new List<FAttribute>();
965        for (FAttribute a : getFAttributes()) 
966            a.scalarize(scalarized, i, s);
967        return scalarized;
968    }
969       
970    public void FAbstractEquation.scalarize(Scalarizer.Equation s) {}
971       
972        /**
973         * Scalarize equation and put all resulting equations in list eqns.
974         */
975    @Override
976    public void FEquation.scalarize(Scalarizer.Equation s) {
977                //log.debug("FEquation.scalarize() " + ndims());
978        if (size().isZero())
979            return;
980       
981        createArrayTemporaries(s);
982                if (ndims()==0) {
983                        /*
984                         * If the equation is of dimension 0, i.e, already scalar,
985                         * the equations is "scalarized" into a simple equation where
986                         * e.g. built in functions are replaced by elementary operations.
987                         */
988                       
989            List<FAttribute> attrs = scalarizeAttributeList(Index.NULL, s);
990            createScalarFEquations(s, attrs, getLeft(), getRight());
991                } else if (ndims() > 0) {
992                        /*
993                         * If the expression is an array expression, then the FExp.getArray()
994                         * element is used to generate scalar equations.
995                         */
996                        // Iterate over array elements and create scalarized equation for each
997                        for (Index i : indices()) {
998                List<FAttribute> attrs = scalarizeAttributeList(i, s);
999                createScalarFEquations(s, attrs, getLeft().getArray().get(i), getRight().getArray().get(i));
1000                        }
1001                } else {
1002                        throw new UnsupportedOperationException("Bad equation: ndims() for equation '" + 
1003                                        this + "' returned " + ndims()); 
1004                }
1005        }
1006       
1007    @Override
1008    public void FAlgorithm.scalarize(Scalarizer.Equation s) {
1009                List<FStatement> stmts = new List<FStatement>();
1010        FStatement.scalarizeStmtList(s.algorithm(stmts), getFStatements());
1011        s.add(new FAlgorithm(stmts));
1012        }
1013       
1014        /**
1015         * Scalarize left and right expressions and create new scalar equations.
1016         */
1017    public void FEquation.createScalarFEquations(Scalarizer.Equation s, List<FAttribute> attrs, FExp left, FExp right) {
1018        if (left.inferType().isRecord()) {
1019            left.inferType().scalarRecordClauses(s, new FAccessEmpty(), left, right);
1020        } else {
1021            s.add(this.setLocationOf(createNode(attrs, left.scalarize(s), right.scalarize(s))));
1022        }
1023        }
1024       
1025        // TODO: Introduce parameter object?
1026        /**
1027         * Generate scalar clauses for this record or record component.
1028         *
1029     * @param s         Scalarization visitor
1030         * @param suffix    add this as a suffix to the name of the uppermost record in uses
1031         * @param left      the left expression from the original equation
1032         * @param right     the right expression from the original equation
1033         */
1034    public void FType.scalarRecordClauses(Scalarizer s, FAccess suffix, FExp left, FExp right) {
1035        left = left.scalarRecordFExp(s, suffix);
1036        right = right.scalarRecordFExp(s, suffix);
1037        s.add(left, right);
1038    }
1039   
1040    @Override
1041    public void FRecordType.scalarRecordClauses(Scalarizer s, FAccess suffix, FExp left, FExp right) {
1042        for (FRecordComponentType comp : getComponents()) {
1043            FAccess next = suffix.copyAndAppend(comp.getName()).asFAccessFull();
1044            comp.getFType().scalarRecordComponentClauses(s, next, left, right);
1045        }
1046    }
1047   
1048        /**
1049         * Generate scalar clauses for this record component.
1050         *
1051     * @param s         Scalarization visitor
1052         * @param suffix    add this as a suffix to the name of the uppermost record in uses
1053         * @param left      the left expression from the original equation
1054         * @param right     the right expression from the original equation
1055         */
1056    public void FType.scalarRecordComponentClauses(Scalarizer s, FAccess suffix, FExp left, FExp right) {
1057                if (isArray()) {
1058                        FAccessFull fullSuffix = suffix.copyAsFAccessFull();
1059                        Indices ind = null;
1060            if (!size().isUnknown())
1061                                ind = indices(); 
1062                        else  // TODO: This is calculated each time - introduce some kind of lazy attribute?
1063                ind = left.dynamicFExp(left.scalarRecordFExp(s, suffix)).indices();
1064                        for (Index i : ind) {
1065                                fullSuffix.addFArraySubscripts(i.createFArraySubscripts());
1066                scalarRecordClauses(s, fullSuffix, left, right);
1067                        }
1068                } else {
1069            scalarRecordClauses(s, suffix, left, right);
1070                }
1071        }
1072       
1073        /**
1074         * Create an FExp that represents a specific scalar component of this record.
1075         *
1076         * @param suffix    the suffix to add to a use of the record to access the specific component
1077         */
1078    public FExp FExp.scalarRecordFExp(Scalarizer s, String suffix) {
1079        return scalarRecordFExp(s, new FAccessString(suffix));
1080    }
1081   
1082    public FExp FExp.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1083        if (useTempVar) {
1084            return tempExp().scalarRecordFExp(s, suffix);
1085        }
1086        return scalarize(s);
1087    }
1088
1089    public FExp FRecordConstructor.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1090        return suffix.scalarRecordFExpForCon(s, this);
1091    }
1092
1093    public FExp FNoEventExp.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1094        return createNode(getFExp().scalarRecordFExp(s, suffix));
1095    }
1096
1097    public FExp FIfExp.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1098        FIfExp res = new FIfExp();
1099        res.setIfExp(getIfExp().scalarize(s));
1100        res.setThenExp(getThenExp().scalarRecordFExp(s, suffix));
1101        res.setElseExp(getElseExp().scalarRecordFExp(s, suffix));
1102        return res;
1103    }
1104
1105    public FExp FAccessExp.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1106      FAccess access = getFAccess();
1107      if (indexNames != null) {
1108          access = access.copyAndAddFas(createIndexNameFas());
1109      }
1110      access = access.asFAccessFull().treeCopy().append(suffix);
1111      access.scalarized = false;
1112      FExp res = createNode(access);
1113      res = dynamicFExp(res).scalarize(s);
1114      res.setLocation(this);
1115      return res;
1116    }
1117
1118    public FExp FSubscriptedExp.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1119        if (indexVariability().indexParameterOrLess() && !getFExp().size().isUnknown()) {
1120            try {
1121                return select().scalarRecordFExp(s, suffix);
1122            } catch (ConstantEvaluationException e) {
1123               
1124            }
1125        }
1126        return new FSubscriptedExp(getFExp().scalarRecordFExp(s, suffix), getFArraySubscripts().scalarize(s));
1127    }
1128
1129    public FExp FArray.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1130        if (useTempVar) {
1131            return tempExp().scalarRecordFExp(s, suffix);
1132        }
1133        if (isIterArray())
1134            return super.scalarRecordFExp(s, suffix);
1135        FArray res = createEmptyNode();
1136        for (FExp e : getFExps())
1137            res.addFExp(e.scalarRecordFExp(s, suffix));
1138        return res;
1139    }
1140
1141    /**
1142     * Create an FExp that represents a specific scalar component of the given record constructor.
1143     *
1144     * @param s
1145     * @param con       the record constructor to extract an expression from
1146     *
1147     * @see FExp#scalarRecordFExp(Map, FAccess)
1148     */
1149    public FExp FAccess.scalarRecordFExpForCon(Scalarizer s, FRecordConstructor con) {
1150        throw new UnsupportedOperationException();
1151    }
1152
1153    public FExp FAccessString.scalarRecordFExpForCon(Scalarizer s, FRecordConstructor con) {
1154        return con.component(getName()).scalarize(s);
1155    }
1156
1157    public FExp FAccessFull.scalarRecordFExpForCon(Scalarizer s, FRecordConstructor con) {
1158        FAccessPart first = getFAccessPart(0);
1159        FExp arg = con.component(first.getName());
1160        if (first.hasFArraySubscripts()) {
1161            if (arg.useTempVar()) {
1162                arg = arg.tempExp(first.getFArraySubscripts());
1163            } else {
1164                arg = arg.extractArrayCell(s, first.getFArraySubscripts().createIndex());
1165            }
1166        }
1167        return copySuffix().scalarRecordFExp(s, arg);
1168    }
1169
1170    public FExp FAccess.scalarRecordFExp(Scalarizer s, FExp exp) {
1171        return exp.scalarRecordFExp(s, this);
1172    }
1173
1174    public FExp FAccessEmpty.scalarRecordFExp(Scalarizer s, FExp exp) {
1175        return exp.scalarize(s);
1176    }
1177
1178
1179    public FExp FExp.extractArrayCell(Scalarizer s, int... index) {
1180        return extractArrayCell(s, new Index(index));
1181    }
1182
1183    public FExp FExp.extractArrayCell(Scalarizer s, Index i) {
1184        if (type().isUnknown() || size().isUnknown()) {
1185            int[] ind = i.index();
1186            FExp[] subs = new FExp[ind.length];
1187            for (int k = 0; k < ind.length; k++) {
1188                subs[k] = new FIntegerLitExp(ind[k]);
1189            }
1190            return extractArrayCell(s, subs);
1191        } else {
1192            return cell(i);
1193        }
1194    }
1195
1196    public FExp FExp.extractArrayCell(Scalarizer s, FExp... subs) {
1197        addArrayUsesToIndexMap(s, subs);
1198        return dynamicFExp(scalarize(s));
1199    }
1200
1201    public FExp CommonAccessExp.extractArrayCell(Scalarizer s, Index i) {
1202        return dynamicFExp(createSpecifiedNode(i, true));
1203    }
1204
1205    public FExp FTempAccessExp.extractArrayCell(Scalarizer s, Index i) {
1206        return dynamicFExp(createNode(getFAccess().copyAndAddFas(i)));
1207    }
1208
1209    public FExp FIfExp.extractArrayCell(Scalarizer s, Index i) {
1210        FIfExp res = new FIfExp();
1211        res.setIfExp(getIfExp().scalarize(s));
1212        res.setThenExp(getThenExp().extractArrayCell(s, i));
1213        res.setElseExp(getElseExp().extractArrayCell(s, i));
1214        return dynamicFExp(res);
1215    }
1216
1217        /**
1218         * Scalarize equation and put all scalarized equations in list eqns.
1219         */
1220    public void FFunctionCallEquation.scalarize(Scalarizer.Equation s) {
1221        if (getCall().isOperatorWithoutOutputs()) {
1222            createArrayTemporaries(s);
1223            getCall().scalarizeOperatorWithoutOutputs(s);
1224        } else {
1225            getCall().createArrayTemporaries(s);
1226            getLefts().createArrayTemporaries(s);
1227        }
1228    }
1229   
1230    syn boolean FAbstractFunctionCall.isOperatorWithoutOutputs() = false;
1231    eq FReinit.isOperatorWithoutOutputs()                        = true;
1232    eq FAssert.isOperatorWithoutOutputs()                        = true;
1233    eq FTerminate.isOperatorWithoutOutputs()                     = true;
1234   
1235    public void FExp.scalarizeOperatorWithoutOutputs(Scalarizer s) {
1236        if (isArray()) {
1237            for (FExp e : getArray().iterable()) {
1238                e.scalarizeOperatorWithoutOutputs(s);
1239            }
1240        } else if (type().isRecord()) {
1241            for (FRecordComponentType frct : ((FRecordType)type()).getComponents()) {
1242                component(frct.getName()).scalarizeOperatorWithoutOutputs(s);
1243            }
1244        } else {
1245            FAbstractFunctionCall call = (FAbstractFunctionCall) scalarizeExp(s);
1246            List<FFunctionCallLeft> lefts = new List<FFunctionCallLeft>();
1247            s.add(lefts, call);
1248        }
1249    }
1250   
1251    public FExp FEndExp.scalarizeExp(Scalarizer s) {
1252        return mySize().createFExp(0);
1253    }
1254       
1255    @Override
1256    public void FIfWhenElseEquation.scalarize(Scalarizer.Equation s) {
1257        List<FAbstractEquation> l = new List<FAbstractEquation>();
1258        scalarizeList(s.block(l), getFAbstractEquations());
1259        FIfWhenElseEquation res = createEmptyNode();
1260        res.setType(getType());
1261        res.setFAbstractEquationList(l);
1262        scalarizeTestAndElse(s, res);
1263        s.add(res);
1264    }
1265
1266    @Override
1267    public void FIfEquation.scalarize(Scalarizer.Equation s) {
1268        boolean lockedBranch = false;
1269        if (getTest().variability().indexParameterOrLess()) {
1270            try {
1271                CValue cval = getTest().ceval();
1272                if (cval.hasBooleanValue()) {
1273                    if (cval.booleanValue()) {
1274                        scalarizeList(s, getFAbstractEquations());
1275                    } else if (hasElse()) {
1276                        scalarizeList(s, getElse().getFAbstractEquations());
1277                    }
1278                    lockedBranch = true;
1279                }
1280            } catch (ConstantEvaluationException e) {}
1281        }
1282        if (!lockedBranch) {
1283            super.scalarize(s);
1284        }
1285    }
1286
1287    public void FIfWhenElseEquation.scalarizeTestAndElse(Scalarizer.Equation s, FIfWhenElseEquation res) {}
1288
1289    public void FIfWhenEquation.scalarizeTestAndElse(Scalarizer.Equation s, FIfWhenElseEquation res) {
1290                FIfWhenEquation res2 = (FIfWhenEquation) res;
1291        res2.setTest(getTest().scalarize(s));
1292                if (hasElse()) {
1293                ArrayList<FExp> tempsToAddToElse = branchTemporaries;
1294                branchTemporaries = null;
1295            List<FAbstractEquation> l = new List();
1296            getElse().scalarize(s.block(l));
1297            res2.setElse((FIfWhenElseEquation)l.getChild(0));
1298                        res2.addDummyEqnsForTemps(branchTemporaries, tempsToAddToElse);
1299                }
1300        branchTemporaries = null;
1301        }
1302       
1303        public void FIfWhenElseEquation.addDummyEqnsForTemps(ArrayList<FExp> tempsForThen, ArrayList<FExp> tempsForElse) {
1304        if (tempsForThen != null) 
1305            for (FExp e : tempsForThen)
1306                e.type().addDummyEqnsForTemp(getFAbstractEquations(), e.tempVarName());
1307        }
1308   
1309    public void FIfWhenEquation.addDummyEqnsForTemps(ArrayList<FExp> tempsForThen, ArrayList<FExp> tempsForElse) {
1310        super.addDummyEqnsForTemps(tempsForThen, tempsForElse);
1311        if (hasElse())
1312            getElse().addDummyEqnsForTemps(tempsForElse, tempsForElse);
1313    }
1314   
1315    public void FType.addDummyEqnsForTemp(List<FAbstractEquation> l, String name) {
1316        if (isArray()) {
1317            FType scalar = scalarType();
1318            for (Index i : indices()) 
1319                scalar.addDummyEqnsForTemp(l, name + i);
1320        } else {
1321            l.add(new FEquation(new FAccessExp(name), zeroLiteral()));
1322        }
1323    }
1324   
1325    public void FRecordType.addDummyEqnsForTemp(List<FAbstractEquation> l, String name) {
1326        if (isArray()) {
1327            super.addDummyEqnsForTemp(l, name);
1328        } else {
1329            for (FRecordComponentType comp : getComponents())
1330                comp.getFType().addDummyEqnsForTemp(l, name + '.' + comp.getName());
1331        }
1332    }
1333       
1334        public void FExp.notifyIfWhenEquationsOfTemporaryVar() {
1335            FIfWhenEquation myIf = surroundingIfOrElse();
1336            if (myIf != null) 
1337                myIf.addBranchTemporary(this);
1338        }
1339       
1340        public void FIfWhenEquation.addBranchTemporary(FExp e) {
1341            if (branchTemporaries == null)
1342                branchTemporaries = new ArrayList<FExp>();
1343            branchTemporaries.add(e);
1344        FIfWhenEquation myIf = surroundingIfOrElse();
1345        if (myIf != null) 
1346            myIf.addBranchTemporary(e);
1347        }
1348       
1349        private ArrayList<FExp> FIfWhenEquation.branchTemporaries = null;
1350       
1351        /**
1352         * Surrounding if or else equation, if any.
1353         *
1354         * Only valid in flat tree.
1355         */
1356    inh FIfWhenEquation FExp.surroundingIfOrElse();
1357    inh FIfWhenEquation FAbstractEquation.surroundingIfOrElse();
1358    eq FClass.getChild().surroundingIfOrElse()                      = null;
1359    eq InstNode.getChild().surroundingIfOrElse()                    = null;
1360    eq Root.getChild().surroundingIfOrElse()                        = null;
1361    eq FIfWhenEquation.getFAbstractEquation().surroundingIfOrElse() = this;
1362    eq FIfWhenEquation.getElse().surroundingIfOrElse()              = this;
1363
1364        /**
1365         * Create a record constructor (or FArray of record constructors), 
1366         *        with the arguments taken from a record variable with the given name.
1367         */
1368        public FExp FType.createRecordConstructor(Scalarizer s, FExp exp) {
1369        if (isArray() || exp.isArray()) {
1370            return createRecordConstructorArray(s, exp, indices().iterator(), 0);
1371        } else {
1372            return createRecordConstructorCell(s, exp);
1373        }
1374        }
1375       
1376        /**
1377         * Create an FArray of expressions, with the arguments taken from a record
1378         * variable or member with the given name.
1379         */
1380        public FExp FType.createRecordConstructorArray(Scalarizer s, FExp exp, Iterator<Index> it, int dim) {
1381        if (isEmpty()) {
1382            return createEmptyExp();
1383        }
1384                FArray arr = new FArray();
1385                boolean last = dim == ndims() - 1;
1386                for (int i = 0, n = size().get(dim); i < n; i++) {
1387                        FExp res;
1388            if (last) {
1389                FExp subExp = exp.extractArrayCell(s, it.next());
1390                FType t = subExp.type();
1391                if (t.isUnknown()) {
1392                    t = this;
1393                }
1394                res = t.createRecordConstructorCell(s, subExp);
1395            } else {
1396                res = createRecordConstructorArray(s, exp, it, dim + 1);
1397            }
1398                        arr.addFExp(res);
1399                }
1400                return arr;
1401        }
1402       
1403    syn boolean FType.isEmpty() = size().isEmpty();
1404    syn FExp FType.createEmptyExp() {
1405        Size s = size();
1406        List<FExp> dims = new List<FExp>();
1407        for (int i = 0, n = s.ndims(); i < n ; i++) {
1408            dims.add(s.createFExp(i));
1409        }
1410        return new FFillExp(dims, zeroLiteral());
1411    }
1412       
1413        /**
1414         * Create a record constructor with the arguments taken from a record
1415         *        variable with the given name.
1416         *
1417         * Assumes that <code>name</code> refers to a non-array variable
1418         * (or a specific cell in an array variable).
1419         */
1420    public FExp FType.createRecordConstructorCell(Scalarizer s, FExp exp) {
1421        return exp.scalarize(s);
1422    }
1423
1424    public FExp FRecordType.createRecordConstructorCell(Scalarizer s, FExp exp) {
1425                FRecordConstructor rc = new FRecordConstructor(new FRecordAccess(getName()), new List());
1426                for (FRecordComponentType comp : getComponents()) {
1427             FExp next = exp.scalarRecordFExp(s, comp.getName());
1428             if (exp.type().isUnknown() || exp.useTempVar) {
1429                 // Work around for expanding FTempAccessExp which doesnt know its type
1430                 next = comp.getFType().createRecordConstructor(s, exp.dynamicFExp(next));
1431             }
1432             rc.addArg(next);
1433                }
1434                return rc;
1435        }
1436
1437        /* Scalarization of expressions is needed in order to compute a simple
1438         * scalar expression from an expression with ndims==0. For example, an
1439         * CommonAccess 'x[2]' needs to be marked as scalarized, and the expression
1440         * scalar(x*A*x) needs to be replaced by a double sum.
1441         */
1442
1443        /**
1444         * Flag that signals that this expression should be replaced with a use of a temporary variable.
1445         */
1446        protected boolean FExp.useTempVar = false;
1447    syn boolean FExp.useTempVar() = useTempVar;
1448       
1449        /**
1450         * Scalarize expressions, replacing array expressions with FArrays of scalarized subexpressions.
1451         *
1452         * The FArrays are needed because function calls need arrays to be passed as arrays.
1453         */
1454    public FExp FExp.scalarize(Scalarizer s) {
1455        FExp exp = useTempVar ? tempExp() : this;
1456        if (scalarizeExpanded(s)) {
1457            return type().createRecordConstructor(s, exp);
1458        } else {
1459            return exp.scalarizeExp(s);
1460        }
1461    }
1462   
1463    public FExp FFunctionCall.scalarize(Scalarizer s) {
1464        FExp exp = super.scalarize(s);
1465        indexNames = null;
1466        return exp;
1467    }
1468
1469    syn boolean FExp.scalarizeExpanded(Scalarizer s);
1470    eq FExp           .scalarizeExpanded(Scalarizer s) = isComposite() && indexNames == null && s.unroll() && !(useTempVar && isForIndexExp());
1471    eq CommonAccessExp.scalarizeExpanded(Scalarizer s) = super.scalarizeExpanded(s) && (!s.inFunction() || isSlice());
1472    eq FFunctionCall  .scalarizeExpanded(Scalarizer s) = super.scalarizeExpanded(s) && ((useTempVar && !s.inFunction()) || isVectorized());
1473    eq FIfExp         .scalarizeExpanded(Scalarizer s) = super.scalarizeExpanded(s) && !isFunctionCallIO()
1474            && !type().isRecord(); /* Workaround for test RecordScalarize52 */
1475   
1476    syn boolean FFunctionCall.isVectorized() = false;
1477    eq FVectorFunctionCall.isVectorized() = true;
1478
1479        /**
1480         * Scalarize expressions.
1481         */
1482        public FExp FExp.scalarizeExp(Scalarizer s) {
1483        return treeCopy();
1484        }
1485
1486        public FExp FArray.scalarizeExp(Scalarizer s) {
1487                if (isIterArray())
1488                        return getFExp(0).scalarize(s);
1489                FArray res = new FArray();
1490                for (FExp e : getFExps())
1491                        res.addFExpNoTransform(e.scalarize(s));
1492                return res;
1493        }
1494
1495    public FExp FAccessExp.scalarizeExp(Scalarizer s) {
1496        return s.scalarizeAccessExp(this);
1497    }
1498
1499    public FExp FTempAccessExp.scalarizeExp(Scalarizer s) {
1500        if (indexNames != null) {
1501            FAccess access = getFAccess().scalarize(s);
1502            access = access.asFAccessFull().addFArraySubscripts(createIndexNameFas());
1503            return setLocationOf(new FAccessExp(access));
1504        }
1505        return super.scalarizeExp(s);
1506    }
1507
1508    @Override
1509    public FExp FDerExp.scalarizeExp(Scalarizer s) {
1510        return new FDerExp(getFAccess().scalarize(s, indexNames), order());
1511    }
1512   
1513    @Override
1514    public FExp FPreExp.scalarizeExp(Scalarizer s) {
1515        return new FPreExp(getFAccess().scalarize(s, indexNames));
1516    }
1517
1518    public FAccess FAccess.scalarize(Scalarizer s, FExp[] indexNames) {
1519        FAccess access = scalarize(s);
1520        if (indexNames != null) {
1521            access = access.asFAccessFull().addFArraySubscripts(getExpandedSubscripts().scalarize(s));
1522        }
1523        return access;
1524    }
1525
1526        public abstract FAccess FAccess.scalarize(Scalarizer s);
1527       
1528        public FAccess FAccessEmpty.scalarize(Scalarizer s) {
1529                return new FAccessEmpty();
1530        }
1531       
1532        public FAccess FAccessString.scalarize(Scalarizer s) {
1533                return new FAccessString(getName());
1534        }
1535
1536    public FRecordAccess FRecordAccess.scalarize(Scalarizer s) {
1537        return new FRecordAccess(getName());
1538    }
1539
1540    public FAccess FAccessFull.scalarize(Scalarizer s) {
1541        if (!inFunction() && !isGlobalAccess()) {
1542            StringBuilder name = new StringBuilder();
1543            getFAccessPart(0).scalarizeAsString(name);
1544            for (int i = 1; i < getNumFAccessPart(); i++) {
1545                name.append(".");
1546                getFAccessPart(i).scalarizeAsString(name);
1547            }
1548            return new FAccessString(name.toString());
1549        } else {
1550            FAccessFull access = new FAccessFull(new List());
1551            for (FAccessPart accessp : getFAccessParts()) 
1552                access.addFAccessPart(accessp.scalarize(s));
1553            return access;
1554        }
1555    }
1556
1557    public void FAccessPart.scalarizeAsString(StringBuilder sb) {
1558        sb.append(name());
1559    }
1560
1561    public void FAccessPartArray.scalarizeAsString(StringBuilder sb) {
1562        super.scalarizeAsString(sb);
1563        sb.append(getFArraySubscripts().createIndex());
1564    }
1565
1566    public FAccessPart FAccessPart.scalarize(Scalarizer s) {
1567        return new FAccessPart(getName());
1568    }
1569   
1570    public FAccessPartArray FAccessPartArray.scalarize(Scalarizer s) {
1571        return new FAccessPartArray(getName(), getFArraySubscripts().scalarize(s));
1572    }
1573
1574    public FArraySubscripts FArraySubscripts.scalarize(Scalarizer s) {
1575        return treeCopy();
1576    }
1577
1578    public FArraySubscripts FArrayExpSubscripts.scalarize(Scalarizer s) {
1579        FArrayExpSubscripts fas = new FArrayExpSubscripts();
1580        for (FSubscript fs : getFSubscripts()) {
1581            fas.addFSubscript(fs.scalarize(s));
1582        }
1583        return fas;
1584    }
1585
1586    public FSubscript FSubscript.scalarize(Scalarizer s) {
1587        return treeCopy();
1588    }
1589   
1590    public FSubscript FColonSubscript.scalarize(Scalarizer s) {
1591        if (indexName == null) {
1592            return treeCopy();
1593        }
1594        return indexName.treeCopy().createFSubscript();
1595    }
1596   
1597    public FSubscript FExpSubscript.scalarize(Scalarizer s) {
1598        return getFExp().scalarize(s).createFSubscript();
1599    }
1600
1601
1602
1603
1604    public FExp FIfExp.scalarizeExp(Scalarizer s) {
1605        if (getIfExp().variability().indexParameterOrLess()) {
1606            try {
1607                return cevalSelectExp().scalarize(s);
1608            } catch (ConstantEvaluationException e) {}
1609        }
1610        return new FIfExp(getIfExp().scalarize(s),
1611                getThenExp().scalarize(s),
1612                getElseExp().scalarize(s));
1613    }
1614
1615        public FExp FMulExp.scalarizeExp(Scalarizer s) {
1616                if (getLeft().isArray() && !isArray()) 
1617                        return dynamicFExp(composeMulScalarCellExp(Index.NULL)).scalarize(s);
1618                else
1619                        return super.scalarizeExp(s);
1620        }
1621       
1622        public FExp FRangeExp.scalarizeExp(Scalarizer s) {
1623        if (indexNames == null) {
1624            return treeCopy();
1625        }
1626        return scalarizeWithIndex(s, indexNames[0].treeCopy());
1627        }
1628       
1629    public FExp FLinspace.scalarizeExp(Scalarizer s) {
1630        FExp index = new FSubExp(indexNames[0].fullCopy(), new FIntegerLitExp(1));
1631        FExp len  = new FSubExp(getStopExp().fullCopy(), getStartExp().fullCopy());
1632        FExp step = new FDivExp(len, new FSubExp(getN().fullCopy(), new FIntegerLitExp(1)));
1633        FExp res = new FAddExp(getStartExp().fullCopy(), new FMulExp(index, step));
1634        return res;
1635    }
1636
1637       
1638        public FExp FSizeExp.scalarizeExp(Scalarizer s) {
1639        if (getFExp().isSlice() || !getFExp().size().isUnknown(dimension())) {
1640            return getFExp().size().scalarize(s, dimension());
1641        } else {
1642            return new FSizeExp(getFExp().scalarize(s), new Opt<FExp>(getDim().scalarize(s)));
1643        }
1644        }
1645       
1646    public FExp FUnknownSizeExp.scalarizeExp(Scalarizer s) {
1647        return new FSizeExp(getFExp().scalarize(s), new Opt<FExp>(getDim().scalarize(s)));
1648    }
1649       
1650        public FExp FNdimsExp.scalarizeExp(Scalarizer s) {
1651                return ceval().buildLiteral();
1652        }
1653
1654    public FExp FSubscriptedExp.scalarizeExp(Scalarizer s) {
1655        if (indexVariability().indexParameterOrLess() && !getFExp().size().isUnknown()) {
1656            try {
1657                return select().scalarize(s);
1658            } catch (ConstantEvaluationException e) {
1659               
1660            }
1661        }
1662        FArraySubscripts fas = getFArraySubscripts().scalarize(s);
1663        if (inFunction()) {
1664            return new FAccessExp(getFExp().tempVarName(), fas);
1665        } else {
1666            FSubscriptedExp res = createEmptyNode();
1667            res.setFExp(getFExp().scalarize(s));
1668            res.setFArraySubscripts(fas);
1669            return res;
1670        }
1671    }
1672
1673    public FExp FCardinality.scalarizeExp(Scalarizer s) {
1674        return new FIntegerLitExp(getFExp().cardinalityValue());
1675    }
1676
1677        public FExp FMinMaxExp.scalarizeExp(Scalarizer s) {
1678                if (hasY())
1679                        return createNode(getX().scalarize(s), getY().scalarize(s));
1680                else
1681                        return getX().reduceToScalarized(this, s);
1682        }
1683       
1684        public FExp FReductionExp.scalarizeExp(Scalarizer s) {
1685                if (getFExp().size().numElements() == 0)
1686                        return reduceStartValue().buildLiteral();
1687                else
1688                        return getFExp().reduceToScalarized(scalarReduceExp(), s);
1689        }
1690       
1691        syn FBinExp FReductionExp.scalarReduceExp();
1692        eq FSumExp.scalarReduceExp()     = new FAddExp();
1693        eq FProductExp.scalarReduceExp() = new FMulExp();
1694       
1695        public FExp FIterExp.scalarizeExp(Scalarizer s) {
1696                return getFExp().scalarize(s);
1697        }
1698       
1699    /**
1700     * Scalarize an expression by recursively scalarizing and combining the contents in its Array.
1701     *
1702     * New nodes are created with <code>template.createNodeBinary()</code>.
1703     */
1704    public FExp FExp.reduceToScalarized(FExp template, Scalarizer s) {
1705        if (isArray()) {
1706            java.util.List<FExp> scalarizedExps = new ArrayList<FExp>();
1707            Iterator<FExp> it = getArray().iteratorFExp();
1708            while (it.hasNext()) {
1709                scalarizedExps.add(it.next().scalarize(s));
1710            }
1711            return createBalancedBinaryTree(template, scalarizedExps);
1712        } else {
1713            return scalarize(s);
1714        }
1715    }
1716
1717    /**
1718     * Constructs a balanced binary tree based on the expression list exps with
1719     * the operation as specified by template.
1720     */
1721    public static FExp FExp.createBalancedBinaryTree(FExp template, java.util.List<FExp> exps) {
1722        return createBalancedBinaryTree(template, exps, 0, exps.size());
1723    }
1724
1725    private static FExp FExp.createBalancedBinaryTree(FExp template, java.util.List<FExp> exps, int start, int end) {
1726        if (start == end) {
1727            return null;
1728        }
1729        if (start == end - 1) {
1730            return exps.get(start);
1731        }
1732        // We want a left heavy tree, hence the modulo part
1733        int half = (start + end) / 2 + (start + end) % 2;
1734        FExp left = createBalancedBinaryTree(template, exps, start, half);
1735        FExp right = createBalancedBinaryTree(template, exps, half, end);
1736        return template.createNodeBinary(left, right);
1737    }
1738
1739        public FExp FBinExp.scalarizeExp(Scalarizer s) { return createNode(getLeft().scalarize(s), getRight().scalarize(s)); }
1740        public FExp FUnaryExp.scalarizeExp(Scalarizer s) { return createNode(getFExp().scalarize(s)); }
1741        public FExp FMathematicalFunctionCall.scalarizeExp(Scalarizer s) { return createNode(getFExp().scalarize(s)); }
1742        public FExp FAtan2Exp.scalarizeExp(Scalarizer s)     { return createNode(getFExp().scalarize(s), getY().scalarize(s)); }
1743        public FExp FUnaryBuiltIn.scalarizeExp(Scalarizer s) { return createNode(getFExp().scalarize(s)); }
1744        public FExp FTranspose.scalarizeExp(Scalarizer s)    { return getFExp().scalarize(s); }
1745       
1746        public FExp FNoArgBuiltIn.scalarizeExp(Scalarizer s) { return createEmptyNode(); }
1747        public FExp FEventGenExp.scalarizeExp(Scalarizer s) { return createNode(getX().scalarize(s)); }
1748        public FExp FBinEventGenExp.scalarizeExp(Scalarizer s) { return createNode(getX().scalarize(s),getY().scalarize(s)); }
1749       
1750        public FExp FLitExp.scalarizeExp(Scalarizer s) { return (FLitExp) fullCopy(); }
1751        public FExp FEnumLitExp.scalarizeExp(Scalarizer s) { 
1752            return inArraySubscripts() ? new FIntegerLitExp(ceval().intValue()) : super.scalarizeExp(s);
1753        }
1754        public FExp FBooleanLitExp.scalarizeExp(Scalarizer s) { 
1755            return inArraySubscripts() ? new FIntegerLitExp(ceval().intValue()) : super.scalarizeExp(s);
1756    }
1757       
1758        public FExp FSmoothExp.scalarizeExp(Scalarizer s)     { return new FSmoothExp(getOrder().scalarize(s), getFExp().scalarize(s)); }
1759        public FExp FSampleExp.scalarizeExp(Scalarizer s)     { return new FSampleExp(getOffset().scalarize(s), getInterval().scalarize(s)); }
1760        public FExp FSemiLinearExp.scalarizeExp(Scalarizer s) { return new FSemiLinearExp(getX().scalarize(s), getPosSlope().scalarize(s), getNegSlope().scalarize(s)); }
1761        public FExp FHomotopyExp.scalarizeExp(Scalarizer s)   { return new FHomotopyExp(getActual().scalarize(s), getSimplified().scalarize(s)); }
1762       
1763        public FExp FStringExp.scalarizeExp(Scalarizer s)  {
1764                FStringExp scalarized = new FStringExp();
1765                scalarized.setValue(getValue().scalarize(s));
1766                if (hasMinimumLength())
1767                        scalarized.setMinimumLength(getMinimumLength().scalarize(s));
1768                if (hasLeftJustified())
1769                        scalarized.setLeftJustified(getLeftJustified().scalarize(s));
1770                if (hasSignificantDigits())
1771                        scalarized.setSignificantDigits(getSignificantDigits().scalarize(s));
1772                if (hasFormat())
1773                        scalarized.setFormat(getFormat().scalarize(s));
1774                return scalarized;
1775        }
1776       
1777        public FExp FRecordConstructor.scalarizeExp(Scalarizer s) {
1778        FRecordConstructor rc = new FRecordConstructor(getRecord().scalarize(s), new List());
1779        for (FExp arg : getArgs()) {
1780            rc.addArg(arg.scalarize(s));
1781        }
1782                return rc;
1783        }
1784       
1785        public FExp FZeros.scalarizeExp(Scalarizer s) {
1786                return new FIntegerLitExp(0);
1787        }
1788       
1789        public FExp FOnes.scalarizeExp(Scalarizer s) {
1790                return new FIntegerLitExp(1);
1791        }
1792   
1793    public FExp FScalarExp.scalarizeExp(Scalarizer s) {
1794        int[] t = new int[getFExp().ndims()];
1795        Arrays.fill(t, 1);
1796        return dynamicFExp(getFExp().extractArrayCell(s, new Index(t))).scalarize(s);
1797    }
1798   
1799        public FExp FFillExp.scalarizeExp(Scalarizer s) {
1800                return getFillExp().fullCopy();
1801        }
1802       
1803    public FFunctionCall FFunctionCall.scalarizeExp(Scalarizer s) {
1804        List<FExp> args = new List<FExp>();
1805        for (FExp arg : getArgs()) {
1806            args.add(arg.scalarize(s));
1807        }
1808        FFunctionCall res = createScalarized(getName().treeCopy(), args, null);
1809        res.setFType(getFType().scalarize(s, res));
1810        return res;
1811    }
1812   
1813    public abstract FType FType.scalarize(Scalarizer s, FExp context);
1814
1815    @Override
1816    public FType FCellType.scalarize(Scalarizer s, FExp context) {
1817        FCellType res = treeCopy();
1818        res.scalarizeTypeSizes(s, context);
1819        return res;
1820    }
1821
1822    @Override
1823    public FType FArrayType.scalarize(Scalarizer s, FExp context) {
1824        FArrayType res = treeCopy();
1825        for (int i = 0; i < getFExps().numChildren(); i++) {
1826            res.setFExp(getFExp(i).scalarize(s), i);
1827        }
1828        return res;
1829    }
1830   
1831    @Override
1832    public FType FFunctionType.scalarize(Scalarizer s, FExp context) {
1833        List<FRecordComponentType> inputs = new List<FRecordComponentType>();
1834        for (FRecordComponentType frct : getInputs()) {
1835            inputs.add(frct.scalarize(s, context));
1836        }
1837        List<FRecordComponentType> outputs = new List<FRecordComponentType>();
1838        for (FRecordComponentType frct : getOutputs()) {
1839            outputs.add(frct.scalarize(s, context));
1840        }
1841        FFunctionType res = new FFunctionType(getSize(), getName(), inputs, outputs, getFClass());
1842        res.setSize(getSize().scalarize(s, context));
1843        return res;
1844    }
1845   
1846    @Override
1847    public FType FRecordType.scalarize(Scalarizer s, FExp context) {
1848        List<FRecordComponentType> comps = new List<FRecordComponentType>();
1849        for (FRecordComponentType frct : getComponents()) {
1850            comps.add(frct.scalarize(s, context));
1851        }
1852        FRecordType res = new FRecordType(getSize(), getName(), comps, getFClass());
1853        res.setSize(getSize().scalarize(s, context));
1854        return res;
1855    }
1856
1857    public FRecordComponentType FRecordComponentType.scalarize(Scalarizer s, FExp context) {
1858        FRecordComponentType res = treeCopy();
1859        res.setFType(getFType().scalarize(s, context));
1860        return res;
1861    }
1862
1863    public abstract void FType.scalarizeTypeSizes(Scalarizer s, FExp context);
1864
1865    @Override
1866    public void FArrayType.scalarizeTypeSizes(Scalarizer s, FExp context) {
1867        scalarizeFExps(s);
1868    }
1869
1870    private void FArrayType.scalarizeFExps(Scalarizer s) {
1871        for (int i = 0; i < getNumFExp(); i++) {
1872            getFExp(i).createArrayTemporaries(s);
1873            setFExp(getFExp(i).scalarize(s), i);
1874        }
1875    }
1876
1877    @Override
1878    public void FCellType.scalarizeTypeSizes(Scalarizer s, FExp context) {
1879        setSize(getSize().scalarize(s, context));
1880    }
1881   
1882    public Size Size.scalarize(Scalarizer s, FExp context) {
1883        return this;
1884    }
1885   
1886    @Override
1887    public Size MutableSize.scalarize(Scalarizer s, FExp context) {
1888        MutableSize res = new MutableSize(ndims());
1889        for (int i = 0; i < exps.length; i++) {
1890            res.size[i] = size[i];
1891            if (exps[i] != null) {
1892                res.exps[i] = exps[i].scalarize(s);
1893                context.dynamicFExp(res.exps[i]);
1894            }
1895        }
1896        return res;
1897    }
1898   
1899    public FExp Size.scalarize(Scalarizer s, int i) {
1900        return createFExp(i);
1901    }
1902   
1903    @Override
1904    public FExp MutableSize.scalarize(Scalarizer s, int i) {
1905        if (exps[i] != null) {
1906            return exps[i].scalarize(s);
1907        } else {
1908            return super.scalarize(s, i);
1909        }
1910    }
1911   
1912    /**
1913     * Create a scalarized list of size expressions.
1914     * Also performs createArrayTemporaries.
1915     */
1916    public List<FExp> Size.scalarizedSizeExpressions(Scalarizer s) {
1917        List<FExp> sizes = new List<FExp>();
1918        for (int i = 0; i < ndims(); i++) {
1919            createArrayTemporaries(s, i);
1920            sizes.add(scalarize(s, i));
1921        }
1922        return sizes;
1923    }
1924   
1925    protected FFunctionCall FFunctionCall.createScalarized(FAccess name, List<FExp> args, FType type) {
1926        return setLocationOf(new FFunctionCall(name, args, type)); 
1927    }
1928   
1929    protected FFunctionCall FPartialFunctionCall.createScalarized(FAccess name, List<FExp> args, FType type) {
1930        return new FPartialFunctionCall(name, args, type, getArgNames().treeCopy()); 
1931    }
1932   
1933        public FAssert FAssert.scalarizeExp(Scalarizer s) {
1934                Opt level = hasLevel() ? new Opt(getLevel().scalarize(s)) : new Opt();
1935        return createNode(getTest().scalarize(s), getMsg().scalarize(s), level);
1936        }
1937
1938    public FReinit FReinit.scalarizeExp(Scalarizer s) {
1939        return new FReinit(getVar().scalarize(s), getFExp().scalarize(s));
1940    }
1941
1942    public FDelayExp FDelayExp.scalarizeExp(Scalarizer s) {
1943        Opt max = hasMax() ? new Opt(getMax().scalarize(s)) : new Opt();
1944        return createNode(getFExp().scalarize(s), getDelay().scalarize(s), max);
1945    }
1946   
1947    public FSpatialDistExp FSpatialDistExp.scalarizeExp(Scalarizer s) {
1948        return new FSpatialDistExp(getIn0().scalarize(s), getIn1().scalarize(s),
1949                getX().scalarize(s), getPositiveVelocity().scalarize(s),
1950                getInitialPoints().scalarize(s), getInitialValues().scalarize(s));
1951    }
1952
1953    public FForIndex FForIndex.scalarize(Scalarizer s) {
1954        return new FForIndex(getFVariable().fullCopy(), getFExp().scalarizeIndexExp(s));
1955    }
1956
1957        /**
1958         * Scalarize the expression of an FForIndex.
1959         */
1960        public FExp FExp.scalarizeIndexExp(Scalarizer s) {
1961                return scalarize(s);
1962        }
1963       
1964        public FRangeExp FRangeExp.scalarizeIndexExp(Scalarizer s) {
1965                List<FExp> exps = new List<FExp>();
1966                for (FExp e : getFExps())
1967                        exps.add(e.scalarize(s));
1968                return new FRangeExp(exps);
1969        }
1970
1971    public FExInStream FExInStream.scalarizeExp(Scalarizer s) {
1972        FExInStream res = new FExInStream(getDefault().scalarize(s), getEps().scalarize(s), new List<FExp>());
1973        for (FExp e : getVars()) {
1974            res.addVarNoTransform(e.scalarize(s));
1975        }
1976        return res;
1977    }
1978
1979        public void ConnectionSetManager.scalarize() {
1980                for (ConnectionSet set : list)
1981                        set.scalarize();
1982                Map<String, CSENameMapEntry> oldCSEStreamMap = cseStreamMap;
1983                cseStreamMap = new HashMap<String, CSENameMapEntry>();
1984                for (CSENameMapEntry entry : oldCSEStreamMap.values()) {
1985            if (entry.outsideCSE != null)
1986                updateCSEMapEntry(entry.outsideCSE, entry.outside);
1987            if (entry.insideCSE != null)
1988                updateCSEMapEntry(entry.insideCSE, entry.inside);
1989                }
1990        }
1991       
1992        public void ConnectionSet.scalarize() {
1993                for (ConnectionSetEntry e : this)
1994                        e.scalarize();
1995        }
1996       
1997        public void ConnectionSetEntry.scalarize() {
1998                if (access.accessNdims() == 0) {
1999                        // Can't use FAccess.scalarize(), since it relies on rewrites
2000                        access = new FAccessString(access.scalarName());
2001                } else {
2002                        Indices ind = Indices.createFromFas(access.getFArraySubscripts());
2003                        scalarNames = new String[ind.numElements()];
2004                        int j = 0;
2005                        for (Index i : ind)
2006                                scalarNames[j++] = access.copyAndAddFas(i.createFArraySubscripts()).scalarName();
2007                }
2008        }
2009
2010    syn lazy List<FStatement> FForStmt.getUnrolledForStmtList() {
2011        List<FStatement> unrolledForStmts = new List<>();
2012       
2013        FVariable index = getIndex().getFVariable();
2014        FExp loopExp = getIndex().getFExp();
2015        for (FExp e : loopExp.getArray().iterable()) {
2016            UnrollingScalarizer s = new UnrollingScalarizer(unrolledForStmts, index, e);
2017            scalarizeStmtList(s, getForStmts());
2018        }
2019        return unrolledForStmts;
2020    }
2021   
2022    public class FForStmt {
2023        private class UnrollingScalarizer extends Scalarizer.Algorithm {
2024           
2025            private FAbstractVariable indexVariable;
2026            private FExp indexValue;
2027           
2028            public UnrollingScalarizer(List<FStatement> stmts, FAbstractVariable indexVariable, FExp indexValue) {
2029                super(new List<FFunctionVariable>(), stmts, new ForNames(), true, true, Variability.DISCRETE);
2030                this.indexVariable = indexVariable;
2031                this.indexValue = indexValue;
2032            }
2033           
2034            @Override
2035            public FExp scalarizeAccessExp(FAccessExp accessExp) {
2036                if (indexVariable.equals(accessExp.myFV())) {
2037                    return accessExp.setLocationOf(indexValue);
2038                }
2039                return super.scalarizeAccessExp(accessExp);
2040            }
2041           
2042            @Override
2043            public Algorithm block(List clauses) {
2044                return new UnrollingScalarizer(clauses, indexVariable, indexValue);
2045            }
2046           
2047            @Override
2048            public Algorithm block(List vars, List clauses) {
2049                return new UnrollingScalarizer(clauses, indexVariable, indexValue);
2050            }
2051        }
2052    }
2053}
Note: See TracBrowser for help on using the repository browser.