Skip to content

Commit

Permalink
Some work-arounds for Ceval of zero-size arrays
Browse files Browse the repository at this point in the history
The Values.mo structure does not store the type of the array which means
that `Values.ARRAY({})` becomes `{} /* T_UNKNOWN[0] */` instead of
containing the actual type. We now have some work-arounds for this case:
- cevalIfConstant will not try to evaluate literal values
- If an empty array is returned in cevalIfConstant, we backpatch the
  array type to the expected type (but this only works for the top-level
  expression; hopefully this is enough to not propagate unknown
  dimensions too far though).

Belonging to [master]:
  - OpenModelica/OMCompiler#2074
  • Loading branch information
sjoelund authored and OpenModelica-Hudson committed Dec 13, 2017
1 parent d1a57b2 commit cdf224b
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 67 deletions.
102 changes: 43 additions & 59 deletions Compiler/FrontEnd/Ceval.mo
Expand Up @@ -885,79 +885,63 @@ public function cevalIfConstant
or if the expression is a call of parameter constness whose return type
contains unknown dimensions (in which case we need to determine the size of
those dimensions)."
input FCore.Cache inCache;
input output FCore.Cache cache;
input FCore.Graph inEnv;
input DAE.Exp inExp;
input DAE.Properties inProp;
input output DAE.Exp exp;
input output DAE.Properties prop;
input Boolean impl;
input SourceInfo inInfo;
output FCore.Cache outCache;
output DAE.Exp outExp;
output DAE.Properties outProp;
algorithm
(outCache, outExp, outProp) :=
matchcontinue(inCache, inEnv, inExp, inProp, impl, inInfo)
if Expression.isEvaluatedConst(exp) then
// Don't mess up the dimensions, etc by using the Values module
return;
end if;
(cache, exp, prop) := matchcontinue prop
local
DAE.Exp e;
Values.Value v;
FCore.Cache cache;
DAE.Properties prop;
Values.Value v;
DAE.Type tp;

/* adrpo: this is not needed! we do dimension propagation on function call!
case (_, _, e as DAE.CALL(attr = DAE.CALL_ATTR(ty = DAE.T_ARRAY(dims = _))),
DAE.PROP(constFlag = DAE.C_PARAM()), _, _)
equation
(e, prop) = cevalWholedimRetCall(e, inCache, inEnv, inInfo, 0);
then
(inCache, e, prop);*/

case (_, _, e, DAE.PROP(constFlag = DAE.C_PARAM(), type_ = tp), _, _) // BoschRexroth specifics
equation
false = Flags.getConfigBool(Flags.CEVAL_EQUATION);
then
(inCache, e, DAE.PROP(tp, DAE.C_VAR()));

case (_, _, e, DAE.PROP(constFlag = DAE.C_CONST()), _, _)
equation
(cache, v, _) = ceval(inCache, inEnv, e, impl, NONE(), Absyn.NO_MSG(), 0);
e = ValuesUtil.valueExp(v);
then
(cache, e, inProp);
case DAE.PROP(constFlag = DAE.C_PARAM(), type_ = tp)
// BoschRexroth specifics
guard not Flags.getConfigBool(Flags.CEVAL_EQUATION)
then (cache, exp, DAE.PROP(tp, DAE.C_VAR()));

case (_, _, e, DAE.PROP_TUPLE(), _, _)
equation
DAE.C_CONST() = Types.propAllConst(inProp);
(cache, v, _) = ceval(inCache, inEnv, e, false, NONE(), Absyn.NO_MSG(), 0);
e = ValuesUtil.valueExp(v);
then
(cache, e, inProp);
case DAE.PROP(constFlag = DAE.C_CONST(), type_ = tp)
algorithm
(cache, v, _) := ceval(cache, inEnv, exp, impl, NONE(), Absyn.NO_MSG(), 0);
exp := ValuesUtil.valueExp(v);
exp := ValuesUtil.fixZeroSizeArray(exp, tp);
then (cache, exp, prop);

case (_, _, _, DAE.PROP_TUPLE(), _, _) // BoschRexroth specifics
equation
false = Flags.getConfigBool(Flags.CEVAL_EQUATION);
DAE.C_PARAM() = Types.propAllConst(inProp);
case DAE.PROP_TUPLE()
algorithm
DAE.C_CONST() := Types.propAllConst(prop);
(cache, v, _) := ceval(cache, inEnv, exp, false, NONE(), Absyn.NO_MSG(), 0);
exp := ValuesUtil.valueExp(v);
then (cache, exp, prop);

case DAE.PROP_TUPLE()
// BoschRexroth specifics
guard not Flags.getConfigBool(Flags.CEVAL_EQUATION)
algorithm
DAE.C_PARAM() := Types.propAllConst(prop);
print(" tuple non constant evaluation not implemented yet\n");
then
fail();
then fail();

case (_, _, e, _, _, _)
equation
true = Expression.isConst(e); // Structural parameters and the like... we can ceval them if we want to
false = Config.acceptMetaModelicaGrammar();
// false = Expression.isConstValue(e);
// print("Try ceval: " + ExpressionDump.printExpStr(e) + "; expect " + Types.unparseType(Types.getPropType(inProp)) + "\n");
(_, v, _) = ceval(inCache, inEnv, e, impl, NONE(), Absyn.NO_MSG(), 0);
// print("Ceval'ed constant: " + ExpressionDump.printExpStr(inExp) + " => " + ValuesUtil.valString(v) + "\n");
e = ValuesUtil.valueExp(v);
// print("Ceval'ed constant: " + ExpressionDump.printExpStr(inExp) + "\n");
then (inCache, e, inProp);
case _
// Structural parameters and the like... we can ceval them if we want to
guard Expression.isConst(exp) and not Config.acceptMetaModelicaGrammar()
algorithm
(_, v, _) := ceval(cache, inEnv, exp, impl, NONE(), Absyn.NO_MSG(), 0);
exp := ValuesUtil.valueExp(v);
exp := ValuesUtil.fixZeroSizeArray(exp, Types.getPropType(prop));
then (cache, exp, prop);

else
equation
algorithm
// If we fail to evaluate, at least we should simplify the expression
(e,_) = ExpressionSimplify.simplify1(inExp);
then (inCache, e, inProp);
(exp,_) := ExpressionSimplify.simplify1(exp);
then (cache, exp, prop);

end matchcontinue;
end cevalIfConstant;
Expand Down
4 changes: 4 additions & 0 deletions Compiler/FrontEnd/ExpressionSimplify.mo
Expand Up @@ -1300,6 +1300,10 @@ algorithm
e = Expression.makeImpureBuiltinCall("delay",{e,e3,e4},tp);
then DAE.UNARY(op,e);

// The sum of an empty array is simply the sum of its elements
case DAE.CALL(path=Absyn.IDENT("sum"),expLst={DAE.ARRAY(array={})}, attr=DAE.CALL_ATTR(ty=tp1))
then Expression.makeConstZero(tp1);

// To calculate sums, first try matrix concatenation
case DAE.CALL(path=Absyn.IDENT("sum"),expLst={DAE.MATRIX(ty=tp1,matrix=mexpl)},attr=DAE.CALL_ATTR(ty=tp2))
equation
Expand Down
12 changes: 4 additions & 8 deletions Compiler/FrontEnd/Static.mo
Expand Up @@ -8462,10 +8462,8 @@ algorithm
// checkModel this should succeed anyway, since we might be checking a function
// that takes a vector of unknown size. So pretend that the dimension is 1.
case (e, (DAE.DIM_UNKNOWN() :: ad), prop)
algorithm
true := Flags.getConfigBool(Flags.CHECK_MODEL);
then
vectorizeCall(e, DAE.DIM_INTEGER(1) :: ad, inSlots, prop, info);
guard Flags.getConfigBool(Flags.CHECK_MODEL)
then vectorizeCall(e, DAE.DIM_INTEGER(1) :: ad, inSlots, prop, info);

/* Scalar expression, i.e function call */
case (e as DAE.CALL(),(dim :: ad),DAE.PROP(tp,c))
Expand All @@ -8474,8 +8472,7 @@ algorithm
exp_type := Types.simplifyType(Types.liftArray(tp, dim)) "pass type of vectorized result expr";
vect_exp := vectorizeCallScalar(e, exp_type, int_dim, inSlots);
tp := Types.liftArray(tp, dim);
then
vectorizeCall(vect_exp, ad, inSlots, DAE.PROP(tp,c),info);
then vectorizeCall(vect_exp, ad, inSlots, DAE.PROP(tp,c),info);

/* array expression of function calls */
case (DAE.ARRAY(),(dim :: ad),DAE.PROP(tp,c))
Expand All @@ -8484,8 +8481,7 @@ algorithm
// _ = Types.simplifyType(Types.liftArray(tp, dim));
vect_exp := vectorizeCallArray(inExp, int_dim, inSlots);
tp := Types.liftArrayRight(tp, dim);
then
vectorizeCall(vect_exp, ad, inSlots, DAE.PROP(tp,c),info);
then vectorizeCall(vect_exp, ad, inSlots, DAE.PROP(tp,c),info);

/* Multiple dimensions are possible to change to a reduction, like:
* f(arr1,arr2) => array(f(x,y) thread for x in arr1, y in arr2)
Expand Down
11 changes: 11 additions & 0 deletions Compiler/FrontEnd/ValuesUtil.mo
Expand Up @@ -2346,5 +2346,16 @@ algorithm
end match;
end typeConvertRecord;

public function fixZeroSizeArray "Work-around for Values.ARRAY({}) becoming T_UNKNOWN in ValuesUtil.valueExp"
input output DAE.Exp e;
input DAE.Type ty;
algorithm
e := match e
case DAE.ARRAY(ty=DAE.T_ARRAY(ty=DAE.T_UNKNOWN()), scalar=false, array={})
then DAE.ARRAY(ty, not Types.isArray(Types.unliftArray(ty)), {});
else e;
end match;
end fixZeroSizeArray;

annotation(__OpenModelica_Interface="frontend");
end ValuesUtil;

0 comments on commit cdf224b

Please sign in to comment.