Skip to content

Commit

Permalink
Codegen/fix record in function modification handling 2 (#490)
Browse files Browse the repository at this point in the history
[NF/OF/Codegen] Fix handling of record variables with modifications on declaration in functions.

NF:
  - Fix the new Front-end to mark modification bindings.

OF:
  - Manually remove Prefixes from cref's TYPES_VARs.

  - Mark record EQBOUND bindings that are created from submods by the old front-end.
       - We will not generate code for these bindings. SimCode will skip them.
          They are redundant. The types_vars of the record variable already have the 
          correct bindings.
       - They are also not 'properly' prefixed anymore since we do not prefix types_vars
          (the bindings are taken from the typesvars by the front end.)
       - The correct way to fix these would have been not to create eqmod modifications
          from submods in the first place. However it is impossible to fix that properly 
          in short time (if possible at all).

  -  Improve constant evaluation.
     - Try not to create DAE.EMPTY from Values.EMPTY().
          - We usually have the original expression before ceval was applied.
             if ceval return values.empty use the original exp if available.
     - Fix match failures caused by unmatched Absyn.NO_MSG(). Use
       Absyn.MSG(dummy) always. We should probably just remove Absyn.Msg altogether.
     - Use the types_var bindings if no bindings are found in Env for records.
     - Remove error messages from constant evaluation failure.
       Failure to constant evaluate is not an error by itself.

Codegen/SimCode:

  - We now create additional constructors  for each unique modification use of a record.
    -  For example R r(a=1), r(b=2) will use two different constructors.
       We only create these constructors if they are actually needed.

  - There are some optimizations and cleanups that can be done. Will be fixed afterwards.

  - Pass correct context to outside bindings in CodeGen.

- Update expected outputs.

    - Some error messages are removed since they report failures in
      constant evaluation. Which is not technically an error.
  • Loading branch information
mahge committed Oct 18, 2019
1 parent 1817194 commit 023bac1
Show file tree
Hide file tree
Showing 28 changed files with 494 additions and 176 deletions.
34 changes: 12 additions & 22 deletions OMCompiler/Compiler/FrontEnd/Ceval.mo
Expand Up @@ -103,7 +103,7 @@ public function ceval "
input FCore.Graph inEnv;
input DAE.Exp inExp;
input Boolean inBoolean "impl";
input Absyn.Msg inMsg = Absyn.NO_MSG();
input Absyn.Msg inMsg = Absyn.MSG(AbsynUtil.dummyInfo);
input Integer numIter = 0 "Maximum recursion depth";
output FCore.Cache outCache;
output Values.Value outValue;
Expand Down Expand Up @@ -285,21 +285,11 @@ algorithm
(cache,Values.LIST(v::vallst));

// MetaModelica Partial Function
case (_,_,DAE.CREF(componentRef = cr,
ty = DAE.T_FUNCTION_REFERENCE_VAR()),_,Absyn.MSG(info = info),_)
equation
str = ComponentReference.crefStr(cr);
Error.addSourceMessage(Error.META_CEVAL_FUNCTION_REFERENCE, {str}, info);
case (_,_,DAE.CREF(componentRef = cr, ty = DAE.T_FUNCTION_REFERENCE_VAR()),
_, _, _)
then
fail();

case (_,_,DAE.CREF(componentRef = cr, ty = DAE.T_FUNCTION_REFERENCE_FUNC()),
_, Absyn.MSG(info = info),_)
equation
str = ComponentReference.crefStr(cr);
Error.addSourceMessage(Error.META_CEVAL_FUNCTION_REFERENCE, {str}, info);
then
fail();

// MetaModelica Uniontype Constructor
case (cache,env,DAE.METARECORDCALL(path=funcpath,args=expl,fieldNames=fieldNames,index=index),impl,msg,_)
Expand Down Expand Up @@ -887,16 +877,16 @@ algorithm

case DAE.PROP(constFlag = DAE.C_CONST(), type_ = tp)
algorithm
(cache, v) := ceval(cache, inEnv, exp, impl, Absyn.NO_MSG(), 0);
exp := ValuesUtil.valueExp(v);
(cache, v) := ceval(cache, inEnv, exp, impl, Absyn.MSG(inInfo), 0);
exp := ValuesUtil.valueExp(v,SOME(exp));
exp := ValuesUtil.fixZeroSizeArray(exp, tp);
then (cache, exp, prop);

case DAE.PROP_TUPLE()
algorithm
DAE.C_CONST() := Types.propAllConst(prop);
(cache, v) := ceval(cache, inEnv, exp, false, Absyn.NO_MSG(), 0);
exp := ValuesUtil.valueExp(v);
(cache, v) := ceval(cache, inEnv, exp, false, Absyn.MSG(inInfo), 0);
exp := ValuesUtil.valueExp(v, SOME(exp));
then (cache, exp, prop);

case DAE.PROP_TUPLE()
Expand All @@ -911,8 +901,8 @@ algorithm
// 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, Absyn.NO_MSG(), 0);
exp := ValuesUtil.valueExp(v);
(_, v) := ceval(cache, inEnv, exp, impl, Absyn.MSG(inInfo), 0);
exp := ValuesUtil.valueExp(v,SOME(exp));
exp := ValuesUtil.fixZeroSizeArray(exp, Types.getPropType(prop));
then (cache, exp, prop);

Expand Down Expand Up @@ -4698,7 +4688,7 @@ algorithm
case (cache,env,DAE.SLICE(exp = e1),_,impl,msg,_)
equation
(cache,v1) = ceval(cache,env, e1, impl,msg,numIter+1);
e1_1 = ValuesUtil.valueExp(v1);
e1_1 = ValuesUtil.valueExp(v1, SOME(e1));
then
(cache,DAE.SLICE(e1_1));

Expand Down Expand Up @@ -5112,8 +5102,8 @@ algorithm
structuralParameters := (AvlSetCR.EMPTY(),{});
functionTree := Mutable.create(functions);
cache := FCore.CACHE(NONE(), functionTree, structuralParameters, Absyn.IDENT(""));
(_,val) := ceval(cache, FGraph.empty(), exp, false, Absyn.NO_MSG(),0);
oexp := ValuesUtil.valueExp(val);
(_,val) := ceval(cache, FGraph.empty(), exp, false, Absyn.MSG(AbsynUtil.dummyInfo),0);
oexp := ValuesUtil.valueExp(val, SOME(exp));
end cevalSimpleWithFunctionTreeReturnExp;

public function cevalAstExp
Expand Down
53 changes: 42 additions & 11 deletions OMCompiler/Compiler/FrontEnd/CevalFunction.mo
Expand Up @@ -1482,7 +1482,7 @@ protected function cevalExp
output FCore.Cache outCache;
output Values.Value outValue;
algorithm
(outCache, outValue) := Ceval.ceval(inCache, inEnv, inExp, true, Absyn.NO_MSG(), 0);
(outCache, outValue) := Ceval.ceval(inCache, inEnv, inExp, true, Absyn.MSG(AbsynUtil.dummyInfo), 0);
false := valueEq(Values.META_FAIL(), outValue);
end cevalExp;

Expand All @@ -1494,7 +1494,7 @@ protected function cevalExpList
output FCore.Cache outCache;
output list<Values.Value> outValue;
algorithm
(outCache, outValue) := Ceval.cevalList(inCache, inEnv, inExpLst, true, Absyn.NO_MSG(), 0);
(outCache, outValue) := Ceval.cevalList(inCache, inEnv, inExpLst, true, Absyn.MSG(AbsynUtil.dummyInfo), 0);
end cevalExpList;

// [EENV] Environment extension functions (add variables).
Expand Down Expand Up @@ -1665,7 +1665,7 @@ algorithm
case (_, _, _, _, _, _)
equation
true = Types.isRecord(inType);
binding = getBinding(inOptValue);
binding = makeBinding(inOptValue);
(cache, ty) =
appendDimensions(inType, inOptValue, inDims, inCache, inEnv);
var = makeFunctionVariable(inName, ty, binding);
Expand All @@ -1689,7 +1689,7 @@ algorithm
// Normal variables.
else
equation
binding = getBinding(inOptValue);
binding = makeBinding(inOptValue);
(cache, ty) =
appendDimensions(inType, inOptValue, inDims, inCache, inEnv);
var = makeFunctionVariable(inName, ty, binding);
Expand Down Expand Up @@ -1723,7 +1723,7 @@ algorithm
outVar := DAE.TYPES_VAR(inName, DAE.dummyAttrVar, inType, inBinding, false, NONE());
end makeFunctionVariable;

protected function getBinding
protected function makeBinding
"Creates a binding from an optional value. If some value is given we return a
value bound binding, otherwise an unbound binding."
input Option<Values.Value> inBindingValue;
Expand All @@ -1734,7 +1734,7 @@ algorithm
case SOME(val) then DAE.VALBOUND(val, DAE.BINDING_FROM_DEFAULT_VALUE());
case NONE() then DAE.UNBOUND();
end match;
end getBinding;
end makeBinding;

protected function makeRecordEnvironment
"This function creates an environment for a record variable by creating a new
Expand Down Expand Up @@ -2346,6 +2346,20 @@ algorithm
outValue := getBindingOrDefault(binding, outType);
end getVariableTypeAndValue;

protected function getBindingValueOpt
"Returns the value in a binding, or NONE()."
input DAE.Binding inBinding;
output Option<Values.Value> outValue;
algorithm
outValue := match(inBinding)
local
Values.Value val;
case DAE.VALBOUND(valBound = val) then SOME(val);
case DAE.EQBOUND(evaluatedExp = SOME(val)) then SOME(val);
else NONE();
end match;
end getBindingValueOpt;

protected function getBindingOrDefault
"Returns the value in a binding, or a default value if binding isn't a value
binding."
Expand All @@ -2357,6 +2371,7 @@ algorithm
local
Values.Value val;
case (DAE.VALBOUND(valBound = val), _) then val;
case (DAE.EQBOUND(evaluatedExp = SOME(val)), _) then val;
else generateDefaultBinding(inType);
end match;
end getBindingOrDefault;
Expand Down Expand Up @@ -2528,9 +2543,10 @@ algorithm
outValues := match(inVars, inEnv)
local
Values.Value val;
Option<Values.Value> oval;
String id;
DAE.Type ty;
DAE.Binding binding;
DAE.Binding binding, tvbinding;

// The component is a record itself.
case (DAE.TYPES_VAR(
Expand All @@ -2542,11 +2558,26 @@ algorithm
val;

// A non-record variable.
case (DAE.TYPES_VAR(name = id, ty = ty), _)
equation
(_, DAE.TYPES_VAR(binding = binding), _, _, _, _) =
case (DAE.TYPES_VAR(name = id, ty = ty, binding = tvbinding), _)
algorithm
(_, DAE.TYPES_VAR(binding = binding), _, _, _, _) :=
Lookup.lookupIdentLocal(FCore.emptyCache(), inEnv, id);
val = getBindingOrDefault(binding, ty);
oval := getBindingValueOpt(binding);

// if no binding from env then use the typesvar binding.
if isNone(oval) then
oval := getBindingValueOpt(tvbinding);
end if;

// if there is still no binding in the typesvar then generated default
// binding. IDK if this is a good idea. It is like generating a default
// equation for a variable if in a model. But this is how it was done.
if isSome(oval) then
SOME(val) := oval;
else
val := generateDefaultBinding(ty);
end if;

then
val;
end match;
Expand Down
1 change: 1 addition & 0 deletions OMCompiler/Compiler/FrontEnd/ClassInf.mo
Expand Up @@ -423,6 +423,7 @@ algorithm
case (SCode.R_PACKAGE(),p) then PACKAGE(p);
case (SCode.R_FUNCTION(SCode.FR_NORMAL_FUNCTION(isImpure)),p) then FUNCTION(p, isImpure);
case (SCode.R_FUNCTION(SCode.FR_EXTERNAL_FUNCTION(isImpure)),p) then FUNCTION(p, isImpure);
case (SCode.R_FUNCTION(SCode.FR_RECORD_CONSTRUCTOR()),p) then FUNCTION(p, false);
case (SCode.R_FUNCTION(_),p) then FUNCTION(p, false);
case (SCode.R_OPERATOR(),p) then FUNCTION(p, false);
case (SCode.R_ENUMERATION(),p) then ENUMERATION(p);
Expand Down
1 change: 1 addition & 0 deletions OMCompiler/Compiler/FrontEnd/DAE.mo
Expand Up @@ -842,6 +842,7 @@ constant Attributes dummyAttrInput = ATTR(NON_CONNECTOR(), SCode.NON_PARALLEL(),
public uniontype BindingSource "where this binding came from: either default binding or start value"
record BINDING_FROM_DEFAULT_VALUE "the binding came from the default value" end BINDING_FROM_DEFAULT_VALUE;
record BINDING_FROM_START_VALUE "the binding came from the start value" end BINDING_FROM_START_VALUE;
record BINDING_FROM_RECORD_SUBMODS "the EQ binding is created from the submods of a record declration" end BINDING_FROM_RECORD_SUBMODS;
end BindingSource;

public
Expand Down
3 changes: 3 additions & 0 deletions OMCompiler/Compiler/FrontEnd/DAEDump.mo
Expand Up @@ -1358,6 +1358,9 @@ algorithm
case(DAE.EQBOUND(exp=e, source=DAE.BINDING_FROM_DEFAULT_VALUE())) equation
str = " = "+ExpressionDump.printExpStr(e);
then str;
case(DAE.EQBOUND(exp=e, source=DAE.BINDING_FROM_RECORD_SUBMODS())) equation
str = " = "+ExpressionDump.printExpStr(e);
then str;
case(DAE.VALBOUND(valBound=v, source=DAE.BINDING_FROM_DEFAULT_VALUE())) equation
str = " = " + ValuesUtil.valString(v);
then str;
Expand Down
1 change: 1 addition & 0 deletions OMCompiler/Compiler/FrontEnd/DAEUtil.mo
Expand Up @@ -5553,6 +5553,7 @@ algorithm
str := match(bindingSource)
local
case(DAE.BINDING_FROM_DEFAULT_VALUE()) then "[DEFAULT VALUE]";
case(DAE.BINDING_FROM_DEFAULT_VALUE()) then "[RECORD SUBMOD]";
case(DAE.BINDING_FROM_START_VALUE()) then "[START VALUE]";
end match;
end printBindingSourceStr;
Expand Down

0 comments on commit 023bac1

Please sign in to comment.