Skip to content

Commit

Permalink
[NF] Evaluation improvements.
Browse files Browse the repository at this point in the history
- 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]:
  - OpenModelica/OMCompiler#2499
  - OpenModelica/OpenModelica-testsuite#972
  • Loading branch information
perost authored and OpenModelica-Hudson committed Jun 8, 2018
1 parent 58dca93 commit 82c686d
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 57 deletions.
8 changes: 6 additions & 2 deletions Compiler/NFFrontEnd/NFBuiltinCall.mo
Expand Up @@ -802,17 +802,21 @@ protected
Type arg_ty;
Function fn;
list<Dimension> dims;
Boolean evaluated;
algorithm
ty_args := {fillArg};
dims := {};
evaluated := true;

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

if arg_var <= Variability.STRUCTURAL_PARAMETER then
if arg_var <= Variability.STRUCTURAL_PARAMETER and not Expression.containsIterator(arg, origin) then
arg := Ceval.evalExp(arg);
arg_ty := Expression.typeOf(arg);
else
evaluated := false;
end if;

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

if variability <= Variability.STRUCTURAL_PARAMETER and intBitAnd(origin, ExpOrigin.FUNCTION) == 0 then
if evaluated and intBitAnd(origin, ExpOrigin.FUNCTION) == 0 then
callExp := Ceval.evalBuiltinFill(ty_args);
else
callExp := Expression.CALL(Call.makeTypedCall(NFBuiltinFuncs.FILL_FUNC, ty_args, variability, ty));
Expand Down
5 changes: 4 additions & 1 deletion Compiler/NFFrontEnd/NFCall.mo
Expand Up @@ -816,6 +816,7 @@ protected
InstNode iter;
list<Dimension> dims = {};
list<tuple<InstNode, Expression>> iters = {};
ExpOrigin.Type next_origin;
algorithm
(call, ty, variability) := match call
// This is always a call to the function array()/$array(). See instIteratorCall.
Expand All @@ -833,7 +834,9 @@ protected
end for;
iters := listReverseInPlace(iters);

(arg, ty) := Typing.typeExp(call.exp, origin, info);
// ExpOrigin.FOR is used here as a marker that this expression may contain iterators.
next_origin := intBitOr(origin, ExpOrigin.FOR);
(arg, ty) := Typing.typeExp(call.exp, next_origin, info);
ty := Type.liftArrayLeftList(ty, dims);
then
(TYPED_MAP_CALL(ty, variability, arg, iters), ty, variability);
Expand Down
74 changes: 51 additions & 23 deletions Compiler/NFFrontEnd/NFCeval.mo
Expand Up @@ -604,7 +604,7 @@ algorithm

else
algorithm
exp := Expression.BINARY(exp1, Operator.makeMul(Type.UNKNOWN()), exp2);
exp := Expression.BINARY(exp1, Operator.makeDiv(Type.UNKNOWN()), exp2);
printFailedEvalError(getInstanceName(), exp, sourceInfo());
then
fail();
Expand Down Expand Up @@ -1279,8 +1279,8 @@ algorithm
case "log10" then evalBuiltinLog10(listHead(args), target);
case "log" then evalBuiltinLog(listHead(args), target);
case "matrix" then evalBuiltinMatrix(listHead(args));
case "max" then evalBuiltinMax(args);
case "min" then evalBuiltinMin(args);
case "max" then evalBuiltinMax(args, fn);
case "min" then evalBuiltinMin(args, fn);
case "mod" then evalBuiltinMod(args);
case "noEvent" then listHead(args); // No events during ceval, just return the argument.
case "ones" then evalBuiltinOnes(args);
Expand Down Expand Up @@ -1755,14 +1755,26 @@ end evalBuiltinMatrix2;

function evalBuiltinMax
input list<Expression> args;
input Function fn;
output Expression result;
protected
Expression e1, e2;
list<Expression> expl;
Type ty;
algorithm
result := match args
case {e1, e2} then evalBuiltinMax2(e1, e2);
case {Expression.ARRAY(elements = expl)} then evalBuiltinMax2(e for e in expl);
case {e1 as Expression.ARRAY(ty = ty)}
algorithm
result := Expression.fold(e1, evalBuiltinMax2, Expression.EMPTY());

if Expression.isEmpty(result) then
result := Expression.CALL(Call.makeTypedCall(fn,
{Expression.ARRAY(ty, {})}, Variability.CONSTANT, Type.arrayElementType(ty)));
end if;
then
result;

else algorithm printWrongArgsError(getInstanceName(), args, sourceInfo()); then fail();
end match;
end evalBuiltinMax;
Expand All @@ -1781,25 +1793,34 @@ algorithm
then if exp1.value < exp2.value then exp2 else exp1;
case (Expression.ENUM_LITERAL(), Expression.ENUM_LITERAL())
then if exp1.index < exp2.index then exp2 else exp1;
case (Expression.ARRAY(), Expression.ARRAY())
then evalBuiltinMax2(evalBuiltinMax2(e for e in exp1.elements),
evalBuiltinMax2(e for e in exp2.elements));
case (Expression.ARRAY(), _)
then evalBuiltinMax2(evalBuiltinMax2(e for e in exp1.elements), exp2);
case (Expression.ARRAY(), _) then exp2;
case (_, Expression.EMPTY()) then exp1;
else algorithm printWrongArgsError(getInstanceName(), {exp1, exp2}, sourceInfo()); then fail();
end match;
end evalBuiltinMax2;

function evalBuiltinMin
input list<Expression> args;
input Function fn;
output Expression result;
protected
Expression e1, e2;
list<Expression> expl;
Type ty;
algorithm
result := match args
case {e1, e2} then evalBuiltinMin2(e1, e2);
case {Expression.ARRAY(elements = expl)} then evalBuiltinMin2(e for e in expl);
case {e1 as Expression.ARRAY(ty = ty)}
algorithm
result := Expression.fold(e1, evalBuiltinMin2, Expression.EMPTY());

if Expression.isEmpty(result) then
result := Expression.CALL(Call.makeTypedCall(fn,
{Expression.ARRAY(ty, {})}, Variability.CONSTANT, Type.arrayElementType(ty)));
end if;
then
result;

else algorithm printWrongArgsError(getInstanceName(), args, sourceInfo()); then fail();
end match;
end evalBuiltinMin;
Expand All @@ -1818,11 +1839,8 @@ algorithm
then if exp1.value > exp2.value then exp2 else exp1;
case (Expression.ENUM_LITERAL(), Expression.ENUM_LITERAL())
then if exp1.index > exp2.index then exp2 else exp1;
case (Expression.ARRAY(), Expression.ARRAY())
then evalBuiltinMin2(evalBuiltinMin2(e for e in exp1.elements),
evalBuiltinMin2(e for e in exp2.elements));
case (Expression.ARRAY(), _)
then evalBuiltinMin2(evalBuiltinMin2(e for e in exp1.elements), exp2);
case (Expression.ARRAY(), _) then exp2;
case (_, Expression.EMPTY()) then exp1;
else algorithm printWrongArgsError(getInstanceName(), {exp1, exp2}, sourceInfo()); then fail();
end match;
end evalBuiltinMin2;
Expand Down Expand Up @@ -1857,11 +1875,16 @@ function evalBuiltinProduct
input Expression arg;
output Expression result;
algorithm
result := matchcontinue Type.arrayElementType(Expression.typeOf(arg))
case Type.INTEGER() then Expression.INTEGER(Expression.fold(arg, evalBuiltinProductInt, 1));
case Type.REAL() then Expression.REAL(Expression.fold(arg, evalBuiltinProductReal, 1.0));
result := match arg
case Expression.ARRAY()
then match Type.arrayElementType(Expression.typeOf(arg))
case Type.INTEGER() then Expression.INTEGER(Expression.fold(arg, evalBuiltinProductInt, 1));
case Type.REAL() then Expression.REAL(Expression.fold(arg, evalBuiltinProductReal, 1.0));
else algorithm printWrongArgsError(getInstanceName(), {arg}, sourceInfo()); then fail();
end match;

else algorithm printWrongArgsError(getInstanceName(), {arg}, sourceInfo()); then fail();
end matchcontinue;
end match;
end evalBuiltinProduct;

function evalBuiltinProductInt
Expand Down Expand Up @@ -2073,11 +2096,16 @@ function evalBuiltinSum
input Expression arg;
output Expression result;
algorithm
result := matchcontinue Type.arrayElementType(Expression.typeOf(arg))
case Type.INTEGER() then Expression.INTEGER(Expression.fold(arg, evalBuiltinSumInt, 0));
case Type.REAL() then Expression.REAL(Expression.fold(arg, evalBuiltinSumReal, 0.0));
result := match arg
case Expression.ARRAY()
then match Type.arrayElementType(Expression.typeOf(arg))
case Type.INTEGER() then Expression.INTEGER(Expression.fold(arg, evalBuiltinSumInt, 0));
case Type.REAL() then Expression.REAL(Expression.fold(arg, evalBuiltinSumReal, 0.0));
else algorithm printWrongArgsError(getInstanceName(), {arg}, sourceInfo()); then fail();
end match;

else algorithm printWrongArgsError(getInstanceName(), {arg}, sourceInfo()); then fail();
end matchcontinue;
end match;
end evalBuiltinSum;

function evalBuiltinSumInt
Expand Down
12 changes: 8 additions & 4 deletions Compiler/NFFrontEnd/NFConnections.mo
Expand Up @@ -80,6 +80,8 @@ public
DAE.ElementSource source;
list<Equation> eql = {};
list<Connector> cl1, cl2;
Expression e1, e2;
Type ty1, ty2;
algorithm
// Collect all flow variables.
for var in flatModel.variables loop
Expand All @@ -95,12 +97,14 @@ public
// Collect all connects.
for eq in flatModel.equations loop
eql := match eq
case Equation.CONNECT(lhs = Expression.CREF(cref = lhs),
rhs = Expression.CREF(cref = rhs), source = source)
case Equation.CONNECT(lhs = Expression.CREF(ty = ty1, cref = lhs),
rhs = Expression.CREF(ty = ty2, cref = rhs), source = source)
algorithm
if not (ComponentRef.isDeleted(lhs) or ComponentRef.isDeleted(rhs)) then
cl1 := Connector.fromExp(ExpandExp.expand(eq.lhs), source);
cl2 := Connector.fromExp(ExpandExp.expand(eq.rhs), source);
e1 := Expression.CREF(ty1, ComponentRef.simplifySubscripts(lhs));
cl1 := Connector.fromExp(ExpandExp.expand(e1), source);
e2 := Expression.CREF(ty2, ComponentRef.simplifySubscripts(rhs));
cl2 := Connector.fromExp(ExpandExp.expand(e2), source);

for c1 in cl1 loop
c2 :: cl2 := cl2;
Expand Down
30 changes: 30 additions & 0 deletions Compiler/NFFrontEnd/NFExpression.mo
Expand Up @@ -61,6 +61,7 @@ public
import NFClassTree.ClassTree;
import NFClass.Class;
import NFComponentRef.Origin;
import NFTyping.ExpOrigin;

record INTEGER
Integer value;
Expand Down Expand Up @@ -2816,6 +2817,18 @@ public
end match;
end isIterator;

function containsIterator
input Expression exp;
input ExpOrigin.Type origin;
output Boolean iter;
algorithm
if intBitAnd(origin, ExpOrigin.FOR) > 0 then
iter := contains(exp, isIterator);
else
iter := false;
end if;
end containsIterator;

function isZero
input Expression exp;
output Boolean isZero;
Expand All @@ -2829,6 +2842,20 @@ public
end match;
end isZero;

function isPositive
input Expression exp;
output Boolean positive;
algorithm
positive := match exp
case INTEGER() then exp.value > 0;
case REAL() then exp.value > 0;
case BOOLEAN() then true;
case ENUM_LITERAL() then true;
case CAST() then isPositive(exp.exp);
case UNARY() then not isPositive(exp.exp);
end match;
end isPositive;

function isScalarLiteral
input Expression exp;
output Boolean literal;
Expand All @@ -2855,6 +2882,9 @@ public
case ENUM_LITERAL() then true;
case ARRAY() then List.all(exp.elements, isLiteral);
case RECORD() then List.all(exp.elements, isLiteral);
case RANGE() then isLiteral(exp.start) and
isLiteral(exp.stop) and
Util.applyOptionOrDefault(exp.step, isLiteral, true);
else false;
end match;
end isLiteral;
Expand Down
2 changes: 2 additions & 0 deletions Compiler/NFFrontEnd/NFFlatten.mo
Expand Up @@ -700,7 +700,9 @@ algorithm
Equation.FOR(iterator = iter, range = SOME(range), body = body) := forLoop;

// Unroll the loop by replacing the iterator with each of its values in the for loop body.
range := Ceval.evalExp(range, Ceval.EvalTarget.RANGE(Equation.info(forLoop)));
range_iter := RangeIterator.fromExp(range);

while RangeIterator.hasNext(range_iter) loop
(range_iter, val) := RangeIterator.next(range_iter);
unrolled_body := list(Equation.mapExp(eq,
Expand Down
42 changes: 37 additions & 5 deletions Compiler/NFFrontEnd/NFRangeIterator.mo
Expand Up @@ -40,10 +40,15 @@ public

record INT_RANGE
Integer current;
Integer stepsize;
Integer last;
end INT_RANGE;

record INT_STEP_RANGE
Integer current;
Integer stepsize;
Integer last;
end INT_STEP_RANGE;

record REAL_RANGE
Real start;
Real stepsize;
Expand Down Expand Up @@ -91,13 +96,12 @@ public
case Expression.RANGE(start = Expression.INTEGER(istart),
step = SOME(Expression.INTEGER(istep)),
stop = Expression.INTEGER(istop))
then
INT_RANGE(istart, istep, istop);
then INT_STEP_RANGE(istart, istep, istop);

case Expression.RANGE(start = Expression.INTEGER(istart),
step = NONE(),
stop = Expression.INTEGER(istop))
then INT_RANGE(istart, 1, istop);
then INT_RANGE(istart, istop);

case Expression.RANGE(start = Expression.REAL(rstart),
step = SOME(Expression.REAL(rstep)),
Expand Down Expand Up @@ -145,7 +149,7 @@ public
Type ty;
list<Expression> expl;

case Dimension.INTEGER() then INT_RANGE(1, 1, dim.size);
case Dimension.INTEGER() then INT_RANGE(1, dim.size);

case Dimension.BOOLEAN()
then ARRAY_RANGE({Expression.BOOLEAN(false), Expression.BOOLEAN(true)});
Expand All @@ -170,6 +174,13 @@ public
algorithm
nextExp := match iterator
case INT_RANGE()
algorithm
nextExp := Expression.INTEGER(iterator.current);
iterator.current := iterator.current + 1;
then
nextExp;

case INT_STEP_RANGE()
algorithm
nextExp := Expression.INTEGER(iterator.current);
iterator.current := iterator.current + iterator.stepsize;
Expand Down Expand Up @@ -205,6 +216,8 @@ public
algorithm
hasNext := match iterator
case INT_RANGE() then iterator.current <= iterator.last;
case INT_STEP_RANGE() then if iterator.stepsize > 0 then iterator.current <= iterator.last
else iterator.current >= iterator.last;
case REAL_RANGE() then iterator.current < iterator.steps;
case ARRAY_RANGE() then not listEmpty(iterator.values);
case INVALID_RANGE()
Expand Down Expand Up @@ -255,5 +268,24 @@ public
lst := listReverse(lst);
end map;

function fold<ArgT>
input RangeIterator iterator;
input FuncT func;
input output ArgT arg;

partial function FuncT
input Expression exp;
input output ArgT arg;
end FuncT;
protected
RangeIterator iter = iterator;
Expression exp;
algorithm
while hasNext(iter) loop
(iter, exp) := next(iter);
arg := func(exp, arg);
end while;
end fold;

annotation(__OpenModelica_Interface="frontend");
end NFRangeIterator;
2 changes: 1 addition & 1 deletion Compiler/NFFrontEnd/NFSimplifyExp.mo
Expand Up @@ -119,7 +119,7 @@ algorithm

// Use Ceval for builtin pure functions with literal arguments.
if builtin and not Function.isImpure(call.fn) and List.all(args, Expression.isLiteral) then
callExp := Ceval.evalBuiltinCall(call.fn, args, EvalTarget.IGNORE_ERRORS());
callExp := Ceval.evalCall(call, EvalTarget.IGNORE_ERRORS());
else
callExp := Expression.CALL(call);
end if;
Expand Down
2 changes: 1 addition & 1 deletion Compiler/NFFrontEnd/NFSimplifyModel.mo
Expand Up @@ -147,7 +147,7 @@ algorithm
algorithm
eq.condition := SimplifyExp.simplify(eq.condition);
then
if Expression.isFalse(eq.condition) then equations else eq :: equations;
if Expression.isTrue(eq.condition) then equations else eq :: equations;

case Equation.REINIT()
algorithm
Expand Down

0 comments on commit 82c686d

Please sign in to comment.