source: branches/dev-mo-2530/Compiler/ModelicaMiddleEnd/src/jastadd/scalarization/Scalarization.jrag @ 13919

Last change on this file since 13919 was 13919, checked in by molsson, 6 weeks ago

Merged revision(s) 13884, 13917 from branches/dev-mo-2278-merge

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