source: trunk/Compiler/ModelicaMiddleEnd/src/jastadd/scalarization/Scalarization.jrag @ 13357

Last change on this file since 13357 was 13357, checked in by Jonathan Kämpe, 3 months ago

#5766 Merging refactoring from branch

File size: 73.7 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            res = new FTempAccessExp(new FAccessFull(name, fas));
927        } else {
928            if (fas == null) {
929                res = new FTempAccessExp(new FAccessString(name));
930            } else {
931                res = new FTempAccessExp(new FAccessString(name + fas));
932            }
933        }
934        return (FTempAccessExp) dynamicFExp(res);
935    }
936
937    /**
938     * Stores FSubscripts to be uses by <code>scalarize()</code>
939     */
940    public FExp[] FExp.indexNames = null;
941    public FExp FColonSubscript.indexName = null;
942   
943    public CommonAccessExp CommonAccessExp.createUseFas(String name) {
944        if (indexNames != null && indexNames.length > 0) {
945            return new FAccessExp(name, createIndexNameFas());
946        } else {
947            return new FAccessExp(name);
948        }
949    }
950   
951    public FArraySubscripts CommonAccessExp.createIndexNameFas() {
952        List<FSubscript> l = new List<FSubscript>();
953        for (FExp e : indexNames) {
954            l.add(e.treeCopy().createFSubscript());
955        }
956        return new FArrayExpSubscripts(l);
957    }
958   
959    public List<FAttribute> FAbstractEquation.scalarizeAttributeList(Index i, Scalarizer s) {
960        List<FAttribute> scalarized = new List<FAttribute>();
961        for (FAttribute a : getFAttributes()) 
962            a.scalarize(scalarized, i, s);
963        return scalarized;
964    }
965       
966    public void FAbstractEquation.scalarize(Scalarizer.Equation s) {}
967       
968        /**
969         * Scalarize equation and put all resulting equations in list eqns.
970         */
971    @Override
972    public void FEquation.scalarize(Scalarizer.Equation s) {
973                //log.debug("FEquation.scalarize() " + ndims());
974        if (size().isZero())
975            return;
976       
977        createArrayTemporaries(s);
978                if (ndims()==0) {
979                        /*
980                         * If the equation is of dimension 0, i.e, already scalar,
981                         * the equations is "scalarized" into a simple equation where
982                         * e.g. built in functions are replaced by elementary operations.
983                         */
984                       
985            List<FAttribute> attrs = scalarizeAttributeList(Index.NULL, s);
986            createScalarFEquations(s, attrs, getLeft(), getRight());
987                } else if (ndims() > 0) {
988                        /*
989                         * If the expression is an array expression, then the FExp.getArray()
990                         * element is used to generate scalar equations.
991                         */
992                        // Iterate over array elements and create scalarized equation for each
993                        for (Index i : indices()) {
994                List<FAttribute> attrs = scalarizeAttributeList(i, s);
995                createScalarFEquations(s, attrs, getLeft().getArray().get(i), getRight().getArray().get(i));
996                        }
997                } else {
998                        throw new UnsupportedOperationException("Bad equation: ndims() for equation '" + 
999                                        this + "' returned " + ndims()); 
1000                }
1001        }
1002       
1003    @Override
1004    public void FAlgorithm.scalarize(Scalarizer.Equation s) {
1005                List<FStatement> stmts = new List<FStatement>();
1006        FStatement.scalarizeStmtList(s.algorithm(stmts), getFStatements());
1007        s.add(new FAlgorithm(stmts));
1008        }
1009       
1010        /**
1011         * Scalarize left and right expressions and create new scalar equations.
1012         */
1013    public void FEquation.createScalarFEquations(Scalarizer.Equation s, List<FAttribute> attrs, FExp left, FExp right) {
1014        if (left.inferType().isRecord()) {
1015            left.inferType().scalarRecordClauses(s, new FAccessEmpty(), left, right);
1016        } else {
1017            s.add(this.setLocationOf(createNode(attrs, left.scalarize(s), right.scalarize(s))));
1018        }
1019        }
1020       
1021        // TODO: Introduce parameter object?
1022        /**
1023         * Generate scalar clauses for this record or record component.
1024         *
1025     * @param s         Scalarization visitor
1026         * @param suffix    add this as a suffix to the name of the uppermost record in uses
1027         * @param left      the left expression from the original equation
1028         * @param right     the right expression from the original equation
1029         */
1030    public void FType.scalarRecordClauses(Scalarizer s, FAccess suffix, FExp left, FExp right) {
1031        left = left.scalarRecordFExp(s, suffix);
1032        right = right.scalarRecordFExp(s, suffix);
1033        s.add(left, right);
1034    }
1035   
1036    @Override
1037    public void FRecordType.scalarRecordClauses(Scalarizer s, FAccess suffix, FExp left, FExp right) {
1038        for (FRecordComponentType comp : getComponents()) {
1039            FAccess next = suffix.copyAndAppend(comp.getName()).asFAccessFull();
1040            comp.getFType().scalarRecordComponentClauses(s, next, left, right);
1041        }
1042    }
1043   
1044        /**
1045         * Generate scalar clauses for this record component.
1046         *
1047     * @param s         Scalarization visitor
1048         * @param suffix    add this as a suffix to the name of the uppermost record in uses
1049         * @param left      the left expression from the original equation
1050         * @param right     the right expression from the original equation
1051         */
1052    public void FType.scalarRecordComponentClauses(Scalarizer s, FAccess suffix, FExp left, FExp right) {
1053                if (isArray()) {
1054                        FAccessFull fullSuffix = suffix.copyAsFAccessFull();
1055                        Indices ind = null;
1056            if (!size().isUnknown())
1057                                ind = indices(); 
1058                        else  // TODO: This is calculated each time - introduce some kind of lazy attribute?
1059                ind = left.dynamicFExp(left.scalarRecordFExp(s, suffix)).indices();
1060                        for (Index i : ind) {
1061                                fullSuffix.addFArraySubscripts(i.createFArraySubscripts());
1062                scalarRecordClauses(s, fullSuffix, left, right);
1063                        }
1064                } else {
1065            scalarRecordClauses(s, suffix, left, right);
1066                }
1067        }
1068       
1069        /**
1070         * Create an FExp that represents a specific scalar component of this record.
1071         *
1072         * @param suffix    the suffix to add to a use of the record to access the specific component
1073         */
1074    public FExp FExp.scalarRecordFExp(Scalarizer s, String suffix) {
1075        return scalarRecordFExp(s, new FAccessString(suffix));
1076    }
1077   
1078    public FExp FExp.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1079        if (useTempVar) {
1080            return tempExp().scalarRecordFExp(s, suffix);
1081        }
1082        return scalarize(s);
1083    }
1084
1085    public FExp FRecordConstructor.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1086        return suffix.scalarRecordFExpForCon(s, this);
1087    }
1088
1089    public FExp FNoEventExp.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1090        return createNode(getFExp().scalarRecordFExp(s, suffix));
1091    }
1092
1093    public FExp FIfExp.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1094        FIfExp res = new FIfExp();
1095        res.setIfExp(getIfExp().scalarize(s));
1096        res.setThenExp(getThenExp().scalarRecordFExp(s, suffix));
1097        res.setElseExp(getElseExp().scalarRecordFExp(s, suffix));
1098        return res;
1099    }
1100
1101    public FExp FAccessExp.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1102      FAccess access = getFAccess();
1103      if (indexNames != null) {
1104          access = access.copyAndAddFas(createIndexNameFas());
1105      }
1106      access = access.asFAccessFull().treeCopy().append(suffix);
1107      access.scalarized = false;
1108      FExp res = createNode(access);
1109      res = dynamicFExp(res).scalarize(s);
1110      res.setLocation(this);
1111      return res;
1112    }
1113
1114    public FExp FSubscriptedExp.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1115        if (indexVariability().indexParameterOrLess() && !getFExp().size().isUnknown()) {
1116            try {
1117                return select().scalarRecordFExp(s, suffix);
1118            } catch (ConstantEvaluationException e) {
1119               
1120            }
1121        }
1122        return new FSubscriptedExp(getFExp().scalarRecordFExp(s, suffix), getFArraySubscripts().scalarize(s));
1123    }
1124
1125    public FExp FArray.scalarRecordFExp(Scalarizer s, FAccess suffix) {
1126        if (useTempVar) {
1127            return tempExp().scalarRecordFExp(s, suffix);
1128        }
1129        if (isIterArray())
1130            return super.scalarRecordFExp(s, suffix);
1131        FArray res = createEmptyNode();
1132        for (FExp e : getFExps())
1133            res.addFExp(e.scalarRecordFExp(s, suffix));
1134        return res;
1135    }
1136
1137    /**
1138     * Create an FExp that represents a specific scalar component of the given record constructor.
1139     *
1140     * @param s
1141     * @param con       the record constructor to extract an expression from
1142     *
1143     * @see FExp#scalarRecordFExp(Map, FAccess)
1144     */
1145    public FExp FAccess.scalarRecordFExpForCon(Scalarizer s, FRecordConstructor con) {
1146        throw new UnsupportedOperationException();
1147    }
1148
1149    public FExp FAccessString.scalarRecordFExpForCon(Scalarizer s, FRecordConstructor con) {
1150        return con.component(getName()).scalarize(s);
1151    }
1152
1153    public FExp FAccessFull.scalarRecordFExpForCon(Scalarizer s, FRecordConstructor con) {
1154        FAccessPart first = getFAccessPart(0);
1155        FExp arg = con.component(first.getName());
1156        if (first.hasFArraySubscripts()) {
1157            if (arg.useTempVar()) {
1158                arg = arg.tempExp(first.getFArraySubscripts());
1159            } else {
1160                arg = arg.extractArrayCell(s, first.getFArraySubscripts().createIndex());
1161            }
1162        }
1163        return copySuffix().scalarRecordFExp(s, arg);
1164    }
1165
1166    public FExp FAccess.scalarRecordFExp(Scalarizer s, FExp exp) {
1167        return exp.scalarRecordFExp(s, this);
1168    }
1169
1170    public FExp FAccessEmpty.scalarRecordFExp(Scalarizer s, FExp exp) {
1171        return exp.scalarize(s);
1172    }
1173
1174
1175    public FExp FExp.extractArrayCell(Scalarizer s, int... index) {
1176        return extractArrayCell(s, new Index(index));
1177    }
1178
1179    public FExp FExp.extractArrayCell(Scalarizer s, Index i) {
1180        if (type().isUnknown() || size().isUnknown()) {
1181            int[] ind = i.index();
1182            FExp[] subs = new FExp[ind.length];
1183            for (int k = 0; k < ind.length; k++) {
1184                subs[k] = new FIntegerLitExp(ind[k]);
1185            }
1186            return extractArrayCell(s, subs);
1187        } else {
1188            return cell(i);
1189        }
1190    }
1191
1192    public FExp FExp.extractArrayCell(Scalarizer s, FExp... subs) {
1193        addArrayUsesToIndexMap(s, subs);
1194        return dynamicFExp(scalarize(s));
1195    }
1196
1197    public FExp CommonAccessExp.extractArrayCell(Scalarizer s, Index i) {
1198        return dynamicFExp(createSpecifiedNode(i, true));
1199    }
1200
1201    public FExp FTempAccessExp.extractArrayCell(Scalarizer s, Index i) {
1202        return dynamicFExp(createNode(getFAccess().copyAndAddFas(i)));
1203    }
1204
1205    public FExp FIfExp.extractArrayCell(Scalarizer s, Index i) {
1206        FIfExp res = new FIfExp();
1207        res.setIfExp(getIfExp().scalarize(s));
1208        res.setThenExp(getThenExp().extractArrayCell(s, i));
1209        res.setElseExp(getElseExp().extractArrayCell(s, i));
1210        return dynamicFExp(res);
1211    }
1212
1213        /**
1214         * Scalarize equation and put all scalarized equations in list eqns.
1215         */
1216    public void FFunctionCallEquation.scalarize(Scalarizer.Equation s) {
1217        if (getCall().isOperatorWithoutOutputs()) {
1218            createArrayTemporaries(s);
1219            getCall().scalarizeOperatorWithoutOutputs(s);
1220        } else {
1221            getCall().createArrayTemporaries(s);
1222            getLefts().createArrayTemporaries(s);
1223        }
1224    }
1225   
1226    syn boolean FAbstractFunctionCall.isOperatorWithoutOutputs() = false;
1227    eq FReinit.isOperatorWithoutOutputs()                        = true;
1228    eq FAssert.isOperatorWithoutOutputs()                        = true;
1229    eq FTerminate.isOperatorWithoutOutputs()                     = true;
1230   
1231    public void FExp.scalarizeOperatorWithoutOutputs(Scalarizer s) {
1232        if (isArray()) {
1233            for (FExp e : getArray().iterable()) {
1234                e.scalarizeOperatorWithoutOutputs(s);
1235            }
1236        } else if (type().isRecord()) {
1237            for (FRecordComponentType frct : ((FRecordType)type()).getComponents()) {
1238                component(frct.getName()).scalarizeOperatorWithoutOutputs(s);
1239            }
1240        } else {
1241            FAbstractFunctionCall call = (FAbstractFunctionCall) scalarizeExp(s);
1242            List<FFunctionCallLeft> lefts = new List<FFunctionCallLeft>();
1243            s.add(lefts, call);
1244        }
1245    }
1246   
1247    public FExp FEndExp.scalarizeExp(Scalarizer s) {
1248        return mySize().createFExp(0);
1249    }
1250       
1251    @Override
1252    public void FIfWhenElseEquation.scalarize(Scalarizer.Equation s) {
1253        List<FAbstractEquation> l = new List<FAbstractEquation>();
1254        scalarizeList(s.block(l), getFAbstractEquations());
1255        FIfWhenElseEquation res = createEmptyNode();
1256        res.setType(getType());
1257        res.setFAbstractEquationList(l);
1258        scalarizeTestAndElse(s, res);
1259        s.add(res);
1260    }
1261
1262    @Override
1263    public void FIfEquation.scalarize(Scalarizer.Equation s) {
1264        boolean lockedBranch = false;
1265        if (getTest().variability().indexParameterOrLess()) {
1266            try {
1267                CValue cval = getTest().ceval();
1268                if (cval.hasBooleanValue()) {
1269                    if (cval.booleanValue()) {
1270                        scalarizeList(s, getFAbstractEquations());
1271                    } else if (hasElse()) {
1272                        scalarizeList(s, getElse().getFAbstractEquations());
1273                    }
1274                    lockedBranch = true;
1275                }
1276            } catch (ConstantEvaluationException e) {}
1277        }
1278        if (!lockedBranch) {
1279            super.scalarize(s);
1280        }
1281    }
1282
1283    public void FIfWhenElseEquation.scalarizeTestAndElse(Scalarizer.Equation s, FIfWhenElseEquation res) {}
1284
1285    public void FIfWhenEquation.scalarizeTestAndElse(Scalarizer.Equation s, FIfWhenElseEquation res) {
1286                FIfWhenEquation res2 = (FIfWhenEquation) res;
1287        res2.setTest(getTest().scalarize(s));
1288                if (hasElse()) {
1289                ArrayList<FExp> tempsToAddToElse = branchTemporaries;
1290                branchTemporaries = null;
1291            List<FAbstractEquation> l = new List();
1292            getElse().scalarize(s.block(l));
1293            res2.setElse((FIfWhenElseEquation)l.getChild(0));
1294                        res2.addDummyEqnsForTemps(branchTemporaries, tempsToAddToElse);
1295                }
1296        branchTemporaries = null;
1297        }
1298       
1299        public void FIfWhenElseEquation.addDummyEqnsForTemps(ArrayList<FExp> tempsForThen, ArrayList<FExp> tempsForElse) {
1300        if (tempsForThen != null) 
1301            for (FExp e : tempsForThen)
1302                e.type().addDummyEqnsForTemp(getFAbstractEquations(), e.tempVarName());
1303        }
1304   
1305    public void FIfWhenEquation.addDummyEqnsForTemps(ArrayList<FExp> tempsForThen, ArrayList<FExp> tempsForElse) {
1306        super.addDummyEqnsForTemps(tempsForThen, tempsForElse);
1307        if (hasElse())
1308            getElse().addDummyEqnsForTemps(tempsForElse, tempsForElse);
1309    }
1310   
1311    public void FType.addDummyEqnsForTemp(List<FAbstractEquation> l, String name) {
1312        if (isArray()) {
1313            FType scalar = scalarType();
1314            for (Index i : indices()) 
1315                scalar.addDummyEqnsForTemp(l, name + i);
1316        } else {
1317            l.add(new FEquation(new FAccessExp(name), zeroLiteral()));
1318        }
1319    }
1320   
1321    public void FRecordType.addDummyEqnsForTemp(List<FAbstractEquation> l, String name) {
1322        if (isArray()) {
1323            super.addDummyEqnsForTemp(l, name);
1324        } else {
1325            for (FRecordComponentType comp : getComponents())
1326                comp.getFType().addDummyEqnsForTemp(l, name + '.' + comp.getName());
1327        }
1328    }
1329       
1330        public void FExp.notifyIfWhenEquationsOfTemporaryVar() {
1331            FIfWhenEquation myIf = surroundingIfOrElse();
1332            if (myIf != null) 
1333                myIf.addBranchTemporary(this);
1334        }
1335       
1336        public void FIfWhenEquation.addBranchTemporary(FExp e) {
1337            if (branchTemporaries == null)
1338                branchTemporaries = new ArrayList<FExp>();
1339            branchTemporaries.add(e);
1340        FIfWhenEquation myIf = surroundingIfOrElse();
1341        if (myIf != null) 
1342            myIf.addBranchTemporary(e);
1343        }
1344       
1345        private ArrayList<FExp> FIfWhenEquation.branchTemporaries = null;
1346       
1347        /**
1348         * Surrounding if or else equation, if any.
1349         *
1350         * Only valid in flat tree.
1351         */
1352    inh FIfWhenEquation FExp.surroundingIfOrElse();
1353    inh FIfWhenEquation FAbstractEquation.surroundingIfOrElse();
1354    eq FClass.getChild().surroundingIfOrElse()                      = null;
1355    eq InstNode.getChild().surroundingIfOrElse()                    = null;
1356    eq Root.getChild().surroundingIfOrElse()                        = null;
1357    eq FIfWhenEquation.getFAbstractEquation().surroundingIfOrElse() = this;
1358    eq FIfWhenEquation.getElse().surroundingIfOrElse()              = this;
1359
1360        /**
1361         * Create a record constructor (or FArray of record constructors), 
1362         *        with the arguments taken from a record variable with the given name.
1363         */
1364        public FExp FType.createRecordConstructor(Scalarizer s, FExp exp) {
1365        if (isArray() || exp.isArray()) {
1366            return createRecordConstructorArray(s, exp, indices().iterator(), 0);
1367        } else {
1368            return createRecordConstructorCell(s, exp);
1369        }
1370        }
1371       
1372        /**
1373         * Create an FArray of expressions, with the arguments taken from a record
1374         * variable or member with the given name.
1375         */
1376        public FExp FType.createRecordConstructorArray(Scalarizer s, FExp exp, Iterator<Index> it, int dim) {
1377        if (isEmpty()) {
1378            return createEmptyExp();
1379        }
1380                FArray arr = new FArray();
1381                boolean last = dim == ndims() - 1;
1382                for (int i = 0, n = size().get(dim); i < n; i++) {
1383                        FExp res;
1384            if (last) {
1385                FExp subExp = exp.extractArrayCell(s, it.next());
1386                FType t = subExp.type();
1387                if (t.isUnknown()) {
1388                    t = this;
1389                }
1390                res = t.createRecordConstructorCell(s, subExp);
1391            } else {
1392                res = createRecordConstructorArray(s, exp, it, dim + 1);
1393            }
1394                        arr.addFExp(res);
1395                }
1396                return arr;
1397        }
1398       
1399    syn boolean FType.isEmpty() = size().isEmpty();
1400    syn FExp FType.createEmptyExp() {
1401        Size s = size();
1402        List<FExp> dims = new List<FExp>();
1403        for (int i = 0, n = s.ndims(); i < n ; i++) {
1404            dims.add(s.createFExp(i));
1405        }
1406        return new FFillExp(dims, zeroLiteral());
1407    }
1408       
1409        /**
1410         * Create a record constructor with the arguments taken from a record
1411         *        variable with the given name.
1412         *
1413         * Assumes that <code>name</code> refers to a non-array variable
1414         * (or a specific cell in an array variable).
1415         */
1416    public FExp FType.createRecordConstructorCell(Scalarizer s, FExp exp) {
1417        return exp.scalarize(s);
1418    }
1419
1420    public FExp FRecordType.createRecordConstructorCell(Scalarizer s, FExp exp) {
1421                FRecordConstructor rc = new FRecordConstructor(new FRecordAccess(getName()), new List());
1422                for (FRecordComponentType comp : getComponents()) {
1423             FExp next = exp.scalarRecordFExp(s, comp.getName());
1424             if (exp.type().isUnknown() || exp.useTempVar) {
1425                 // Work around for expanding FTempAccessExp which doesnt know its type
1426                 next = comp.getFType().createRecordConstructor(s, exp.dynamicFExp(next));
1427             }
1428             rc.addArg(next);
1429                }
1430                return rc;
1431        }
1432
1433        /* Scalarization of expressions is needed in order to compute a simple
1434         * scalar expression from an expression with ndims==0. For example, an
1435         * CommonAccess 'x[2]' needs to be marked as scalarized, and the expression
1436         * scalar(x*A*x) needs to be replaced by a double sum.
1437         */
1438
1439        /**
1440         * Flag that signals that this expression should be replaced with a use of a temporary variable.
1441         */
1442        protected boolean FExp.useTempVar = false;
1443    syn boolean FExp.useTempVar() = useTempVar;
1444       
1445        /**
1446         * Scalarize expressions, replacing array expressions with FArrays of scalarized subexpressions.
1447         *
1448         * The FArrays are needed because function calls need arrays to be passed as arrays.
1449         */
1450    public FExp FExp.scalarize(Scalarizer s) {
1451        FExp exp = useTempVar ? tempExp() : this;
1452        if (scalarizeExpanded(s)) {
1453            return type().createRecordConstructor(s, exp);
1454        } else {
1455            return exp.scalarizeExp(s);
1456        }
1457    }
1458   
1459    public FExp FFunctionCall.scalarize(Scalarizer s) {
1460        FExp exp = super.scalarize(s);
1461        indexNames = null;
1462        return exp;
1463    }
1464
1465    syn boolean FExp.scalarizeExpanded(Scalarizer s);
1466    eq FExp           .scalarizeExpanded(Scalarizer s) = isComposite() && indexNames == null && s.unroll() && !(useTempVar && isForIndexExp());
1467    eq CommonAccessExp.scalarizeExpanded(Scalarizer s) = super.scalarizeExpanded(s) && (!s.inFunction() || isSlice());
1468    eq FFunctionCall  .scalarizeExpanded(Scalarizer s) = super.scalarizeExpanded(s) && ((useTempVar && !s.inFunction()) || isVectorized());
1469    eq FIfExp         .scalarizeExpanded(Scalarizer s) = super.scalarizeExpanded(s) && !isFunctionCallIO()
1470            && !type().isRecord(); /* Workaround for test RecordScalarize52 */
1471   
1472    syn boolean FFunctionCall.isVectorized() = false;
1473    eq FVectorFunctionCall.isVectorized() = true;
1474
1475        /**
1476         * Scalarize expressions.
1477         */
1478        public FExp FExp.scalarizeExp(Scalarizer s) {
1479        return treeCopy();
1480        }
1481
1482        public FExp FArray.scalarizeExp(Scalarizer s) {
1483                if (isIterArray())
1484                        return getFExp(0).scalarize(s);
1485                FArray res = new FArray();
1486                for (FExp e : getFExps())
1487                        res.addFExpNoTransform(e.scalarize(s));
1488                return res;
1489        }
1490
1491    public FExp FAccessExp.scalarizeExp(Scalarizer s) {
1492        return s.scalarizeAccessExp(this);
1493    }
1494
1495    public FExp FTempAccessExp.scalarizeExp(Scalarizer s) {
1496        if (indexNames != null) {
1497            FAccess access = getFAccess().scalarize(s);
1498            access = access.asFAccessFull().addFArraySubscripts(createIndexNameFas());
1499            return setLocationOf(new FAccessExp(access));
1500        }
1501        return super.scalarizeExp(s);
1502    }
1503
1504    @Override
1505    public FExp FDerExp.scalarizeExp(Scalarizer s) {
1506        return new FDerExp(getFAccess().scalarize(s, indexNames), order());
1507    }
1508   
1509    @Override
1510    public FExp FPreExp.scalarizeExp(Scalarizer s) {
1511        return new FPreExp(getFAccess().scalarize(s, indexNames));
1512    }
1513
1514    public FAccess FAccess.scalarize(Scalarizer s, FExp[] indexNames) {
1515        FAccess access = scalarize(s);
1516        if (indexNames != null) {
1517            access = access.asFAccessFull().addFArraySubscripts(getExpandedSubscripts().scalarize(s));
1518        }
1519        return access;
1520    }
1521
1522        public abstract FAccess FAccess.scalarize(Scalarizer s);
1523       
1524        public FAccess FAccessEmpty.scalarize(Scalarizer s) {
1525                return new FAccessEmpty();
1526        }
1527       
1528        public FAccess FAccessString.scalarize(Scalarizer s) {
1529                return new FAccessString(getName());
1530        }
1531
1532    public FRecordAccess FRecordAccess.scalarize(Scalarizer s) {
1533        return new FRecordAccess(getName());
1534    }
1535
1536    public FAccess FAccessFull.scalarize(Scalarizer s) {
1537        if (!inFunction() && !isGlobalAccess()) {
1538            StringBuilder name = new StringBuilder();
1539            getFAccessPart(0).scalarizeAsString(name);
1540            for (int i = 1; i < getNumFAccessPart(); i++) {
1541                name.append(".");
1542                getFAccessPart(i).scalarizeAsString(name);
1543            }
1544            return new FAccessString(name.toString());
1545        } else {
1546            FAccessFull access = new FAccessFull(new List());
1547            for (FAccessPart accessp : getFAccessParts()) 
1548                access.addFAccessPart(accessp.scalarize(s));
1549            return access;
1550        }
1551    }
1552
1553    public void FAccessPart.scalarizeAsString(StringBuilder sb) {
1554        sb.append(name());
1555    }
1556
1557    public void FAccessPartArray.scalarizeAsString(StringBuilder sb) {
1558        super.scalarizeAsString(sb);
1559        sb.append(getFArraySubscripts().createIndex());
1560    }
1561
1562    public FAccessPart FAccessPart.scalarize(Scalarizer s) {
1563        return new FAccessPart(getName());
1564    }
1565   
1566    public FAccessPartArray FAccessPartArray.scalarize(Scalarizer s) {
1567        return new FAccessPartArray(getName(), getFArraySubscripts().scalarize(s));
1568    }
1569
1570    public FArraySubscripts FArraySubscripts.scalarize(Scalarizer s) {
1571        return treeCopy();
1572    }
1573
1574    public FArraySubscripts FArrayExpSubscripts.scalarize(Scalarizer s) {
1575        FArrayExpSubscripts fas = new FArrayExpSubscripts();
1576        for (FSubscript fs : getFSubscripts()) {
1577            fas.addFSubscript(fs.scalarize(s));
1578        }
1579        return fas;
1580    }
1581
1582    public FSubscript FSubscript.scalarize(Scalarizer s) {
1583        return treeCopy();
1584    }
1585   
1586    public FSubscript FColonSubscript.scalarize(Scalarizer s) {
1587        if (indexName == null) {
1588            return treeCopy();
1589        }
1590        return indexName.treeCopy().createFSubscript();
1591    }
1592   
1593    public FSubscript FExpSubscript.scalarize(Scalarizer s) {
1594        return getFExp().scalarize(s).createFSubscript();
1595    }
1596
1597
1598
1599
1600    public FExp FIfExp.scalarizeExp(Scalarizer s) {
1601        if (getIfExp().variability().indexParameterOrLess()) {
1602            try {
1603                return cevalSelectExp().scalarize(s);
1604            } catch (ConstantEvaluationException e) {}
1605        }
1606        return new FIfExp(getIfExp().scalarize(s),
1607                getThenExp().scalarize(s),
1608                getElseExp().scalarize(s));
1609    }
1610
1611        public FExp FMulExp.scalarizeExp(Scalarizer s) {
1612                if (getLeft().isArray() && !isArray()) 
1613                        return dynamicFExp(composeMulScalarCellExp(Index.NULL)).scalarize(s);
1614                else
1615                        return super.scalarizeExp(s);
1616        }
1617       
1618        public FExp FRangeExp.scalarizeExp(Scalarizer s) {
1619        if (indexNames == null) {
1620            return treeCopy();
1621        }
1622        return scalarizeWithIndex(s, indexNames[0].treeCopy());
1623        }
1624       
1625    public FExp FLinspace.scalarizeExp(Scalarizer s) {
1626        FExp index = new FSubExp(indexNames[0].fullCopy(), new FIntegerLitExp(1));
1627        FExp len  = new FSubExp(getStopExp().fullCopy(), getStartExp().fullCopy());
1628        FExp step = new FDivExp(len, new FSubExp(getN().fullCopy(), new FIntegerLitExp(1)));
1629        FExp res = new FAddExp(getStartExp().fullCopy(), new FMulExp(index, step));
1630        return res;
1631    }
1632
1633       
1634        public FExp FSizeExp.scalarizeExp(Scalarizer s) {
1635        if (getFExp().isSlice() || !getFExp().size().isUnknown(dimension())) {
1636            return getFExp().size().scalarize(s, dimension());
1637        } else {
1638            return new FSizeExp(getFExp().scalarize(s), new Opt<FExp>(getDim().scalarize(s)));
1639        }
1640        }
1641       
1642    public FExp FUnknownSizeExp.scalarizeExp(Scalarizer s) {
1643        return new FSizeExp(getFExp().scalarize(s), new Opt<FExp>(getDim().scalarize(s)));
1644    }
1645       
1646        public FExp FNdimsExp.scalarizeExp(Scalarizer s) {
1647                return ceval().buildLiteral();
1648        }
1649
1650    public FExp FSubscriptedExp.scalarizeExp(Scalarizer s) {
1651        if (indexVariability().indexParameterOrLess() && !getFExp().size().isUnknown()) {
1652            try {
1653                return select().scalarize(s);
1654            } catch (ConstantEvaluationException e) {
1655               
1656            }
1657        }
1658        FArraySubscripts fas = getFArraySubscripts().scalarize(s);
1659        if (inFunction()) {
1660            return new FAccessExp(getFExp().tempVarName(), fas);
1661        } else {
1662            FSubscriptedExp res = createEmptyNode();
1663            res.setFExp(getFExp().scalarize(s));
1664            res.setFArraySubscripts(fas);
1665            return res;
1666        }
1667    }
1668
1669    public FExp FCardinality.scalarizeExp(Scalarizer s) {
1670        return new FIntegerLitExp(getFExp().cardinalityValue());
1671    }
1672
1673        public FExp FMinMaxExp.scalarizeExp(Scalarizer s) {
1674                if (hasY())
1675                        return createNode(getX().scalarize(s), getY().scalarize(s));
1676                else
1677                        return getX().reduceToScalarized(this, s);
1678        }
1679       
1680        public FExp FReductionExp.scalarizeExp(Scalarizer s) {
1681                if (getFExp().size().numElements() == 0)
1682                        return reduceStartValue().buildLiteral();
1683                else
1684                        return getFExp().reduceToScalarized(scalarReduceExp(), s);
1685        }
1686       
1687        syn FBinExp FReductionExp.scalarReduceExp();
1688        eq FSumExp.scalarReduceExp()     = new FAddExp();
1689        eq FProductExp.scalarReduceExp() = new FMulExp();
1690       
1691        public FExp FIterExp.scalarizeExp(Scalarizer s) {
1692                return getFExp().scalarize(s);
1693        }
1694       
1695    /**
1696     * Scalarize an expression by recursively scalarizing and combining the contents in its Array.
1697     *
1698     * New nodes are created with <code>template.createNodeBinary()</code>.
1699     */
1700    public FExp FExp.reduceToScalarized(FExp template, Scalarizer s) {
1701        if (isArray()) {
1702            java.util.List<FExp> scalarizedExps = new ArrayList<FExp>();
1703            Iterator<FExp> it = getArray().iteratorFExp();
1704            while (it.hasNext()) {
1705                scalarizedExps.add(it.next().scalarize(s));
1706            }
1707            return createBalancedBinaryTree(template, scalarizedExps);
1708        } else {
1709            return scalarize(s);
1710        }
1711    }
1712
1713    /**
1714     * Constructs a balanced binary tree based on the expression list exps with
1715     * the operation as specified by template.
1716     */
1717    public static FExp FExp.createBalancedBinaryTree(FExp template, java.util.List<FExp> exps) {
1718        return createBalancedBinaryTree(template, exps, 0, exps.size());
1719    }
1720
1721    private static FExp FExp.createBalancedBinaryTree(FExp template, java.util.List<FExp> exps, int start, int end) {
1722        if (start == end) {
1723            return null;
1724        }
1725        if (start == end - 1) {
1726            return exps.get(start);
1727        }
1728        // We want a left heavy tree, hence the modulo part
1729        int half = (start + end) / 2 + (start + end) % 2;
1730        FExp left = createBalancedBinaryTree(template, exps, start, half);
1731        FExp right = createBalancedBinaryTree(template, exps, half, end);
1732        return template.createNodeBinary(left, right);
1733    }
1734
1735        public FExp FBinExp.scalarizeExp(Scalarizer s) { return createNode(getLeft().scalarize(s), getRight().scalarize(s)); }
1736        public FExp FUnaryExp.scalarizeExp(Scalarizer s) { return createNode(getFExp().scalarize(s)); }
1737        public FExp FMathematicalFunctionCall.scalarizeExp(Scalarizer s) { return createNode(getFExp().scalarize(s)); }
1738        public FExp FAtan2Exp.scalarizeExp(Scalarizer s)     { return createNode(getFExp().scalarize(s), getY().scalarize(s)); }
1739        public FExp FUnaryBuiltIn.scalarizeExp(Scalarizer s) { return createNode(getFExp().scalarize(s)); }
1740        public FExp FTranspose.scalarizeExp(Scalarizer s)    { return getFExp().scalarize(s); }
1741       
1742        public FExp FNoArgBuiltIn.scalarizeExp(Scalarizer s) { return createEmptyNode(); }
1743        public FExp FEventGenExp.scalarizeExp(Scalarizer s) { return createNode(getX().scalarize(s)); }
1744        public FExp FBinEventGenExp.scalarizeExp(Scalarizer s) { return createNode(getX().scalarize(s),getY().scalarize(s)); }
1745       
1746        public FExp FLitExp.scalarizeExp(Scalarizer s) { return (FLitExp) fullCopy(); }
1747        public FExp FEnumLitExp.scalarizeExp(Scalarizer s) { 
1748            return inArraySubscripts() ? new FIntegerLitExp(ceval().intValue()) : super.scalarizeExp(s);
1749        }
1750        public FExp FBooleanLitExp.scalarizeExp(Scalarizer s) { 
1751            return inArraySubscripts() ? new FIntegerLitExp(ceval().intValue()) : super.scalarizeExp(s);
1752    }
1753       
1754        public FExp FSmoothExp.scalarizeExp(Scalarizer s)     { return new FSmoothExp(getOrder().scalarize(s), getFExp().scalarize(s)); }
1755        public FExp FSampleExp.scalarizeExp(Scalarizer s)     { return new FSampleExp(getOffset().scalarize(s), getInterval().scalarize(s)); }
1756        public FExp FSemiLinearExp.scalarizeExp(Scalarizer s) { return new FSemiLinearExp(getX().scalarize(s), getPosSlope().scalarize(s), getNegSlope().scalarize(s)); }
1757        public FExp FHomotopyExp.scalarizeExp(Scalarizer s)   { return new FHomotopyExp(getActual().scalarize(s), getSimplified().scalarize(s)); }
1758       
1759        public FExp FStringExp.scalarizeExp(Scalarizer s)  {
1760                FStringExp scalarized = new FStringExp();
1761                scalarized.setValue(getValue().scalarize(s));
1762                if (hasMinimumLength())
1763                        scalarized.setMinimumLength(getMinimumLength().scalarize(s));
1764                if (hasLeftJustified())
1765                        scalarized.setLeftJustified(getLeftJustified().scalarize(s));
1766                if (hasSignificantDigits())
1767                        scalarized.setSignificantDigits(getSignificantDigits().scalarize(s));
1768                if (hasFormat())
1769                        scalarized.setFormat(getFormat().scalarize(s));
1770                return scalarized;
1771        }
1772       
1773        public FExp FRecordConstructor.scalarizeExp(Scalarizer s) {
1774        FRecordConstructor rc = new FRecordConstructor(getRecord().scalarize(s), new List());
1775        for (FExp arg : getArgs()) {
1776            rc.addArg(arg.scalarize(s));
1777        }
1778                return rc;
1779        }
1780       
1781        public FExp FZeros.scalarizeExp(Scalarizer s) {
1782                return new FIntegerLitExp(0);
1783        }
1784       
1785        public FExp FOnes.scalarizeExp(Scalarizer s) {
1786                return new FIntegerLitExp(1);
1787        }
1788   
1789    public FExp FScalarExp.scalarizeExp(Scalarizer s) {
1790        int[] t = new int[getFExp().ndims()];
1791        Arrays.fill(t, 1);
1792        return dynamicFExp(getFExp().extractArrayCell(s, new Index(t))).scalarize(s);
1793    }
1794   
1795        public FExp FFillExp.scalarizeExp(Scalarizer s) {
1796                return getFillExp().fullCopy();
1797        }
1798       
1799    public FFunctionCall FFunctionCall.scalarizeExp(Scalarizer s) {
1800        List<FExp> args = new List<FExp>();
1801        for (FExp arg : getArgs()) {
1802            args.add(arg.scalarize(s));
1803        }
1804        FFunctionCall res = createScalarized(getName().treeCopy(), args, null);
1805        res.setFType(getFType().scalarize(s, res));
1806        return res;
1807    }
1808   
1809    public abstract FType FType.scalarize(Scalarizer s, FExp context);
1810
1811    @Override
1812    public FType FCellType.scalarize(Scalarizer s, FExp context) {
1813        FCellType res = treeCopy();
1814        res.scalarizeTypeSizes(s, context);
1815        return res;
1816    }
1817
1818    @Override
1819    public FType FArrayType.scalarize(Scalarizer s, FExp context) {
1820        FArrayType res = treeCopy();
1821        for (int i = 0; i < getFExps().numChildren(); i++) {
1822            res.setFExp(getFExp(i).scalarize(s), i);
1823        }
1824        return res;
1825    }
1826   
1827    @Override
1828    public FType FFunctionType.scalarize(Scalarizer s, FExp context) {
1829        List<FRecordComponentType> inputs = new List<FRecordComponentType>();
1830        for (FRecordComponentType frct : getInputs()) {
1831            inputs.add(frct.scalarize(s, context));
1832        }
1833        List<FRecordComponentType> outputs = new List<FRecordComponentType>();
1834        for (FRecordComponentType frct : getOutputs()) {
1835            outputs.add(frct.scalarize(s, context));
1836        }
1837        FFunctionType res = new FFunctionType(getSize(), getName(), inputs, outputs, getFClass());
1838        res.setSize(getSize().scalarize(s, context));
1839        return res;
1840    }
1841   
1842    @Override
1843    public FType FRecordType.scalarize(Scalarizer s, FExp context) {
1844        List<FRecordComponentType> comps = new List<FRecordComponentType>();
1845        for (FRecordComponentType frct : getComponents()) {
1846            comps.add(frct.scalarize(s, context));
1847        }
1848        FRecordType res = new FRecordType(getSize(), getName(), comps, getFClass());
1849        res.setSize(getSize().scalarize(s, context));
1850        return res;
1851    }
1852
1853    public FRecordComponentType FRecordComponentType.scalarize(Scalarizer s, FExp context) {
1854        FRecordComponentType res = treeCopy();
1855        res.setFType(getFType().scalarize(s, context));
1856        return res;
1857    }
1858
1859    public abstract void FType.scalarizeTypeSizes(Scalarizer s, FExp context);
1860
1861    @Override
1862    public void FArrayType.scalarizeTypeSizes(Scalarizer s, FExp context) {
1863        scalarizeFExps(s);
1864    }
1865
1866    private void FArrayType.scalarizeFExps(Scalarizer s) {
1867        for (int i = 0; i < getNumFExp(); i++) {
1868            getFExp(i).createArrayTemporaries(s);
1869            setFExp(getFExp(i).scalarize(s), i);
1870        }
1871    }
1872
1873    @Override
1874    public void FCellType.scalarizeTypeSizes(Scalarizer s, FExp context) {
1875        setSize(getSize().scalarize(s, context));
1876    }
1877   
1878    public Size Size.scalarize(Scalarizer s, FExp context) {
1879        return this;
1880    }
1881   
1882    @Override
1883    public Size MutableSize.scalarize(Scalarizer s, FExp context) {
1884        MutableSize res = new MutableSize(ndims());
1885        for (int i = 0; i < exps.length; i++) {
1886            res.size[i] = size[i];
1887            if (exps[i] != null) {
1888                res.exps[i] = exps[i].scalarize(s);
1889                context.dynamicFExp(res.exps[i]);
1890            }
1891        }
1892        return res;
1893    }
1894   
1895    public FExp Size.scalarize(Scalarizer s, int i) {
1896        return createFExp(i);
1897    }
1898   
1899    @Override
1900    public FExp MutableSize.scalarize(Scalarizer s, int i) {
1901        if (exps[i] != null) {
1902            return exps[i].scalarize(s);
1903        } else {
1904            return super.scalarize(s, i);
1905        }
1906    }
1907   
1908    /**
1909     * Create a scalarized list of size expressions.
1910     * Also performs createArrayTemporaries.
1911     */
1912    public List<FExp> Size.scalarizedSizeExpressions(Scalarizer s) {
1913        List<FExp> sizes = new List<FExp>();
1914        for (int i = 0; i < ndims(); i++) {
1915            createArrayTemporaries(s, i);
1916            sizes.add(scalarize(s, i));
1917        }
1918        return sizes;
1919    }
1920   
1921    protected FFunctionCall FFunctionCall.createScalarized(FAccess name, List<FExp> args, FType type) {
1922        return setLocationOf(new FFunctionCall(name, args, type)); 
1923    }
1924   
1925    protected FFunctionCall FPartialFunctionCall.createScalarized(FAccess name, List<FExp> args, FType type) {
1926        return new FPartialFunctionCall(name, args, type, getArgNames().treeCopy()); 
1927    }
1928   
1929        public FAssert FAssert.scalarizeExp(Scalarizer s) {
1930                Opt level = hasLevel() ? new Opt(getLevel().scalarize(s)) : new Opt();
1931        return createNode(getTest().scalarize(s), getMsg().scalarize(s), level);
1932        }
1933
1934    public FReinit FReinit.scalarizeExp(Scalarizer s) {
1935        return new FReinit(getVar().scalarize(s), getFExp().scalarize(s));
1936    }
1937
1938    public FDelayExp FDelayExp.scalarizeExp(Scalarizer s) {
1939        Opt max = hasMax() ? new Opt(getMax().scalarize(s)) : new Opt();
1940        return createNode(getFExp().scalarize(s), getDelay().scalarize(s), max);
1941    }
1942   
1943    public FSpatialDistExp FSpatialDistExp.scalarizeExp(Scalarizer s) {
1944        return new FSpatialDistExp(getIn0().scalarize(s), getIn1().scalarize(s),
1945                getX().scalarize(s), getPositiveVelocity().scalarize(s),
1946                getInitialPoints().scalarize(s), getInitialValues().scalarize(s));
1947    }
1948
1949    public FForIndex FForIndex.scalarize(Scalarizer s) {
1950        return new FForIndex(getFVariable().fullCopy(), getFExp().scalarizeIndexExp(s));
1951    }
1952
1953        /**
1954         * Scalarize the expression of an FForIndex.
1955         */
1956        public FExp FExp.scalarizeIndexExp(Scalarizer s) {
1957                return scalarize(s);
1958        }
1959       
1960        public FRangeExp FRangeExp.scalarizeIndexExp(Scalarizer s) {
1961                List<FExp> exps = new List<FExp>();
1962                for (FExp e : getFExps())
1963                        exps.add(e.scalarize(s));
1964                return new FRangeExp(exps);
1965        }
1966
1967    public FExInStream FExInStream.scalarizeExp(Scalarizer s) {
1968        FExInStream res = new FExInStream(getDefault().scalarize(s), getEps().scalarize(s), new List<FExp>());
1969        for (FExp e : getVars()) {
1970            res.addVarNoTransform(e.scalarize(s));
1971        }
1972        return res;
1973    }
1974
1975        public void ConnectionSetManager.scalarize() {
1976                for (ConnectionSet set : list)
1977                        set.scalarize();
1978                Map<String, CSENameMapEntry> oldCSEStreamMap = cseStreamMap;
1979                cseStreamMap = new HashMap<String, CSENameMapEntry>();
1980                for (CSENameMapEntry entry : oldCSEStreamMap.values()) {
1981            if (entry.outsideCSE != null)
1982                updateCSEMapEntry(entry.outsideCSE, entry.outside);
1983            if (entry.insideCSE != null)
1984                updateCSEMapEntry(entry.insideCSE, entry.inside);
1985                }
1986        }
1987       
1988        public void ConnectionSet.scalarize() {
1989                for (ConnectionSetEntry e : this)
1990                        e.scalarize();
1991        }
1992       
1993        public void ConnectionSetEntry.scalarize() {
1994                if (access.accessNdims() == 0) {
1995                        // Can't use FAccess.scalarize(), since it relies on rewrites
1996                        access = new FAccessString(access.scalarName());
1997                } else {
1998                        Indices ind = Indices.createFromFas(access.getFArraySubscripts());
1999                        scalarNames = new String[ind.numElements()];
2000                        int j = 0;
2001                        for (Index i : ind)
2002                                scalarNames[j++] = access.copyAndAddFas(i.createFArraySubscripts()).scalarName();
2003                }
2004        }
2005
2006    syn lazy List<FStatement> FForStmt.getUnrolledForStmtList() {
2007        List<FStatement> unrolledForStmts = new List<>();
2008       
2009        FVariable index = getIndex().getFVariable();
2010        FExp loopExp = getIndex().getFExp();
2011        for (FExp e : loopExp.getArray().iterable()) {
2012            UnrollingScalarizer s = new UnrollingScalarizer(unrolledForStmts, index, e);
2013            scalarizeStmtList(s, getForStmts());
2014        }
2015        return unrolledForStmts;
2016    }
2017   
2018    public class FForStmt {
2019        private class UnrollingScalarizer extends Scalarizer.Algorithm {
2020           
2021            private FAbstractVariable indexVariable;
2022            private FExp indexValue;
2023           
2024            public UnrollingScalarizer(List<FStatement> stmts, FAbstractVariable indexVariable, FExp indexValue) {
2025                super(new List<FFunctionVariable>(), stmts, new ForNames(), true, true, Variability.DISCRETE);
2026                this.indexVariable = indexVariable;
2027                this.indexValue = indexValue;
2028            }
2029           
2030            @Override
2031            public FExp scalarizeAccessExp(FAccessExp accessExp) {
2032                if (indexVariable.equals(accessExp.myFV())) {
2033                    return accessExp.setLocationOf(indexValue);
2034                }
2035                return super.scalarizeAccessExp(accessExp);
2036            }
2037           
2038            @Override
2039            public Algorithm block(List clauses) {
2040                return new UnrollingScalarizer(clauses, indexVariable, indexValue);
2041            }
2042           
2043            @Override
2044            public Algorithm block(List vars, List clauses) {
2045                return new UnrollingScalarizer(clauses, indexVariable, indexValue);
2046            }
2047        }
2048    }
2049}
Note: See TracBrowser for help on using the repository browser.