Skip to content
This repository was archived by the owner on May 18, 2019. It is now read-only.

Commit 82c686d

Browse files
perostOpenModelica-Hudson
authored andcommitted
[NF] Evaluation improvements.
- Guard against evaluating expressions containing iterators. - Move evaluation of for-loop ranges to the unrolling phase, to make it possible to handle ranges with iterators in them. - Handle evaluation of min/max of empty arrays. - Fix SimplifyModel so that it removes assertions with condition true, not false. Belonging to [master]: - #2499 - OpenModelica/OpenModelica-testsuite#972
1 parent 58dca93 commit 82c686d

File tree

11 files changed

+158
-57
lines changed

11 files changed

+158
-57
lines changed

Compiler/NFFrontEnd/NFBuiltinCall.mo

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -802,17 +802,21 @@ protected
802802
Type arg_ty;
803803
Function fn;
804804
list<Dimension> dims;
805+
Boolean evaluated;
805806
algorithm
806807
ty_args := {fillArg};
807808
dims := {};
809+
evaluated := true;
808810

809811
// Type the dimension arguments.
810812
for arg in dimensionArgs loop
811813
(arg, arg_ty, arg_var) := Typing.typeExp(arg, origin, info);
812814

813-
if arg_var <= Variability.STRUCTURAL_PARAMETER then
815+
if arg_var <= Variability.STRUCTURAL_PARAMETER and not Expression.containsIterator(arg, origin) then
814816
arg := Ceval.evalExp(arg);
815817
arg_ty := Expression.typeOf(arg);
818+
else
819+
evaluated := false;
816820
end if;
817821

818822
// Each dimension argument must be an Integer expression.
@@ -833,7 +837,7 @@ protected
833837
{fn} := Function.typeRefCache(fnRef);
834838
ty := Type.liftArrayLeftList(fillType, dims);
835839

836-
if variability <= Variability.STRUCTURAL_PARAMETER and intBitAnd(origin, ExpOrigin.FUNCTION) == 0 then
840+
if evaluated and intBitAnd(origin, ExpOrigin.FUNCTION) == 0 then
837841
callExp := Ceval.evalBuiltinFill(ty_args);
838842
else
839843
callExp := Expression.CALL(Call.makeTypedCall(NFBuiltinFuncs.FILL_FUNC, ty_args, variability, ty));

Compiler/NFFrontEnd/NFCall.mo

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,7 @@ protected
816816
InstNode iter;
817817
list<Dimension> dims = {};
818818
list<tuple<InstNode, Expression>> iters = {};
819+
ExpOrigin.Type next_origin;
819820
algorithm
820821
(call, ty, variability) := match call
821822
// This is always a call to the function array()/$array(). See instIteratorCall.
@@ -833,7 +834,9 @@ protected
833834
end for;
834835
iters := listReverseInPlace(iters);
835836

836-
(arg, ty) := Typing.typeExp(call.exp, origin, info);
837+
// ExpOrigin.FOR is used here as a marker that this expression may contain iterators.
838+
next_origin := intBitOr(origin, ExpOrigin.FOR);
839+
(arg, ty) := Typing.typeExp(call.exp, next_origin, info);
837840
ty := Type.liftArrayLeftList(ty, dims);
838841
then
839842
(TYPED_MAP_CALL(ty, variability, arg, iters), ty, variability);

Compiler/NFFrontEnd/NFCeval.mo

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ algorithm
604604

605605
else
606606
algorithm
607-
exp := Expression.BINARY(exp1, Operator.makeMul(Type.UNKNOWN()), exp2);
607+
exp := Expression.BINARY(exp1, Operator.makeDiv(Type.UNKNOWN()), exp2);
608608
printFailedEvalError(getInstanceName(), exp, sourceInfo());
609609
then
610610
fail();
@@ -1279,8 +1279,8 @@ algorithm
12791279
case "log10" then evalBuiltinLog10(listHead(args), target);
12801280
case "log" then evalBuiltinLog(listHead(args), target);
12811281
case "matrix" then evalBuiltinMatrix(listHead(args));
1282-
case "max" then evalBuiltinMax(args);
1283-
case "min" then evalBuiltinMin(args);
1282+
case "max" then evalBuiltinMax(args, fn);
1283+
case "min" then evalBuiltinMin(args, fn);
12841284
case "mod" then evalBuiltinMod(args);
12851285
case "noEvent" then listHead(args); // No events during ceval, just return the argument.
12861286
case "ones" then evalBuiltinOnes(args);
@@ -1755,14 +1755,26 @@ end evalBuiltinMatrix2;
17551755

17561756
function evalBuiltinMax
17571757
input list<Expression> args;
1758+
input Function fn;
17581759
output Expression result;
17591760
protected
17601761
Expression e1, e2;
17611762
list<Expression> expl;
1763+
Type ty;
17621764
algorithm
17631765
result := match args
17641766
case {e1, e2} then evalBuiltinMax2(e1, e2);
1765-
case {Expression.ARRAY(elements = expl)} then evalBuiltinMax2(e for e in expl);
1767+
case {e1 as Expression.ARRAY(ty = ty)}
1768+
algorithm
1769+
result := Expression.fold(e1, evalBuiltinMax2, Expression.EMPTY());
1770+
1771+
if Expression.isEmpty(result) then
1772+
result := Expression.CALL(Call.makeTypedCall(fn,
1773+
{Expression.ARRAY(ty, {})}, Variability.CONSTANT, Type.arrayElementType(ty)));
1774+
end if;
1775+
then
1776+
result;
1777+
17661778
else algorithm printWrongArgsError(getInstanceName(), args, sourceInfo()); then fail();
17671779
end match;
17681780
end evalBuiltinMax;
@@ -1781,25 +1793,34 @@ algorithm
17811793
then if exp1.value < exp2.value then exp2 else exp1;
17821794
case (Expression.ENUM_LITERAL(), Expression.ENUM_LITERAL())
17831795
then if exp1.index < exp2.index then exp2 else exp1;
1784-
case (Expression.ARRAY(), Expression.ARRAY())
1785-
then evalBuiltinMax2(evalBuiltinMax2(e for e in exp1.elements),
1786-
evalBuiltinMax2(e for e in exp2.elements));
1787-
case (Expression.ARRAY(), _)
1788-
then evalBuiltinMax2(evalBuiltinMax2(e for e in exp1.elements), exp2);
1796+
case (Expression.ARRAY(), _) then exp2;
1797+
case (_, Expression.EMPTY()) then exp1;
17891798
else algorithm printWrongArgsError(getInstanceName(), {exp1, exp2}, sourceInfo()); then fail();
17901799
end match;
17911800
end evalBuiltinMax2;
17921801

17931802
function evalBuiltinMin
17941803
input list<Expression> args;
1804+
input Function fn;
17951805
output Expression result;
17961806
protected
17971807
Expression e1, e2;
17981808
list<Expression> expl;
1809+
Type ty;
17991810
algorithm
18001811
result := match args
18011812
case {e1, e2} then evalBuiltinMin2(e1, e2);
1802-
case {Expression.ARRAY(elements = expl)} then evalBuiltinMin2(e for e in expl);
1813+
case {e1 as Expression.ARRAY(ty = ty)}
1814+
algorithm
1815+
result := Expression.fold(e1, evalBuiltinMin2, Expression.EMPTY());
1816+
1817+
if Expression.isEmpty(result) then
1818+
result := Expression.CALL(Call.makeTypedCall(fn,
1819+
{Expression.ARRAY(ty, {})}, Variability.CONSTANT, Type.arrayElementType(ty)));
1820+
end if;
1821+
then
1822+
result;
1823+
18031824
else algorithm printWrongArgsError(getInstanceName(), args, sourceInfo()); then fail();
18041825
end match;
18051826
end evalBuiltinMin;
@@ -1818,11 +1839,8 @@ algorithm
18181839
then if exp1.value > exp2.value then exp2 else exp1;
18191840
case (Expression.ENUM_LITERAL(), Expression.ENUM_LITERAL())
18201841
then if exp1.index > exp2.index then exp2 else exp1;
1821-
case (Expression.ARRAY(), Expression.ARRAY())
1822-
then evalBuiltinMin2(evalBuiltinMin2(e for e in exp1.elements),
1823-
evalBuiltinMin2(e for e in exp2.elements));
1824-
case (Expression.ARRAY(), _)
1825-
then evalBuiltinMin2(evalBuiltinMin2(e for e in exp1.elements), exp2);
1842+
case (Expression.ARRAY(), _) then exp2;
1843+
case (_, Expression.EMPTY()) then exp1;
18261844
else algorithm printWrongArgsError(getInstanceName(), {exp1, exp2}, sourceInfo()); then fail();
18271845
end match;
18281846
end evalBuiltinMin2;
@@ -1857,11 +1875,16 @@ function evalBuiltinProduct
18571875
input Expression arg;
18581876
output Expression result;
18591877
algorithm
1860-
result := matchcontinue Type.arrayElementType(Expression.typeOf(arg))
1861-
case Type.INTEGER() then Expression.INTEGER(Expression.fold(arg, evalBuiltinProductInt, 1));
1862-
case Type.REAL() then Expression.REAL(Expression.fold(arg, evalBuiltinProductReal, 1.0));
1878+
result := match arg
1879+
case Expression.ARRAY()
1880+
then match Type.arrayElementType(Expression.typeOf(arg))
1881+
case Type.INTEGER() then Expression.INTEGER(Expression.fold(arg, evalBuiltinProductInt, 1));
1882+
case Type.REAL() then Expression.REAL(Expression.fold(arg, evalBuiltinProductReal, 1.0));
1883+
else algorithm printWrongArgsError(getInstanceName(), {arg}, sourceInfo()); then fail();
1884+
end match;
1885+
18631886
else algorithm printWrongArgsError(getInstanceName(), {arg}, sourceInfo()); then fail();
1864-
end matchcontinue;
1887+
end match;
18651888
end evalBuiltinProduct;
18661889

18671890
function evalBuiltinProductInt
@@ -2073,11 +2096,16 @@ function evalBuiltinSum
20732096
input Expression arg;
20742097
output Expression result;
20752098
algorithm
2076-
result := matchcontinue Type.arrayElementType(Expression.typeOf(arg))
2077-
case Type.INTEGER() then Expression.INTEGER(Expression.fold(arg, evalBuiltinSumInt, 0));
2078-
case Type.REAL() then Expression.REAL(Expression.fold(arg, evalBuiltinSumReal, 0.0));
2099+
result := match arg
2100+
case Expression.ARRAY()
2101+
then match Type.arrayElementType(Expression.typeOf(arg))
2102+
case Type.INTEGER() then Expression.INTEGER(Expression.fold(arg, evalBuiltinSumInt, 0));
2103+
case Type.REAL() then Expression.REAL(Expression.fold(arg, evalBuiltinSumReal, 0.0));
2104+
else algorithm printWrongArgsError(getInstanceName(), {arg}, sourceInfo()); then fail();
2105+
end match;
2106+
20792107
else algorithm printWrongArgsError(getInstanceName(), {arg}, sourceInfo()); then fail();
2080-
end matchcontinue;
2108+
end match;
20812109
end evalBuiltinSum;
20822110

20832111
function evalBuiltinSumInt

Compiler/NFFrontEnd/NFConnections.mo

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ public
8080
DAE.ElementSource source;
8181
list<Equation> eql = {};
8282
list<Connector> cl1, cl2;
83+
Expression e1, e2;
84+
Type ty1, ty2;
8385
algorithm
8486
// Collect all flow variables.
8587
for var in flatModel.variables loop
@@ -95,12 +97,14 @@ public
9597
// Collect all connects.
9698
for eq in flatModel.equations loop
9799
eql := match eq
98-
case Equation.CONNECT(lhs = Expression.CREF(cref = lhs),
99-
rhs = Expression.CREF(cref = rhs), source = source)
100+
case Equation.CONNECT(lhs = Expression.CREF(ty = ty1, cref = lhs),
101+
rhs = Expression.CREF(ty = ty2, cref = rhs), source = source)
100102
algorithm
101103
if not (ComponentRef.isDeleted(lhs) or ComponentRef.isDeleted(rhs)) then
102-
cl1 := Connector.fromExp(ExpandExp.expand(eq.lhs), source);
103-
cl2 := Connector.fromExp(ExpandExp.expand(eq.rhs), source);
104+
e1 := Expression.CREF(ty1, ComponentRef.simplifySubscripts(lhs));
105+
cl1 := Connector.fromExp(ExpandExp.expand(e1), source);
106+
e2 := Expression.CREF(ty2, ComponentRef.simplifySubscripts(rhs));
107+
cl2 := Connector.fromExp(ExpandExp.expand(e2), source);
104108

105109
for c1 in cl1 loop
106110
c2 :: cl2 := cl2;

Compiler/NFFrontEnd/NFExpression.mo

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ public
6161
import NFClassTree.ClassTree;
6262
import NFClass.Class;
6363
import NFComponentRef.Origin;
64+
import NFTyping.ExpOrigin;
6465

6566
record INTEGER
6667
Integer value;
@@ -2816,6 +2817,18 @@ public
28162817
end match;
28172818
end isIterator;
28182819

2820+
function containsIterator
2821+
input Expression exp;
2822+
input ExpOrigin.Type origin;
2823+
output Boolean iter;
2824+
algorithm
2825+
if intBitAnd(origin, ExpOrigin.FOR) > 0 then
2826+
iter := contains(exp, isIterator);
2827+
else
2828+
iter := false;
2829+
end if;
2830+
end containsIterator;
2831+
28192832
function isZero
28202833
input Expression exp;
28212834
output Boolean isZero;
@@ -2829,6 +2842,20 @@ public
28292842
end match;
28302843
end isZero;
28312844

2845+
function isPositive
2846+
input Expression exp;
2847+
output Boolean positive;
2848+
algorithm
2849+
positive := match exp
2850+
case INTEGER() then exp.value > 0;
2851+
case REAL() then exp.value > 0;
2852+
case BOOLEAN() then true;
2853+
case ENUM_LITERAL() then true;
2854+
case CAST() then isPositive(exp.exp);
2855+
case UNARY() then not isPositive(exp.exp);
2856+
end match;
2857+
end isPositive;
2858+
28322859
function isScalarLiteral
28332860
input Expression exp;
28342861
output Boolean literal;
@@ -2855,6 +2882,9 @@ public
28552882
case ENUM_LITERAL() then true;
28562883
case ARRAY() then List.all(exp.elements, isLiteral);
28572884
case RECORD() then List.all(exp.elements, isLiteral);
2885+
case RANGE() then isLiteral(exp.start) and
2886+
isLiteral(exp.stop) and
2887+
Util.applyOptionOrDefault(exp.step, isLiteral, true);
28582888
else false;
28592889
end match;
28602890
end isLiteral;

Compiler/NFFrontEnd/NFFlatten.mo

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -700,7 +700,9 @@ algorithm
700700
Equation.FOR(iterator = iter, range = SOME(range), body = body) := forLoop;
701701

702702
// Unroll the loop by replacing the iterator with each of its values in the for loop body.
703+
range := Ceval.evalExp(range, Ceval.EvalTarget.RANGE(Equation.info(forLoop)));
703704
range_iter := RangeIterator.fromExp(range);
705+
704706
while RangeIterator.hasNext(range_iter) loop
705707
(range_iter, val) := RangeIterator.next(range_iter);
706708
unrolled_body := list(Equation.mapExp(eq,

Compiler/NFFrontEnd/NFRangeIterator.mo

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,15 @@ public
4040

4141
record INT_RANGE
4242
Integer current;
43-
Integer stepsize;
4443
Integer last;
4544
end INT_RANGE;
4645

46+
record INT_STEP_RANGE
47+
Integer current;
48+
Integer stepsize;
49+
Integer last;
50+
end INT_STEP_RANGE;
51+
4752
record REAL_RANGE
4853
Real start;
4954
Real stepsize;
@@ -91,13 +96,12 @@ public
9196
case Expression.RANGE(start = Expression.INTEGER(istart),
9297
step = SOME(Expression.INTEGER(istep)),
9398
stop = Expression.INTEGER(istop))
94-
then
95-
INT_RANGE(istart, istep, istop);
99+
then INT_STEP_RANGE(istart, istep, istop);
96100

97101
case Expression.RANGE(start = Expression.INTEGER(istart),
98102
step = NONE(),
99103
stop = Expression.INTEGER(istop))
100-
then INT_RANGE(istart, 1, istop);
104+
then INT_RANGE(istart, istop);
101105

102106
case Expression.RANGE(start = Expression.REAL(rstart),
103107
step = SOME(Expression.REAL(rstep)),
@@ -145,7 +149,7 @@ public
145149
Type ty;
146150
list<Expression> expl;
147151

148-
case Dimension.INTEGER() then INT_RANGE(1, 1, dim.size);
152+
case Dimension.INTEGER() then INT_RANGE(1, dim.size);
149153

150154
case Dimension.BOOLEAN()
151155
then ARRAY_RANGE({Expression.BOOLEAN(false), Expression.BOOLEAN(true)});
@@ -170,6 +174,13 @@ public
170174
algorithm
171175
nextExp := match iterator
172176
case INT_RANGE()
177+
algorithm
178+
nextExp := Expression.INTEGER(iterator.current);
179+
iterator.current := iterator.current + 1;
180+
then
181+
nextExp;
182+
183+
case INT_STEP_RANGE()
173184
algorithm
174185
nextExp := Expression.INTEGER(iterator.current);
175186
iterator.current := iterator.current + iterator.stepsize;
@@ -205,6 +216,8 @@ public
205216
algorithm
206217
hasNext := match iterator
207218
case INT_RANGE() then iterator.current <= iterator.last;
219+
case INT_STEP_RANGE() then if iterator.stepsize > 0 then iterator.current <= iterator.last
220+
else iterator.current >= iterator.last;
208221
case REAL_RANGE() then iterator.current < iterator.steps;
209222
case ARRAY_RANGE() then not listEmpty(iterator.values);
210223
case INVALID_RANGE()
@@ -255,5 +268,24 @@ public
255268
lst := listReverse(lst);
256269
end map;
257270

271+
function fold<ArgT>
272+
input RangeIterator iterator;
273+
input FuncT func;
274+
input output ArgT arg;
275+
276+
partial function FuncT
277+
input Expression exp;
278+
input output ArgT arg;
279+
end FuncT;
280+
protected
281+
RangeIterator iter = iterator;
282+
Expression exp;
283+
algorithm
284+
while hasNext(iter) loop
285+
(iter, exp) := next(iter);
286+
arg := func(exp, arg);
287+
end while;
288+
end fold;
289+
258290
annotation(__OpenModelica_Interface="frontend");
259291
end NFRangeIterator;

Compiler/NFFrontEnd/NFSimplifyExp.mo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ algorithm
119119

120120
// Use Ceval for builtin pure functions with literal arguments.
121121
if builtin and not Function.isImpure(call.fn) and List.all(args, Expression.isLiteral) then
122-
callExp := Ceval.evalBuiltinCall(call.fn, args, EvalTarget.IGNORE_ERRORS());
122+
callExp := Ceval.evalCall(call, EvalTarget.IGNORE_ERRORS());
123123
else
124124
callExp := Expression.CALL(call);
125125
end if;

Compiler/NFFrontEnd/NFSimplifyModel.mo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ algorithm
147147
algorithm
148148
eq.condition := SimplifyExp.simplify(eq.condition);
149149
then
150-
if Expression.isFalse(eq.condition) then equations else eq :: equations;
150+
if Expression.isTrue(eq.condition) then equations else eq :: equations;
151151

152152
case Equation.REINIT()
153153
algorithm

0 commit comments

Comments
 (0)