Skip to content

Commit

Permalink
- Started the implementation of sharing constant literals
Browse files Browse the repository at this point in the history
  - It is a one-pass phase on list<DAE.Function>, right before code generation starts
  - For now, it is limited to string constants (not even boxed strings...)
  - It is also limited to function code (not simulations) as equation-systems in general don't use MetaModelica types, which will benefit the most from this change (gcc already shares string constants)


git-svn-id: https://openmodelica.org/svn/OpenModelica/trunk@7548 f25d12d1-65f4-0310-ae8a-bbce733d8d8e
  • Loading branch information
sjoelund committed Dec 22, 2010
1 parent 10398a7 commit fefa1ea
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 8 deletions.
65 changes: 62 additions & 3 deletions Compiler/BackEnd/SimCode.mo
Expand Up @@ -61,6 +61,7 @@ public import Types;
public import Env;
public import Dependency;
public import Interactive;
public import HashTableExpToIndex;
public import Absyn;
public import Ceval;
public import Tpl;
Expand All @@ -76,6 +77,7 @@ protected import BackendDAETransform;
protected import BackendEquation;
protected import BackendVariable;
protected import BackendVarTransform;
protected import BaseHashTable;
protected import ClassInf;
protected import ComponentReference;
protected import DAEUtil;
Expand Down Expand Up @@ -118,6 +120,7 @@ uniontype SimCode
record SIMCODE
ModelInfo modelInfo;
list<Function> functions;
list<DAE.Exp> literals "shared literals";
list<RecordDeclaration> recordDecls;
list<String> externalFunctionIncludes;
list<SimEqSystem> allEquations;
Expand Down Expand Up @@ -167,6 +170,7 @@ uniontype FunctionCode
String name;
Function mainFunction "This function is special; the 'in'-function should be generated for it";
list<Function> functions;
list<DAE.Exp> literals "shared literals";
list<String> externalFunctionIncludes;
MakefileParams makefileParams;
list<RecordDeclaration> extraRecordDecls;
Expand Down Expand Up @@ -1057,21 +1061,75 @@ algorithm
MakefileParams makefileParams;
FunctionCode fnCode;
list<RecordDeclaration> extraRecordDecls;
list<DAE.Exp> literals;
case (name, daeMainFunction, daeElements, metarecordTypes)
equation
// Create FunctionCode
/* TODO: Check if this is actually 100% certain to be the function given by name? */
(mainFunction::fns, extraRecordDecls, includes, libs) = elaborateFunctions(daeMainFunction::daeElements, metarecordTypes);
(daeElements,(_,(_,_,literals))) = DAEUtil.traverseDAEFunctions(daeMainFunction::daeElements,Expression.traverseSubexpressionsHelper,(replaceLiteralExp,(0,HashTableExpToIndex.emptyHashTableSized(24971),{})));
literals = listReverse(literals);
(mainFunction::fns, extraRecordDecls, includes, libs) = elaborateFunctions(daeElements, metarecordTypes);
checkValidMainFunction(name, mainFunction);
makefileParams = createMakefileParams(libs);
fnCode = FUNCTIONCODE(name, mainFunction, fns, includes, makefileParams, extraRecordDecls);
fnCode = FUNCTIONCODE(name, mainFunction, fns, literals, includes, makefileParams, extraRecordDecls);
// Generate code
_ = Tpl.tplString(SimCodeC.translateFunctions, fnCode);
then
();
end matchcontinue;
end translateFunctions;

protected function replaceLiteralExp
"The tuples contain:
* The expression to be replaced (or not)
* Index of next literal
* HashTable Exp->Index (Number of the literal)
* The list of literals
"
input tuple<DAE.Exp,tuple<Integer,HashTableExpToIndex.HashTable,list<DAE.Exp>>> inTpl;
output tuple<DAE.Exp,tuple<Integer,HashTableExpToIndex.HashTable,list<DAE.Exp>>> outTpl;
algorithm
outTpl := matchcontinue inTpl
local
DAE.Exp exp,nexp;
Integer i,ix;
list<DAE.Exp> l;
DAE.ExpType et;
HashTableExpToIndex.HashTable ht;
case ((DAE.SHARED_LITERAL(index=_),_)) then inTpl;
case ((exp,_))
equation
failure(isLiteralExp(exp));
then inTpl;
case ((exp,(i,ht,l)))
equation
ix = BaseHashTable.get(exp,ht);
et = Expression.typeof(exp);
nexp = DAE.SHARED_LITERAL(ix,et);
then ((nexp,(i,ht,l)));
case ((exp,(i,ht,l)))
equation
ht = BaseHashTable.add((exp,i),ht);
et = Expression.typeof(exp);
nexp = DAE.SHARED_LITERAL(i,et);
then ((nexp,(i+1,ht,exp::l)));
else
equation
Error.addMessage(Error.INTERNAL_ERROR, {"SimCode.replaceLiteralExp failed. Falling back to not replacing the literal."});
then inTpl;
end matchcontinue;
end replaceLiteralExp;

protected function isLiteralExp
"Returns if the expression may be replaced by a constant literal"
input DAE.Exp exp;
algorithm
_ := match exp
case DAE.SCONST(_) then ();
case DAE.SHARED_LITERAL(index=_) then ();
else fail();
end match;
end isLiteralExp;

protected function checkValidMainFunction
"Verifies that an in-function can be generated.
This is not the case if the input involves function-pointers."
Expand Down Expand Up @@ -1764,6 +1822,7 @@ algorithm

simCode = SIMCODE(modelInfo,
functions,
{},
recordDecls,
externalFunctionIncludes,
allEquations,
Expand Down
13 changes: 11 additions & 2 deletions Compiler/FrontEnd/DAE.mo
Expand Up @@ -1154,14 +1154,23 @@ uniontype Exp "Expressions
ExpType et;
end MATCHEXPRESSION;

record BOX
record BOX "MetaModelica boxed value"
Exp exp;
end BOX;

record UNBOX
record UNBOX "MetaModelica value unboxing (similar to a cast)"
Exp exp;
ExpType ty;
end UNBOX;

record SHARED_LITERAL
"Before code generation, we make a pass that replaces constant literals
with a SHARED_LITERAL expression. Any immutable type can be shared:
basic MetaModelica types and Modelica strings are fine. There is no point
to share Real, Integer, Boolean or Enum though."
Integer index;
ExpType ty "The type is required for code generation to work properly";
end SHARED_LITERAL;

/* --- */

Expand Down
23 changes: 23 additions & 0 deletions Compiler/FrontEnd/DAEUtil.mo
Expand Up @@ -3653,6 +3653,29 @@ algorithm
end matchcontinue;
end traverseDAEFuncLst;

public function traverseDAEFunctions "Traverses the functions.
Note: Only calls the top-most expressions If you need to also traverse the
expression, use an extra helper function."
input list<DAE.Function> funcLst;
input FuncExpType func;
input Type_a extraArg;
output list<DAE.Function> outFuncLst;
output Type_a oextraArg;
partial function FuncExpType input tuple<DAE.Exp,Type_a> arg; output tuple<DAE.Exp,Type_a> oarg; end FuncExpType;
replaceable type Type_a subtypeof Any;
algorithm
(outFuncLst,oextraArg) := matchcontinue(funcLst,func,extraArg)
local
DAE.Function daeFunc;
case({},func,extraArg) then ({},extraArg);
case(daeFunc::funcLst,func,extraArg)
equation
(daeFunc,extraArg) = traverseDAEFunc(daeFunc,func,extraArg);
(funcLst,extraArg) = traverseDAEFunctions(funcLst,func,extraArg);
then (daeFunc::funcLst,extraArg);
end matchcontinue;
end traverseDAEFunctions;

protected function traverseDAEFunc
input DAE.Function daeFn;
input FuncExpType func;
Expand Down
6 changes: 6 additions & 0 deletions Compiler/FrontEnd/Expression.mo
Expand Up @@ -1525,6 +1525,7 @@ algorithm
case (DAE.METARECORDCALL(path=_)) then DAE.ET_METATYPE();
case (DAE.BOX(_)) then DAE.ET_METATYPE();
case (DAE.UNBOX(ty = tp)) then tp;
case (DAE.SHARED_LITERAL(ty = tp)) then tp;
case e
equation
msg = "- Expression.typeof failed for " +& ExpressionDump.printExpStr(e);
Expand Down Expand Up @@ -3729,6 +3730,11 @@ algorithm
then
((e,ext_arg_3));

case (e as DAE.SHARED_LITERAL(index = _),rel,ext_arg)
equation
res = rel((e,ext_arg));
then res;

case (e,rel,ext_arg)
equation
str = ExpressionDump.printExpStr(e);
Expand Down
2 changes: 2 additions & 0 deletions Compiler/FrontEnd/ExpressionDump.mo
Expand Up @@ -893,6 +893,8 @@ algorithm
s2 = printExp2Str(DAE.TUPLE(es), stringDelimiter, opcreffunc, opcallfunc);
s = stringAppendList({s1,s2,"\n","#cases#\n","end ",s1});
then s;

case (DAE.SHARED_LITERAL(index=_), _, _, _) then "#SHARED LITERAL#";

case (e, _, _, _)
equation
Expand Down
1 change: 1 addition & 0 deletions Compiler/Makefile.common
Expand Up @@ -123,6 +123,7 @@ HashTable3.mo \
HashTable5.mo \
HashTableCG.mo \
HashTableStringToPath.mo \
HashTableExpToIndex.mo \
IOStream.mo \
Util.mo \
VarTransform.mo \
Expand Down
2 changes: 1 addition & 1 deletion Compiler/Util/BaseHashTable.mo
Expand Up @@ -57,7 +57,7 @@ protected import Util;
// Generic hashtable code below

// adrpo: use a prime here (pick your poison):
// 1013 2053 3023 4013 4999 5051 5087
// 1013 2053 3023 4013 4999 5051 5087 24971
public constant Integer defaultBucketSize = 2053;

public function emptyHashTableWork
Expand Down
91 changes: 91 additions & 0 deletions Compiler/Util/HashTableExpToIndex.mo
@@ -0,0 +1,91 @@
encapsulated package HashTableExpToIndex "
This file is an extension to OpenModelica.

Copyright (c) 2007 MathCore Engineering AB

All rights reserved.

RCS: $Id$

"

/* Below is the instance specific code. For each hashtable the user must define:
Key - The key used to uniquely define elements in a hashtable
Value - The data to associate with each key
hashFunc - A function that maps a key to a positive integer.
keyEqual - A comparison function between two keys, returns true if equal.
*/

/* HashTable instance specific code */

public import BaseHashTable;
public import DAE;
protected import Expression;
protected import ExpressionDump;

public type Key = DAE.Exp;
public type Value = Integer;

public type HashTableCrefFunctionsType = tuple<FuncHashCref,FuncCrefEqual,FuncCrefStr,FuncExpStr>;
public type HashTable = tuple<
array<list<tuple<Key,Integer>>>,
tuple<Integer,Integer,array<Option<tuple<Key,Value>>>>,
Integer,
Integer,
HashTableCrefFunctionsType
>;

partial function FuncHashCref
input Key cr;
output Integer res;
end FuncHashCref;

partial function FuncCrefEqual
input Key cr1;
input Key cr2;
output Boolean res;
end FuncCrefEqual;

partial function FuncCrefStr
input Key cr;
output String res;
end FuncCrefStr;

partial function FuncExpStr
input Value exp;
output String res;
end FuncExpStr;

protected function hashFunc
"Calculates a hash value for Key"
input Key cr;
output Integer res;
String crstr;
algorithm
crstr := ExpressionDump.printExpStr(cr);
res := stringHashDjb2(crstr);
end hashFunc;

public function emptyHashTable
"
Returns an empty HashTable.
Using the bucketsize 1000 and array size 100.
"
output HashTable hashTable;
algorithm
hashTable := emptyHashTableSized(BaseHashTable.defaultBucketSize);
end emptyHashTable;

public function emptyHashTableSized
"
Returns an empty HashTable.
Using the bucketsize size and arraysize size/10.
"
input Integer size;
output HashTable hashTable;
algorithm
hashTable := BaseHashTable.emptyHashTableWork(size,intDiv(size,10),(hashFunc,Expression.expEqual,ExpressionDump.printExpStr,intString));
end emptyHashTableSized;

end HashTableExpToIndex;
23 changes: 21 additions & 2 deletions Compiler/susan_codegen/SimCode/SimCodeC.tpl
Expand Up @@ -75,7 +75,7 @@ match functionCode
case FUNCTIONCODE(__) then
let filePrefix = name
let()= textFile(functionsHeaderFile(filePrefix, mainFunction, functions, extraRecordDecls, externalFunctionIncludes), '<%filePrefix%>.h')
let()= textFile(functionsFile(filePrefix, mainFunction, functions), '<%filePrefix%>.c')
let()= textFile(functionsFile(filePrefix, mainFunction, functions, literals), '<%filePrefix%>.c')
let()= textFile(recordsFile(filePrefix, extraRecordDecls), '<%filePrefix%>_records.c')
let()= textFile(functionsMakefile(functionCode), '<%filePrefix%>.makefile')
"" // Return empty result since result written to files directly
Expand Down Expand Up @@ -2516,7 +2516,8 @@ end commonHeader;

template functionsFile(String filePrefix,
Function mainFunction,
list<Function> functions)
list<Function> functions,
list<Exp> literals)
"Generates the contents of the main C file for the function case."
::=
<<
Expand All @@ -2526,6 +2527,9 @@ template functionsFile(String filePrefix,
#define MODELICA_TERMINATE(msg) { fprintf(stderr,"Modelica Terminate: %s!\n", msg); fflush(stderr); }

extern "C" {
<%literals |> literal hasindex i0 from 0 => literalExpConst(literal,i0) ; separator="\n"%>
<%functionBody(mainFunction,true)%>
<%functionBodies(functions)%>
}
Expand Down Expand Up @@ -4515,6 +4519,7 @@ template daeExp(Exp exp, Context context, Text &preExp /*BUFP*/, Text &varDecls
case e as MATCHEXPRESSION(__) then daeExpMatch(e, context, &preExp /*BUFC*/, &varDecls /*BUFD*/)
case e as BOX(__) then daeExpBox(e, context, &preExp /*BUFC*/, &varDecls /*BUFD*/)
case e as UNBOX(__) then daeExpUnbox(e, context, &preExp /*BUFC*/, &varDecls /*BUFD*/)
case e as SHARED_LITERAL(__) then daeExpSharedLiteral(e, context, &preExp /*BUFC*/, &varDecls /*BUFD*/)
else '<%\n%>#error "UNKNOWN_EXP <%ExpressionDump.printExpStr(exp)%>"<%\n%>'
end daeExp;

Expand Down Expand Up @@ -5545,6 +5550,12 @@ case exp as UNBOX(__) then
'mmc_unbox_<%ty%>(<%res%>)'
end daeExpUnbox;

template daeExpSharedLiteral(Exp exp, Context context, Text &preExp /*BUFP*/, Text &varDecls /*BUFP*/)
"Generates code for a match expression."
::=
match exp case exp as SHARED_LITERAL(__) then '_OMC_LIT<%exp.index%>'
end daeExpSharedLiteral;


// TODO: Optimize as in Codegen
// TODO: Use this function in other places where almost the same thing is hard
Expand Down Expand Up @@ -5919,6 +5930,7 @@ template expTypeFromExpFlag(Exp exp, Integer flag)
case REDUCTION(__) then expTypeFromExpFlag(expr, flag)
case BOX(__) then match flag case 1 then "metatype" else "modelica_metatype"
case c as UNBOX(__) then expTypeFlag(c.ty, flag)
case c as SHARED_LITERAL(__) then expTypeFlag(c.ty, flag)
else "expTypeFromExpFlag:ERROR"
end expTypeFromExpFlag;

Expand Down Expand Up @@ -6085,6 +6097,13 @@ template assertCommon(Exp condition, Exp message, Context context, Text &varDecl
>>
end assertCommon;

template literalExpConst(Exp lit, Integer index) "These should all be declared static X const"
::=
match lit
case SCONST(__) then 'static modelica_string const _OMC_LIT<%index%> = "<%Util.escapeModelicaStringToCString(string)%>";'
else '<%\n%>#error "literalExpConst failed: <%printExpStr(lit)%>"<%\n%>'
end literalExpConst;

end SimCodeC;

// vim: filetype=susan sw=2 sts=2

0 comments on commit fefa1ea

Please sign in to comment.