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

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

#5862 Fixed bug where empty array subscripts added during scalarization lead to c-compilation error.

File size: 45.4 KB
Line 
1/*
2    Copyright (C) 2016 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
17aspect FunctionScalarization {
18   
19    /**
20     * Scalarize the function, replacing all array assignments with separate scalar
21     *        assignments and scalarize all expressions.
22     */
23    public void FFunctionDecl.scalarize(boolean unroll) {
24        List<FStatement> stmts = new List<FStatement>();
25        List<FAttribute> attrs = new List<FAttribute>();
26        try {
27            FStatement.scalarizeStmtList(Scalarizer.function(getFFunctionVariables(), stmts, unroll), getFAlgorithm().getFStatements());
28        } catch (ModelicaException e) {
29            throw e;
30        } catch (Exception e) {
31            throw new org.jmodelica.util.exceptions.InternalCompilerError("Exception caught while scalarizing function'" + name() + "'", e);
32        }
33        setFAlgorithm(new FAlgorithm(stmts));
34        clearScalarized();  // Functions need scalarized = false in FAccesss
35        flushAllRecursive();
36    }
37   
38    /**
39     * Post processing FFunctionDecls after scalarization.
40     * Clear the scalarized flag for all FAccesss.
41     * Rewrite FTempAccessExp to FAccessExp
42     */
43    public void ASTNode.clearScalarized() {
44        for (ASTNode node : this)
45            node.clearScalarized();
46    }
47   
48    public void FAccess.clearScalarized() {
49        scalarized = false;
50    }
51   
52    private boolean FTempAccessExp.clearScalarized = false;
53    public void FTempAccessExp.clearScalarized() {
54        super.clearScalarized();
55        clearScalarized = true;
56    }
57   
58    rewrite FTempAccessExp {
59        when (clearScalarized) to FAccessExp new FAccessExp(getFAccess());
60    }
61   
62    /**
63     * Should this expression be extracted into its own statement?
64     */
65    syn boolean FExp.extractTemp(Scalarizer s);
66    eq FExp               .extractTemp(Scalarizer s) =
67            (!s.unroll() && extractTempArray() && extractTempContext()) || extractForIndexTemp();
68   
69    eq FAccessExp         .extractTemp(Scalarizer s) = super.extractTemp(s) && isSlice() && !isFunctionCallLeft();
70    eq FFunctionCall      .extractTemp(Scalarizer s) = isFunctionCallClause() || 
71            ((isFVectorFunctionCallArg() || !isFunctionCallIO()) &&
72                (isComposite() || isForIndexExp()));
73       
74    eq FSpatialDistExp    .extractTemp(Scalarizer s) = isFunctionCallClause() || super.extractTemp(s);
75    eq FVectorFunctionCall.extractTemp(Scalarizer s) = true;
76   
77   
78    syn boolean FExp .extractTempArray();
79    eq FExp          .extractTempArray() = isArray();
80    eq FMulExp       .extractTempArray() = getLeft().isArray() || getRight().isArray();
81    eq FReductionExp .extractTempArray() = getFExp().isArray();
82    eq FMinMaxExp    .extractTempArray() = getX().isArray();
83    eq FTempAccessExp.extractTempArray() = false;
84    eq FIfExp        .extractTempArray() = false;
85   
86    syn boolean FExp    .extractTempContext();
87    eq FExp             .extractTempContext() = isFunctionCallIO();
88    eq FMulExp          .extractTempContext() = isFunctionCallIO() || !isElementWise();
89    eq FArray           .extractTempContext() = !keepSimple();
90    eq FReductionExp    .extractTempContext() = true;
91    eq FMinMaxExp       .extractTempContext() = true;
92    eq FSizeExp         .extractTempContext() = true;
93    eq FAbstractCat     .extractTempContext() = true;
94    eq FAbstractDiagonal.extractTempContext() = true;
95    eq FVectorExp       .extractTempContext() = true;
96    eq FMatrixExp       .extractTempContext() = true;
97    eq FCross           .extractTempContext() = true;
98    eq FSkew            .extractTempContext() = true;
99    eq FSymmetric       .extractTempContext() = true;
100    eq FOuterProduct    .extractTempContext() = true;
101   
102    syn boolean FExp.extractForIndexTemp() = isForIndexExp();
103    eq FRangeExp.extractForIndexTemp()     = false;
104   
105    syn boolean FArray.keepSimple() = isFunctionCallIO() && !isFVectorFunctionCallArg()
106                && ndims() == 1 && !isIterArray() && type().isPrimitive();
107   
108   
109    inh boolean FExp.isFunctionCallIO();
110    eq BaseNode.getChild().isFunctionCallIO()         = false;
111    eq FFunctionCall.getArg().isFunctionCallIO()      = true;
112    eq FFunctionCallLeft.getFExp().isFunctionCallIO() = true;
113    eq FIfExp.getChild().isFunctionCallIO()           = isFunctionCallIO();
114   
115    inh boolean FExp.isForIndexExp();
116    eq BaseNode.getChild().isForIndexExp() = false;
117    eq FForIndex.getFExp().isForIndexExp() = true;
118   
119    inh boolean FExp.isFVectorFunctionCallArg();
120    eq BaseNode.getChild().isFVectorFunctionCallArg()          = false;
121    eq FVectorFunctionCall.getArg().isFVectorFunctionCallArg() = true;
122   
123    syn boolean FAssignStmt.extractTemp(Scalarizer.Algorithm s) {
124        if (type().isArray()) {
125            Set<FAbstractVariable> left = getLeft().usesInScalarizedExp(s);
126            Set<FAbstractVariable> right = getRight().usesInScalarizedExp(s);
127            for (FAbstractVariable fv : left) {
128                if (right.contains(fv)) {
129                    return true;
130                }
131            }
132        }
133        return false;
134    }
135   
136    syn Set<FAbstractVariable> FExp.usesInScalarizedExp(Scalarizer.Algorithm s) {
137        Set<FAbstractVariable> res = new HashSet<FAbstractVariable>();
138        usesInScalarizedExp(s, res);
139        return res;
140    }
141   
142    public void ASTNode.usesInScalarizedExp(Scalarizer.Algorithm s, Set<FAbstractVariable> res) {
143        for (ASTNode n : this)
144            n.usesInScalarizedExp(s, res);
145    }
146   
147    public void FExp.usesInScalarizedExp(Scalarizer.Algorithm s, Set<FAbstractVariable> res) {
148        if (!extractTemp(s)) {
149            super.usesInScalarizedExp(s, res);
150        }
151    }
152   
153    public void FAccessExp.usesInScalarizedExp(Scalarizer.Algorithm s, Set<FAbstractVariable> res) {
154        res.add(myFV());
155    }
156   
157    public void FSizeExp.usesInScalarizedExp(Scalarizer.Algorithm s, Set<FAbstractVariable> res) {
158       
159    }
160   
161    /**
162     * Traverser for {@link FExp#createArrayTemporaries(Scalarizer s)}.
163     */
164    public void ASTNode.createArrayTemporaries(Scalarizer s) {
165        for (ASTNode n : this)
166            n.createArrayTemporaries(s);
167    }
168   
169    public void Array.createArrayTemporaries(Scalarizer s);
170   
171    public void ArrayExp.createArrayTemporaries(Scalarizer s) {
172        super.createArrayTemporaries(s);
173    }
174   
175    /**
176     * Finds, extracts, and replaces expressions with temporaries
177     */
178    public void FExp.createArrayTemporaries(Scalarizer s) {
179        if (extractTemp(s)) {
180            if (!s.unroll()) {
181                unknownFunctionArrayTemporaries(s);
182                useTempVar = true;
183            } else {
184                knownArrayTemporaries(s);
185            }
186        } else {
187            createArrayTemporariesInChildren(s);
188        }
189    }
190   
191    public void FExp.createArrayTemporariesInChildren(Scalarizer s) {
192        for (ASTNode n : this) {
193            n.createArrayTemporaries(s);
194        }
195    }
196   
197    public void FIfExp.createArrayTemporariesInChildren(Scalarizer s) {
198        if (inFAlgorithm()) {
199            List thenClauses = new List();
200            List elseClauses = new List();
201            getIfExp().createArrayTemporaries(s);
202            getThenExp().createArrayTemporaries(s.block(thenClauses));
203            getElseExp().createArrayTemporaries(s.block(elseClauses));
204            if (thenClauses.getNumChild() > 0 || elseClauses.getNumChild() > 0) {
205                List<FIfWhenClause> cl = new List<FIfWhenClause>();
206                cl.add(new FIfClause(getIfExp().scalarize(s), thenClauses));
207                ((Scalarizer.Algorithm)s).add(new FIfStmtTemp(cl, elseClauses));
208            }
209        } else {
210            createArrayTemporariesIfBranch(null, s);
211        }
212    }
213   
214    public void FExp.createArrayTemporariesIfBranch(FExp ifExp, Scalarizer s) {
215        List thenClauses = new List();
216        List elseClauses = new List();
217        List<FAbstractVariable> thenVars = new List<FAbstractVariable>();
218        createArrayTemporaries(s.block(thenVars, thenClauses));
219        if (thenClauses.getNumChild() > 0) {
220            if (inFAlgorithm()) {
221                List<FIfWhenClause> cl = new List<FIfWhenClause>();
222                cl.add(new FIfClause(ifExp, thenClauses));
223                s.add(new FIfStmtTemp(cl, elseClauses));
224            } else {
225                for (FAbstractVariable fv : thenVars) {
226                    elseClauses.add(new FEquation(fv.createAccessExp(), fv.type().zeroLiteral()));
227                }
228                FElseEquation elseClause = new FElseEquation(EquationType.NORMAL, elseClauses);
229                FIfEquation equation = new FIfEquation(EquationType.NORMAL, thenClauses, ifExp, new Opt<FIfWhenElseEquation>(elseClause));
230                equation.setIsTempAssign();
231                s.add(equation);
232            }
233            s.add(thenVars);
234        }
235    }
236   
237    private boolean FIfWhenElseEquation.isTempAssign = false;
238    public void FIfWhenElseEquation.setIsTempAssign() { isTempAssign = true; }
239    public boolean FIfWhenElseEquation.isTempAssign() { return isTempAssign; }
240   
241    public void FIfExp.createArrayTemporariesIfBranch(FExp guard, Scalarizer s) {
242        if (guard == null) {
243            getIfExp().createArrayTemporaries(s);
244        } else {
245            getIfExp().createArrayTemporariesIfBranch(guard.treeCopyNoTransform(), s);
246        }
247        FExp ifExp = getIfExp().scalarize(s);
248        FExp thenGuard = ifExp.treeCopyNoTransform();
249        FExp elseGuard = new FNotExp(ifExp.treeCopyNoTransform());
250        if (guard != null) {
251            thenGuard = new FAndExp(guard.treeCopyNoTransform(), thenGuard);
252            elseGuard = new FAndExp(guard.treeCopyNoTransform(), elseGuard);
253        }
254        getThenExp().createArrayTemporariesIfBranch(thenGuard, s);
255        getElseExp().createArrayTemporariesIfBranch(elseGuard, s);
256    }
257   
258   
259    public void FFunctionCall.createArrayTemporaries(Scalarizer s) {
260        // No names available as a function call arg.
261        boolean b = !extractTemp(s);
262        if (b)
263            s.getNames().addLayer(0);
264        super.createArrayTemporaries(s);
265        if (b)
266            s.getNames().removeLayer();
267    }
268   
269    public void FRecordConstructor.createArrayTemporaries(Scalarizer s) {
270        // No names available as record con arg.
271        boolean b = !extractTemp(s);
272        if (b)
273            s.getNames().addLayer(0);
274        super.createArrayTemporaries(s);
275        if (b)
276            s.getNames().removeLayer();
277    }
278   
279    public void FSizeExp.createArrayTemporaries(Scalarizer s) {
280        boolean b = !extractTemp(s);
281        if (b) {
282            s.getNames().addLayer(0);
283        }
284        if (extractTemp(s)) {
285            knownArrayTemporaries(s);
286        } else {
287            createArrayTemporariesInChildren(s);
288        }
289        if (b) {
290            s.getNames().removeLayer();
291        }
292    }
293   
294    public void FSizeExp.createArrayTemporariesInChildren(Scalarizer s) {
295        if (!isArray() && (getFExp().isSlice() || !getFExp().size().isUnknown(dimension()))) {
296            getFExp().size().createArrayTemporaries(s, dimension());
297        } else {
298            if (isArray()) {
299                getArray().createArrayTemporaries(s);
300            } else {
301                super.createArrayTemporariesInChildren(s);
302            }
303        }
304    }
305   
306    public void Size.createArrayTemporaries(Scalarizer s, int i) {
307       
308    }
309   
310    @Override
311    public void MutableSize.createArrayTemporaries(Scalarizer s, int i) {
312        if (exps[i] != null) {
313            exps[i].createArrayTemporaries(s);
314        } else {
315            super.createArrayTemporaries(s, i);
316        }
317    }
318   
319
320    /**
321     * Create clauses for and replace this known size expression with a temp variable.
322     * Used in both functions and equations.
323     * @param s Scalarization visitor
324     */
325    public void FExp.knownArrayTemporaries(Scalarizer s) {
326        s.addTempVar(this, true);
327        Array arr = getArray();
328        for (Index i : indices()) {
329            arr.get(i).createArrayTemporaries(s);
330            s.add(tempExp(i), arr.get(i).scalarize(s));
331        }
332        useTempVar = true;
333    }
334   
335    @Override
336    public void FAbstractFunctionCall.knownArrayTemporaries(Scalarizer s) {
337        if (scalarizeAsFunctionCallClause()) {
338            createArrayTemporariesInChildren(s);
339            List<FFunctionCallLeft> lefts = new List<>();
340            if (isFunctionCallClause()) {
341                for (FFunctionCallLeft left : myLefts()) {
342                    lefts.add(left.scalarize(s));
343                }
344                useTempVar = true;
345            } else {
346                s.addTempVar(this, true);
347                useTempVar = true;
348                lefts.add(new FFunctionCallLeft(new Opt<FExp>(scalarize(s))));
349            }
350            s.add(lefts, (FAbstractFunctionCall)scalarizeExp(s));
351        } else {
352            super.knownArrayTemporaries(s);
353        }
354    }
355   
356    syn boolean FAbstractFunctionCall.scalarizeAsFunctionCallClause() = false;
357    eq FFunctionCall  .scalarizeAsFunctionCallClause() = true;
358    eq FSpatialDistExp.scalarizeAsFunctionCallClause() = isFunctionCallClause();
359   
360    public FFunctionCallLeft FFunctionCallLeft.scalarize(Scalarizer s) {
361        if (hasFExp()) {
362            return getFExp().scalarizeLeft(s);
363        } else {
364            return new FFunctionCallLeft();
365        }
366    }
367   
368    public FFunctionCallLeft FExp.scalarizeLeft(Scalarizer s) {
369        if (size().isEmpty()) {
370            return new FFunctionCallLeft();
371        }
372       
373        FExp exp = this;
374        if (isSlice() && !s.unroll()) {
375            s.addTempVar(exp, true);
376            exp = exp.tempExp();
377            exp = exp.scalarizeExp(s);
378        } else if (!s.inFunction() || isSlice()) {
379            exp = type().createRecordConstructor(s, exp);
380        } else {
381            exp = exp.scalarizeExp(s);
382        }
383        return new FFunctionCallLeft(new Opt<FExp>(exp));
384    }
385   
386    @Override
387    public void FFunctionCallLeft.createArrayTemporaries(Scalarizer s) {
388        if (hasFExp()) {
389            getFExp().createArrayTemporaries(s);
390            if (getFExp().isSlice() && !s.unroll()) {
391                type().scalarizeAssignment((Scalarizer.Algorithm)s, (FAssignableExp)getFExp(), getFExp().tempExp());
392            }
393        }
394    }
395   
396    public void FVectorFunctionCall.knownArrayTemporaries(Scalarizer s) {
397        getArray().createArrayTemporaries(s);
398    }
399   
400    /**
401     * Create clauses for and replace this unknown size expression with a temp variable.
402     * Used in functions.
403     * @param s Scalarization visitor
404     */
405    public void FExp.unknownFunctionArrayTemporaries(Scalarizer s) {
406        s.addTempVar(this, false);
407        createArrayTemporariesInChildren(s);
408        useTempVar = false;
409        type().scalarizeAssignment((Scalarizer.Algorithm)s, tempExp(), this);
410        indexNames = null;
411    }
412
413    public void FAbstractFunctionCall.unknownFunctionArrayTemporaries(Scalarizer s) {
414        if (scalarizeAsFunctionCallClause()) {
415            knownArrayTemporaries(s);
416        } else {
417            super.unknownFunctionArrayTemporaries(s);
418        }
419    }
420   
421    public void FVectorFunctionCall.unknownFunctionArrayTemporaries(Scalarizer s) {
422        s.addTempVar(this, true);
423        List<FExp> newArgs = new List<FExp>();
424        List<FStatement> result = new List<FStatement>();
425        List<FStatement> outer = s.getClauses();
426        ForNames names = s.getNames();
427
428        names.addLayer(ndims());
429        names.fillLayer(this);
430
431        List<FStatement> firstLoop = new List<FStatement>();
432        FAccessExp funcLeft = tempExp(names.createFArraySubscripts(1));
433
434        for (int i = 0; i < getNumArg(); ++i) {
435            FExp arg = getArg(i);
436
437            arg.createArrayTemporaries(s.block(outer));
438
439            if (getVectorized()[i]) {
440                arg.addArrayUsesToIndexMap(s);
441                int dimDiff = arg.ndims() - ndims();
442
443                if (dimDiff > 0) {
444                    names.addLayer(dimDiff + 1);
445                    names.promote(0);
446                    names.fillLayer(arg);
447                   
448                    String tempName = arg.calcTempVarName();
449                    FAccessExp tempExp = new FAccessExp(new FAccessString(tempName));
450
451                    FType tempType = arg.type().arrayType(arg.size().contract(1));
452                    s.block(firstLoop).addTempVar(tempType, tempName, true, true);
453
454                    newArgs.add(tempExp(tempName, names.createFArraySubscripts(0, dimDiff - 1)));
455
456                    FAssignableExp left = tempExp(tempName, names.createFArraySubscripts(1, dimDiff + 1));
457                    FExp right = arg.tempExp(names.createFArraySubscripts(0, dimDiff + 1));
458                    List<FStatement> inner = new List<FStatement>();
459                    inner.add(new FAssignStmt(left, right));
460                    names.createForLoops(s, firstLoop, inner, arg.size(), 1, dimDiff + 1);
461                    names.removeLayer();
462                } else {
463                    newArgs.add(arg.scalarize(s));
464                }
465            } else {
466                newArgs.add(arg.scalarize(s));
467            }
468        }
469
470        FFunctionCall funcRight = new FFunctionCall(getName().fullCopy(), newArgs, getFType().scalarType());
471        firstLoop.add(new FAssignStmt(funcLeft, funcRight));
472
473        names.createForLoops(s, outer, firstLoop, size(), 0, 1);
474        names.removeLayer();
475    }
476   
477    public void FArray.unknownFunctionArrayTemporaries(Scalarizer s) {
478        s.addTempVar(this, true);
479        ForNames names = s.getNames();
480        boolean iter = isIterArray();
481        names.addLayer(ndims()- (iter ? 0 : 1));
482        names.fillLayer(this);
483
484        for (int i = 0; i < getNumFExp(); i++) {
485            List<FStatement> inner = new List<FStatement>();
486            List<FStatement> outer = s.getClauses();
487            FExp right = getFExp(i);
488            FAccessExp left;
489            if (iter) {
490                left = tempExp(names.createFArraySubscripts());
491                getFExp(0).editNamesIter(s);
492                right.createArrayTemporaries(s.block(inner));
493                right.addArrayUsesToIndexMap(s);
494                names.removeLayer();
495                right = ((FIterExp) right).getFExp();
496            } else {
497                List<FSubscript> subs = new List<FSubscript>();
498                subs.add(new FIntegerSubscript(i+1));
499                subs.addAll(names.createFArraySubscripts().copyAsFArrayExpSubscripts().getFSubscriptListNoTransform());
500                left = tempExp(new FArrayExpSubscripts(subs));
501                right.createArrayTemporaries(s);
502                right.addArrayUsesToIndexMap(s);
503            }
504            type().scalarizeAssignment_sub((Scalarizer.Algorithm)s.block(inner), left, right);
505            s.createForLoops(inner, getFExp(i));
506        }
507
508        names.removeLayer();
509    }
510   
511    public void FMulExp.unknownFunctionArrayTemporaries(Scalarizer s) {
512        s.addTempVar(this, true);
513        if (isElementWise()) {
514            unknownFunctionArrayTemporariesElementWise(s);
515        } else {
516            unknownFunctionArrayTemporariesMatrix(s);
517        }
518    }
519   
520    public void FMulExp.unknownFunctionArrayTemporariesMatrix(Scalarizer s) {
521        ForNames names = s.getNames();
522        FAccessExp sum = new FAccessExp(calcTempVarName());
523        s.addTempVar(type().scalarType(), sum.name(), true, true);
524       
525        names.addLayer(ndims());
526        names.fillLayer(this);
527       
528        // Set up indices for the left operand
529        FExp exp = getLeft();
530        names.addLayer(exp.ndims());
531        if (names.size() > 1)
532            names.promote(0);
533        String i = names.create(this);
534       
535        // Scalarize left operand
536        exp.createArrayTemporaries(s);
537        exp.addArrayUsesToIndexMap(s);
538        FExp left = exp.scalarize(s);
539        names.removeLayer();
540       
541        // Set up indices and scalarize the right operand
542        exp = getRight();
543        names.addLayer(exp.ndims());
544        names.add(i);
545        if (names.size() > 1)
546            names.promote(ndims() - 1);
547        exp.createArrayTemporaries(s);
548        exp.addArrayUsesToIndexMap(s);
549        FExp right = exp.scalarize(s);
550        names.removeLayer();
551       
552        // Add statement updating temp var to loop
553        FExp mul = new FMulExp(left, right);
554        FExp add = new FAddExp(sum.fullCopy(), mul);
555        List<FStatement> inner = new List<FStatement>();
556        inner.add(new FAssignStmt(sum.fullCopy(), add));
557       
558        // Create inner loop
559        FForStmt fs = new FForStmt(new FForIndex(i, getRight().size().createFExp(0)), inner);
560       
561        // Create outer loops
562        List<FStatement> outer = new List<FStatement>();
563        outer.add(new FAssignStmt(sum, type().scalarType().zeroLiteral()));
564        outer.add(fs);
565        outer.add(new FAssignStmt(tempExp(names.createFArraySubscripts()), sum.fullCopy()));
566       
567        s.createForLoops(outer, this);
568       
569        names.removeLayer();
570    }
571   
572    public void FMulExp.unknownFunctionArrayTemporariesElementWise(Scalarizer s) {
573        ForNames names = s.getNames();
574        FAccessExp sum = new FAccessExp(calcTempVarName());
575        s.addTempVar(type().scalarType(), sum.name(), true, true);
576       
577        names.addLayer(ndims());
578        names.fillLayer(this);
579       
580        FExp left = getLeft();
581        left.createArrayTemporaries(s);
582        left.addArrayUsesToIndexMap(s);
583        left = left.scalarize(s);
584       
585        FExp right = getRight();
586        right.createArrayTemporaries(s);
587        right.addArrayUsesToIndexMap(s);
588        right = right.scalarize(s);
589       
590        List<FStatement> inner = new List<>();
591        FAccessExp temp = tempExp(names.createFArraySubscripts());
592        FExp mul = dynamicFExp(new FMulExp(left, right));
593        type().scalarizeAssignment_sub((Scalarizer.Algorithm)s.block(inner), temp, mul);
594        s.createForLoops(inner, this);
595       
596        names.removeLayer();
597    }
598   
599    public void FAbstractCat.unknownFunctionArrayTemporaries(Scalarizer s) {
600        s.addTempVar(this, true);
601        ForNames names = s.getNames();
602        int catDim  = dimension();
603        FExp offset = new FIntegerLitExp(0);
604        FExp firstArg = getFExp(0);
605        ForNames orig = names.copySurface();
606       
607        for (FExp exp : getFExps()) {
608            names.addLayer(exp.ndims());
609            names.fillLayer(exp);
610           
611            exp.createArrayTemporaries(s);
612            exp.addArrayUsesToIndexMap(s);
613           
614            FArrayExpSubscripts fas = names.createFArraySubscripts(ndims());
615            FExp ind = fas.getFSubscript(catDim).createFExp();
616            ind = new FAddExp(ind, offset.fullCopy());
617            fas.setFSubscript(new FExpSubscript(ind), catDim);
618           
619            s.createForLoops(tempExp(fas), exp.scalarize(s), exp);
620            names.removeLayer();
621           
622            offset = new FAddExp(offset, exp.size().has(catDim) ? exp.size().createFExp(catDim) : new FIntegerLitExp(1));
623        }
624    }
625   
626    public void FAbstractDiagonal.unknownFunctionArrayTemporaries(Scalarizer s) {
627        s.addTempVar(this, true);
628        ForNames names = s.getNames();
629        names.addLayer(ndims());
630        names.fillLayer(this);
631       
632        getFExp().createArrayTemporaries(s);
633        getFExp().addArrayUsesToIndexMap(s);
634       
635        FIfExp right = new FIfExp(
636                new FEqExp(new FAccessExp(names.get(0)), new FAccessExp(names.get(1))),
637                scalarizeDiagonalElement(s),
638                new FIntegerLitExp(0)
639        );
640        s.createForLoops(tempExp(names.createFArraySubscripts(ndims())), right, this);
641        names.removeLayer();
642    }
643   
644    syn FExp FAbstractDiagonal.scalarizeDiagonalElement(Scalarizer s);
645    eq FIdentity.scalarizeDiagonalElement(Scalarizer s) = new FIntegerLitExp(1);
646    eq FDiagonal.scalarizeDiagonalElement(Scalarizer s) = getFExp().scalarize(s);
647   
648    public void FVectorExp.unknownFunctionArrayTemporaries(Scalarizer s) {
649        s.addTempVar(this, true);
650        ForNames names = s.getNames();
651        names.addLayer(getFExp().ndims());
652        names.fillLayer(getFExp());
653       
654        getFExp().createArrayTemporaries(s);
655        getFExp().addArrayUsesToIndexMap(s);
656       
657        FExp ind = null;
658        for (int i = 0; i < names.size(); i++) {
659            FAccessExp u = new FAccessExp(names.get(i));
660            FSubExp u1 = new FSubExp(u, new FIntegerLitExp(1));
661            if (ind != null) {
662                ind = new FMulExp(ind, getFExp().size().createFExp(i));
663                ind = new FAddExp(ind, u1);
664            } else {
665                ind = u1;
666            }
667        }
668        if (ind == null) {
669            ind = new FIntegerLitExp(1);
670        } else {
671            ind = new FAddExp(ind, new FIntegerLitExp(1));
672        }
673       
674        FArrayExpSubscripts fas = new FArrayExpSubscripts();
675        fas.addFSubscript(new FExpSubscript(ind));
676
677        FExp right = getFExp().scalarize(s);
678
679        s.createForLoops(tempExp(fas), right, getFExp());
680        names.removeLayer();
681    }
682   
683    public void FMatrixExp.unknownFunctionArrayTemporaries(Scalarizer s) {
684        s.addTempVar(this, true);
685        ForNames names = s.getNames();
686        names.addLayer(getFExp().ndims());
687        names.fillLayer(getFExp());
688       
689        getFExp().createArrayTemporaries(s);
690        getFExp().addArrayUsesToIndexMap(s);
691
692        s.createForLoops(tempExp(names.createFArraySubscripts(2)), getFExp().scalarize(s), getFExp());
693        names.removeLayer();
694    }
695
696    public void FReductionExp.unknownFunctionArrayTemporaries(Scalarizer s) {
697        s.addTempVar(this, true);
698        unknownReductionSub(s, getFExp());
699    }
700
701    public void FMinMaxExp.unknownFunctionArrayTemporaries(Scalarizer s) {
702        s.addTempVar(this, true);
703        unknownReductionSub(s, getX());
704    }
705
706    public void FCross.unknownFunctionArrayTemporaries(Scalarizer s) {
707        s.addTempVar(this, true);
708        createArrayTemporariesInChildren(s);
709        FExp x = getX();
710        FExp y = getY();
711        for (Index i : indices()) {
712            int j = i.first() % 3 + 1;
713            int k = j % 3 + 1;
714            FExp m1 = new FMulExp(x.extractArrayCell(s, j), y.extractArrayCell(s, k));
715            FExp m2 = new FMulExp(x.extractArrayCell(s, k), y.extractArrayCell(s, j));
716            s.add(tempExp(i), new FSubExp(m1, m2));
717        }
718    }
719
720    public void FSkew.unknownFunctionArrayTemporaries(Scalarizer s) {
721        s.addTempVar(this, true);
722        createArrayTemporariesInChildren(s);
723       
724        FExp inner = getFExp();
725        for (Index i : indices()) {
726            /* Result is:
727             * [    0, -x[3],  x[2];
728             *   x[3],     0, -x[1];
729             *  -x[2],  x[1],     0 ]
730             */
731            FExp cell = null;
732            int j = 6 - i.get(0) - i.get(1);
733            switch ((i.get(0) - i.get(1) + 2) % 3) {
734            case 0:
735                cell = inner.extractArrayCell(s, j);
736                break;
737            case 1:
738                cell = inner.extractArrayCell(s, j);
739                cell = new FNegExp(cell);
740                break;
741            case 2:
742                cell = new FIntegerLitExp(0);
743                break;
744            }
745            s.add(tempExp(i), cell);
746        }
747    }
748
749    public void FSymmetric.unknownFunctionArrayTemporaries(Scalarizer s) {
750        s.addTempVar(this, true);
751        createArrayTemporariesInChildren(s);
752        FExp exp = getFExp();
753       
754        ForNames names = s.getNames();
755        names.addLayer(2);
756        names.fillLayer(this);
757       
758        FAccessExp left = tempExp(names.createFArraySubscripts());
759        FExp[] ijs = names.createFExpArray();
760        FExp expIJ = exp.extractArrayCell(s, ijs);
761        names.createTransposedLayer();
762        FExp expJI = exp.extractArrayCell(s, names.createFExpArray());
763        names.removeLayer();
764        FExp right = new FIfExp(new FLeqExp(ijs[0], ijs[1]), expIJ, expJI);
765       
766        List<FStatement> inner = new List<FStatement>();
767        right = dynamicFExp(right);
768        type().scalarizeAssignment_sub((Scalarizer.Algorithm)s.block(inner), left, right);
769        s.createForLoops(inner, exp);
770        names.removeLayer();
771    }
772
773    public void FOuterProduct.unknownFunctionArrayTemporaries(Scalarizer s) {
774        s.addTempVar(this, true);
775        createArrayTemporariesInChildren(s);
776       
777        ForNames names = s.getNames();
778        names.addLayer(2);
779        names.fillLayer(this);
780       
781        FAccessExp left = tempExp(names.createFArraySubscripts());
782        FExp[] ijs = names.createFExpArray();
783        FExp x = getX().extractArrayCell(s, ijs[0]);
784        FExp y = getY().extractArrayCell(s, ijs[1]);
785        FExp right = new FMulExp(x, y);
786       
787        List<FStatement> inner = new List<FStatement>();
788        right = dynamicFExp(right);
789        type().scalarizeAssignment_sub((Scalarizer.Algorithm)s.block(inner), left, right);
790        s.createForLoops(inner, this);
791        names.removeLayer();
792    }
793   
794    syn FAssignableExp FBuiltInFunctionCall.reducerTempExp(Scalarizer s) = type().isArray() ? 
795            tempExp(s.getNames().createFArraySubscripts(ndims())) : tempExp();
796   
797    syn FExp FBuiltInFunctionCall.scalarReduceExp(FExp reducer,  FExp scalar) = null;
798    eq FSumExp.scalarReduceExp(FExp reducer,     FExp scalar) = new FAddExp(reducer, scalar);
799    eq FProductExp.scalarReduceExp(FExp reducer, FExp scalar) = new FMulExp(reducer, scalar);
800    eq FMaxExp.scalarReduceExp(FExp reducer, FExp scalar) =
801            new FIfExp(new FGtExp(reducer, scalar.treeCopy()), reducer.treeCopy(), scalar.treeCopy());
802    eq FMinExp.scalarReduceExp(FExp reducer, FExp scalar) =
803            new FIfExp(new FLtExp(reducer, scalar.treeCopy()), reducer.treeCopy(), scalar.treeCopy());
804   
805    protected void FBuiltInFunctionCall.unknownReductionSub(Scalarizer s, FExp exp) {
806        ForNames names = s.getNames();
807        List<FStatement> clauses = s.getClauses();
808
809        names.addLayer(exp.ndims());
810        names.fillLayer(this);
811
812        List<FStatement> inner = new List<FStatement>();
813        List<FStatement> mid   = new List<FStatement>();
814        boolean iter = exp.editNamesIter(s);
815        if (iter) {
816            exp.createArrayTemporaries(s.block(inner));
817        } else {
818            exp.createArrayTemporaries(s.block(mid));
819        }
820        exp.addArrayUsesToIndexMap(s);
821        if (iter) {
822            names.removeLayer();
823        }
824
825        mid.add(new FAssignStmt(reducerTempExp(s), scalarReduceStartValue().buildLiteral()));
826        inner.add(new FAssignStmt(reducerTempExp(s), scalarReduceExp(reducerTempExp(s), exp.scalarize(s))));
827
828        names.createForLoops(s, mid, inner, exp.size(), ndims(), exp.ndims());
829        names.createForLoops(s, clauses, mid, exp.size(), 0, ndims());
830        names.removeLayer();
831    }
832   
833    /**
834     * Helper for unknown size expressions containing iteration expressions.
835     */
836    public boolean FExp.editNamesIter(Scalarizer s) {
837        return false;
838    }
839    public boolean FIterExp.editNamesIter(Scalarizer s) {
840        ForNames names = s.getNames();
841        int i = 0;
842        for (; i < getNumForIndex(); i++) {
843            getForIndex(i).setIndexName(names.get(i));
844        }
845        names.addLayer(getFExp().ndims());
846        for (; i < getFExp().ndims() + getNumForIndex(); i++) {
847            names.promote(i);
848        }
849        return true;
850    }
851
852    private String FForIndex.indexName = null;
853    public void CommonForIndex.setIndexName(String indexName) {}
854    public void FForIndex.setIndexName(String indexName) { this.indexName = indexName; }
855
856    inh String FAbstractVariable.myForIndexName();
857    eq ASTNode.getChild().myForIndexName()       = null;
858    eq FForIndex.getFVariable().myForIndexName() = indexName;
859
860    inh FExp FAbstractVariable.scalarizeIterIndex(Scalarizer s);
861    eq FForIndex.getFVariable().scalarizeIterIndex(Scalarizer s) = 
862        indexName == null ? null : getFExp().scalarizeWithIndex(s, new FAccessExp(indexName));
863    eq ASTNode  .getChild()    .scalarizeIterIndex(Scalarizer s) = null;
864
865    public FExp FExp.scalarizeWithIndex(Scalarizer s, FExp res) {
866        return null;
867    }
868
869    public FExp FRangeExp.scalarizeWithIndex(Scalarizer s, FExp res) {
870        boolean startIsOne = getFExp(0).isIntegerLiteral(1);
871        if (!startIsOne || hasStep()) {
872            res = new FSubExp(res, new FIntegerLitExp(1));
873            if (hasStep())
874                res = new FMulExp(res, getFExp(1).scalarize(s));
875            res = new FAddExp(getFExp(0).scalarize(s), res);
876        }
877        return res;
878    }
879
880    /**
881     * Wrapper for {@link ASTNode#addArrayUsesToIndexMap(Scalarizer s, FExp[] names)}.
882     */
883    public void ASTNode.addArrayUsesToIndexMap(Scalarizer s) {
884        if (s.getNames().size() > 0) {
885            addArrayUsesToIndexMap(s, s.getNames().createFExpArray());
886        }
887    }
888   
889    /**
890     * Traverser for {@link FExp#addArrayUsesToIndexMap(FExp[] names)}.
891     */
892    public void ASTNode.addArrayUsesToIndexMap(Scalarizer s, FExp[] names) {
893        for (ASTNode n : this)
894            n.addArrayUsesToIndexMap(s, names);
895    }
896   
897    /**
898     * Copies top layer in <code>names</code> to id uses and creates entries
899     * in <code>indexNames</code> for expressions replaced with temps.
900     */
901    public void FExp.addArrayUsesToIndexMap(Scalarizer s, FExp[] names) {
902        if (useTempVar) {
903            if (isArray()) {
904                indexNames = names;
905            }
906        } else {
907            super.addArrayUsesToIndexMap(s, names);
908        }
909    }
910   
911    public void FSizeExp.addArrayUsesToIndexMap(Scalarizer s, FExp[] names) {
912        if (useTempVar() && isArray()) {
913            indexNames = names;
914        }
915    }
916   
917    public void FAccessExp.addArrayUsesToIndexMap(Scalarizer s, FExp[] names) {
918        if (!hasFArraySubscripts() && myFV().isArray()) {
919            indexNames = names;
920        }
921        super.addArrayUsesToIndexMap(s, names);
922    }
923   
924    public void CommonAccess.addArrayUsesToIndexMap(Scalarizer s, FExp[] names) {
925        if (isArray()) {
926            int i = 0;
927            for (FArraySubscripts fas : allFArraySubscripts()) {
928                i = fas.addArrayUsesToIndexMap(s, names, i);
929            }
930        }
931    }
932
933    public int FArraySubscripts.addArrayUsesToIndexMap(Scalarizer s, FExp[] names, int i) { return i; }
934    public int FArrayExpSubscripts.addArrayUsesToIndexMap(Scalarizer s, FExp[] names, int i) {
935        for (FSubscript fs : getFSubscripts()) {
936            if (fs.ndims() > 0) {
937                FExp[] indexNames = new FExp[1];
938                indexNames[0] = names[i];
939                fs.addArrayUsesToIndexMap(s, indexNames);
940                i++;
941            }
942        }
943        return i;
944    }
945
946    public void FTempAccessExp.addArrayUsesToIndexMap(Scalarizer s, FExp[] names) {
947        indexNames = names;
948    }
949
950    public void FRangeExp.addArrayUsesToIndexMap(Scalarizer s, FExp[] names) {
951        indexNames = names;
952        super.addArrayUsesToIndexMap(s, names);
953    }
954
955    public void FLinspace.addArrayUsesToIndexMap(Scalarizer s, FExp[] names) {
956        indexNames = names;
957        super.addArrayUsesToIndexMap(s,names);
958    }
959
960    public void FColonSubscript.addArrayUsesToIndexMap(Scalarizer s, FExp[] names) {
961        indexName = names[0];
962    }
963
964    public void FTranspose.addArrayUsesToIndexMap(Scalarizer s, FExp[] names) {
965        FExp[] local = names.clone();
966        local[0] = names[1];
967        local[1] = names[0];
968        super.addArrayUsesToIndexMap(s, local);
969    }
970
971    public void FFunctionCall.addArrayUsesToIndexMap(Scalarizer s, FExp[] names) {
972        // No names available as a function call arg.
973        if (extractTemp(s)) {
974            super.addArrayUsesToIndexMap(s, names);
975        }
976    }
977
978    public void FRecordConstructor.addArrayUsesToIndexMap(Scalarizer s, FExp[] names) {
979        // No names available as record con arg.
980        if (extractTemp(s)) {
981            super.addArrayUsesToIndexMap(s, names);
982        }
983    }
984
985}
986
987aspect FunctionScalarizationHelpers {
988   
989    /**
990     * A node that can look up variable names in the flat tree.
991     */
992    public interface FlatLookupNode {
993        public FAbstractVariable lookupFV(String name);
994    }
995    FFunctionVariable implements FlatLookupNode;
996    FExp implements FlatLookupNode;
997
998    inh FAbstractVariable FFunctionVariable.lookupFV(String name);
999    inh FAbstractVariable FExp.lookupFV(String name);
1000
1001    /**
1002     * Creates and organizes names of for indices for generated for loops.
1003     */
1004    public class ForNames implements Iterable<String> {
1005        private ArrayList<String[]> names;
1006        private ArrayList<Integer> last;
1007        private int pos;
1008       
1009        /**
1010         * Standard constructor.
1011         */
1012        public ForNames() {
1013            names = new ArrayList<String[]>();
1014            last = new ArrayList<Integer>();
1015            last.add(0);
1016        }
1017       
1018        /**
1019         * Creates a new ForNames with a single layer with space for <code>n</code> names.
1020         */
1021        public ForNames(int n) {
1022            this();
1023            addLayer(n);
1024        }
1025       
1026        /**
1027         * Add a new layer of names, that can be filled with new names or names
1028         *        from the layer underneath.
1029         *
1030         * @param n  the number of names in the new layer
1031         */
1032        public void addLayer(int n) {
1033            names.add(new String[n]);
1034            pos = 0;
1035            last.add(last());
1036        }
1037       
1038        /**
1039         * Fills all empty spots in the top layer with newly created names.
1040         */
1041        public void fillLayer(FlatLookupNode context) {
1042            String[] top = topLayer();
1043            for (int i = pos; i < top.length; i++) 
1044                create(context);
1045        }
1046       
1047        /**
1048         * Removes the top layer, exposing the layer underneath.
1049         */
1050        public void removeLayer() {
1051            names.remove(names.size() - 1);
1052            last.remove(last.size() - 1);
1053        }
1054
1055        private String[] topLayer() {
1056            return names.get(names.size() - 1);
1057        }
1058       
1059        public boolean hasNames() {
1060            return names.size() > 0 && topLayer().length > 0;
1061        }
1062       
1063        /**
1064         * Gets name with index <code>i</code> in the top layer.
1065         */
1066        public String get(int i) {
1067            return topLayer()[i];
1068        }
1069       
1070        /**
1071         * Adds a name to the top layer.
1072         */
1073        public void add(String name) {
1074            topLayer()[pos++] = name;
1075        }
1076       
1077        /**
1078         * Creates a new name and adds it to the top layer.
1079         *
1080         * @return the created name
1081         */
1082        public String create(FlatLookupNode context) {
1083            String name;
1084            int l = last();
1085            do {
1086                name = "i" + (++l);
1087            } while (context != null && !context.lookupFV(name).isUnknown()); 
1088            add(name);
1089            last.set(last.size()-1, l);
1090            return name;
1091        }
1092       
1093        private int last() {
1094            return last.get(last.size()-1);
1095        }
1096       
1097        /**
1098         * Adds a name from the underlying layer to the top layer.
1099         *
1100         * @param i  the index in the underlying layer
1101         */
1102        public void promote(int i) {
1103            add(names.get(names.size() - 2)[i]);
1104        }
1105       
1106        /**
1107         * Checks if there are enough layers to promote a name.
1108         */
1109        public boolean canPromote() {
1110            return names.size() > 1;
1111        }
1112       
1113        /**
1114         * Return the number of names in the top layer.
1115         */
1116        public int size() {
1117            return topLayer().length;
1118        }
1119       
1120        /**
1121         * Iterates over the top layer.
1122         */
1123        public Iterator<String> iterator() {
1124            return Arrays.asList(topLayer()).iterator();
1125        }
1126       
1127        /**
1128         * Pushes a copy of the top layer with first and second names switched
1129         */
1130        public void createTransposedLayer() {
1131            String[] lay = topLayer();
1132            addLayer(lay.length);
1133            for (int i = 0; i < lay.length; i++) {
1134                promote(i);
1135            }
1136            topLayer()[0] = lay[1];
1137            topLayer()[1] = lay[0];
1138           
1139        }
1140       
1141        /**
1142         * Creates nestled for loops using the top layer of names.
1143         * 
1144         * Adds the outermost for loop to a list of statements.
1145         *
1146         * @param outer  list to add the created for statements to
1147         * @param inner  list of statements put inside the loop
1148         * @param sizes  array of expressions describing the size of each dimension
1149         */
1150        public void createForLoops(List<FStatement> outer, List<FStatement> inner, FExp[] sizes, int startDim) {
1151            if (startDim < sizes.length) {
1152                List<FStatement> mid = new List<FStatement>();
1153                createForLoops(mid, inner, sizes, startDim + 1);
1154                FForIndex ffi = new FForIndex(topLayer()[startDim], sizes[startDim]);
1155                outer.add(new FForStmt(ffi, mid));
1156            } else {
1157                outer.addAll(inner);
1158            }
1159        }
1160       
1161        /**
1162         * Creates nestled for loops over a single variable, using the top layer of names.
1163         * 
1164         * Adds the outermost for loop to a list of statements.
1165         *
1166         * @param outer  list to add the created for statements to
1167         * @param inner  list of statements put inside the loop
1168         * @param var    name of the variable to loop over
1169         */
1170        public void createForLoops(List<FStatement> outer, List<FStatement> inner, FAccess var) {
1171            int n = topLayer().length;
1172            FExp[] sizes = new FExp[n];
1173            for (int i = 0; i < n; i++) {
1174                sizes[i] = new FSizeExp(var, i);
1175            }
1176            createForLoops(outer, inner, sizes, 0);
1177        }
1178
1179        /**
1180         * Creates nestled (from d1 to d2) for loops over an expression,
1181         * using the top layer of names.
1182         * 
1183         * Adds the outermost for loop to a list of statements.
1184         *
1185         * @param outer  list to add the created for statements to
1186         * @param inner  list of statements put inside the loop
1187         * @param exp    expression to loop over
1188         * @param d1     dimensions to start in
1189         * @param d2     dimensions to end in
1190         */
1191        public void createForLoops(Scalarizer s, List<FStatement> outer, List<FStatement> inner, Size size, int d1, int d2) {
1192            FExp[] sizes = new FExp[d2];
1193            for (int i = d1; i < d2; i++) {
1194                sizes[i] = size.scalarize(s, i);
1195            }
1196            createForLoops(outer, inner, sizes, d1);
1197        }
1198       
1199        /**
1200         * Creates nestled for loops over an expression, using the top layer of names.
1201         * 
1202         * Adds the outermost for loop to a list of statements.
1203         *
1204         * @param outer  list to add the created for statements to
1205         * @param inner  list of statements put inside the loop
1206         * @param exp    expression to loop over
1207         */
1208        public void createForLoops(Scalarizer s, List<FStatement> outer, List<FStatement> inner, Size size) {
1209            createForLoops(s, outer, inner, size, 0, size.ndims());
1210        }
1211
1212        /**
1213         * Creates a new FArraySubscripts with uses of the <code>d1</code> to <code>d2</code> names
1214         * in the top layer as subscripts. When out of names, adds 1s.
1215         */
1216        public FArrayExpSubscripts createFArraySubscripts(int d1, int d2) {
1217            if (d1 < 0)
1218                throw new UnsupportedOperationException();
1219            FArrayExpSubscripts fas = new FArrayExpSubscripts();
1220            for (int i = d1; i < d2; ++i) {
1221                if (i < topLayer().length)
1222                    fas.addFSubscript(new FExpSubscript(new FTempAccessExp(new FAccessFull(topLayer()[i]))));
1223                else
1224                    fas.addFSubscript(new FIntegerSubscript(1));
1225            }
1226            return fas;
1227        }
1228       
1229        /**
1230         * Creates a new FArraySubscripts with uses of the <code>d</code>
1231         * first names in the top layer as subscripts. When out of names, adds 1s.
1232         */
1233        public FArrayExpSubscripts createFArraySubscripts(int d) {
1234            return createFArraySubscripts(0, d);
1235        }
1236       
1237        /**
1238         * Creates a new FArraySubscripts with uses of all the names in the top layer.
1239         */
1240        public FArrayExpSubscripts createFArraySubscripts() {
1241            return createFArraySubscripts(topLayer().length);
1242        }
1243
1244        public FExp[] createFExpArray() {
1245            if (!hasNames())
1246                return new FExp[0];
1247            FExp[] subs = new FExp[topLayer().length];
1248            int i = 0;
1249            for (String s : topLayer()) {
1250                subs[i++] = new FAccessExp(s);
1251            }
1252            return subs;
1253        }
1254       
1255        /**
1256         * Creates a new ForNames with the top layer copied
1257         */
1258        public ForNames copySurface() {
1259            ForNames fn = new ForNames();
1260            if (names.size() > 0) {
1261                fn.addLayer(topLayer().length);
1262                for (String s : topLayer())
1263                    fn.add(s);
1264            }
1265            fn.last.add(last());
1266            return fn;
1267        }
1268    }
1269}
Note: See TracBrowser for help on using the repository browser.