Skip to content

Commit

Permalink
9036 record constants (#9186)
Browse files Browse the repository at this point in the history
[BE/NF/Template] Constant record variable bindings handled

  * During the phase of lowering FE->BE:
    * Traverse all equations and collect record types from exps
    * Traverse all variables and update record types with bindings of record elements
    * Traverse all equations and apply updated record types
  * Generate C code from record EQBOUND binding

Co-authored-by: Philip Hannebohm <phannebohm@users.noreply.github.com>
Co-authored-by: AnHeuermann <AnHeuermann @users.noreply.github.com>
  • Loading branch information
3 people committed Jul 15, 2022
1 parent 7ed14b8 commit dfb10fc
Show file tree
Hide file tree
Showing 8 changed files with 401 additions and 39 deletions.
211 changes: 211 additions & 0 deletions OMCompiler/Compiler/BackEnd/BackendDAECreate.mo
Expand Up @@ -79,13 +79,34 @@ import SCode;
import StackOverflow;
import System;
import Types;
import UnorderedMap;
import Util;
import VarTransform;
import Vectorization;
import ZeroCrossings;

protected type Functiontuple = tuple<Option<DAE.FunctionTree>,list<DAE.InlineType>>;

protected type ArrayBindingList = list<tuple<list<Integer>,DAE.Exp>>;

function printArrayBindingList
input ArrayBindingList arrayBindingList;
output String str = "";
protected
list<Integer> subscriptLst;
DAE.Exp bindingExp;
algorithm
for tpl in arrayBindingList loop
(subscriptLst, bindingExp) := tpl;
str := str + "[";
for subscript in subscriptLst loop
str := str + intString(subscript) + " ";
end for;
str := str + "]";
str := str + " : " + ExpressionDump.dumpExpStr(bindingExp, 0);
end for;
end printArrayBindingList;

public function lower "This function translates a DAE, which is the result from instantiating a
class, into a more precise form, called BackendDAE.BackendDAE defined in this module.
The BackendDAE.BackendDAE representation splits the DAE into equations and variables
Expand Down Expand Up @@ -118,6 +139,8 @@ protected
String neqStr, nvarStr;
Integer varSize, eqnSize, numCheckpoints;
BackendDAE.EqSystem syst;
UnorderedMap<DAE.ComponentRef, DAE.Type> map;
UnorderedMap<DAE.ComponentRef, ArrayBindingList> arrayMap;
algorithm
numCheckpoints:=ErrorExt.getNumCheckpoints();
try
Expand All @@ -131,6 +154,33 @@ algorithm
(DAE.DAE(elems), functionTree, timeEvents) := processBuiltinExpressions(lst, functionTree);
(varlst, globalKnownVarLst, extvarlst, eqns, reqns, ieqns, constrs, clsAttrs, extObjCls, aliaseqns, _) :=
lower2(listReverse(elems), functionTree, HashTableExpToExp.emptyHashTable());

// ticket #9036
// propagate record bindings from attributes to their parent record types in all crefs of all equations O(n)

// 1. collect all possible record types from eqns
// (the frontend does not keep correct types at the variables so they have to be grabbed from eqns beforehand
// i don't like it but thats how it is).
map := UnorderedMap.new<DAE.Type>(ComponentReference.hashComponentRefMod, ComponentReference.crefEqual);
eqns := List.map(eqns, function collectRecordTypesEqn(map = map));
reqns := List.map(reqns, function collectRecordTypesEqn(map = map));
ieqns := List.map(ieqns, function collectRecordTypesEqn(map = map));

// 2. collect bindings from variables and update in types
// (ToDo: update the types?)
arrayMap := UnorderedMap.new<ArrayBindingList>(ComponentReference.hashComponentRefMod, ComponentReference.crefEqual);

_ := List.map(varlst, function collectRecordElementBindings(map = map, arrayMap = arrayMap));
_ := List.map(globalKnownVarLst, function collectRecordElementBindings(map = map, arrayMap = arrayMap));
_ := List.map(extvarlst, function collectRecordElementBindings(map = map, arrayMap = arrayMap));

map := collapseArrayBindings(arrayMap, map);

// 3. replace the types in eqns
eqns := List.map(eqns, function updateRecordTypesEqn(map = map));
reqns := List.map(reqns, function updateRecordTypesEqn(map = map));
ieqns := List.map(ieqns, function updateRecordTypesEqn(map = map));

vars := BackendVariable.listVar(varlst);
globalKnownVars := BackendVariable.listVar(globalKnownVarLst);
localKnownVars := BackendVariable.emptyVars();
Expand Down Expand Up @@ -190,6 +240,167 @@ algorithm
fail();
end lower;

protected function collectRecordElementBindings
input BackendDAE.Var var;
input UnorderedMap<DAE.ComponentRef, DAE.Type> map;
input UnorderedMap<DAE.ComponentRef, ArrayBindingList> arrayMap;
protected
DAE.ComponentRef rec_cref;
Boolean is_rec;
algorithm
(rec_cref, is_rec) := ComponentReference.crefGetFirstRec(var.varName);
() := match var.bindExp
local
DAE.Exp binding;
DAE.Type ty;

DAE.Exp arrayBinding;
DAE.ComponentRef arrayCref;
ArrayBindingList arrayBindingExpList;
list<DAE.Subscript> subscriptLst;
list<Integer> intSubLst;

case SOME(binding) guard(is_rec and UnorderedMap.contains(rec_cref, map) and Expression.isConst(binding)) algorithm

if ComponentReference.isArrayElement(var.varName) then
arrayCref := ComponentReference.crefStripSubsExceptModelSubs(var.varName);
arrayBindingExpList := UnorderedMap.getOrDefault(arrayCref, arrayMap, {});

subscriptLst := ComponentReference.crefSubs(var.varName);
intSubLst := list(match subscript
local
Integer i;
case DAE.INDEX(DAE.ICONST(i)) then i;
else algorithm
Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because index not integer."});
then fail();
end match for subscript in subscriptLst);
UnorderedMap.add(arrayCref, (intSubLst, binding)::arrayBindingExpList, arrayMap);
else

ty := match UnorderedMap.getSafe(rec_cref, map)
case ty as DAE.T_COMPLEX() algorithm
ty.varLst := list(updateConstantRecordElementBinding(v, binding, ComponentReference.crefLastIdent(var.varName)) for v in ty.varLst);
then ty;
else algorithm
Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because the type is not T_COMPLEX."});
then fail();
end match;
UnorderedMap.add(rec_cref, ty, map);
end if;
then ();
else ();
end match;
end collectRecordElementBindings;

function updateConstantRecordElementBinding
input output DAE.Var var;
input DAE.Exp binding;
input String name;
protected
DAE.Const const;
algorithm
if var.name == name then
const := if Expression.isConst(binding) then DAE.C_CONST() else DAE.C_VAR();
var.binding := DAE.EQBOUND(binding, NONE(), const, DAE.BINDING_FROM_DEFAULT_VALUE());
end if;
end updateConstantRecordElementBinding;

protected function collectRecordTypesEqn
input output BackendDAE.Equation eqn;
input UnorderedMap<DAE.ComponentRef, DAE.Type> map;
algorithm
(eqn, _) := BackendEquation.traverseExpsOfEquation(eqn, function Expression.traverseExpTopDown(func=collectRecordTypesExp), map);
end collectRecordTypesEqn;

protected function updateRecordTypesEqn
input output BackendDAE.Equation eqn;
input UnorderedMap<DAE.ComponentRef, DAE.Type> map;
algorithm
(eqn, _) := BackendEquation.traverseExpsOfEquation(eqn, function Expression.traverseExpTopDown(func=updateRecordTypesExp), map);
end updateRecordTypesEqn;

protected function collectRecordTypesExp
input output DAE.Exp exp;
output Boolean cont;
input output UnorderedMap<DAE.ComponentRef, DAE.Type> map;
algorithm
cont := match exp
local
DAE.ComponentRef cref;
case DAE.CREF(componentRef = cref) guard(Types.isRecord(exp.ty)) algorithm
UnorderedMap.add(cref, exp.ty, map);
then false;
else true;
end match;
end collectRecordTypesExp;

protected function updateRecordTypesExp
input output DAE.Exp exp;
output Boolean cont;
input output UnorderedMap<DAE.ComponentRef, DAE.Type> map;
algorithm
(exp, cont) := match exp
local
DAE.ComponentRef cref;
case DAE.CREF(componentRef = cref) guard(UnorderedMap.contains(cref, map)) algorithm
exp.ty := UnorderedMap.getSafe(cref, map);
then (exp, false);
else (exp, true);
end match;
end updateRecordTypesExp;

protected function collapseArrayBindings
input UnorderedMap<DAE.ComponentRef, ArrayBindingList> arrayMap;
input output UnorderedMap<DAE.ComponentRef, DAE.Type> map;
protected
DAE.ComponentRef cref;
DAE.ComponentRef rec_cref;
ArrayBindingList arrayBindingExpList;
list<Integer> subscriptLst;
DAE.Exp binding;
DAE.Exp scalarBinding;
list<DAE.Exp> expLst;
DAE.Type ty;
list<DAE.Dimension> dims;
Integer firstDim;
algorithm

// TODO: Sort by index
for pair in UnorderedMap.toList(arrayMap) loop
(cref, arrayBindingExpList) := pair;

expLst := {};
for scalBind in arrayBindingExpList loop
(subscriptLst, scalarBinding) := scalBind;
expLst := scalarBinding :: expLst;
end for;

binding := match listLength(subscriptLst)
case 1 then DAE.ARRAY(ComponentReference.crefTypeFull(cref), true, expLst);
case 2 algorithm
dims := Types.getDimensions(ComponentReference.crefLastType(cref));
firstDim := match List.first(dims)
case DAE.DIM_INTEGER(firstDim) then firstDim;
end match;
then DAE.MATRIX(ComponentReference.crefTypeFull(cref), firstDim, List.splitEqualParts(expLst, firstDim)); // TODO: Reshape list to list of list
else fail();
end match;

// Update binding in map
(rec_cref, true) := ComponentReference.crefGetFirstRec(cref);
ty := match UnorderedMap.getSafe(rec_cref, map)
case ty as DAE.T_COMPLEX() algorithm
ty.varLst := list(updateConstantRecordElementBinding(v, binding, ComponentReference.crefLastIdent(cref)) for v in ty.varLst);
then ty;
else algorithm
Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because the type is not T_COMPLEX."});
then fail();
end match;
UnorderedMap.add(rec_cref, ty, map);
end for;
end collapseArrayBindings;

protected function getExternalObjectAlias "Checks equations if there is an alias equation for external objects.
If yes, assign alias var, replace equations, remove alias equation.
author: waurich TUD 2016-10"
Expand Down
51 changes: 35 additions & 16 deletions OMCompiler/Compiler/FrontEnd/ComponentReference.mo
Expand Up @@ -1535,6 +1535,28 @@ algorithm
isRec := isRecIn or Types.isRecord(crefLastType(cref));
end crefIsRec;

public function crefGetFirstRec
input DAE.ComponentRef cref;
output DAE.ComponentRef result;
output Boolean isRec;
algorithm
(result, isRec) := match cref
local
DAE.ComponentRef innerCref;
case DAE.CREF_IDENT() then (cref, Types.isRecord(crefType(cref)));
case DAE.CREF_QUAL() algorithm
if Types.isRecord(crefType(cref)) then
result := DAE.CREF_IDENT(cref.ident, cref.identType, cref.subscriptLst);
isRec := true;
else
(innerCref, isRec) := crefGetFirstRec(cref.componentRef);
result := DAE.CREF_QUAL(cref.ident, cref.identType, cref.subscriptLst, innerCref);
end if;
then (result, isRec);
else (cref, false);
end match;
end crefGetFirstRec;

protected function containWholeDim2 "
A function to check if a cref contains a [:] wholedim element in the subscriptlist."
input list<DAE.Subscript> inRef;
Expand Down Expand Up @@ -2072,7 +2094,7 @@ crefPrependIdent(a,c,{1},Integer[1]) => a.c[1] [Integer[1]]
alternative names: crefAddSuffix, crefAddIdent
"
input DAE.ComponentRef icr;
input String ident;
input DAE.Ident ident;
input list<DAE.Subscript> subs;
input DAE.Type tp;
output DAE.ComponentRef newCr;
Expand Down Expand Up @@ -2503,24 +2525,21 @@ end crefApplySubs;

public function crefSetType "
sets the type of a cref."
input DAE.ComponentRef inRef;
input DAE.Type newType;
output DAE.ComponentRef outRef;
input output DAE.ComponentRef cref;
input DAE.Type ty;
algorithm
outRef := match (inRef,newType)
local
DAE.Type ty;
DAE.ComponentRef child;
list<DAE.Subscript> subs;
DAE.Ident id;
cref := match cref
case DAE.CREF_IDENT() algorithm
cref.identType := ty;
then cref;

case(DAE.CREF_IDENT(id,_,subs),_)
then
makeCrefIdent(id,newType,subs);
case DAE.CREF_QUAL() algorithm
cref.identType := ty;
then cref;

case(DAE.CREF_QUAL(id,_,subs,child),_)
then
makeCrefQual(id,newType,subs,child);
else algorithm
Error.addInternalError(getInstanceName() + " was applied on a cref that has no type: " + crefStr(cref), sourceInfo());
then fail();
end match;
end crefSetType;

Expand Down
8 changes: 4 additions & 4 deletions OMCompiler/Compiler/FrontEnd/DAEUtil.mo
Expand Up @@ -5591,10 +5591,10 @@ public function printBindingSourceStr "prints a binding source as a string"
output String str;
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]";
case(DAE.BINDING_FROM_DEFAULT_VALUE()) then "[DEFAULT VALUE]";
case(DAE.BINDING_FROM_START_VALUE()) then "[START VALUE]";
case(DAE.BINDING_FROM_RECORD_SUBMODS()) then "[RECORD SUBMODS]";
case(DAE.BINDING_FROM_DERIVED_RECORD_DECL()) then "[DERIVED RECORD]";
end match;
end printBindingSourceStr;

Expand Down

0 comments on commit dfb10fc

Please sign in to comment.