Skip to content

Commit

Permalink
- Added codegen test of reductions (list/listReverse/min/max/sum/prod…
Browse files Browse the repository at this point in the history
…uct/array), using both lists and arrays as the input

  - Note that array-reductions now work in generated code
  - TODO: More general reductions (sum of strings for example)


git-svn-id: https://openmodelica.org/svn/OpenModelica/trunk@8171 f25d12d1-65f4-0310-ae8a-bbce733d8d8e
  • Loading branch information
sjoelund committed Mar 10, 2011
1 parent 3ca1659 commit e442e91
Show file tree
Hide file tree
Showing 9 changed files with 330 additions and 90 deletions.
2 changes: 2 additions & 0 deletions Compiler/FrontEnd/DAE.mo
Expand Up @@ -1129,6 +1129,8 @@ uniontype Exp "Expressions
Option<Exp> guardExp "Boolean guard-expression";
Exp range "range Reduction expression e.g. 1:4" ;
Option<Values.Value> defaultValue "if there is no default value, the reduction is not defined for 0-length arrays/lists";
/* DAE.Type resultType */
/* Option<Exp> foldExp "For example, max(ident,$res) or ident+$res; array() does not use this feature."; */
end REDUCTION;

record END "array index to last element, e.g. a{end}:=1;" end END;
Expand Down
2 changes: 2 additions & 0 deletions Compiler/FrontEnd/Expression.mo
Expand Up @@ -1528,6 +1528,8 @@ algorithm
then
tp;
case (DAE.CODE(ty = tp)) then tp;
case (DAE.REDUCTION(path = Absyn.IDENT("array"),expr = e))
then liftArrayR(typeof(e),DAE.DIM_UNKNOWN());
case (DAE.REDUCTION(expr = e)) then typeof(e);
case (DAE.END()) then DAE.ET_OTHER(); /* Can be any type. */
case (DAE.SIZE(_,NONE())) then DAE.ET_INT();
Expand Down
12 changes: 11 additions & 1 deletion Compiler/FrontEnd/ExpressionDump.mo
Expand Up @@ -838,7 +838,7 @@ algorithm
then
str;

case (DAE.REDUCTION(path = fcn,expr = exp,ident = id,range = iterexp), _, _, _)
case (DAE.REDUCTION(path = fcn,expr = exp,ident = id,guardExp = NONE(), range = iterexp), _, _, _)
equation
fs = Absyn.pathString(fcn);
expstr = printExp2Str(exp, stringDelimiter, opcreffunc, opcallfunc);
Expand All @@ -847,6 +847,16 @@ algorithm
then
str;

case (DAE.REDUCTION(path = fcn,expr = exp,ident = id,guardExp = SOME(e), range = iterexp), _, _, _)
equation
fs = Absyn.pathString(fcn);
expstr = printExp2Str(exp, stringDelimiter, opcreffunc, opcallfunc);
iterstr = printExp2Str(iterexp, stringDelimiter, opcreffunc, opcallfunc);
str = printExp2Str(e, stringDelimiter, opcreffunc, opcallfunc);
str = stringAppendList({"<reduction>",fs,"(",expstr," for ",id," guard ",str," in ",iterstr,")"});
then
str;

// MetaModelica tuple
case (DAE.META_TUPLE(es), _, _, _)
equation
Expand Down
22 changes: 21 additions & 1 deletion Compiler/FrontEnd/ExpressionSimplify.mo
Expand Up @@ -3949,12 +3949,32 @@ protected function simplifyReduction
algorithm
outValue := match(inReduction)
local
DAE.Exp expr, value, cref;
DAE.Exp expr, value, cref, range;
DAE.Ident iter_name;
DAE.ExpType ty;
list<DAE.Exp> values;
Option<Values.Value> defaultValue;
Absyn.Path path;
Boolean b;
Values.Value v;

case (DAE.REDUCTION(path = path, expr = expr, ident = iter_name, guardExp = SOME(DAE.BCONST(true)), range = range, defaultValue = defaultValue))
equation
expr = DAE.REDUCTION(path,expr,iter_name,NONE(),range,defaultValue);
then
simplifyReduction(expr);

case (DAE.REDUCTION(path = path, expr = expr, ident = iter_name, guardExp = SOME(DAE.BCONST(false)), defaultValue = SOME(v)))
equation
expr = ValuesUtil.valueExp(v);
then
simplify1(expr);

case (DAE.REDUCTION(path = path, expr = expr, ident = iter_name, guardExp = SOME(DAE.BCONST(false))))
equation
expr = ValuesUtil.valueExp(Values.META_FAIL());
then
expr;

case (DAE.REDUCTION(path = path, expr = expr, ident = iter_name, guardExp = NONE(), range = DAE.ARRAY(array = values), defaultValue = defaultValue))
equation
Expand Down
133 changes: 105 additions & 28 deletions Compiler/FrontEnd/Static.mo
Expand Up @@ -1067,7 +1067,7 @@ algorithm
(cache,guardExp,DAE.PROP(_, guardconst),st) = elabExpOptAndMatchType(cache, env_1, aguardExp, DAE.T_BOOL_DEFAULT, impl, st, doVect,pre,info);
const = Types.constAnd(Types.constAnd(expconst, iterconst), guardconst);
fn_1 = Absyn.crefToPath(fn);
(cache,exp_1,expty,v) = reductionType(cache,env,fn_1, exp_1, expty, fulliterty, info);
(cache,exp_1,expty,v,fn_1) = reductionType(cache,env,fn_1, exp_1, expty, fulliterty, info);
prop = DAE.PROP(expty, const);
exp_1 = DAE.REDUCTION(fn_1,exp_1,iter,guardExp,iterexp_1,v);
exp_1 = ExpressionSimplify.simplify1(exp_1) "only needed because unelabMod is silly";
Expand All @@ -1093,68 +1093,145 @@ protected function reductionType
output DAE.Exp outExp;
output DAE.Type outType;
output Option<Values.Value> defaultValue;
output Absyn.Path outPath;
algorithm
(outCache,outExp,outType,defaultValue) := match (cache, env, fn, inExp, inType, rangeType, info)
(outCache,outExp,outType,defaultValue,outPath) := match (cache, env, fn, inExp, inType, rangeType, info)
local
Integer i;
Real r;
String s;
DAE.Dimension dim;
list<DAE.Type> fnTypes;
DAE.Type typeA,typeB,resType;
Absyn.Path path;
case (cache,env,Absyn.IDENT(name = "array"), _, _, (DAE.T_ARRAY(arrayDim = dim),_), _)
then (cache,inExp, Types.liftArray(inType, dim), SOME(Values.ARRAY({}, {0})));
then (cache,inExp, Types.liftArray(inType, dim), SOME(Values.ARRAY({}, {0})),fn);
case (cache,env,Absyn.IDENT(name = "array"), _, _, (DAE.T_LIST(_),_), _)
then (cache,inExp, Types.liftArray(inType, DAE.DIM_UNKNOWN()), SOME(Values.ARRAY({}, {0})),fn);
case (cache,env,Absyn.IDENT(name = "list"), inExp, _, _, _)
equation
(inExp,inType) = Types.matchType(inExp, inType, DAE.T_BOXED_DEFAULT, true);
then (cache,inExp,(DAE.T_LIST(inType), NONE()),SOME(Values.LIST({})));
then (cache,inExp,(DAE.T_LIST(inType), NONE()),SOME(Values.LIST({})),fn);
case (cache,env,Absyn.IDENT(name = "listReverse"), inExp, _, _, _)
equation
(inExp,inType) = Types.matchType(inExp, inType, DAE.T_BOXED_DEFAULT, true);
then (cache,inExp,(DAE.T_LIST(inType), NONE()),SOME(Values.LIST({})));
then (cache,inExp,(DAE.T_LIST(inType), NONE()),SOME(Values.LIST({})),fn);
case (cache,env,Absyn.IDENT("min"),inExp,(DAE.T_REAL(_),_),_,info)
equation
r = System.realMaxLit();
then (cache,inExp,DAE.T_REAL_DEFAULT,SOME(Values.REAL(r)));
then (cache,inExp,DAE.T_REAL_DEFAULT,SOME(Values.REAL(r)),fn);
case (cache,env,Absyn.IDENT("min"),inExp,(DAE.T_INTEGER(_),_),_,info)
equation
i = System.intMaxLit();
then (cache,inExp,DAE.T_INTEGER_DEFAULT,SOME(Values.INTEGER(i)));
case (cache,env,Absyn.IDENT("min"),inExp,(DAE.T_BOOL(_),_),_,info) then (cache,inExp,DAE.T_BOOL_DEFAULT,SOME(Values.BOOL(true)));
case (cache,env,Absyn.IDENT("min"),inExp,(DAE.T_STRING(_),_),_,info) then (cache,inExp,DAE.T_STRING_DEFAULT,NONE());
then (cache,inExp,DAE.T_INTEGER_DEFAULT,SOME(Values.INTEGER(i)),fn);
case (cache,env,Absyn.IDENT("min"),inExp,(DAE.T_BOOL(_),_),_,info) then (cache,inExp,DAE.T_BOOL_DEFAULT,SOME(Values.BOOL(true)),fn);
case (cache,env,Absyn.IDENT("min"),inExp,(DAE.T_STRING(_),_),_,info) then (cache,inExp,DAE.T_STRING_DEFAULT,NONE(),fn);

case (cache,env,Absyn.IDENT("max"),inExp,(DAE.T_REAL(_),_),_,info)
equation
r = realNeg(System.realMaxLit());
then (cache,inExp,DAE.T_REAL_DEFAULT,SOME(Values.REAL(r)));
then (cache,inExp,DAE.T_REAL_DEFAULT,SOME(Values.REAL(r)),fn);
case (cache,env,Absyn.IDENT("max"),inExp,(DAE.T_INTEGER(_),_),_,info)
equation
i = intNeg(System.intMaxLit());
then (cache,inExp,DAE.T_INTEGER_DEFAULT,SOME(Values.INTEGER(i)));
case (cache,env,Absyn.IDENT("max"),inExp,(DAE.T_BOOL(_),_),_,info) then (cache,inExp,DAE.T_BOOL_DEFAULT,SOME(Values.BOOL(false)));
case (cache,env,Absyn.IDENT("max"),inExp,(DAE.T_STRING(_),_),_,info) then (cache,inExp,DAE.T_STRING_DEFAULT,SOME(Values.STRING("")));

case (cache,env,Absyn.IDENT("sum"),inExp,(DAE.T_REAL(_),_),_,info) then (cache,inExp,DAE.T_REAL_DEFAULT,SOME(Values.REAL(0.0)));
case (cache,env,Absyn.IDENT("sum"),inExp,(DAE.T_INTEGER(_),_),_,info) then (cache,inExp,DAE.T_INTEGER_DEFAULT,SOME(Values.INTEGER(0)));
case (cache,env,Absyn.IDENT("sum"),inExp,(DAE.T_BOOL(_),_),_,info) then (cache,inExp,DAE.T_BOOL_DEFAULT,SOME(Values.BOOL(false)));
case (cache,env,Absyn.IDENT("sum"),inExp,(DAE.T_STRING(_),_),_,info) then (cache,inExp,DAE.T_STRING_DEFAULT,SOME(Values.STRING("")));
case (cache,env,Absyn.IDENT("sum"),inExp,(DAE.T_ARRAY(arrayDim=_),_),_,info) then (cache,inExp,inType,NONE());

case (cache,env,Absyn.IDENT("product"),inExp,(DAE.T_REAL(_),_),_,info) then (cache,inExp,DAE.T_REAL_DEFAULT,SOME(Values.REAL(1.0)));
case (cache,env,Absyn.IDENT("product"),inExp,(DAE.T_INTEGER(_),_),_,info) then (cache,inExp,DAE.T_INTEGER_DEFAULT,SOME(Values.INTEGER(1)));
case (cache,env,Absyn.IDENT("product"),inExp,(DAE.T_BOOL(_),_),_,info) then (cache,inExp,DAE.T_BOOL_DEFAULT,SOME(Values.BOOL(true)));
then (cache,inExp,DAE.T_INTEGER_DEFAULT,SOME(Values.INTEGER(i)),fn);
case (cache,env,Absyn.IDENT("max"),inExp,(DAE.T_BOOL(_),_),_,info) then (cache,inExp,DAE.T_BOOL_DEFAULT,SOME(Values.BOOL(false)),fn);
case (cache,env,Absyn.IDENT("max"),inExp,(DAE.T_STRING(_),_),_,info) then (cache,inExp,DAE.T_STRING_DEFAULT,SOME(Values.STRING("")),fn);

case (cache,env,Absyn.IDENT("sum"),inExp,(DAE.T_REAL(_),_),_,info) then (cache,inExp,DAE.T_REAL_DEFAULT,SOME(Values.REAL(0.0)),fn);
case (cache,env,Absyn.IDENT("sum"),inExp,(DAE.T_INTEGER(_),_),_,info) then (cache,inExp,DAE.T_INTEGER_DEFAULT,SOME(Values.INTEGER(0)),fn);
case (cache,env,Absyn.IDENT("sum"),inExp,(DAE.T_BOOL(_),_),_,info) then (cache,inExp,DAE.T_BOOL_DEFAULT,SOME(Values.BOOL(false)),fn);
case (cache,env,Absyn.IDENT("sum"),inExp,(DAE.T_STRING(_),_),_,info) then (cache,inExp,DAE.T_STRING_DEFAULT,SOME(Values.STRING("")),fn);
case (cache,env,Absyn.IDENT("sum"),inExp,(DAE.T_ARRAY(arrayDim=_),_),_,info) then (cache,inExp,inType,NONE(),fn);

case (cache,env,Absyn.IDENT("product"),inExp,(DAE.T_REAL(_),_),_,info) then (cache,inExp,DAE.T_REAL_DEFAULT,SOME(Values.REAL(1.0)),fn);
case (cache,env,Absyn.IDENT("product"),inExp,(DAE.T_INTEGER(_),_),_,info) then (cache,inExp,DAE.T_INTEGER_DEFAULT,SOME(Values.INTEGER(1)),fn);
case (cache,env,Absyn.IDENT("product"),inExp,(DAE.T_BOOL(_),_),_,info) then (cache,inExp,DAE.T_BOOL_DEFAULT,SOME(Values.BOOL(true)),fn);
case (cache,env,Absyn.IDENT("product"),inExp,(DAE.T_STRING(_),_),_,info)
equation
Error.addSourceMessage(Error.INTERNAL_ERROR, {"product reduction not defined for String"},info);
then fail();
case (cache,env,Absyn.IDENT("product"),inExp,(DAE.T_ARRAY(arrayDim=_),_),_,info) then (cache,inExp,inType,NONE());
case (cache,env,Absyn.IDENT("product"),inExp,(DAE.T_ARRAY(arrayDim=_),_),_,info) then (cache,inExp,inType,NONE(),fn);

else
case (cache,env,path,inExp,inType,_,info)
equation
s = "Reductions not defined for function " +& Absyn.pathString(fn) +& " of type " +& Types.unparseType(inType);
Error.addSourceMessage(Error.INTERNAL_ERROR, {s},info);
then fail();
(cache,fnTypes) = Lookup.lookupFunctionsInEnv(cache, env, path, info);
(typeA,typeB,resType,path) = checkReductionType1(env,path,fnTypes,info);
inExp = checkReductionType2(inExp,inType,typeA,typeB,resType,Types.equivtypes(typeA,typeB),Types.equivtypes(typeB,resType),info);
(cache,Util.SUCCESS()) = instantiateDaeFunction(cache, env, path, false, NONE(), true);
Error.assertionOrAddSourceMessage(RTOpts.acceptMetaModelicaGrammar() or RTOpts.debugFlag("experimentalReductions"), Error.COMPILER_NOTIFICATION, {"Custom reduction functions are an OpenModelica extension to the Modelica Specification. Do not use them if you need your model to compile using other tools or if you are concerned about using experimental features. Use +d=experimentalReductions to disable this message."}, info);
then (cache,inExp,resType,NONE(),path);
end match;
end reductionType;

protected function checkReductionType1
input Env.Env env;
input Absyn.Path path;
input list<DAE.Type> fnTypes;
input Absyn.Info info;
output DAE.Type typeA;
output DAE.Type typeB;
output DAE.Type resType;
output Absyn.Path outPath;
algorithm
(typeA,typeB,resType,outPath) := match (env,path,fnTypes,info)
local
String str1,str2;
case (env, path, {}, info)
equation
str1 = Absyn.pathString(path);
str2 = Env.printEnvPathStr(env);
Error.addSourceMessage(Error.LOOKUP_FUNCTION_ERROR, {str1,str2}, info);
then fail();
case (env, _, {(DAE.T_FUNCTION(funcArg={(_,typeA),(_,typeB)},funcResultType=resType),SOME(path))}, info)
then (typeA,typeB,resType,path);
case (env, path, fnTypes, info)
equation
str1 = Util.stringDelimitList(Util.listMap(fnTypes, Types.unparseType), ",");
Error.addSourceMessage(Error.UNSUPPORTED_REDUCTION_TYPE, {str1}, info);
then fail();
end match;
end checkReductionType1;

protected function checkReductionType2
input DAE.Exp exp;
input DAE.Type expType;
input DAE.Type typeA;
input DAE.Type typeB;
input DAE.Type typeC;
input Boolean equivAB;
input Boolean equivBC;
input Absyn.Info info;
output DAE.Exp outExp;
algorithm
outExp := matchcontinue (exp,expType,typeA,typeB,typeC,equivAB,equivBC,info)
local
String str1,str2;
case (_,_,_,_,_,_,false,info)
equation
str1 = Types.unparseType(typeB);
str2 = Types.unparseType(typeC);
Error.addSourceMessage(Error.REDUCTION_TYPE_ERROR,{"second argument", "result-type", "identical", str1, str2},info);
then fail();
case (_,_,_,_,_,false,true,info)
equation
str1 = Types.unparseType(typeA);
str2 = Types.unparseType(typeB);
Error.addSourceMessage(Error.REDUCTION_TYPE_ERROR,{"first", "second arguments", "identical", str1, str2},info);
then fail();
case (exp,expType,typeA,_,_,true,true,info)
equation
(exp,_) = Types.matchType(exp,expType,typeA,true);
then exp;
case (_,_,_,_,_,true,true,info)
equation
str1 = Types.unparseType(expType);
str2 = Types.unparseType(typeA);
Error.addSourceMessage(Error.REDUCTION_TYPE_ERROR,{"reduction expression", "first argument", "compatible", str1, str2},info);
then fail();
end matchcontinue;
end checkReductionType2;

protected function constToVariability "translates an DAE.Const to a SCode.Variability"
input DAE.Const const;
output SCode.Variability variability;
Expand Down
7 changes: 4 additions & 3 deletions Compiler/Template/Unparsing.mo
Expand Up @@ -157,7 +157,8 @@ algorithm
local
Tpl.Text txt;
Absyn.Path i_path;
Absyn.Ident i_name;
Absyn.Ident i_name_1;
String i_name;

case ( txt,
Absyn.IDENT(name = i_name) )
Expand All @@ -166,9 +167,9 @@ algorithm
then txt;

case ( txt,
Absyn.QUALIFIED(name = i_name, path = i_path) )
Absyn.QUALIFIED(name = i_name_1, path = i_path) )
equation
txt = Tpl.writeStr(txt, i_name);
txt = Tpl.writeStr(txt, i_name_1);
txt = Tpl.writeTok(txt, Tpl.ST_STRING("."));
txt = pathString(txt, i_path);
then txt;
Expand Down
4 changes: 4 additions & 0 deletions Compiler/Util/Error.mo
Expand Up @@ -317,6 +317,8 @@ public constant ErrorID META_DEAD_CODE=5026;
public constant ErrorID META_UNUSED_DECL=5027;
public constant ErrorID META_UNUSED_AS_BINDING=5028;
public constant ErrorID MATCH_TO_SWITCH_OPTIMIZATION=5029;
public constant ErrorID REDUCTION_TYPE_ERROR=5030;
public constant ErrorID UNSUPPORTED_REDUCTION_TYPE=5031;

public constant ErrorID COMPILER_WARNING = 6000;
public constant ErrorID COMPILER_NOTIFICATION = 6001;
Expand Down Expand Up @@ -723,6 +725,8 @@ protected constant list<tuple<Integer, MessageType, Severity, String>> errorTabl
(MATCH_TO_SWITCH_OPTIMIZATION,TRANSLATION(),NOTIFICATION(),"Converted match expression to switch of type %s."),
(ELAB_CODE_EXP_FAILED,TRANSLATION(),ERROR(),"Failed to elaborate %s as a code expression of type %s."),
(METARECORD_CONTAINS_METARECORD_MEMBER,TRANSLATION(),ERROR(),"The called uniontype record (%s) contains a member (%s) that has a uniontype record as its type instead of a uniontype."),
(REDUCTION_TYPE_ERROR,TRANSLATION(),ERROR(),"Reductions require the types of the %s and %s to be %s, but got: %s and %s."),
(UNSUPPORTED_REDUCTION_TYPE,TRANSLATION(),ERROR(),"Expected a reduction function with type signature ('A,'B) => 'B, but got %s."),

(COMPILER_NOTIFICATION,TRANSLATION(),NOTIFICATION(),"%s"),
(COMPILER_WARNING,TRANSLATION(),WARNING(),"%s")
Expand Down

0 comments on commit e442e91

Please sign in to comment.