Skip to content

Commit

Permalink
[NF] Initial function evaluation implementation.
Browse files Browse the repository at this point in the history
- Implemented basic function evaluation that supports all control
  structures and scalar assignments, but not e.g. arrays or records.
- Moved storage of iteration ranges from the mutable iterators to the
  loop or reductions themselves, so they can safely be modified.
- Added new mutable Expression for use by the function evaluation to
  avoid having to do name lookup.
- Added flags --evalLoopLimit and --evalRecursionLimit to let users
  set the limits used to avoid infinite evaluation or stack overflows.

Belonging to [master]:
  - #73
  - OpenModelica/OMCompiler#2407
  - OpenModelica/OpenModelica-testsuite#936
  • Loading branch information
perost authored and OpenModelica-Hudson committed May 3, 2018
1 parent f92e6eb commit cd7b28a
Show file tree
Hide file tree
Showing 18 changed files with 675 additions and 250 deletions.
41 changes: 27 additions & 14 deletions Compiler/NFFrontEnd/NFBuiltinFuncs.mo
Expand Up @@ -128,7 +128,7 @@ constant InstNode INTEGER_DUMMY_NODE = NFInstNode.CLASS_NODE("Integer",
constant Function INTEGER_FUNCTION = Function.FUNCTION(Path.IDENT("Integer"),
INTEGER_DUMMY_NODE, {ENUM_PARAM}, {}, {}, {
Slot.SLOT("e", SlotType.POSITIONAL, NONE(), NONE())
}, Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
}, Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true), Pointer.createImmutable(0));

constant InstNode INTEGER_NODE = InstNode.CLASS_NODE("IntegerFunc",
DUMMY_ELEMENT, Visibility.PUBLIC,
Expand All @@ -153,38 +153,43 @@ constant Function STRING_REAL = Function.FUNCTION(Path.IDENT("String"),
Slot.SLOT("significantDigits", SlotType.NAMED, SOME(Expression.INTEGER(6)), NONE()),
Slot.SLOT("minimumLength", SlotType.NAMED, SOME(Expression.INTEGER(0)), NONE()),
Slot.SLOT("leftJustified", SlotType.NAMED, SOME(Expression.BOOLEAN(true)), NONE())
}, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
}, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

// String(r, format="-0.6g")
constant Function STRING_REAL_FORMAT = Function.FUNCTION(Path.IDENT("String"),
STRING_DUMMY_NODE, {REAL_PARAM, STRING_PARAM}, {STRING_PARAM}, {}, {
Slot.SLOT("r", SlotType.POSITIONAL, NONE(), NONE()),
Slot.SLOT("format", SlotType.NAMED, NONE(), NONE())
}, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
}, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

// String(i, minimumLength=0, leftJustified=true)
constant Function STRING_INT = Function.FUNCTION(Path.IDENT("String"),
STRING_DUMMY_NODE, {INT_PARAM, INT_PARAM, BOOL_PARAM}, {STRING_PARAM}, {}, {
Slot.SLOT("i", SlotType.POSITIONAL, NONE(), NONE()),
Slot.SLOT("minimumLength", SlotType.NAMED, SOME(Expression.INTEGER(0)), NONE()),
Slot.SLOT("leftJustified", SlotType.NAMED, SOME(Expression.BOOLEAN(true)), NONE())
}, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
}, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

// String(b, minimumLength=0, leftJustified=true)
constant Function STRING_BOOL = Function.FUNCTION(Path.IDENT("String"),
STRING_DUMMY_NODE, {BOOL_PARAM, INT_PARAM, BOOL_PARAM}, {STRING_PARAM}, {}, {
Slot.SLOT("b", SlotType.POSITIONAL, NONE(), NONE()),
Slot.SLOT("minimumLength", SlotType.NAMED, SOME(Expression.INTEGER(0)), NONE()),
Slot.SLOT("leftJustified", SlotType.NAMED, SOME(Expression.BOOLEAN(true)), NONE())
}, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
}, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

// String(e, minimumLength=0, leftJustified=true)
constant Function STRING_ENUM = Function.FUNCTION(Path.IDENT("String"),
STRING_DUMMY_NODE, {ENUM_PARAM, INT_PARAM, BOOL_PARAM}, {STRING_PARAM}, {}, {
Slot.SLOT("e", SlotType.POSITIONAL, NONE(), NONE()),
Slot.SLOT("minimumLength", SlotType.NAMED, SOME(Expression.INTEGER(0)), NONE()),
Slot.SLOT("leftJustified", SlotType.NAMED, SOME(Expression.BOOLEAN(true)), NONE())
}, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
}, Type.STRING(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

constant InstNode STRING_NODE = InstNode.CLASS_NODE("String",
DUMMY_ELEMENT, Visibility.PUBLIC,
Expand All @@ -208,35 +213,43 @@ constant ComponentRef STRING_CREF =

constant Function ABS_REAL = Function.FUNCTION(Path.IDENT("abs"),
InstNode.EMPTY_NODE(), {REAL_PARAM, REAL_PARAM}, {REAL_PARAM}, {}, {},
Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

constant Function MAX_REAL = Function.FUNCTION(Path.IDENT("max"),
InstNode.EMPTY_NODE(), {REAL_PARAM, REAL_PARAM}, {REAL_PARAM}, {}, {},
Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

constant Function POSITIVE_MAX_REAL = Function.FUNCTION(Path.IDENT("$OMC$PositiveMax"),
InstNode.EMPTY_NODE(), {REAL_PARAM, REAL_PARAM}, {REAL_PARAM}, {}, {},
Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

constant Function IN_STREAM = Function.FUNCTION(Path.IDENT("inStream"),
InstNode.EMPTY_NODE(), {REAL_PARAM}, {REAL_PARAM}, {}, {},
Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

constant Function PROMOTE = Function.FUNCTION(Path.IDENT("promote"),
InstNode.EMPTY_NODE(), {}, {}, {}, {},
Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

constant Function CAT = Function.FUNCTION(Path.IDENT("cat"),
InstNode.EMPTY_NODE(), {}, {}, {}, {},
Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

constant Function ARRAY_FUNC = Function.FUNCTION(Path.IDENT("array"),
InstNode.EMPTY_NODE(), {}, {}, {}, {},
Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

constant Function FILL_FUNC = Function.FUNCTION(Path.IDENT("fill"),
InstNode.EMPTY_NODE(), {}, {}, {}, {},
Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN, Pointer.createImmutable(true));
Type.UNKNOWN(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

annotation(__OpenModelica_Interface="frontend");
end NFBuiltinFuncs;
171 changes: 81 additions & 90 deletions Compiler/NFFrontEnd/NFCall.mo
Expand Up @@ -165,15 +165,15 @@ uniontype Call
record UNTYPED_MAP_CALL
// Function fn;
Expression exp;
list<InstNode> iters;
list<tuple<InstNode, Expression>> iters;
end UNTYPED_MAP_CALL;

record TYPED_MAP_CALL
// Function fn;
Type ty;
Variability var;
Expression exp;
list<InstNode> iters;
list<tuple<InstNode, Expression>> iters;
end TYPED_MAP_CALL;

function instantiate
Expand Down Expand Up @@ -271,7 +271,7 @@ uniontype Call
protected
ComponentRef fn_ref, arr_fn_ref;
Expression exp;
list<InstNode> iters;
list<tuple<InstNode, Expression>> iters;
Call call;
Boolean is_builtin_reduction, is_array;
algorithm
Expand Down Expand Up @@ -320,7 +320,7 @@ uniontype Call
input InstNode scope;
input SourceInfo info;
output Expression exp;
output list<InstNode> iters;
output list<tuple<InstNode, Expression>> iters;
algorithm
_ := match args
local
Expand All @@ -340,16 +340,15 @@ uniontype Call
input InstNode scope;
input SourceInfo info;
output InstNode outScope = scope;
output list<InstNode> outIters = {};
output list<tuple<InstNode, Expression>> outIters = {};
protected
Binding binding;
Expression range;
InstNode iter;
algorithm
for i in inIters loop
binding := Binding.fromAbsyn(i.range, false, 0, outScope, info);
binding := Inst.instBinding(binding);
(outScope, iter) := Inst.addIteratorToScope(i.name, binding, outScope, info);
outIters := iter :: outIters;
range := Inst.instExp(Util.getOption(i.range), outScope, info);
(outScope, iter) := Inst.addIteratorToScope(i.name, outScope, info);
outIters := (iter, range) :: outIters;
end for;

outIters := listReverse(outIters);
Expand Down Expand Up @@ -489,35 +488,40 @@ uniontype Call
output Type ty;
output Variability variability;
protected
Expression arg;
Type arg_ty;
Expression arg, range;
Type iter_ty;
Binding binding;
Variability arg_var;
Variability iter_var;
InstNode iter;
list<Dimension> dims = {};
list<tuple<InstNode, Expression>> iters = {};
algorithm
(call, ty, variability) := match call
// This is always a call to the function array()/$array(). See instIteratorCall.
// Other mapping function calls are already wrapped by array() at this point.
case UNTYPED_MAP_CALL() algorithm

for iter in call.iters loop
Typing.typeIterator(iter, ExpOrigin.FUNCTION, structural = false);
end for;
(arg, arg_ty, arg_var) := Typing.typeExp(call.exp, origin, info);

ty := arg_ty;
variability := Variability.CONSTANT;
for iter in call.iters loop
binding := Component.getBinding(InstNode.component(iter));
ty := Type.liftArrayLeftList(ty,Type.arrayDims(Binding.getType(binding)));
variability := Variability.variabilityMax(variability,Binding.variability(binding));
end for;
then
(TYPED_MAP_CALL(ty, variability, arg, call.iters), ty, variability);
case UNTYPED_MAP_CALL()
algorithm
variability := Variability.CONSTANT;

for i in call.iters loop
(iter, range) := i;
(range, iter_ty, iter_var) := Typing.typeIterator(iter, range, ExpOrigin.FUNCTION, structural = false);
dims := listAppend(Type.arrayDims(iter_ty), dims);
variability := Variability.variabilityMax(variability, iter_var);
iters := (iter, range) :: iters;
end for;
iters := listReverseInPlace(iters);

else algorithm
Error.assertion(false, getInstanceName() + " got invalid function call expression", sourceInfo());
then
fail();
(arg, ty) := Typing.typeExp(call.exp, origin, info);
ty := Type.liftArrayLeftList(ty, dims);
then
(TYPED_MAP_CALL(ty, variability, arg, iters), ty, variability);

else
algorithm
Error.assertion(false, getInstanceName() + " got invalid function call expression", sourceInfo());
then
fail();
end match;
end typeMapIteratorCall;

Expand Down Expand Up @@ -646,69 +650,60 @@ uniontype Call
function vectorizeCall
input Call base_call;
input FunctionMatchKind mk;
input InstNode call_scope;
input InstNode scope;
input SourceInfo info;
output Call vectorized_call;
protected
Type ty, vect_ty;
Expression exp;
Binding bind;
list<InstNode> iters;
InstNode iter, iter_scope;
list<tuple<InstNode, Expression>> iters;
InstNode iter;
BindingOrigin origin;
Integer i;
list<Dimension> vect_dims;
list<Boolean> arg_is_vected, b_list;
Boolean b;
list<Expression> vect_args;
algorithm

vectorized_call := match base_call
case TYPED_CALL() algorithm

FunctionMatchKind.VECTORIZED(vect_dims, arg_is_vected) := mk;
iters := {};
iter_scope := call_scope;
i := 1;

for dim in vect_dims loop

// Create a range binding on which we will iterate to vectorize.
ty := Type.ARRAY(Type.INTEGER(), {dim});
exp := Expression.RANGE(ty, Expression.INTEGER(1), NONE(), Expression.INTEGER(Dimension.size(dim)));
origin := BindingOrigin.create(0, NFBindingOrigin.ElementType.COMPONENT, info);
bind := Binding.TYPED_BINDING(exp, ty, Variability.CONSTANT, origin, false);

// Add an iterator to the call scope.
(iter_scope, iter) := Inst.addIteratorToScope("$i" + intString(i), bind, iter_scope, info, Type.INTEGER());
iters := iter::iters;

// Now that iterator is ready apply it, as a subscript, to each argument that is supposed to be vectorized
// Make a cref expression from the iterator
exp := Expression.CREF(Type.INTEGER(), ComponentRef.makeIterator(iter, Type.INTEGER()));
vect_args := {};
b_list := arg_is_vected;
for arg in base_call.arguments loop
b::b_list := b_list;
// If the argument is supposed to be vectorized
if b then
vect_args := Expression.applyIndexSubscript(exp, arg)::vect_args;
else
vect_args := arg::vect_args;
end if;
end for;
base_call.arguments := listReverse(vect_args);

i := i + 1;
end for;
// iters := listReverse(iters);
case TYPED_CALL()
algorithm
FunctionMatchKind.VECTORIZED(vect_dims, arg_is_vected) := mk;
iters := {};
i := 1;

for dim in vect_dims loop
// Create the range on which we will iterate to vectorize.
ty := Type.ARRAY(Type.INTEGER(), {dim});
exp := Expression.RANGE(ty, Expression.INTEGER(1), NONE(), Expression.INTEGER(Dimension.size(dim)));

// Create the iterator.
iter := InstNode.fromComponent("$i" + intString(i),
Component.ITERATOR(Type.INTEGER(), Variability.CONSTANT, info), scope);

iters := (iter, exp) :: iters;

// Now that iterator is ready apply it, as a subscript, to each argument that is supposed to be vectorized
// Make a cref expression from the iterator
exp := Expression.CREF(Type.INTEGER(), ComponentRef.makeIterator(iter, Type.INTEGER()));
vect_args := {};
b_list := arg_is_vected;
for arg in base_call.arguments loop
// If the argument is supposed to be vectorized
b :: b_list := b_list;
vect_args := (if b then Expression.applyIndexSubscript(exp, arg) else arg) :: vect_args;
end for;

vect_ty := Type.liftArrayLeftList(base_call.ty, vect_dims);
base_call.arguments := listReverse(vect_args);
i := i + 1;
end for;

then TYPED_MAP_CALL(vect_ty, base_call.var, Expression.CALL(base_call), iters);
vect_ty := Type.liftArrayLeftList(base_call.ty, vect_dims);
then
TYPED_MAP_CALL(vect_ty, base_call.var, Expression.CALL(base_call), iters);

end match;

end vectorizeCall;

function evaluateCallType
Expand Down Expand Up @@ -1235,19 +1230,17 @@ protected
end toDAE;

function iteratorToDAE
input InstNode iter;
input tuple<InstNode, Expression> iter;
output DAE.ReductionIterator diter;
protected
InstNode iter_node;
Expression iter_range;
Component c;
Binding b;
algorithm
c := InstNode.component(iter);
diter := match c
case Component.ITERATOR() algorithm
b := Component.getBinding(c);
then
DAE.REDUCTIONITER(InstNode.name(iter), Expression.toDAE(Binding.getTypedExp(b)), NONE(), Type.toDAE(Binding.getType(b)));
end match;
(iter_node, iter_range) := iter;
diter := DAE.REDUCTIONITER(InstNode.name(iter_node), Expression.toDAE(iter_range), NONE(),
Type.toDAE(Expression.typeOf(iter_range)));
end iteratorToDAE;

function toString
Expand Down Expand Up @@ -1295,10 +1288,8 @@ protected
algorithm
name := Absyn.pathString(Function.name(NFBuiltinFuncs.ARRAY_FUNC));
arg_str := Expression.toString(call.exp);
c := stringDelimitList(list(
InstNode.name(iter) + " in "+ Binding.toString(Component.getBinding(InstNode.component(iter)))
for iter in call.iters)
, ", ");
c := stringDelimitList(list(InstNode.name(Util.tuple21(iter)) + " in " +
Expression.toString(Util.tuple22(iter)) for iter in call.iters), ", ");
then
name + "(" + arg_str + " for " + c + ")";

Expand Down

0 comments on commit cd7b28a

Please sign in to comment.