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

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

#5843 Removes CausalityConnectorPrefix from parameters when scalarizing records.

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