Skip to content

Commit

Permalink
[NF] Inlining fixes.
Browse files Browse the repository at this point in the history
- Create an appropriate dimension expression for ranges of unknown size.
- Do replacements in array dimensions during inlining too.
- Fix Call.typeArgs so that only external function arguments are left
  unevaluated, and not all function arguments.

Belonging to [master]:
  - OpenModelica/OMCompiler#2418
  • Loading branch information
perost authored and OpenModelica-Hudson committed May 8, 2018
1 parent bc9cece commit 4912fd6
Show file tree
Hide file tree
Showing 6 changed files with 328 additions and 78 deletions.
25 changes: 25 additions & 0 deletions Compiler/NFFrontEnd/NFBuiltinFuncs.mo
Expand Up @@ -216,11 +216,36 @@ constant Function ABS_REAL = Function.FUNCTION(Path.IDENT("abs"),
Type.REAL(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

constant Function MAX_INT = Function.FUNCTION(Path.IDENT("max"),
InstNode.EMPTY_NODE(), {INT_PARAM, INT_PARAM}, {INT_PARAM}, {}, {},
Type.INTEGER(), 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), Pointer.createImmutable(0));

constant Function DIV_INT = Function.FUNCTION(Path.IDENT("div"),
InstNode.EMPTY_NODE(), {INT_PARAM, INT_PARAM}, {INT_PARAM}, {}, {},
Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

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

constant Function INTEGER_REAL = Function.FUNCTION(Path.IDENT("integer"),
InstNode.EMPTY_NODE(), {REAL_PARAM}, {INT_PARAM}, {}, {},
Type.INTEGER(), DAE.FUNCTION_ATTRIBUTES_BUILTIN,
Pointer.createImmutable(true), Pointer.createImmutable(0));

constant Function INTEGER_ENUM = Function.FUNCTION(Path.IDENT("Integer"),
InstNode.EMPTY_NODE(), {ENUM_PARAM}, {INT_PARAM}, {}, {},
Type.INTEGER(), 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,
Expand Down
47 changes: 34 additions & 13 deletions Compiler/NFFrontEnd/NFCall.mo
Expand Up @@ -550,15 +550,25 @@ uniontype Call
input SourceInfo info;
algorithm
call := match call
case UNTYPED_CALL() algorithm
typeCachedFunctions(call.ref);
then
typeArgs(call, origin, info);
local
list<Function> fnl;
Boolean is_external;

else algorithm
Error.assertion(false, getInstanceName() + " got invalid function call expression", sourceInfo());
then
fail();
case UNTYPED_CALL()
algorithm
fnl := typeCachedFunctions(call.ref);
// Don't evaluate constants or structural parameters for external functions,
// the code generation can't handle it in some cases (see bug #4904).
// TODO: Remove this when #4904 is fixed.
is_external := if listEmpty(fnl) then false else Function.isExternal(listHead(fnl));
then
typeArgs(call, not is_external, origin, info);

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

Expand All @@ -576,6 +586,7 @@ uniontype Call
case ComponentRef.CREF(node = fn_node)
algorithm
CachedData.FUNCTION(functions, typed, special) := InstNode.getFuncCache(fn_node);

// Type the function(s) if not already done.
if not typed then
functions := list(Function.typeFunction(f) for f in functions);
Expand Down Expand Up @@ -613,9 +624,6 @@ uniontype Call
matchedFunc := checkMatchingFunctions(call,info);

func := matchedFunc.func;
// Don't evaluate structural parameters for external functions, the code generation can't handle it in
// some cases (see bug #4904). For constants we'll get issues no matter if we evaluate them or not,
// but evaluating them will probably cause the last amount of issues.
typed_args := matchedFunc.args;

args := {};
Expand Down Expand Up @@ -840,6 +848,7 @@ uniontype Call

function typeArgs
input output Call call;
input Boolean replaceConstants;
input ExpOrigin.Type origin;
input SourceInfo info;
algorithm
Expand All @@ -856,7 +865,7 @@ uniontype Call
algorithm
typedArgs := {};
for arg in call.arguments loop
(arg, arg_ty, arg_var) := Typing.typeExp(arg, origin, info, replaceConstants = false);
(arg, arg_ty, arg_var) := Typing.typeExp(arg, origin, info, replaceConstants = replaceConstants);
typedArgs := (arg, arg_ty, arg_var) :: typedArgs;
end for;

Expand All @@ -865,7 +874,7 @@ uniontype Call
typedNamedArgs := {};
for narg in call.named_args loop
(name,arg) := narg;
(arg, arg_ty, arg_var) := Typing.typeExp(arg, origin, info, replaceConstants = false);
(arg, arg_ty, arg_var) := Typing.typeExp(arg, origin, info, replaceConstants = replaceConstants);
typedNamedArgs := (name, arg, arg_ty, arg_var) :: typedNamedArgs;
end for;

Expand Down Expand Up @@ -1512,6 +1521,18 @@ protected
callExp := Expression.CALL(call);
end typeStringCall;

function isExternal
input Call call;
output Boolean isExternal;
algorithm
isExternal := match call
case UNTYPED_CALL() then Class.isExternalFunction(InstNode.getClass(ComponentRef.node(call.ref)));
case ARG_TYPED_CALL() then Class.isExternalFunction(InstNode.getClass(ComponentRef.node(call.ref)));
case TYPED_CALL() then Function.isExternal(call.fn);
else false;
end match;
end isExternal;

protected
function typeDiscreteCall
"Types a function call that can be typed normally, but which always has
Expand Down
85 changes: 61 additions & 24 deletions Compiler/NFFrontEnd/NFExpression.mo
Expand Up @@ -528,35 +528,61 @@ public
output Type ty;
algorithm
ty := match exp
case INTEGER() then Type.INTEGER();
case REAL() then Type.REAL();
case STRING() then Type.STRING();
case BOOLEAN() then Type.BOOLEAN();
case ENUM_LITERAL() then exp.ty;
case CREF() then exp.ty;
case ARRAY() then exp.ty;
case RANGE() then exp.ty;
case TUPLE() then exp.ty;
case RECORD() then exp.ty;
case CALL() then Call.typeOf(exp.call);
case SIZE(dimIndex = SOME(_)) then Type.INTEGER();
case SIZE() then typeOf(exp.exp);
case END() then Type.INTEGER();
case BINARY() then Operator.typeOf(exp.operator);
case UNARY() then Operator.typeOf(exp.operator);
case LBINARY() then Operator.typeOf(exp.operator);
case LUNARY() then Operator.typeOf(exp.operator);
case RELATION() then Operator.typeOf(exp.operator);
case IF() then typeOf(exp.trueBranch);
case CAST() then exp.ty;
case UNBOX() then exp.ty;
case INTEGER() then Type.INTEGER();
case REAL() then Type.REAL();
case STRING() then Type.STRING();
case BOOLEAN() then Type.BOOLEAN();
case ENUM_LITERAL() then exp.ty;
case CREF() then exp.ty;
case ARRAY() then exp.ty;
case RANGE() then exp.ty;
case TUPLE() then exp.ty;
case RECORD() then exp.ty;
case CALL() then Call.typeOf(exp.call);
case SIZE() then if isSome(exp.dimIndex) then
Type.INTEGER() else typeOf(exp.exp);
case END() then Type.INTEGER();
case BINARY() then Operator.typeOf(exp.operator);
case UNARY() then Operator.typeOf(exp.operator);
case LBINARY() then Operator.typeOf(exp.operator);
case LUNARY() then Operator.typeOf(exp.operator);
case RELATION() then Operator.typeOf(exp.operator);
case IF() then typeOf(exp.trueBranch);
case CAST() then exp.ty;
case UNBOX() then exp.ty;
case SUBSCRIPTED_EXP() then exp.ty;
case TUPLE_ELEMENT() then exp.ty;
case BOX() then Type.METABOXED(typeOf(exp.exp));
case TUPLE_ELEMENT() then exp.ty;
case BOX() then Type.METABOXED(typeOf(exp.exp));
else Type.UNKNOWN();
end match;
end typeOf;

function setType
input Type ty;
input output Expression exp;
algorithm
() := match exp
case ENUM_LITERAL() algorithm exp.ty := ty; then ();
case CREF() algorithm exp.ty := ty; then ();
case TYPENAME() algorithm exp.ty := ty; then ();
case ARRAY() algorithm exp.ty := ty; then ();
case RANGE() algorithm exp.ty := ty; then ();
case TUPLE() algorithm exp.ty := ty; then ();
case RECORD() algorithm exp.ty := ty; then ();
case CALL() algorithm exp.call := Call.setType(exp.call, ty); then ();
case BINARY() algorithm exp.operator := Operator.setType(ty, exp.operator); then ();
case UNARY() algorithm exp.operator := Operator.setType(ty, exp.operator); then ();
case LBINARY() algorithm exp.operator := Operator.setType(ty, exp.operator); then ();
case LUNARY() algorithm exp.operator := Operator.setType(ty, exp.operator); then ();
case RELATION() algorithm exp.operator := Operator.setType(ty, exp.operator); then ();
case CAST() algorithm exp.ty := ty; then ();
case UNBOX() algorithm exp.ty := ty; then ();
case SUBSCRIPTED_EXP() algorithm exp.ty := ty; then ();
case TUPLE_ELEMENT() algorithm exp.ty := ty; then ();
else ();
end match;
end setType;

function typeCast
input Expression exp;
input Type castTy;
Expand Down Expand Up @@ -3491,5 +3517,16 @@ public
end match;
end lookupRecordField;

function enumIndexExp
input Expression enumExp;
output Expression indexExp;
algorithm
indexExp := match enumExp
case ENUM_LITERAL() then INTEGER(enumExp.index);
else CALL(Call.makeBuiltinCall(
NFBuiltinFuncs.INTEGER_ENUM, {enumExp}, variability(enumExp)));
end match;
end enumIndexExp;

annotation(__OpenModelica_Interface="frontend");
end NFExpression;
41 changes: 37 additions & 4 deletions Compiler/NFFrontEnd/NFInline.mo
Expand Up @@ -39,6 +39,8 @@ import DAE.InlineType;
import NFFunction.Function;
import NFInstNode.InstNode;
import Subscript = NFSubscript;
import Dimension = NFDimension;
import Type = NFType;

function inlineCallExp
input Expression callExp;
Expand Down Expand Up @@ -95,6 +97,9 @@ algorithm

stmt := listHead(body);

// TODO: Instead of repeating this for each input we should probably
// just build a lookup tree or hash table and go through the
// statement once.
for i in inputs loop
arg :: args := args;
stmt := Statement.mapExp(stmt,
Expand All @@ -112,12 +117,13 @@ function replaceCrefNode
input output Expression exp;
input InstNode node;
input Expression value;
protected
InstNode cr_node;
ComponentRef rest_cr;
list<Subscript> subs;
Type ty, repl_ty;
algorithm
exp := match exp
local
InstNode cr_node;
ComponentRef rest_cr;
list<Subscript> subs;

// TODO: This only works for simple crefs, for complex crefs (i.e. records)
// we need to somehow replace the rest of the cref with nodes from the
Expand All @@ -128,8 +134,35 @@ algorithm

else exp;
end match;

// Replace expressions in dimensions too.
ty := Expression.typeOf(exp);
repl_ty := Type.mapDims(ty, function replaceDimExp(node = node, value = value));

if not referenceEq(ty, repl_ty) then
exp := Expression.setType(repl_ty, exp);
end if;
end replaceCrefNode;

function replaceDimExp
input output Dimension dim;
input InstNode node;
input Expression value;
algorithm
dim := match dim
local
Expression exp;

case Dimension.EXP()
algorithm
exp := Expression.map(dim.exp, function replaceCrefNode(node = node, value = value));
then
Dimension.fromExp(exp, dim.var);

else dim;
end match;
end replaceDimExp;

function getOutputExp
input Statement stmt;
input InstNode outputNode;
Expand Down
37 changes: 37 additions & 0 deletions Compiler/NFFrontEnd/NFType.mo
Expand Up @@ -517,6 +517,43 @@ public
end match;
end dimensionCount;

function mapDims
input output Type ty;
input FuncT func;

partial function FuncT
input output Dimension dim;
end FuncT;
algorithm
() := match ty
case ARRAY()
algorithm
ty.dimensions := list(func(d) for d in ty.dimensions);
then
();

case TUPLE()
algorithm
ty.types := list(mapDims(t, func) for t in ty.types);
then
();

case FUNCTION()
algorithm
ty.resultType := mapDims(ty.resultType, func);
then
();

case METABOXED()
algorithm
ty.ty := mapDims(ty.ty, func);
then
();

else ();
end match;
end mapDims;

function nthEnumLiteral
input Type ty;
input Integer index;
Expand Down

0 comments on commit 4912fd6

Please sign in to comment.