Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 67.3% 409 / 0 / 608
Functions: -% 0 / 1 / 1
Branches: 39.7% 250 / 0 / 629

OMCompiler/Compiler/SimCode/SimCodeFunctionUtil.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated package SimCodeFunctionUtil "SimCode functions not related to equation systems"
37
38 import DAE;
39 import AbsynUtil;
40 import ClassInf;
41 import Settings;
42 import Types;
43 import Util;
44 import Global;
45 import ProgramUtil;
46 import HashTableStringToPath;
47 import SimCodeFunction;
48 import SimCodeVar;
49
50 protected
51
52 import Absyn;
53 import Array;
54 import Autoconf;
55 import BaseHashTable;
56 import ComponentReference;
57 import ComponentReferenceBasics;
58 import DAEDump;
59 import DAEUtil;
60 import ElementSource;
61 import Error;
62 import Expression;
63 import ExpressionBasics;
64 import ExpressionSimplify;
65 import Flags;
66 import Graph;
67 import List;
68 import Mod;
69 import Patternm;
70 import SCode;
71 import SCodeUtil;
72 import StringUtil;
73 import Testsuite;
74 import UnorderedMap;
75 import Config;
76 import System;
77
78 public
79
80 public function elementVars
81 "Used by templates to get a list of variables from a valueblock."
82 input list<DAE.Element> ild;
83 output list<SimCodeFunction.Variable> vars;
84 protected
85 list<DAE.Element> ld;
86 algorithm
87 6332 ld := List.filterOnTrue(ild, isVarQ);
88 6332 vars := List.map(ld, daeInOutSimVar);
89 end elementVars;
90
91 public function crefSubIsScalar
92 "Used by templates to determine if a component reference's subscripts are
93 scalar."
94 input DAE.ComponentRef cref;
95 output Boolean isScalar;
96 protected
97 list<DAE.Subscript> subs;
98 algorithm
99 56571 subs := ComponentReferenceBasics.crefSubs(cref);
100 56571 isScalar := subsToScalar(subs);
101 end crefSubIsScalar;
102
103 protected function subsToScalar "scalar expression."
104 input list<DAE.Subscript> inExpSubscriptLst;
105 output Boolean outBoolean;
106 algorithm
107 outBoolean := match inExpSubscriptLst
108 local
109 Boolean b;
110 list<DAE.Subscript> r;
111 case {} then true;
112 case DAE.SLICE() :: _ then false;
113 case DAE.WHOLEDIM() :: _ then false;
114 case DAE.INDEX() :: r
115 algorithm
116 42894 b := subsToScalar(r);
117 then
118 b;
119 end match;
120 end subsToScalar;
121
122 public function crefNoSub
123 "Used by templates to determine if a component reference has no subscripts."
124 input DAE.ComponentRef cref;
125 output Boolean noSub;
126 algorithm
127 ✗ noSub := not ComponentReference.crefHaveSubs(cref);
128 end crefNoSub;
129
130 public function inFunctionContext
131 input SimCodeFunction.Context inContext;
132 output Boolean outInFunction;
133 algorithm
134 outInFunction := match inContext
135 case SimCodeFunction.FUNCTION_CONTEXT() then true;
136 else false;
137 end match;
138 end inFunctionContext;
139
140 public function crefIsScalar
141 "Whether a component reference is a scalar depends on what context we are in.
142 If we are generating code for a function, then only crefs without subscripts
143 are scalar. If we are generating code for simulation though, then crefs with
144 only constant subscripts are also scalars, since a variable is generated for
145 each element of an array in the model."
146 input DAE.ComponentRef cref;
147 input SimCodeFunction.Context context;
148 output Boolean isScalar;
149 algorithm
150
2/2
✓ Branch 1 taken 101084 times.
✓ Branch 2 taken 37936 times.
139020 if inFunctionContext(context) then
151 101084 isScalar := listEmpty(ComponentReference.crefLastSubs(cref));
152 elseif Flags.isSet(Flags.NF_SCALARIZE) then
153 37602 isScalar := ComponentReference.crefHasScalarSubscripts(cref);
154 else
155 334 isScalar := not ComponentReference.crefHaveSubs(cref);
156 end if;
157 end crefIsScalar;
158
159 public function buildCrefExpFromAsub
160 "Used by templates to convert an ASUB expression to a component reference
161 with subscripts."
162 input DAE.Exp cref;
163 input list<DAE.Exp> subs;
164 output DAE.Exp cRefOut;
165 algorithm
166 cRefOut := match(cref, subs)
167 local
168 DAE.Exp crefExp;
169 DAE.Type ty;
170 DAE.ComponentRef crNew;
171 list<DAE.Subscript> indexes;
172
173 case (_, {}) then cref;
174 case (DAE.CREF(componentRef=crNew, ty=ty), _)
175 algorithm
176 ✗ indexes := List.map(subs, Expression.makeIndexSubscript);
177 ✗ crNew := ComponentReference.subscriptCref(crNew, indexes);
178 ✗ crefExp := Expression.makeCrefExp(crNew, ty);
179 then
180 crefExp;
181 end match;
182 end buildCrefExpFromAsub;
183
184 public function buildCrefExpFromSubs
185 "Used by templates to convert an ASUB expression to a component reference
186 with subscripts."
187 input DAE.Exp cref;
188 input list<DAE.Subscript> subs;
189 output DAE.Exp cRefOut;
190 algorithm
191 cRefOut := match(cref, subs)
192 local
193 DAE.Exp crefExp;
194 DAE.Type ty;
195 DAE.ComponentRef crNew;
196
197 case (_, {}) then cref;
198 case (DAE.CREF(componentRef=crNew, ty=ty), _)
199 algorithm
200 ✗ crNew := ComponentReference.subscriptCref(crNew, subs);
201 ✗ crefExp := Expression.makeCrefExp(crNew, ty);
202 then
203 crefExp;
204 end match;
205 end buildCrefExpFromSubs;
206
207 public function padAsubSubscripts
208 "Used by templates: the subscripts of an ASUB of exp, with a whole-dimension
209 subscript for each trailing dimension they leave out."
210 input DAE.Exp exp;
211 input list<DAE.Subscript> subs;
212 output list<DAE.Subscript> outSubs;
213 protected
214 Integer n = listLength(Expression.arrayDimension(Expression.typeof(exp))) - listLength(subs);
215 algorithm
216 ✗ outSubs := if n > 0 then listAppend(subs, List.fill(DAE.WHOLEDIM(), n)) else subs;
217 end padAsubSubscripts;
218
219 public function incrementInt
220 "Used by templates to create new integers that are increments of another."
221 input Integer inInt;
222 input Integer increment;
223 output Integer outInt;
224 algorithm
225 6971 outInt := inInt + increment;
226 end incrementInt;
227
228 public function decrementInt
229 "Used by templates to create new integers that are increments of another."
230 input Integer inInt;
231 input Integer decrement;
232 output Integer outInt;
233 algorithm
234 ✗ outInt := inInt - decrement;
235 end decrementInt;
236
237
238 public function protectedVars
239 input list<SimCodeVar.SimVar> InSimVars;
240 output list<SimCodeVar.SimVar> OutSimVars;
241 algorithm
242 147 OutSimVars:= List.filterOnTrue(InSimVars,isNotProtected);
243 end protectedVars;
244
245 protected function isNotProtected
246 input SimCodeVar.SimVar simVar;
247 output Boolean isProtected;
248 algorithm
249 2604 SimCodeVar.SIMVAR(isProtected=isProtected) := simVar;
250 2604 isProtected := not isProtected;
251 end isNotProtected;
252
253
254 public function makeCrefRecordExp
255 "Helper function to generate records."
256 input DAE.ComponentRef inCRefRecord;
257 input DAE.Var inVar;
258 output DAE.Exp outExp;
259 algorithm
260 outExp := match (inCRefRecord, inVar)
261 local
262 DAE.ComponentRef cr, cr1;
263 String name;
264 DAE.Type tp;
265 case (cr, DAE.TYPES_VAR(name=name, ty=tp))
266 algorithm
267 19899 cr1 := ComponentReference.crefPrependIdent(cr, name, {}, tp);
268 19899 outExp := Expression.makeCrefExp(cr1, tp);
269 then
270 outExp;
271 end match;
272 end makeCrefRecordExp;
273
274 public function splitRecordAssignmentToMemberAssignments
275 "This function is used by the templates to split up a record assignment to
276 assignments of each of the members. This is needed in simulation context
277 since there is no 'record' per se. Instead the elements(locations) of the record are
278 scattered through the SIMVAR structure.
279
280 Note that this does not recurse to check if a member itself is a record as well i.e.
281 we generate an assignment of records. But since these assignments are sent the codegen
282 template we will indirectly come back here and resolve them."
283 input DAE.ComponentRef lhs_cref;
284 input DAE.Type lhs_type;
285 input String rhs_cref_str;
286 output list<DAE.Statement> outAssigns;
287 protected
288 DAE.ComponentRef rhs_cref;
289 algorithm
290
291 outAssigns := {};
292 769 rhs_cref := DAE.CREF_IDENT(rhs_cref_str, lhs_type, {});
293
294 () := match lhs_type
295 local
296 DAE.Exp l_v_exp, r_v_exp;
297 DAE.Statement stmt;
298
299 case DAE.T_COMPLEX() algorithm
300
2/2
✓ Branch 0 taken 8805 times.
✓ Branch 1 taken 769 times.
9574 for v in lhs_type.varLst loop
301 // l_v_cref := ComponentReference.crefPrependIdent(lhs_cref, v.name, {}, v.ty);
302 // r_v_cref := ComponentReference.crefPrependIdent(rhs_cref, v.name, {}, v.ty);
303
304 // l_v_exp := Expression.makeCrefExp(l_v_cref, v.ty);
305 // r_v_exp := Expression.makeCrefExp(r_v_cref, v.ty);
306
307 8805 l_v_exp := makeCrefRecordExp(lhs_cref, v);
308 8805 r_v_exp := makeCrefRecordExp(rhs_cref, v);
309
310
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 8791 times.
8805 if Types.isArray(v.ty) then
311 14 stmt := DAE.STMT_ASSIGN_ARR(v.ty, l_v_exp, r_v_exp, DAE.emptyElementSource);
312 else
313 8791 stmt := DAE.STMT_ASSIGN(v.ty, l_v_exp, r_v_exp, DAE.emptyElementSource);
314 end if;
315
316 outAssigns := stmt::outAssigns;
317 end for;
318
319 769 outAssigns := listReverse(outAssigns);
320 then ();
321
322 end match;
323 end splitRecordAssignmentToMemberAssignments;
324
325 public function derComponentRef
326 "Used by templates to derrive a cref in a der(cref) expression.
327 Particularly, this function is called for the C# code generator,
328 while for C/C++, it is solved by prefixing the cref with '$P$DER' in daeExpCall() template.
329 The prefixing technique is not usable for C#, because there is no macroprocessor in C#.
330 TODO: all der(cref) expressions should be eliminated before the expressions enter templates
331 to pull this logic (and this function) out of templates."
332 input DAE.ComponentRef inCref;
333 output DAE.ComponentRef derCref;
334 algorithm
335 ✗ derCref := ComponentReference.crefPrefixDer(inCref);
336 end derComponentRef;
337
338 public function hackArrayReverseToCref
339 "This is a hack transformation of an expanded array back to its cref.
340 It is used in daeExpArray() (for C# yet) to optimize the generated code.
341 TODO: This function should not exist!
342 Rather the array should not be let expanded when SimCode is entering templates.
343 "
344 input DAE.Exp inExp;
345 input SimCodeFunction.Context context;
346 output DAE.Exp outExp;
347 algorithm
348 outExp := matchcontinue inExp
349 local
350 list<DAE.Exp> aRest;
351 DAE.ComponentRef cr;
352 DAE.Type aty;
353 DAE.Exp crefExp;
354
355 case DAE.ARRAY(ty=aty, scalar=true, array =(DAE.CREF(componentRef=cr) ::aRest))
356 algorithm
357 ✗ failure(SimCodeFunction.FUNCTION_CONTEXT():=context); // only in the function context
358 ✗ { DAE.INDEX(DAE.ICONST(1)) } := ComponentReference.crefLastSubs(cr);
359 ✗ cr := ComponentReferenceBasics.crefStripLastSubs(cr);
360 ✗ true := isArrayExpansion(aRest, cr, 2);
361 ✗ crefExp := Expression.makeCrefExp(cr, aty);
362 then
363 crefExp;
364
365 else inExp;
366
367 end matchcontinue;
368 end hackArrayReverseToCref;
369
370 protected function isArrayExpansion
371 "Helper funtion to hackArrayReverseToCref."
372 input list<DAE.Exp> inArrayElems;
373 input DAE.ComponentRef inCref;
374 input Integer index;
375 output Boolean isExpanded;
376 algorithm
377 isExpanded := matchcontinue inArrayElems
378 local
379 list<DAE.Exp> aRest;
380 Integer i;
381 DAE.ComponentRef cr;
382 case {} then true;
383 case DAE.CREF(componentRef=cr) :: aRest
384 algorithm
385 ✗ { DAE.INDEX(DAE.ICONST(i)) } := ComponentReference.crefLastSubs(cr);
386 ✗ true := (i == index);
387 ✗ cr := ComponentReferenceBasics.crefStripLastSubs(cr);
388 ✗ true := ComponentReferenceBasics.crefEqualNoStringCompare(inCref, cr);
389 ✗ then isArrayExpansion(aRest, inCref, index+1);
390 else false;
391 end matchcontinue;
392 end isArrayExpansion;
393
394 public function hackMatrixReverseToCref
395 "This is a hack transformation of an expanded matrix back to its cref.
396 It is used in daeExpMatrix() (for C# yet) to optimize the generated code.
397 TODO: This function should not exist!
398 Rather the matrix should not be let expanded when SimCode is entering templates
399 "
400 input DAE.Exp inExp;
401 input SimCodeFunction.Context context;
402 output DAE.Exp outExp;
403 algorithm
404 outExp := matchcontinue inExp
405 local
406 DAE.ComponentRef cr;
407 DAE.Type aty;
408 list<list<DAE.Exp>> rows;
409 DAE.Exp crefExp;
410
411 case DAE.MATRIX(ty=aty, matrix = rows as (((DAE.CREF(componentRef=cr))::_)::_) )
412 algorithm
413 ✗ failure(SimCodeFunction.FUNCTION_CONTEXT():=context);
414 ✗ { DAE.INDEX(DAE.ICONST(1)), DAE.INDEX(DAE.ICONST(1)) } := ComponentReference.crefLastSubs(cr);
415 ✗ cr := ComponentReferenceBasics.crefStripLastSubs(cr);
416 ✗ true := isMatrixExpansion(rows, cr, 1, 1);
417 ✗ crefExp := Expression.makeCrefExp(cr, aty);
418 then
419 crefExp;
420
421 else inExp;
422
423 end matchcontinue;
424 end hackMatrixReverseToCref;
425
426 protected function isMatrixExpansion
427 "Helper funtion to hackMatrixReverseToCref."
428 input list<list<DAE.Exp>> rows;
429 input DAE.ComponentRef inCref;
430 input Integer rowIndex;
431 input Integer colIndex;
432 output Boolean isExpanded;
433 algorithm
434 isExpanded := matchcontinue rows
435 local
436 list<list<DAE.Exp>> restRows;
437 list<DAE.Exp> restElems;
438 Integer r, c;
439 DAE.ComponentRef cr;
440 case {} then true;
441 ✗ case {} :: restRows then isMatrixExpansion(restRows, inCref, rowIndex+1, 1);
442 case (DAE.CREF(componentRef=cr) :: restElems) :: restRows
443 algorithm
444 ✗ { DAE.INDEX(DAE.ICONST(r)), DAE.INDEX(DAE.ICONST(c)) } := ComponentReference.crefLastSubs(cr);
445 ✗ true := (r == rowIndex) and (c == colIndex);
446 ✗ cr := ComponentReferenceBasics.crefStripLastSubs(cr);
447 ✗ true := ComponentReferenceBasics.crefEqualNoStringCompare(inCref, cr);
448 ✗ then isMatrixExpansion(restElems :: restRows, inCref, rowIndex, colIndex+1);
449 else false;
450 end matchcontinue;
451 end isMatrixExpansion;
452
453 public function hackGetFirstExternalFunctionLib
454 "This is a hack to get the original library name given to an external function.
455 TODO: redesign OMC and Modelica specification so they are not so C/C++ centric."
456 input list<String> libs;
457 output String outFirstLib;
458 algorithm
459 outFirstLib := matchcontinue libs
460 local
461 String lib;
462
463 case _
464 algorithm
465 ✗ lib := List.last(libs);
466 ✗ lib := System.stringReplace(lib, "-l", "");
467 then
468 lib;
469
470 else "NO_LIB";
471
472 end matchcontinue;
473 end hackGetFirstExternalFunctionLib;
474
475 public function createAssertforSqrt
476 input DAE.Exp inExp;
477 output DAE.Exp outExp;
478 algorithm
479 1 outExp :=
480 match inExp
481 case _
482 algorithm
483 // Simplify things like abs(exp) >= 0 to exp
484 (outExp, _) := ExpressionSimplify.simplify(DAE.RELATION(inExp, DAE.GREATEREQ(DAE.T_REAL_DEFAULT), DAE.RCONST(0.0), -1, NONE()));
485 then outExp;
486 end match;
487 end createAssertforSqrt;
488
489 public function createDAEString
490 input String inString;
491 output DAE.Exp outExp;
492 annotation(__OpenModelica_EarlyInline = true);
493 algorithm
494 1 outExp := DAE.SCONST(inString);
495 end createDAEString;
496
497 /* end of TypeView published functions */
498
499 // =============================================================================
500 // section to generate SimCode from functions
501 //
502 // Finds the called functions in BackendDAE and transforms them to a list of
503 // libraries and a list of SimCodeFunction.Function uniontypes.
504 // =============================================================================
505
506 protected function orderRecordDecls
507 input SimCodeFunction.RecordDeclaration decl1;
508 input SimCodeFunction.RecordDeclaration decl2;
509 output Boolean b;
510 algorithm
511 b := match (decl1,decl2)
512 local
513 Absyn.Path path1,path2;
514 130359 case (SimCodeFunction.RECORD_DECL_DEF(path=path1),SimCodeFunction.RECORD_DECL_DEF(path=path2)) then AbsynUtil.pathGe(path1,path2);
515 else true;
516 end match;
517 end orderRecordDecls;
518
519 public function elaborateFunctions
520 input Absyn.Program program;
521 input list<DAE.Function> daeElements;
522 input list<DAE.Type> metarecordTypes;
523 input list<DAE.Exp> literals;
524 input list<String> includes;
525 output list<SimCodeFunction.Function> functions;
526 output list<SimCodeFunction.RecordDeclaration> recordDecls;
527 output list<String> outIncludes;
528 output list<String> includeDirs;
529 output list<String> libs;
530 output list<String> libpaths;
531 protected
532 HashTableStringToPath.HashTable ht;
533 list<tuple<SimCodeFunction.RecordDeclaration,list<SimCodeFunction.RecordDeclaration>>> g;
534 UnorderedMap<String, SimCodeFunction.RecordDeclaration> recDeclsMap;
535 algorithm
536 1407 recDeclsMap := UnorderedMap.new<SimCodeFunction.RecordDeclaration>(stringHashDjb2, stringEq);
537 1407 (functions, outIncludes, includeDirs, libs, libpaths) := elaborateFunctions2(program, daeElements, {}, includes, {}, {}, {}, recDeclsMap);
538
539 1407 collectRecDeclsFromMetaRecCallExps(literals, recDeclsMap);
540 1407 collectRecDeclsFromTypes(metarecordTypes, recDeclsMap);
541 1407 addRecordDeclsForExtraConstructors(recDeclsMap);
542
543 1407 recordDecls := UnorderedMap.valueList(recDeclsMap);
544 1407 recordDecls := List.sort(recordDecls, orderRecordDecls);
545
546 1407 ht := HashTableStringToPath.emptyHashTableSized(BaseHashTable.lowBucketSize);
547 1407 (recordDecls,_) := List.mapFold(recordDecls, aliasRecordDeclarations, ht);
548 // Topological sort since we have no guarantees in the order of generated records
549 1407 g := Graph.buildGraph(recordDecls, getRecordDependencies, recordDecls);
550
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1407 times.
1407 (recordDecls, {}) := Graph.topologicalSort(g, isRecordDeclEqual);
551 end elaborateFunctions;
552
553 protected function addRecordDeclsForExtraConstructors
554 "An extra constructor builds a struct of its record type, which is otherwise
555 only declared where the record is used with its own defaults. Added after
556 collecting, so that such a use always provides the declaration."
557 input UnorderedMap<String, SimCodeFunction.RecordDeclaration> recDeclsMap;
558 algorithm
559
2/2
✓ Branch 1 taken 21711 times.
✓ Branch 2 taken 1407 times.
23118 for decl in UnorderedMap.valueList(recDeclsMap) loop
560 () := match decl
561 case SimCodeFunction.RECORD_DECL_ADD_CONSTRCTOR() guard not UnorderedMap.contains(decl.name, recDeclsMap)
562 algorithm
563
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 3 times.
10 UnorderedMap.add(decl.name, SimCodeFunction.RECORD_DECL_FULL(decl.name, NONE(), decl.defPath,
564 list(variableWithoutBinding(v) for v in decl.variables), decl.usedExternally), recDeclsMap);
565 then ();
566 else ();
567 end match;
568 end for;
569 end addRecordDeclsForExtraConstructors;
570
571 protected function variableWithoutBinding
572 input output SimCodeFunction.Variable var;
573 algorithm
574 () := match var
575 case SimCodeFunction.VARIABLE()
576 algorithm
577 7 var.value := NONE();
578 7 var.bind_from_outside := false;
579 then ();
580 else ();
581 end match;
582 end variableWithoutBinding;
583
584 protected function getRecordDependencies
585 input SimCodeFunction.RecordDeclaration decl;
586 input list<SimCodeFunction.RecordDeclaration> allDecls;
587 output list<SimCodeFunction.RecordDeclaration> dependencies;
588 algorithm
589 dependencies := match decl
590 local
591 String name;
592 list<SimCodeFunction.Variable> vars;
593 list<DAE.Type> tys;
594 list<list<DAE.Type>> tyss;
595 case SimCodeFunction.RECORD_DECL_FULL(aliasName=SOME(name))
596 3352 then List.select1(allDecls, recordDeclHasName, name);
597 case SimCodeFunction.RECORD_DECL_ADD_CONSTRCTOR(name=name)
598 19 then List.select1(allDecls, recordDeclHasName, name);
599 case SimCodeFunction.RECORD_DECL_FULL(variables=vars)
600 algorithm
601
4/4
✓ Branch 0 taken 9039 times.
✓ Branch 1 taken 980 times.
✓ Branch 2 taken 9039 times.
✓ Branch 3 taken 980 times.
10019 tys := list(getVarType(v) for v in vars);
602 980 tyss := List.map1(tys, Types.getAllInnerTypesOfType, Util.anyReturnTrue);
603 980 tys := List.flatten(tyss);
604 980 dependencies := List.filterMap1(tys, getRecordDependenciesFromType, allDecls);
605 980 then List.unique(dependencies);
606 else {};
607 end match;
608 end getRecordDependencies;
609
610 protected function getVarType
611 input SimCodeFunction.Variable var;
612 output DAE.Type ty;
613 algorithm
614 ty := match var
615 case SimCodeFunction.VARIABLE(ty=ty) then ty;
616 else DAE.T_ANYTYPE_DEFAULT;
617 end match;
618 end getVarType;
619
620 protected function getRecordDependenciesFromType
621 input DAE.Type ty;
622 input list<SimCodeFunction.RecordDeclaration> allDecls;
623 output SimCodeFunction.RecordDeclaration decl;
624 protected
625 Absyn.Path path;
626 String name;
627 algorithm
628
3/4
✓ Branch 0 taken 9330 times.
✓ Branch 1 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
9367 DAE.T_COMPLEX(complexClassType = ClassInf.RECORD(path)) := ty;
629 37 name := AbsynUtil.pathStringUnquoteReplaceDot(path, "_");
630 37 decl := List.find1(allDecls, recordDeclHasName, name);
631 end getRecordDependenciesFromType;
632
633 public function setTrivialRecords
634 "Registers the records whose members are all scalars without references, or
635 such records. The declarations come sorted by their dependencies."
636 input list<SimCodeFunction.RecordDeclaration> recordDecls;
637 protected
638 list<String> trivial = {};
639 algorithm
640
2/2
✓ Branch 0 taken 21714 times.
✓ Branch 1 taken 1399 times.
23113 for decl in recordDecls loop
641 () := match decl
642 case SimCodeFunction.RECORD_DECL_FULL()
643 guard List.all(decl.variables, function isTrivialRecordMember(allDecls = recordDecls, trivial = trivial))
644 algorithm
645 1558 trivial := decl.name :: trivial;
646 then ();
647 else ();
648 end match;
649 end for;
650 1399 setGlobalRoot(Global.trivialRecords, trivial);
651 end setTrivialRecords;
652
653 public function isTrivialRecord
654 input String name;
655 output Boolean b;
656 algorithm
657 966986 b := listMember(name, getGlobalRoot(Global.trivialRecords));
658 end isTrivialRecord;
659
660 protected function isTrivialRecordMember
661 input SimCodeFunction.Variable var;
662 input list<SimCodeFunction.RecordDeclaration> allDecls;
663 input list<String> trivial;
664 output Boolean b;
665 protected
666 String name;
667 algorithm
668 b := match getVarType(var)
669 case DAE.T_REAL() then true;
670 case DAE.T_INTEGER() then true;
671 case DAE.T_BOOL() then true;
672 case DAE.T_ENUMERATION() then true;
673 case DAE.T_COMPLEX(complexClassType = ClassInf.RECORD())
674 algorithm
675 try
676
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
15 SimCodeFunction.RECORD_DECL_FULL(name = name) := getRecordDependenciesFromType(getVarType(var), allDecls);
677 15 b := listMember(name, trivial);
678 else
679 b := false;
680 end try;
681 then b;
682 else false;
683 end match;
684 end isTrivialRecordMember;
685
686 protected function recordDeclHasName
687 input SimCodeFunction.RecordDeclaration decl;
688 input String name;
689 output Boolean b;
690 algorithm
691 b := match decl
692
4/4
✓ Branch 0 taken 7638 times.
✓ Branch 1 taken 3378006 times.
✓ Branch 3 taken 4230 times.
✓ Branch 4 taken 3408 times.
3385644 case SimCodeFunction.RECORD_DECL_FULL() then stringEq(name, decl.name);
693 else false;
694 end match;
695 end recordDeclHasName;
696
697 protected function isRecordDeclEqual
698 input SimCodeFunction.RecordDeclaration decl1;
699 input SimCodeFunction.RecordDeclaration decl2;
700 output Boolean b;
701 algorithm
702 b := match (decl1,decl2)
703
4/4
✓ Branch 0 taken 3549 times.
✓ Branch 1 taken 7138 times.
✓ Branch 3 taken 164 times.
✓ Branch 4 taken 3385 times.
10687 case (SimCodeFunction.RECORD_DECL_FULL(),SimCodeFunction.RECORD_DECL_FULL()) then stringEq(decl1.name, decl2.name);
704 ✗ case (SimCodeFunction.RECORD_DECL_DEF(),SimCodeFunction.RECORD_DECL_DEF()) then AbsynUtil.pathEqual(decl1.path, decl2.path);
705 else false;
706 end match;
707 end isRecordDeclEqual;
708
709 protected function elaborateFunctions2
710 input Absyn.Program program;
711 input list<DAE.Function> daeElements;
712 input list<SimCodeFunction.Function> inFunctions;
713 input list<String> inIncludes;
714 input list<String> inIncludeDirs;
715 input list<String> inLibs;
716 input list<String> inPaths;
717 input UnorderedMap<String, SimCodeFunction.RecordDeclaration> recDeclsMap;
718 output list<SimCodeFunction.Function> outFunctions;
719 output list<String> outIncludes;
720 output list<String> outIncludeDirs;
721 output list<String> outLibs;
722 output list<String> outLibsPaths;
723 algorithm
724 (outFunctions, outIncludes, outIncludeDirs, outLibs,outLibsPaths) :=
725 match (daeElements, inFunctions, inIncludes, inIncludeDirs, inLibs, inPaths)
726 local
727 Boolean b;
728 list<SimCodeFunction.Function> accfns, fns;
729 SimCodeFunction.Function fn;
730 list<String> includes, libs,libPaths;
731 DAE.Function fel;
732 list<DAE.Function> rest;
733 String name, fname;
734 list<String> includeDirs;
735 Absyn.Path path;
736
737 case ({}, accfns, includes, includeDirs, libs, libPaths)
738
1/2
✓ Branch 1 taken 1407 times.
✗ Branch 2 not taken.
1407 then (listReverse(accfns), includes, includeDirs, libs,libPaths);
739 case ((DAE.FUNCTION( type_ = DAE.T_FUNCTION(functionAttributes=DAE.FUNCTION_ATTRIBUTES(isBuiltin=DAE.FUNCTION_BUILTIN_PTR()))) :: rest), accfns, includes, includeDirs, libs, libPaths)
740 algorithm
741 // skip over builtin functions
742 13519 (fns, includes, includeDirs, libs,libPaths) := elaborateFunctions2(program, rest, accfns, includes, includeDirs, libs,libPaths, recDeclsMap);
743 then
744 (fns, includes, includeDirs, libs,libPaths);
745 case ((DAE.FUNCTION(partialPrefix = true) :: rest), accfns, includes, includeDirs, libs, libPaths)
746 algorithm
747 // skip over partial functions
748 ✗ (fns, includes, includeDirs, libs,libPaths) := elaborateFunctions2(program, rest, accfns, includes, includeDirs, libs,libPaths, recDeclsMap);
749 then
750 (fns, includes, includeDirs, libs,libPaths);
751 case ((fel as DAE.FUNCTION(path = path, functions = DAE.FUNCTION_EXT(externalDecl = DAE.EXTERNALDECL(name=name, language="builtin"))::_))::rest, accfns, includes, includeDirs, libs, libPaths)
752 algorithm
753 // skip over builtin functions @adrpo: we should skip ONLY IF THE NAME OF THE FUNCTION IS THE SAME AS THE NAME OF THE EXTERNAL FUNCTION!
754 652 fname := AbsynUtil.pathString(AbsynUtil.makeNotFullyQualified(path));
755
3/4
✓ Branch 0 taken 649 times.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 649 times.
652 b := stringEq(fname, name);
756 if not b then
757 3 (fn, includes, includeDirs, libs,libPaths) := elaborateFunction(program, fel, includes, includeDirs, libs,libPaths, recDeclsMap);
758 accfns := fn :: accfns;
759 end if;
760 652 (fns, includes, includeDirs, libs,libPaths) := elaborateFunctions2(program, rest, accfns, includes, includeDirs, libs,libPaths, recDeclsMap);
761 then
762 (fns, includes, includeDirs, libs,libPaths);
763
764 case ((fel as DAE.FUNCTION(path = path, functions = DAE.FUNCTION_EXT(externalDecl = DAE.EXTERNALDECL(name=name, language="C"))::_))::rest, accfns, includes, includeDirs, libs, libPaths)
765 algorithm
766 // skip over known external C functions @adrpo: we should skip ONLY IF THE NAME OF THE FUNCTION IS THE SAME AS THE NAME OF THE EXTERNAL FUNCTION!
767 596 fname := AbsynUtil.pathString(AbsynUtil.makeNotFullyQualified(path));
768
1/6
✗ Branch 1 not taken.
✓ Branch 2 taken 596 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
596 b := listMember(name, SCodeUtil.knownExternalCFunctions) and stringEq(fname, name);
769 if not b then
770 596 (fn, includes, includeDirs, libs,libPaths) := elaborateFunction(program, fel, includes, includeDirs, libs,libPaths, recDeclsMap);
771 accfns := fn :: accfns;
772 end if;
773 596 (fns, includes, includeDirs, libs,libPaths) := elaborateFunctions2(program, rest, accfns, includes, includeDirs, libs,libPaths, recDeclsMap);
774 then
775 (fns, includes, includeDirs, libs,libPaths);
776
777 case ((fel :: rest), accfns, includes, includeDirs, libs, libPaths)
778 algorithm
779 12267 (fn, includes, includeDirs, libs,libPaths) := elaborateFunction(program, fel, includes, includeDirs, libs,libPaths, recDeclsMap);
780 12267 (fns, includes, includeDirs, libs,libPaths) := elaborateFunctions2(program, rest, (fn :: accfns), includes, includeDirs, libs,libPaths, recDeclsMap);
781 then
782 (fns, includes, includeDirs, libs,libPaths);
783 end match;
784 end elaborateFunctions2;
785
786 /* Does the actual work of transforming a DAE.FUNCTION to a SimCodeFunction.Function. */
787 protected function elaborateFunction
788 input Absyn.Program program;
789 input DAE.Function inElement;
790 input list<String> inIncludes;
791 input list<String> inIncludeDirs;
792 input list<String> inLibs;
793 input list<String> inLibPaths;
794 input UnorderedMap<String, SimCodeFunction.RecordDeclaration> recDeclsMap;
795 output SimCodeFunction.Function outFunction;
796 output list<String> outIncludes;
797 output list<String> outIncludeDirs;
798 output list<String> outLibs;
799 output list<String> outLibPaths;
800 algorithm
801 (outFunction, outIncludes, outIncludeDirs, outLibs,outLibPaths):=
802 matchcontinue (inElement, inIncludes, inIncludeDirs, inLibs, inLibPaths)
803 local
804 DAE.Function fn;
805 String extfnname, lang;
806 list<DAE.Element> vars; // , bivars, invars, outvars;
807 list<String> includes, libs, libPaths, fn_libs,fn_paths, fn_includes, fn_includeDirs;
808 Absyn.Path fpath;
809 list<DAE.FuncArg> args;
810 DAE.Type restype;
811 list<DAE.ExtArg> extargs;
812 list<SimCodeFunction.SimExtArg> simextargs;
813 SimCodeFunction.SimExtArg extReturn;
814 DAE.ExtArg extretarg;
815 Option<SCode.Annotation> ann;
816 DAE.ExternalDecl extdecl;
817 list<SimCodeFunction.Variable> outVars, inVars, biVars, funArgs, varDecls;
818 list<DAE.Statement> bodyStmts;
819 list<DAE.Element> daeElts;
820 Absyn.Path name;
821 DAE.ElementSource source;
822 SourceInfo info;
823 Boolean dynamicLoad;
824 list<String> includeDirs;
825 DAE.FunctionAttributes funAttrs;
826 list<DAE.Var> varlst;
827 SCode.Visibility visibility;
828
829 // Modelica function
830 case (DAE.FUNCTION(path = fpath, source = source, visibility = visibility,
831 functions = DAE.FUNCTION_DEF(body = daeElts)::_, // might be followed by derivative maps
832 type_ = DAE.T_FUNCTION(funcArg=args, functionAttributes=funAttrs),
833 partialPrefix=false), includes, includeDirs, libs, libPaths)
834 algorithm
835
836
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7933 times.
7933 DAE.FUNCTION_ATTRIBUTES(functionParallelism=DAE.FP_NON_PARALLEL()) := funAttrs;
837
838 7933 daeElts := optMRFAElems(daeElts);
839 7933 outVars := List.map(DAEUtil.getOutputElements(daeElts), daeInOutSimVar);
840 7933 funArgs := List.map1(args, typesSimFunctionArg, NONE());
841 7933 collectRecDeclsFromElems(daeElts, recDeclsMap);
842 7933 vars := List.filterOnTrue(daeElts, isVarQ);
843 7933 varDecls := List.map(vars, daeInOutSimVar);
844
6/6
✓ Branch 1 taken 56323 times.
✓ Branch 2 taken 7881 times.
✓ Branch 3 taken 64204 times.
✓ Branch 4 taken 7933 times.
✓ Branch 5 taken 7881 times.
✓ Branch 6 taken 7933 times.
72137 bodyStmts := listAppend(elaborateStatement(e) for e guard DAEUtil.isAlgorithm(e) in daeElts);
845 7933 info := ElementSource.getElementSourceFileInfo(source);
846 7933 then
847 (SimCodeFunction.FUNCTION(fpath, outVars, funArgs, varDecls, bodyStmts, visibility, info), includes, includeDirs, libs,libPaths);
848
849 // Kernel function
850 case (DAE.FUNCTION(path = fpath, source = source,
851 functions = DAE.FUNCTION_DEF(body = daeElts)::_, // might be followed by derivative maps
852 type_ = DAE.T_FUNCTION(funcArg=args, functionAttributes=funAttrs),
853 partialPrefix=false), includes, includeDirs, libs, libPaths)
854 algorithm
855
856 ✗ DAE.FUNCTION_ATTRIBUTES(functionParallelism=DAE.FP_KERNEL_FUNCTION()) := funAttrs;
857
858 ✗ daeElts := optMRFAElems(daeElts);
859 ✗ outVars := List.map(DAEUtil.getOutputElements(daeElts), daeInOutSimVar);
860 ✗ funArgs := List.map1(args, typesSimFunctionArg, NONE());
861 ✗ collectRecDeclsFromElems(daeElts, recDeclsMap);
862 ✗ vars := List.filterOnTrue(daeElts, isVarNotInputNotOutput);
863 ✗ varDecls := List.map(vars, daeInOutSimVar);
864 ✗ bodyStmts := listAppend(elaborateStatement(e) for e guard DAEUtil.isAlgorithm(e) in daeElts);
865 ✗ info := ElementSource.getElementSourceFileInfo(source);
866 ✗ then
867 (SimCodeFunction.KERNEL_FUNCTION(fpath, outVars, funArgs, varDecls, bodyStmts, info), includes, includeDirs, libs,libPaths);
868
869 // Parallel function
870 case (DAE.FUNCTION(path = fpath, source = source,
871 functions = DAE.FUNCTION_DEF(body = daeElts)::_, // might be followed by derivative maps
872 type_ = DAE.T_FUNCTION(funcArg=args, functionAttributes = funAttrs),
873 partialPrefix=false), includes, includeDirs, libs, libPaths)
874 algorithm
875
876 ✗ DAE.FUNCTION_ATTRIBUTES(functionParallelism=DAE.FP_PARALLEL_FUNCTION()) := funAttrs;
877
878 ✗ daeElts := optMRFAElems(daeElts);
879 ✗ outVars := List.map(DAEUtil.getOutputElements(daeElts), daeInOutSimVar);
880 ✗ funArgs := List.map1(args, typesSimFunctionArg, NONE());
881 ✗ collectRecDeclsFromElems(daeElts, recDeclsMap);
882 ✗ vars := List.filterOnTrue(daeElts, isVarQ);
883 ✗ varDecls := List.map(vars, daeInOutSimVar);
884 ✗ bodyStmts := listAppend(elaborateStatement(e) for e guard DAEUtil.isAlgorithm(e) in daeElts);
885 ✗ info := ElementSource.getElementSourceFileInfo(source);
886 ✗ then
887 (SimCodeFunction.PARALLEL_FUNCTION(fpath, outVars, funArgs, varDecls, bodyStmts, info), includes, includeDirs, libs,libPaths);
888
889 // External functions.
890 case (DAE.FUNCTION(path = fpath, source = source, visibility = visibility,
891 functions = DAE.FUNCTION_EXT(body = daeElts, externalDecl = extdecl)::_, // might be followed by derivative maps
892 type_ = (DAE.T_FUNCTION(funcArg = args))), includes, includeDirs, libs, libPaths)
893 algorithm
894 616 DAE.EXTERNALDECL(name=extfnname, args=extargs,
895 returnArg=extretarg, language=lang, ann=ann) := extdecl;
896 // outvars = DAEUtil.getOutputElements(daeElts);
897 // invars = DAEUtil.getInputVars(daeElts);
898 // bivars = DAEUtil.getBidirVars(daeElts);
899 616 funArgs := List.map1(args, typesSimFunctionArg, NONE());
900 616 outVars := List.map(DAEUtil.getOutputElements(daeElts), daeInOutSimVar);
901 616 inVars := List.map(DAEUtil.getInputVars(daeElts), daeInOutSimVar);
902 616 biVars := List.map(DAEUtil.getBidirElements(daeElts), daeInOutSimVar);
903 616 collectRecDeclsFromElems(daeElts, recDeclsMap);
904 616 info := ElementSource.getElementSourceFileInfo(source);
905 616 (fn_includes, fn_includeDirs, fn_libs, fn_paths,dynamicLoad) := generateExtFunctionIncludes(program, fpath, ann, info);
906 616 includes := List.union(fn_includes, includes);
907 616 includeDirs := List.union(fn_includeDirs, includeDirs);
908 616 libs := List.union(fn_libs, libs);
909 616 libPaths := List.union(fn_paths, libPaths);
910 616 simextargs := List.map(extargs, extArgsToSimExtArgs);
911 616 extReturn := extArgsToSimExtArgs(extretarg);
912 616 (simextargs, extReturn) := fixOutputIndex(outVars, simextargs, extReturn);
913 // make lang to-upper as we have FORTRAN 77 and Fortran 77 in the Modelica Library!
914 616 lang := System.toupper(lang);
915
1/2
✓ Branch 0 taken 616 times.
✗ Branch 1 not taken.
1232 then
916 (SimCodeFunction.EXTERNAL_FUNCTION(fpath, extfnname, funArgs, simextargs, extReturn,
917 inVars, outVars, biVars, fn_includes, fn_libs, lang, visibility, info, dynamicLoad), includes, includeDirs, libs,libPaths);
918
919 // Record constructor
920 case (DAE.RECORD_CONSTRUCTOR(source = source, type_ = DAE.T_FUNCTION(funcArg = args, funcResultType = restype as DAE.T_COMPLEX(complexClassType = ClassInf.RECORD(name)))), includes, includeDirs, libs, libPaths)
921 algorithm
922 4317 funArgs := List.map1(args, typesSimFunctionArg, NONE());
923 4317 collectRecDeclsFromType(restype, recDeclsMap);
924
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4317 times.
4317 DAE.T_COMPLEX(varLst = varlst) := restype;
925 // varlst = List.filterOnTrue(varlst, Types.isProtectedVar);
926 4317 varlst := List.filterOnFalse(varlst, Types.isModifiableTypesVar);
927 4317 varDecls := List.map(varlst, typesVar);
928 4317 info := ElementSource.getElementSourceFileInfo(source);
929 4317 then
930 (SimCodeFunction.RECORD_CONSTRUCTOR(name, funArgs, varDecls, SCode.PUBLIC(), info), includes, includeDirs, libs,libPaths);
931
932 // failure
933 case (fn, _, _, _, _)
934 algorithm
935 ✗ Error.addInternalError("function elaborateFunction failed for function:\n" + DAEDump.dumpFunctionStr(fn), sourceInfo());
936 ✗ then
937 fail();
938 end matchcontinue;
939 end elaborateFunction;
940
941 protected function typesSimFunctionArg
942 "Generates code from a function argument."
943 input DAE.FuncArg inFuncArg;
944 input Option<DAE.Exp> binding;
945 output SimCodeFunction.Variable outVar;
946 algorithm
947 outVar := matchcontinue inFuncArg
948 local
949 DAE.Type tty;
950 String name;
951 DAE.ComponentRef cref_;
952 DAE.Const const;
953 list<DAE.FuncArg> args;
954 DAE.Type res_ty;
955 list<SimCodeFunction.Variable> var_args;
956 list<DAE.Type> tys;
957 DAE.VarKind kind;
958 DAE.VarParallelism prl;
959
960 case DAE.FUNCARG(name=name, ty=DAE.T_FUNCTION(funcArg = args, funcResultType = DAE.T_TUPLE(types = tys)))
961 algorithm
962 37 var_args := List.map1(args, typesSimFunctionArg, NONE());
963 37 tys := List.map(tys, Types.simplifyType);
964 37 then
965 SimCodeFunction.FUNCTION_PTR(name, tys, var_args, binding);
966
967 case DAE.FUNCARG(name=name, ty=DAE.T_FUNCTION(funcArg = args, funcResultType = DAE.T_NORETCALL()))
968 algorithm
969 2 var_args := List.map1(args, typesSimFunctionArg, NONE());
970 2 then
971 SimCodeFunction.FUNCTION_PTR(name, {}, var_args, binding);
972
973 case DAE.FUNCARG(name=name, ty=DAE.T_FUNCTION(funcArg = args, funcResultType = res_ty))
974 algorithm
975 156 res_ty := Types.simplifyType(res_ty);
976 156 var_args := List.map1(args, typesSimFunctionArg, NONE());
977 156 then
978 SimCodeFunction.FUNCTION_PTR(name, {res_ty}, var_args, binding);
979
980 case DAE.FUNCARG(name=name, ty=tty, par=prl, const=const)
981 algorithm
982 63403 tty := Types.simplifyType(tty);
983 63403 cref_ := ComponentReferenceBasics.makeCrefIdent(name, tty, {});
984 63403 kind := DAEUtil.const2VarKind(const);
985 63403 then
986 SimCodeFunction.VARIABLE(cref_, tty, binding, {}, prl, kind, false);
987 end matchcontinue;
988 end typesSimFunctionArg;
989
990 protected function daeInOutSimVar
991 input DAE.Element inElement;
992 output SimCodeFunction.Variable outVar;
993 algorithm
994 outVar := matchcontinue inElement
995 local
996 String name;
997 DAE.Type daeType;
998 DAE.ComponentRef id;
999 DAE.VarKind kind;
1000 DAE.VarParallelism prl;
1001 list<DAE.Dimension> inst_dims;
1002 // list<DAE.Exp> inst_dims_exp;
1003 Option<DAE.Exp> binding;
1004 SimCodeFunction.Variable var;
1005 case DAE.VAR(componentRef = DAE.CREF_IDENT(ident=name), ty = daeType as DAE.T_FUNCTION(), parallelism = prl, binding = binding)
1006 algorithm
1007 21 var := typesSimFunctionArg(DAE.FUNCARG(name, daeType, DAE.C_VAR(), prl, NONE()), binding);
1008 then var;
1009
1010 case DAE.VAR(componentRef = id,
1011 parallelism = prl,
1012 ty = daeType,
1013 binding = binding,
1014 dims = inst_dims,
1015 kind = kind
1016 )
1017 algorithm
1018 53999 daeType := Types.simplifyType(daeType);
1019 // inst_dims_exp := List.map(inst_dims, Expression.dimensionSizeExpHandleUnkown);
1020 53999 then SimCodeFunction.VARIABLE(id, daeType, binding, inst_dims, prl, kind, false);
1021 else
1022 algorithm
1023 // TODO: ArrayEqn fails here
1024 ✗ Error.addInternalError("function daeInOutSimVar failed\n", sourceInfo());
1025 ✗ then
1026 fail();
1027 end matchcontinue;
1028 end daeInOutSimVar;
1029
1030 protected function extArgsToSimExtArgs
1031 input DAE.ExtArg extArg;
1032 output SimCodeFunction.SimExtArg simExtArg;
1033 algorithm
1034 simExtArg :=
1035 match extArg
1036 local
1037 DAE.ComponentRef componentRef;
1038 Absyn.Direction dir;
1039 DAE.Type type_;
1040 Boolean isInput;
1041 Boolean isOutput;
1042 Boolean isArray;
1043 DAE.Exp exp_;
1044 Integer outputIndex;
1045
1046 case DAE.EXTARG(componentRef, dir, type_)
1047 algorithm
1048 1958 isInput := AbsynUtil.isInput(dir);
1049 1958 isOutput := AbsynUtil.isOutput(dir);
1050
2/2
✓ Branch 0 taken 1488 times.
✓ Branch 1 taken 470 times.
1958 outputIndex := if isOutput then -1 else 0; // correct output index is added later by fixOutputIndex
1051 1958 isArray := Types.isArray(type_);
1052 1958 type_ := Types.simplifyType(type_);
1053
4/4
✓ Branch 0 taken 1689 times.
✓ Branch 1 taken 269 times.
✓ Branch 2 taken 547 times.
✓ Branch 3 taken 1411 times.
4194 then SimCodeFunction.SIMEXTARG(componentRef, isInput, outputIndex, isArray, false /*fixed later*/, type_);
1054
1055 case DAE.EXTARGEXP(exp_, type_)
1056 algorithm
1057 55 type_ := Types.simplifyType(type_);
1058 55 then SimCodeFunction.SIMEXTARGEXP(exp_, type_);
1059
1060 case DAE.EXTARGSIZE(componentRef, type_, exp_)
1061 algorithm
1062 170 type_ := Types.simplifyType(type_);
1063 170 then SimCodeFunction.SIMEXTARGSIZE(componentRef, true, 0, type_, exp_);
1064
1065 case DAE.NOEXTARG() then SimCodeFunction.SIMNOEXTARG();
1066 end match;
1067 end extArgsToSimExtArgs;
1068
1069 protected function fixOutputIndex
1070 input list<SimCodeFunction.Variable> outVars;
1071 input list<SimCodeFunction.SimExtArg> simExtArgsIn;
1072 input SimCodeFunction.SimExtArg extReturnIn;
1073 output list<SimCodeFunction.SimExtArg> simExtArgsOut;
1074 output SimCodeFunction.SimExtArg extReturnOut;
1075 algorithm
1076 (simExtArgsOut, extReturnOut) := match extReturnIn
1077 local
1078 case _
1079 algorithm
1080 616 simExtArgsOut := List.map1(simExtArgsIn, assignOutputIndex, outVars);
1081 616 extReturnOut := assignOutputIndex(extReturnIn, outVars);
1082 then
1083 (simExtArgsOut, extReturnOut);
1084 end match;
1085 end fixOutputIndex;
1086
1087 protected function assignOutputIndex
1088 input SimCodeFunction.SimExtArg simExtArgIn;
1089 input list<SimCodeFunction.Variable> outVars;
1090 output SimCodeFunction.SimExtArg simExtArgOut;
1091 algorithm
1092 simExtArgOut :=
1093 matchcontinue simExtArgIn
1094 local
1095 DAE.ComponentRef cref, fcref;
1096 Boolean isInput;
1097 Integer outputIndex; // > 0 if output
1098 Boolean isArray, hasBinding;
1099 DAE.Type type_;
1100 DAE.Exp exp;
1101 Integer newOutputIndex;
1102
1103 case SimCodeFunction.SIMEXTARG(cref, isInput, outputIndex, isArray, _, type_)
1104 algorithm
1105
2/2
✓ Branch 0 taken 1488 times.
✓ Branch 1 taken 470 times.
1958 true := outputIndex == -1;
1106 470 fcref := ComponentReferenceBasics.crefFirstCref(cref);
1107 470 (newOutputIndex, hasBinding) := findIndexInList(fcref, outVars, 1);
1108
5/6
✓ Branch 0 taken 458 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 379 times.
✓ Branch 3 taken 91 times.
✓ Branch 4 taken 470 times.
✗ Branch 5 not taken.
1777 then
1109 SimCodeFunction.SIMEXTARG(cref, isInput, newOutputIndex, isArray, hasBinding, type_);
1110
1111 case SimCodeFunction.SIMEXTARGSIZE(cref, isInput, outputIndex, type_, exp)
1112 algorithm
1113
1/2
✓ Branch 0 taken 170 times.
✗ Branch 1 not taken.
170 true := outputIndex == -1;
1114 ✗ (newOutputIndex, _) := findIndexInList(cref, outVars, 1);
1115 ✗ then
1116 SimCodeFunction.SIMEXTARGSIZE(cref, isInput, newOutputIndex, type_, exp);
1117
1118 else
1119 simExtArgIn;
1120 end matchcontinue;
1121 end assignOutputIndex;
1122
1123 protected function findIndexInList
1124 input DAE.ComponentRef cref;
1125 input list<SimCodeFunction.Variable> outVars;
1126 input Integer inCurrentIndex;
1127 output Integer crefIndexInOutVars;
1128 output Boolean hasBinding;
1129 algorithm
1130 (crefIndexInOutVars, hasBinding) :=
1131 matchcontinue (outVars, inCurrentIndex)
1132 local
1133 DAE.ComponentRef name;
1134 list<SimCodeFunction.Variable> restOutVars;
1135 Option<DAE.Exp> v;
1136 Integer currentIndex;
1137
1138 ✗ case ({}, _) then (-1, false);
1139 case (SimCodeFunction.VARIABLE(name=name, value=v) :: _, currentIndex)
1140 algorithm
1141
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 470 times.
580 true := ComponentReferenceBasics.crefEqualNoStringCompare(cref, name);
1142
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 470 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 458 times.
482 then (currentIndex, isSome(v));
1143 case (_ :: restOutVars, currentIndex)
1144 algorithm
1145 110 currentIndex := currentIndex + 1;
1146 110 (currentIndex, hasBinding) := findIndexInList(cref, restOutVars, currentIndex);
1147 then (currentIndex, hasBinding);
1148 end matchcontinue;
1149 end findIndexInList;
1150
1151 protected function elaborateStatement
1152 input DAE.Element inElement;
1153 output list<DAE.Statement> stmts;
1154 algorithm
1155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7881 times.
7881 DAE.ALGORITHM(algorithm_ = DAE.ALGORITHM_STMTS(statementLst = stmts)) := inElement;
1156 end elaborateStatement;
1157
1158 protected function optMRFAElems
1159 "Applies DAEUtil.optimizeMetaRecordFieldAssigns to every algorithm body in
1160 the DAE element list and lifts the temp DAE.VAR declarations the pass
1161 created into the function's local-var section. Runs before
1162 collectRecDeclsFromElems so that any METARECORDCALL expressions
1163 introduced by the pass are picked up when the record-declaration map
1164 is populated. See issue #11909."
1165 input output list<DAE.Element> elems;
1166 protected
1167 list<DAE.Element> processed = {};
1168 list<DAE.Element> tempVars = {};
1169 DAE.Element e2;
1170 algorithm
1171
2/2
✓ Branch 0 taken 64204 times.
✓ Branch 1 taken 7933 times.
72137 for e in elems loop
1172 64204 (e2, tempVars) := optMRFAElem(e, tempVars);
1173 processed := e2 :: processed;
1174 end for;
1175 // Prepend new temp DAE.VAR declarations. Inputs/outputs are filtered
1176 // by direction downstream, not by position, so the extra BIDIR locals
1177 // do not perturb the function signature.
1178 7933 elems := listAppend(listReverse(tempVars), listReverse(processed));
1179 end optMRFAElems;
1180
1181 protected function optMRFAElem
1182 input output DAE.Element elem;
1183 input output list<DAE.Element> tempVars;
1184 algorithm
1185 (elem, tempVars) := match elem
1186 local
1187 list<DAE.Statement> stmts;
1188 case DAE.ALGORITHM(algorithm_ = DAE.ALGORITHM_STMTS(statementLst = stmts))
1189 algorithm
1190 7881 (stmts, tempVars) := DAEUtil.optimizeMetaRecordFieldAssigns(stmts, tempVars);
1191 15762 elem.algorithm_ := DAE.ALGORITHM_STMTS(stmts);
1192 7881 then (elem, tempVars);
1193 else (elem, tempVars);
1194 end match;
1195 end optMRFAElem;
1196
1197 public function checkValidMainFunction
1198 "Verifies that an in-function can be generated.
1199 This is not the case if the input involves function-pointers."
1200 input String name;
1201 input SimCodeFunction.Function fn;
1202 algorithm
1203 () := matchcontinue fn
1204 local
1205 list<SimCodeFunction.Variable> inVars;
1206 case SimCodeFunction.FUNCTION(functionArguments = inVars)
1207 algorithm
1208
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 126 times.
252 failure(List.find(inVars, isFunctionPtr));
1209 then ();
1210 case SimCodeFunction.EXTERNAL_FUNCTION(inVars = inVars)
1211 algorithm
1212
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
32 failure(List.find(inVars, isFunctionPtr));
1213 then ();
1214 else
1215 algorithm
1216 ✗ Error.addMessage(Error.GENERATECODE_INVARS_HAS_FUNCTION_PTR, {name});
1217 ✗ then fail();
1218 end matchcontinue;
1219 end checkValidMainFunction;
1220
1221 public function isBoxedFunction
1222 "Verifies that an in-function can be generated.
1223 This is not the case if the input involves function-pointers."
1224 input SimCodeFunction.Function fn;
1225 output Boolean b;
1226 algorithm
1227 b := matchcontinue fn
1228 local
1229 list<SimCodeFunction.Variable> inVars, outVars;
1230 case SimCodeFunction.FUNCTION(functionArguments = inVars, outVars = outVars)
1231 algorithm
1232 15306 List.map_0(inVars, isBoxedArg);
1233 2710 List.map_0(outVars, isBoxedArg);
1234 then true;
1235 case SimCodeFunction.EXTERNAL_FUNCTION(inVars = inVars, outVars = outVars)
1236 algorithm
1237 1110 List.map_0(inVars, isBoxedArg);
1238 196 List.map_0(outVars, isBoxedArg);
1239 then true;
1240 else false;
1241 end matchcontinue;
1242 end isBoxedFunction;
1243
1244 protected function isFunctionPtr
1245 "Checks if an input variable is a function pointer"
1246 input SimCodeFunction.Variable var;
1247 output Boolean b;
1248 algorithm
1249 b := match var
1250 /* Yes, they are VARIABLE, not SimCodeFunction.FUNCTION_PTR. */
1251 case SimCodeFunction.FUNCTION_PTR() then true;
1252 else false;
1253 end match;
1254 end isFunctionPtr;
1255
1256 protected function isBoxedArg
1257 "Checks if a variable is a boxed datatype"
1258 input SimCodeFunction.Variable var;
1259 algorithm
1260 () := match var
1261 case SimCodeFunction.FUNCTION_PTR() then ();
1262 case SimCodeFunction.VARIABLE(ty = DAE.T_METABOXED()) then ();
1263 case SimCodeFunction.VARIABLE(ty = DAE.T_METATYPE()) then ();
1264 case SimCodeFunction.VARIABLE(ty = DAE.T_STRING()) then ();
1265 end match;
1266 end isBoxedArg;
1267
1268 public function funcHasParallelInOutArrays
1269 "checks if a boxed function can be generated.
1270 currently this is not the case if the input/output
1271 involves parallel (global/local) array variables."
1272 input SimCodeFunction.Function fn;
1273 output Boolean b;
1274 protected
1275 list<SimCodeFunction.Variable> inVars, outVars;
1276 algorithm
1277
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15306 times.
15306 SimCodeFunction.FUNCTION(functionArguments = inVars, outVars = outVars) := fn;
1278
2/2
✓ Branch 0 taken 35958 times.
✓ Branch 1 taken 15306 times.
51264 for e in inVars loop
1279
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 35958 times.
35958 if isParallelArrayVar(e) then
1280 b := true;
1281 ✗ return;
1282 end if;
1283 end for;
1284
1285
2/2
✓ Branch 0 taken 18644 times.
✓ Branch 1 taken 15306 times.
33950 for e in outVars loop
1286
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 18644 times.
18644 if isParallelArrayVar(e) then
1287 b := true;
1288 ✗ return;
1289 end if;
1290 end for;
1291
1292 b := false;
1293 end funcHasParallelInOutArrays;
1294
1295 protected function isParallelArrayVar
1296 "Checks if a variable is a boxed datatype"
1297 input SimCodeFunction.Variable var;
1298 output Boolean b;
1299 algorithm
1300 b := match var
1301 case SimCodeFunction.VARIABLE(ty = DAE.T_ARRAY(), parallelism = DAE.PARGLOBAL()) then true;
1302 case SimCodeFunction.VARIABLE(ty = DAE.T_ARRAY(), parallelism = DAE.PARLOCAL()) then true;
1303 else false;
1304 end match;
1305 end isParallelArrayVar;
1306
1307 public function findLiterals
1308 "Finds all literal expressions in functions"
1309 input list<DAE.Function> fns;
1310 output list<DAE.Function> ofns;
1311 output list<DAE.Exp> literals;
1312 algorithm
1313 148 (ofns, (_, _, literals)) := DAEUtil.traverseDAEFunctions(
1314 fns, findLiteralsHelper,
1315 (0, newExpIndexMap(), {}));
1316 148 literals := listReverse(literals);
1317 end findLiterals;
1318
1319 public
1320
1321 function newExpIndexMap
1322 output UnorderedMap<DAE.Exp, Integer> map = UnorderedMap.new<Integer>(ExpressionBasics.hashExp, ExpressionBasics.expEqual, BaseHashTable.bigBucketSize);
1323 end newExpIndexMap;
1324
1325 function findLiteralsHelper
1326 input DAE.Exp inExp;
1327 input tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> inTpl;
1328 output DAE.Exp exp;
1329 output tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> tpl;
1330 algorithm
1331 exp := inExp;
1332 293616 tpl := inTpl;
1333 293616 (exp, tpl) := Expression.traverseExpBottomUp(exp,
1334 function Patternm.traverseConstantPatternsHelper(func=replaceLiteralExp),
1335 tpl);
1336 293616 (exp, tpl) := Expression.traverseExpTopDown(exp, replaceLiteralArrayExp, tpl);
1337 end findLiteralsHelper;
1338
1339 function findLiteralsHelperKeepSingle
1340 "findLiteralsHelper, except that a string used once (per uses) that is not
1341 a literal yet stays in place."
1342 input DAE.Exp inExp;
1343 input UnorderedMap<DAE.Exp, Integer> uses;
1344 input tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> inTpl;
1345 output DAE.Exp exp;
1346 output tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> tpl;
1347 algorithm
1348 392411 (exp, tpl) := Expression.traverseExpBottomUp(inExp,
1349 function Patternm.traverseConstantPatternsHelper(func=function replaceLiteralExpKeepSingle(uses=uses)),
1350 inTpl);
1351 392411 (exp, tpl) := Expression.traverseExpTopDown(exp, replaceLiteralArrayExp, tpl);
1352 end findLiteralsHelperKeepSingle;
1353
1354 function countStringUses
1355 input DAE.Exp inExp;
1356 input UnorderedMap<DAE.Exp, Integer> inUses;
1357 output DAE.Exp exp = inExp;
1358 output UnorderedMap<DAE.Exp, Integer> uses;
1359 algorithm
1360 392411 (_, uses) := Expression.traverseExpBottomUp(inExp, countStringUse, inUses);
1361 end countStringUses;
1362
1363 protected
1364
1365 function isSconst
1366 input DAE.Exp e;
1367 output Boolean b;
1368 algorithm
1369 b := match e case DAE.SCONST() then true; else false; end match;
1370 end isSconst;
1371
1372 function countStringUse
1373 input DAE.Exp inExp;
1374 input UnorderedMap<DAE.Exp, Integer> inUses;
1375 output DAE.Exp exp = inExp;
1376 output UnorderedMap<DAE.Exp, Integer> uses = inUses;
1377 algorithm
1378
2/2
✓ Branch 1 taken 78795 times.
✓ Branch 2 taken 1771981 times.
1850776 if isSconst(inExp) then
1379 78795 uses := addStringUse(inExp, uses);
1380 else
1381 // A lifted literal array cannot hold an unlifted string
1382
2/2
✓ Branch 1 taken 49790 times.
✓ Branch 2 taken 1771981 times.
1821771 for e in literalElements(inExp) loop
1383
2/2
✓ Branch 1 taken 240 times.
✓ Branch 2 taken 49550 times.
49790 if isSconst(e) then
1384 240 uses := addStringUse(e, uses);
1385 end if;
1386 end for;
1387 end if;
1388 end countStringUse;
1389
1390 function addStringUse
1391 input DAE.Exp e;
1392 input output UnorderedMap<DAE.Exp, Integer> uses;
1393 algorithm
1394 79035 UnorderedMap.add(e, UnorderedMap.getOrDefault(e, uses, 0) + 1, uses);
1395 end addStringUse;
1396
1397 function literalElements
1398 input DAE.Exp e;
1399 output list<DAE.Exp> elts;
1400 algorithm
1401 elts := match e
1402 local
1403 DAE.Exp e1, e2;
1404 8200 case DAE.ARRAY() then e.array;
1405 64 case DAE.MATRIX() then List.flatten(e.matrix);
1406 case DAE.BOX(e1) then {e1};
1407 case DAE.META_OPTION(SOME(e1)) then {e1};
1408 case DAE.CONS(e1, e2) then {e1, e2};
1409 ✗ case DAE.LIST() then e.valList;
1410 ✗ case DAE.META_TUPLE() then e.listExp;
1411 4 case DAE.METARECORDCALL() then e.args;
1412 ✗ case DAE.CALL(path = Absyn.IDENT("listArrayLiteral")) then e.expLst;
1413 else {};
1414 end match;
1415 end literalElements;
1416
1417 function replaceLiteralExpKeepSingle
1418 input DAE.Exp inExp;
1419 input UnorderedMap<DAE.Exp, Integer> uses;
1420 input tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> inTpl;
1421 output DAE.Exp outExp;
1422 output tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> outTpl;
1423 protected
1424 UnorderedMap<DAE.Exp, Integer> ht;
1425 algorithm
1426 1850776 (_, ht, _) := inTpl;
1427
6/6
✓ Branch 1 taken 78795 times.
✓ Branch 2 taken 1771981 times.
✓ Branch 4 taken 31561 times.
✓ Branch 5 taken 47234 times.
✓ Branch 7 taken 31558 times.
✓ Branch 8 taken 3 times.
1850776 if isSconst(inExp) and UnorderedMap.getOrDefault(inExp, uses, 0) == 1 and not UnorderedMap.contains(inExp, ht) then
1428 outExp := inExp;
1429 31558 outTpl := inTpl;
1430 else
1431 1819218 (outExp, outTpl) := replaceLiteralExp(inExp, inTpl);
1432 end if;
1433 end replaceLiteralExpKeepSingle;
1434
1435
1436 function replaceLiteralArrayExp
1437 "The tuples contain:
1438 * The expression to be replaced (or not)
1439 * Index of next literal
1440 * HashTable Exp->Index (Number of the literal)
1441 * The list of literals
1442
1443 Handles only array expressions (needs to be performed in a top-down fashion)
1444 "
1445 input DAE.Exp inExp;
1446 input tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> inTpl;
1447 output DAE.Exp outExp;
1448 output Boolean cont=true;
1449 output tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> outTpl;
1450 algorithm
1451 (outExp,outTpl) := match (inExp,inTpl)
1452 local
1453 DAE.Exp exp2;
1454 tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> tpl;
1455 case (DAE.ARRAY(), tpl)
1456 algorithm
1457 try
1458 8321 isLiteralArrayExp(inExp);
1459 5589 (exp2, tpl) := replaceLiteralExp2(inExp, tpl);
1460 cont := false;
1461 else
1462 exp2 := inExp;
1463 end try;
1464 8321 then (exp2, tpl);
1465 case (DAE.MATRIX(), tpl)
1466 algorithm
1467 try
1468 83 isLiteralArrayExp(inExp);
1469 36 (exp2, tpl) := replaceLiteralExp2(inExp, tpl);
1470 cont := false;
1471 else
1472 exp2 := inExp;
1473 end try;
1474 83 then (exp2, tpl);
1475 else (inExp, inTpl);
1476 end match;
1477 end replaceLiteralArrayExp;
1478
1479 function replaceLiteralExp
1480 "The tuples contain:
1481 * The expression to be replaced (or not)
1482 * Index of next literal
1483 * HashTable Exp->Index (Number of the literal)
1484 * The list of literals
1485 "
1486 input DAE.Exp inExp;
1487 input tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> inTpl;
1488 output DAE.Exp outExp;
1489 output tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> outTpl;
1490 algorithm
1491 (outExp,outTpl) := matchcontinue (inExp,inTpl)
1492 local
1493 DAE.Exp exp;
1494 String msg;
1495 tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> t;
1496 list<DAE.Exp> es;
1497 case (exp, t)
1498 algorithm
1499
2/2
✓ Branch 0 taken 3347684 times.
✓ Branch 1 taken 1958459 times.
5306143 failure(isLiteralExp(exp)); // exit if the expression is not literal
1500 1958459 then (exp, t);
1501 case (exp, t)
1502 algorithm
1503 1389225 isTrivialLiteralExp(exp);
1504 1267317 then (exp, t);
1505 case (DAE.LIST(valList=es), t)
1506 algorithm
1507
2/2
✓ Branch 1 taken 305 times.
✓ Branch 2 taken 16 times.
321 true := listLength(es) > 25;
1508 16 (exp,t) := replaceLiteralExp2(inExp, t);
1509 then (exp, t); // Too large list; causes performance issues to find all sublists...
1510 case (exp, t)
1511 algorithm
1512 121892 exp := listToCons(exp);
1513 305 (exp, t) := Expression.traverseExpBottomUp(exp, replaceLiteralExp, t);
1514 then (exp, t); // All sublists should also be added as literals...
1515 case (exp, _)
1516 algorithm
1517
2/2
✓ Branch 0 taken 121587 times.
✓ Branch 1 taken 121587 times.
243174 failure(listToCons(exp));
1518 121587 (exp,t) := replaceLiteralExp2(exp, inTpl);
1519 then (exp, t);
1520 case (exp, _)
1521 algorithm
1522 ✗ msg := "function replaceLiteralExp failed. Falling back to not replacing "+ExpressionBasics.printExpStr(exp)+".";
1523 ✗ Error.addInternalError(msg, sourceInfo());
1524 ✗ then (inExp,inTpl);
1525 end matchcontinue;
1526 end replaceLiteralExp;
1527
1528 function replaceLiteralExp2
1529 "The tuples contain:
1530 * The expression to be replaced (or not)
1531 * Index of next literal
1532 * HashTable Exp->Index (Number of the literal)
1533 * The list of literals
1534 "
1535 input DAE.Exp inExp;
1536 input tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> inTpl;
1537 output DAE.Exp outExp;
1538 output tuple<Integer, UnorderedMap<DAE.Exp, Integer>, list<DAE.Exp>> outTpl;
1539 algorithm
1540 (outExp,outTpl) := matchcontinue (inExp,inTpl)
1541 local
1542 DAE.Exp exp, nexp;
1543 Integer i, ix;
1544 list<DAE.Exp> l;
1545 UnorderedMap<DAE.Exp, Integer> ht;
1546 case (exp, (_, ht, _))
1547 algorithm
1548 127228 ix := UnorderedMap.getOrFail(exp, ht);
1549 111551 nexp := DAE.SHARED_LITERAL(ix, exp);
1550 then (nexp, inTpl);
1551 case (exp, (i, ht, l))
1552 algorithm
1553 15677 UnorderedMap.add(exp, i, ht);
1554 15677 nexp := DAE.SHARED_LITERAL(i, exp);
1555 15677 then (nexp, (i+1, ht, exp::l));
1556 end matchcontinue;
1557 end replaceLiteralExp2;
1558
1559 function listToCons
1560 "Converts a DAE.LIST to a chain of DAE.CONS"
1561 input DAE.Exp e;
1562 output DAE.Exp o;
1563 algorithm
1564 o := match e
1565 local
1566 list<DAE.Exp> es;
1567 305 case DAE.LIST(es as _::_) then listToCons2(es);
1568 end match;
1569 end listToCons;
1570
1571 function listToCons2
1572 "Converts a DAE.LIST to a chain of DAE.CONS"
1573 input list<DAE.Exp> ies;
1574 output DAE.Exp o;
1575 algorithm
1576 o := match ies
1577 local
1578 DAE.Exp car, cdr;
1579 list<DAE.Exp> es;
1580 case {} then DAE.LIST({});
1581 case car::es
1582 algorithm
1583 1414 cdr := listToCons2(es);
1584 1414 then DAE.CONS(car, cdr);
1585 end match;
1586 end listToCons2;
1587
1588 function isTrivialLiteralExp
1589 "Succeeds if the expression should not be translated to a constant literal because it is too simple"
1590 input DAE.Exp exp;
1591 algorithm
1592 () := match exp
1593 ✗ case DAE.BOX(DAE.SCONST(_)) then fail();
1594 136 case DAE.BOX(DAE.RCONST(_)) then fail();
1595 case DAE.BOX(_) then ();
1596 case DAE.ICONST(_) then ();
1597 case DAE.BCONST(_) then ();
1598 case DAE.RCONST(_) then ();
1599 case DAE.ENUM_LITERAL() then ();
1600 case DAE.LIST(valList={}) then ();
1601 case DAE.META_OPTION(NONE()) then ();
1602 case DAE.SHARED_LITERAL() then ();
1603 else fail();
1604 end match;
1605 end isTrivialLiteralExp;
1606
1607 function isLiteralArrayExp
1608 input DAE.Exp iexp;
1609 algorithm
1610 () := match iexp
1611 local
1612 DAE.Exp e1, e2, exp;
1613 list<DAE.Exp> expl;
1614 list<list<DAE.Exp>> expll;
1615
1616 case DAE.SCONST(_) then ();
1617 case DAE.ICONST(_) then ();
1618 case DAE.RCONST(_) then ();
1619 case DAE.BCONST(_) then ();
1620 48911 case DAE.ARRAY(array=expl) algorithm List.map_0(expl, isLiteralArrayExp); then ();
1621 83 case DAE.MATRIX(matrix=expll) algorithm List.map_0(List.flatten(expll), isLiteralArrayExp); then ();
1622 case DAE.ENUM_LITERAL() then ();
1623 case DAE.META_OPTION(NONE()) then ();
1624 ✗ case DAE.META_OPTION(SOME(exp)) algorithm isLiteralArrayExp(exp); then ();
1625 ✗ case DAE.BOX(exp) algorithm isLiteralArrayExp(exp); then ();
1626 ✗ case DAE.CONS(car = e1, cdr = e2) algorithm isLiteralArrayExp(e1); isLiteralArrayExp(e2); then ();
1627 ✗ case DAE.LIST(valList = expl) algorithm List.map_0(expl, isLiteralArrayExp); then ();
1628 ✗ case DAE.META_TUPLE(expl) algorithm List.map_0(expl, isLiteralArrayExp); then ();
1629 ✗ case DAE.METARECORDCALL(args=expl) algorithm List.map_0(expl, isLiteralArrayExp); then ();
1630 case DAE.SHARED_LITERAL() then ();
1631 else fail();
1632 end match;
1633 end isLiteralArrayExp;
1634
1635 function isLiteralExp
1636 "Returns if the expression may be replaced by a constant literal"
1637 input DAE.Exp iexp;
1638 algorithm
1639 () := match iexp
1640 local
1641 DAE.Exp e1, e2, exp;
1642 list<DAE.Exp> expl;
1643 case DAE.SCONST(_) then ();
1644 case DAE.ICONST(_) then ();
1645 case DAE.RCONST(_) then ();
1646 case DAE.BCONST(_) then ();
1647 case DAE.ENUM_LITERAL() then ();
1648 case DAE.META_OPTION(NONE()) then ();
1649 414 case DAE.META_OPTION(SOME(exp)) algorithm isLiteralExp(exp); then ();
1650 10257 case DAE.BOX(exp) algorithm isLiteralExp(exp); then ();
1651 1742 case DAE.CONS(car = e1, cdr = e2) algorithm isLiteralExp(e1); isLiteralExp(e2); then ();
1652 5922 case DAE.LIST(valList = expl) algorithm List.map_0(expl, isLiteralExp); then ();
1653 1226 case DAE.META_TUPLE(expl) algorithm List.map_0(expl, isLiteralExp); then ();
1654 8723 case DAE.METARECORDCALL(args=expl) algorithm List.map_0(expl, isLiteralExp); then ();
1655 case DAE.SHARED_LITERAL() then ();
1656 ✗ case DAE.CALL(path=Absyn.IDENT("listArrayLiteral"), expLst=expl) algorithm List.map_0(expl, isLiteralExp); then ();
1657 else fail();
1658 end match;
1659 end isLiteralExp;
1660
1661 protected function collectRecDeclsFromTypes
1662 input list<DAE.Type> inTypes;
1663 input UnorderedMap<String, SimCodeFunction.RecordDeclaration> recDeclsMap;
1664 algorithm
1665
2/2
✓ Branch 0 taken 17359 times.
✓ Branch 1 taken 1407 times.
18766 for ty in inTypes loop
1666 17359 collectRecDeclsFromType(ty, recDeclsMap);
1667 end for;
1668 end collectRecDeclsFromTypes;
1669
1670 protected function collectRecDeclsFromElems
1671 "Translate all records used by varlist to structs."
1672 input list<DAE.Element> inElems;
1673 input UnorderedMap<String, SimCodeFunction.RecordDeclaration> recDeclsMap;
1674 algorithm
1675
5/5
✓ Branch 0 taken 58448 times.
✓ Branch 1 taken 7881 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 66404 times.
✓ Branch 4 taken 8549 times.
74953 for elem in inElems loop
1676
1677 () := match elem
1678 case DAE.VAR() algorithm
1679 58448 collectRecDeclsFromType(elem.ty, recDeclsMap);
1680
1681
5/6
✗ Branch 0 not taken.
✓ Branch 1 taken 58448 times.
✓ Branch 2 taken 7284 times.
✓ Branch 3 taken 51164 times.
✓ Branch 5 taken 697 times.
✓ Branch 6 taken 6587 times.
58448 if isSome(elem.binding) and Config.acceptMetaModelicaGrammar() then
1682 697 Expression.traverseExpBottomUp(Util.getOption(elem.binding), collectRecDeclsFromMetaRecCallExp, recDeclsMap);
1683 end if;
1684 then ();
1685
1686 case DAE.ALGORITHM() algorithm
1687
2/2
✓ Branch 1 taken 1687 times.
✓ Branch 2 taken 6194 times.
7881 if Config.acceptMetaModelicaGrammar() then
1688 1687 DAEUtil.traverseAlgorithmExps(elem.algorithm_, Expression.traverseSubexpressionsHelper, (collectRecDeclsFromMetaRecCallExp, recDeclsMap));
1689 end if;
1690 then ();
1691
1692 else ();
1693 end match;
1694
1695 end for;
1696 end collectRecDeclsFromElems;
1697
1698 protected function isVarQ
1699 "Succeeds if inElement is a variable or constant that is not input."
1700 input DAE.Element inElement;
1701 output Boolean outB;
1702 algorithm
1703 outB := match inElement
1704 local
1705 DAE.VarKind vk;
1706 DAE.VarDirection vd;
1707 case DAE.VAR(kind=vk, direction=vd)
1708 guard
1709 isVarKindVarOrParameter(vk) and
1710 isDirectionNotInput(vd)
1711 then true;
1712 else false;
1713 end match;
1714 end isVarQ;
1715
1716 protected function isVarNotInputNotOutput
1717 "Succeeds if inElement is a variable or constant that is not input or output.
1718 needed in kernel functions since they shouldn't have output vars."
1719 input DAE.Element inElement;
1720 output Boolean outB;
1721 algorithm
1722 outB := match inElement
1723 local
1724 DAE.VarKind vk;
1725 DAE.VarDirection vd;
1726 case DAE.VAR(kind=vk, direction=vd)
1727 guard
1728 isVarKindVarOrParameter(vk) and
1729 isDirectionNotInputNotOutput(vd)
1730 then true;
1731 else false;
1732 end match;
1733 end isVarNotInputNotOutput;
1734
1735 protected function isVarKindVarOrParameter
1736 input DAE.VarKind inVarKind;
1737 output Boolean outB;
1738 algorithm
1739 outB := match inVarKind
1740 case DAE.VARIABLE() then true;
1741 case DAE.PARAM() then true;
1742 case DAE.CONST() then true;
1743 else false;
1744 end match;
1745 end isVarKindVarOrParameter;
1746
1747 protected function isDirectionNotInput
1748 input DAE.VarDirection inVarDirection;
1749 output Boolean outB;
1750 algorithm
1751 outB := match inVarDirection
1752 case DAE.OUTPUT() then true;
1753 case DAE.BIDIR() then true;
1754 else false;
1755 end match;
1756 end isDirectionNotInput;
1757
1758 protected function isDirectionNotInputNotOutput
1759 input DAE.VarDirection inVarDirection;
1760 output Boolean outB;
1761 algorithm
1762 outB := match inVarDirection
1763 case DAE.BIDIR() then true;
1764 else false;
1765 end match;
1766 end isDirectionNotInputNotOutput;
1767
1768 protected function filterNg "Sets the number of zero crossings to zero if events are disabled."
1769 input Integer ng;
1770 output Integer outInteger;
1771 algorithm
1772 ✗ outInteger := if useZerocrossing() then ng else 0;
1773 end filterNg;
1774
1775 protected function useZerocrossing
1776 output Boolean res;
1777 algorithm
1778 ✗ res := Flags.isSet(Flags.EVENTS);
1779 end useZerocrossing;
1780
1781 protected function getCrefFromExp "Assume input Exp is CREF and return the ComponentRef, fail otherwise."
1782 input DAE.Exp e;
1783 output Absyn.ComponentRef c;
1784 algorithm
1785 c := match e
1786 local
1787 DAE.ComponentRef crefe;
1788 Absyn.ComponentRef crefa;
1789
1790 case DAE.CREF(componentRef = crefe)
1791 algorithm
1792 261 crefa := ComponentReference.unelabCref(crefe);
1793 then
1794 crefa;
1795
1796 else
1797 algorithm
1798 ✗ Error.addInternalError("function getCrefFromExp failed: input was not of type DAE.CREF", sourceInfo());
1799 ✗ then
1800 fail();
1801 end match;
1802 end getCrefFromExp;
1803
1804 protected function collectRecDeclsFromType
1805 "Helper function to generateStructsForRecords."
1806 input DAE.Type inRecordType;
1807 input UnorderedMap<String, SimCodeFunction.RecordDeclaration> recDeclsMap;
1808 algorithm
1809 () := match inRecordType
1810 local
1811 Absyn.Path path;
1812 list<DAE.Var> varlst;
1813 String name,sname;
1814 list<String> fieldNames;
1815 list<SimCodeFunction.Variable> vars;
1816 SimCodeFunction.RecordDeclaration recDecl;
1817 Option<SimCodeFunction.RecordDeclaration> optRecDecl;
1818 Boolean is_default, usedExternally, bool1, changed;
1819
1820 case DAE.T_COMPLEX(complexClassType = ClassInf.RECORD(path), varLst = varlst, usedExternally = usedExternally)
1821 algorithm
1822 9457 name := AbsynUtil.pathStringUnquoteReplaceDot(path, "_");
1823 9457 (sname, is_default) := checkBindingsandGetConstructorName(name, varlst);
1824
1825 9457 optRecDecl := UnorderedMap.get(sname, recDeclsMap);
1826
1827
2/2
✓ Branch 0 taken 9432 times.
✓ Branch 1 taken 25 times.
9457 if is_default then
1828 // If it already exists check if we need to update it.
1829
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 9432 times.
✓ Branch 2 taken 4329 times.
✓ Branch 3 taken 5103 times.
9432 if isSome(optRecDecl) then
1830
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5103 times.
5103 SOME(SimCodeFunction.RECORD_DECL_FULL(_, _, _, vars, bool1)) := optRecDecl;
1831 5103 (vars, changed) := addMissingDefaults(vars, varlst);
1832
1833
4/4
✓ Branch 0 taken 5102 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5100 times.
5103 if changed or (usedExternally and not bool1) then
1834
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2 times.
4 recDecl := SimCodeFunction.RECORD_DECL_FULL(sname, NONE(), path, vars, usedExternally or bool1);
1835 3 UnorderedMap.add(sname, recDecl, recDeclsMap);
1836 end if;
1837 // Add it if it does not exist.
1838 else
1839 4329 vars := List.map(varlst, typesVar);
1840
2/2
✓ Branch 0 taken 1419 times.
✓ Branch 1 taken 2910 times.
5748 recDecl := SimCodeFunction.RECORD_DECL_FULL(sname, NONE(), path, vars, usedExternally);
1841 4329 UnorderedMap.add(sname, recDecl, recDeclsMap);
1842
1843 4329 collectRecDeclsFromTypesVars(varlst, recDeclsMap);
1844 end if;
1845
1846 // It is not a default construtor
1847 else
1848 // Add it if does not exist. Otherwise do nothing.
1849
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 6 times.
25 if isNone(optRecDecl) then
1850 19 vars := List.map(varlst, typesVar);
1851
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
38 recDecl := SimCodeFunction.RECORD_DECL_ADD_CONSTRCTOR(sname, name, vars, path, usedExternally);
1852 19 UnorderedMap.add(sname, recDecl, recDeclsMap);
1853 19 collectRecDeclsFromTypesVars(varlst, recDeclsMap);
1854 end if;
1855 end if;
1856 then ();
1857
1858 case DAE.T_COMPLEX(complexClassType = ClassInf.RECORD(_)) then ();
1859
1860 case DAE.T_METARECORD(path = Absyn.QUALIFIED(name="SourceInfo")) then ();
1861
1862 case DAE.T_METARECORD(fields = varlst, path=path)
1863 algorithm
1864 17335 sname := AbsynUtil.pathStringUnquoteReplaceDot(path, "_");
1865 17335 fieldNames := List.map(varlst, generateVarName);
1866 17335 UnorderedMap.tryAdd(sname, SimCodeFunction.RECORD_DECL_DEF(path, fieldNames), recDeclsMap);
1867 17335 collectRecDeclsFromTypesVars(varlst, recDeclsMap);
1868 then ();
1869
1870 case _ then ();
1871
1872 end match;
1873 end collectRecDeclsFromType;
1874
1875 protected function addMissingDefaults
1876 "Not every type of a record carries the defaults of its fields, so the
1877 declaration takes each missing default from the next type that has it."
1878 input list<SimCodeFunction.Variable> inVars;
1879 input list<DAE.Var> typeVars;
1880 output list<SimCodeFunction.Variable> vars = {};
1881 output Boolean changed = false;
1882 protected
1883 Option<DAE.Exp> value;
1884 SimCodeFunction.Variable var;
1885 algorithm
1886
2/2
✓ Branch 0 taken 61802 times.
✓ Branch 1 taken 5103 times.
66905 for v in inVars loop
1887 var := v;
1888 () := match var
1889 case SimCodeFunction.VARIABLE(value = NONE())
1890 algorithm
1891
1/2
✓ Branch 0 taken 606371 times.
✗ Branch 1 not taken.
606371 for tv in typeVars loop
1892
4/4
✓ Branch 1 taken 113260 times.
✓ Branch 2 taken 493111 times.
✓ Branch 5 taken 52077 times.
✓ Branch 6 taken 61183 times.
606371 if stringEq(tv.name, ComponentReferenceBasics.crefFirstIdent(var.name)) then
1893 52077 value := checkSourceAndGetBindingExp(tv.binding);
1894
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 52077 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 52075 times.
52077 if isSome(value) then
1895 2 var.value := value;
1896 changed := true;
1897 end if;
1898 break;
1899 end if;
1900 end for;
1901 then ();
1902 else ();
1903 end match;
1904 vars := var :: vars;
1905 end for;
1906 5103 vars := listReverse(vars);
1907 end addMissingDefaults;
1908
1909 protected function typesVarNoBinding
1910 input DAE.Var inTypesVar;
1911 output SimCodeFunction.Variable outVar;
1912 algorithm
1913 outVar := match inTypesVar
1914 local
1915 String name;
1916 DAE.Type ty;
1917 DAE.ComponentRef cref_;
1918 DAE.Attributes attr;
1919 SCode.Parallelism scPrl;
1920 DAE.VarParallelism prl;
1921
1922 case DAE.TYPES_VAR(name=name, attributes = attr, ty=ty)
1923 algorithm
1924 ✗ ty := Types.simplifyType(ty);
1925 ✗ cref_ := ComponentReferenceBasics.makeCrefIdent(name, ty, {});
1926 ✗ DAE.ATTR(parallelism = scPrl) := attr;
1927 ✗ prl := scodeParallelismToDAEParallelism(scPrl);
1928 ✗ then SimCodeFunction.VARIABLE(cref_, ty, NONE(), {}, prl,DAE.VARIABLE(), false);
1929 end match;
1930 end typesVarNoBinding;
1931
1932 protected function typesVar
1933 input DAE.Var inTypesVar;
1934 output SimCodeFunction.Variable outVar;
1935 algorithm
1936 outVar := match inTypesVar
1937 local
1938 String name;
1939 DAE.Type ty;
1940 DAE.ComponentRef cref_;
1941 DAE.Attributes attr;
1942 SCode.Parallelism scPrl;
1943 DAE.VarParallelism prl;
1944 Option<DAE.Exp> bindExp;
1945
1946 case DAE.TYPES_VAR(name=name, attributes = attr, ty=ty)
1947 algorithm
1948 43726 ty := Types.simplifyType(ty);
1949 43726 cref_ := ComponentReferenceBasics.makeCrefIdent(name, ty, {});
1950 43726 DAE.ATTR(parallelism = scPrl) := attr;
1951 43726 prl := scodeParallelismToDAEParallelism(scPrl);
1952 43726 bindExp := checkSourceAndGetBindingExp(inTypesVar.binding);
1953 43726 then SimCodeFunction.VARIABLE(cref_, ty, bindExp, {}, prl, DAE.VARIABLE(), inTypesVar.bind_from_outside);
1954 end match;
1955 end typesVar;
1956
1957 protected function checkBindingsandGetConstructorName
1958 input String rec_name;
1959 input list<DAE.Var> vars;
1960 output String ctor_name;
1961 output Boolean is_default;
1962 protected
1963 Integer varnum;
1964 algorithm
1965 is_default := true;
1966
1967 ctor_name := rec_name;
1968 varnum := 1;
1969
1970
2/2
✓ Branch 0 taken 105298 times.
✓ Branch 1 taken 9457 times.
114755 for var in vars loop
1971
3/4
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 105247 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
105298 if var.bind_from_outside and not isBindingFromDerivedRecordDeclaration(var.binding) then
1972 is_default := false;
1973 51 ctor_name := ctor_name + "_" + intString(varnum);
1974 end if;
1975
1976 105298 varnum := intAdd(varnum,1);
1977 end for;
1978 end checkBindingsandGetConstructorName;
1979
1980 protected function isBindingFromDerivedRecordDeclaration
1981 input DAE.Binding bind;
1982 output Boolean b;
1983 algorithm
1984 b := match bind
1985 case DAE.EQBOUND(source=DAE.BINDING_FROM_DERIVED_RECORD_DECL()) then true;
1986 else false;
1987 end match;
1988 end isBindingFromDerivedRecordDeclaration;
1989
1990 protected function checkSourceAndGetBindingExp
1991 input DAE.Binding inBinding;
1992 output Option<DAE.Exp> bindExp;
1993 algorithm
1994 bindExp := match inBinding
1995 local
1996 case DAE.EQBOUND(source=DAE.BINDING_FROM_RECORD_SUBMODS()) then NONE();
1997 7500 case DAE.EQBOUND() then SOME(inBinding.exp);
1998 else NONE();
1999 end match;
2000 end checkSourceAndGetBindingExp;
2001
2002 protected function scodeParallelismToDAEParallelism
2003 input SCode.Parallelism inParallelism;
2004 output DAE.VarParallelism outParallelism;
2005 algorithm
2006 outParallelism := match inParallelism
2007 case SCode.PARGLOBAL() then DAE.PARGLOBAL();
2008 case SCode.PARLOCAL() then DAE.PARLOCAL();
2009 case SCode.NON_PARALLEL() then DAE.NON_PARALLEL();
2010 end match;
2011 end scodeParallelismToDAEParallelism;
2012
2013 protected function variableName
2014 input SimCodeFunction.Variable v;
2015 output String s;
2016 algorithm
2017 s := match v
2018 case SimCodeFunction.VARIABLE(name=DAE.CREF_IDENT(ident=s)) then s;
2019 case SimCodeFunction.FUNCTION_PTR(name=s) then s;
2020 end match;
2021 end variableName;
2022
2023 protected function compareVariable
2024 input SimCodeFunction.Variable v1;
2025 input SimCodeFunction.Variable v2;
2026 output Boolean b;
2027 algorithm
2028 ✗ b := stringCompare(variableName(v1),variableName(v2)) > 0;
2029 end compareVariable;
2030
2031 protected function generateVarName
2032 input DAE.Var inVar;
2033 output String outName;
2034 algorithm
2035 outName :=
2036 match inVar
2037 local
2038 DAE.Ident name;
2039 case DAE.TYPES_VAR(name = name) then name;
2040 else "NULL";
2041 end match;
2042 end generateVarName;
2043
2044 protected function collectRecDeclsFromTypesVars
2045 "Helper function to collectRecDeclsFromElems."
2046 input list<DAE.Var> inRecordTypeVars;
2047 input UnorderedMap<String, SimCodeFunction.RecordDeclaration> recDeclsMap;
2048 algorithm
2049
2/2
✓ Branch 1 taken 75522 times.
✓ Branch 2 taken 21683 times.
97205 for recTyVar in inRecordTypeVars loop
2050 () := match Types.arrayElementType(recTyVar.ty)
2051 local
2052 DAE.Type ty;
2053 case ty as DAE.T_COMPLEX(complexClassType = ClassInf.RECORD(_)) algorithm
2054 19 collectRecDeclsFromType(ty, recDeclsMap);
2055 then ();
2056
2057 else ();
2058 end match;
2059 end for;
2060 end collectRecDeclsFromTypesVars;
2061
2062 protected function collectRecDeclsFromMetaRecCallExps
2063 input list<DAE.Exp> inExpl;
2064 input UnorderedMap<String, SimCodeFunction.RecordDeclaration> recDeclsMap;
2065 algorithm
2066
2/2
✓ Branch 0 taken 13956 times.
✓ Branch 1 taken 1407 times.
15363 for exp in inExpl loop
2067 13956 collectRecDeclsFromMetaRecCallExp(exp, recDeclsMap);
2068 end for;
2069 end collectRecDeclsFromMetaRecCallExps;
2070
2071 protected function collectRecDeclsFromMetaRecCallExp
2072 input output DAE.Exp inExp;
2073 input output UnorderedMap<String, SimCodeFunction.RecordDeclaration> recDeclsMap;
2074 protected
2075 String name;
2076 algorithm
2077 () := match inExp
2078 case DAE.METARECORDCALL() algorithm
2079
2/2
✓ Branch 0 taken 3231 times.
✓ Branch 1 taken 2 times.
3233 if inExp.index <> -1 then
2080 3231 name := AbsynUtil.pathStringUnquoteReplaceDot(inExp.path, "_");
2081 3231 UnorderedMap.tryAdd(name, SimCodeFunction.RECORD_DECL_DEF(inExp.path, inExp.fieldNames), recDeclsMap);
2082 end if;
2083 then ();
2084
2085 else ();
2086 end match;
2087 end collectRecDeclsFromMetaRecCallExp;
2088
2089
2090 protected function generateExtFunctionIncludes "by investigating the annotation of an external function."
2091 input Absyn.Program program;
2092 input Absyn.Path path;
2093 input Option<SCode.Annotation> inAbsynAnnotationOption;
2094 input SourceInfo info;
2095 output list<String> includes;
2096 output list<String> includeDirs;
2097 output list<String> libs;
2098 output list<String> paths;
2099 output Boolean dynamcLoad;
2100 algorithm
2101 (includes, includeDirs, libs,paths, dynamcLoad):=
2102 match inAbsynAnnotationOption
2103 local
2104 SCode.Mod mod;
2105 Boolean b, isWasm;
2106 String target;
2107 Option<String> resources;
2108 list<String> libNames, fullLibNames, dirs;
2109
2110 case SOME(SCode.ANNOTATION(mod))
2111 algorithm
2112 608 b := generateExtFunctionDynamicLoad(mod);
2113 608 target := Flags.getConfigString(Flags.TARGET);
2114 608 (libs, libNames) := generateExtFunctionIncludesLibstr(target,mod);
2115 608 includes := generateExtFunctionIncludesIncludestr(mod);
2116 608 (libs, dirs, resources) := generateExtFunctionLibraryDirectoryFlags(program, path, mod, libs);
2117 608 isWasm := isWasmSimCodeTarget();
2118 608 paths := generateExtFunctionLibraryDirectoryPaths(program, path, mod);
2119
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 608 times.
608 if isWasm then
2120 ✗ dirs := List.union(dirs, paths);
2121 end if;
2122 // A bundle installPackage put there covers the `Library` names, some of
2123 // which it links in privately.
2124
4/8
✓ Branch 1 taken 608 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 608 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 978 times.
✓ Branch 9 taken 608 times.
2194 for name in if Flags.isSet(Flags.CHECK_EXT_LIBS) and not (isWasm and hasWasmBundle(dirs)) then libNames else {} loop
2125 // A wasm run uses either form, so both are looked for and built, unless
2126 // the module it loads is there already.
2127
13/14
✓ Branch 3 taken 1956 times.
✓ Branch 4 taken 978 times.
✓ Branch 5 taken 1956 times.
✓ Branch 6 taken 978 times.
✓ Branch 7 taken 15216 times.
✓ Branch 8 taken 1956 times.
✓ Branch 9 taken 15216 times.
✓ Branch 10 taken 1956 times.
✓ Branch 13 taken 17172 times.
✓ Branch 14 taken 1956 times.
✓ Branch 15 taken 17172 times.
✓ Branch 16 taken 1956 times.
✓ Branch 19 taken 978 times.
✗ Branch 20 not taken.
36300 if not (isWasm and max(System.regularFileExists(d + n) for d in "" :: list(d + "/" for d in dirs), n in {name + ".wasm", "lib" + name + ".wasm"})) then
2128
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 978 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
978 if getGerneralTarget(target)=="msvc" or Autoconf.os=="Windows_NT" then
2129 ✗ fullLibNames := {name + Autoconf.dllExt, "lib" + name + ".a", "lib" + name + ".lib"};
2130 else
2131 978 fullLibNames := {"lib" + name + ".a", "lib" + name + Autoconf.dllExt};
2132 end if;
2133 978 lookForExtFunctionLibrary(fullLibNames, dirs, name, resources, path, info, false);
2134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 978 times.
978 if isWasm then
2135 ✗ lookForExtFunctionLibrary({name + ".wasm", "lib" + name + ".wasm"},
2136 dirs, name, resources, path, info, true);
2137 end if;
2138 end if;
2139 end for;
2140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 608 times.
608 if isWasm then
2141 // A wasm target gets no -L flags, so the search dirs travel as libPaths.
2142 ✗ paths := List.union(paths, list(d for d guard System.directoryExists(d) in listReverse(dirs)));
2143 end if;
2144 608 includeDirs := generateExtFunctionIncludeDirectoryFlags(program, path, mod, includes);
2145 then
2146 (includes, includeDirs, libs,paths, b);
2147 case NONE() then ({}, {}, {},{}, false);
2148 end match;
2149 end generateExtFunctionIncludes;
2150
2151 protected function hasWasmBundle
2152 "Whether installPackage put prebuilt wasm modules (an `omc-<generation>`
2153 directory) in one of `dirs`."
2154 input list<String> dirs;
2155 output Boolean b = false;
2156 algorithm
2157 ✗ for d in dirs loop
2158 ✗ if (StringUtil.endsWith(d, "wasm32-wasip1") or StringUtil.endsWith(d, "wasm32-wasip1/")) and System.directoryExists(d) then
2159 ✗ if List.any(System.subDirectories(d), function StringUtil.startsWith(prefix = "omc-")) then
2160 b := true;
2161 ✗ return;
2162 end if;
2163 end if;
2164 end for;
2165 end hasWasmBundle;
2166
2167 protected function lookForExtFunctionLibrary
2168 "`forWasm` looks for the wasm module a simulation loads rather than the platform
2169 library a host links, and builds that instead. A library without a wasm build is
2170 the ordinary case, so this pass does not report one missing."
2171 input list<String> names;
2172 input list<String> dirs;
2173 input String name;
2174 input Option<String> resources;
2175 input Absyn.Path path;
2176 input SourceInfo info;
2177 input Boolean forWasm;
2178 protected
2179 list<String> dirs2;
2180 algorithm
2181 978 dirs2 := Settings.getInstallationDirectoryPath() + "/lib/" + Autoconf.triple + "/omc"::"/usr/lib/"+Autoconf.triple::"/lib/"+Autoconf.triple::"/usr/lib/"::"/lib/"::dirs; // We could also try to look in ldconfig, etc for system libraries
2182
9/10
✓ Branch 0 taken 1956 times.
✓ Branch 1 taken 978 times.
✓ Branch 2 taken 1956 times.
✓ Branch 3 taken 978 times.
✓ Branch 4 taken 24996 times.
✓ Branch 5 taken 1956 times.
✓ Branch 6 taken 24996 times.
✓ Branch 7 taken 1956 times.
✓ Branch 11 taken 978 times.
✗ Branch 12 not taken.
27930 if not max(System.regularFileExists(d+"/"+n) for d in dirs2, n in names) then
2183 () := match resources
2184 local
2185 String resourcesStr, tmpdir, srcdir, builddir, cmd, pwd, contents, found;
2186 Integer status;
2187 Boolean didFind, isCMake;
2188 case SOME(resourcesStr)
2189 algorithm
2190 ✗ if System.directoryExists(resourcesStr) and not extLibraryBuildAttempted(resourcesStr, name, forWasm) then
2191 didFind := false;
2192 ✗ for dir in extLibraryBuildProjects(resourcesStr, forWasm) loop
2193 ✗ srcdir := resourcesStr + (if dir == "." then "" else "/" + dir);
2194 ✗ isCMake := System.regularFileExists(srcdir + "/CMakeLists.txt");
2195 ✗ tmpdir := System.createTemporaryDirectory(Settings.getTempDirectoryPath() + "/omc_compile_" + name + "_");
2196 ✗ Error.addSourceMessage(Error.COMPILER_NOTIFICATION, {"Created directory " + tmpdir}, info);
2197 ✗ if isCMake then
2198 // Out of source: the project is read where it lies.
2199 builddir := tmpdir;
2200 else
2201 // autotools builds in-tree, so it gets a copy of Resources.
2202 ✗ builddir := tmpdir + "/" + dir;
2203 ✗ cmd := "cp -a \"" + resourcesStr + "\"/* \"" + tmpdir + "\"";
2204 ✗ Error.addSourceMessage(Error.COMPILER_NOTIFICATION, {cmd}, info);
2205 ✗ System.systemCall(cmd);
2206 end if;
2207 ✗ pwd := System.pwd();
2208 ✗ if 0==System.cd(builddir) then
2209 ✗ Error.addSourceMessage(Error.COMPILER_NOTIFICATION, {"Changed directory to " + System.pwd()}, info);
2210 ✗ cmd := extLibraryBuildCommand(path, forWasm, if isCMake then srcdir else "");
2211 ✗ status := System.systemCall(cmd, "log");
2212 ✗ contents := System.readFile("log");
2213 ✗ if status <> 0 then
2214 ✗ Error.addSourceMessage(Error.COMPILER_WARNING, {"Failed to run "+cmd+": " + contents}, info);
2215 else
2216 ✗ Error.addSourceMessage(Error.COMPILER_NOTIFICATION, {"Succeeded with compilation and installation of the library using:\ncommand: "+cmd+"\n" + contents}, info);
2217 // The names are spellings of one library, not files that must all exist.
2218 ✗ didFind := max(System.regularFileExists(d+"/"+n) for d in dirs2, n in names);
2219 ✗ if didFind then
2220 ✗ found := listHead(list(x for x guard System.regularFileExists(x) in List.flatten(list(d+"/"+n for d in dirs2, n in names))));
2221 ✗ Error.addSourceMessage(Error.COMPILER_NOTIFICATION, {"Compiled "+found+" by running build project " + resourcesStr + "/" + dir}, info);
2222 else
2223 ✗ Error.addSourceMessage(Error.EXT_LIBRARY_NOT_FOUND_DESPITE_COMPILATION_SUCCESS, {name, cmd, System.pwd()}, info);
2224 end if;
2225 end if;
2226 else
2227 ✗ Error.addSourceMessage(Error.COMPILER_WARNING, {"Failed to change directory to " + builddir}, info);
2228 end if;
2229 ✗ System.cd(pwd);
2230 ✗ System.removeDirectory(tmpdir);
2231 ✗ Error.addSourceMessage(Error.COMPILER_NOTIFICATION, {"Removed directory " + tmpdir}, info);
2232 ✗ if didFind then
2233 break;
2234 end if;
2235 end for;
2236 end if;
2237 then ();
2238 else ();
2239 end match;
2240 ✗ if not max(System.regularFileExists(d+"/"+n) for d in dirs2, n in names) then
2241 // suppress this warning if we're running the testsuite
2242 ✗ if not (forWasm or Testsuite.isRunning()) then
2243 ✗ Error.addSourceMessage(Error.EXT_LIBRARY_NOT_FOUND, {name, sum("\n " + d + "/" + n for d in dirs2, n in names)}, info);
2244 end if;
2245 end if;
2246 end if;
2247 end lookForExtFunctionLibrary;
2248
2249 protected function generateExtFunctionIncludeDirectoryFlags
2250 "Process LibraryDirectory and IncludeDirectory"
2251 input Absyn.Program program;
2252 input Absyn.Path path;
2253 input SCode.Mod inMod;
2254 input list<String> includes;
2255 output list<String> outDirs;
2256 algorithm
2257 outDirs := matchcontinue includes
2258 local
2259 String str,istr;
2260 case {} then {};
2261 case _
2262 algorithm
2263
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 69 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 69 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 69 times.
120 SCode.MOD(binding = SOME(Absyn.STRING(str))) :=
2264 Mod.getUnelabedSubMod(inMod, "IncludeDirectory");
2265 69 str := ProgramUtil.getFullPathFromUri(program, str, false);
2266 69 istr := "\"-I"+str+"\"";
2267
1/2
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
69 then if System.directoryExists(str) then {istr} else {};
2268 case _
2269 algorithm
2270 51 str := "modelica://" + AbsynUtil.pathFirstIdent(path) + "/Resources/Include";
2271 51 str := ProgramUtil.getFullPathFromUri(program, str, false);
2272 51 istr := "\"-I"+str+"\"";
2273
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 43 times.
51 then if System.directoryExists(str) then {istr} else {};
2274 // Read SourceInfo instead?
2275 else {};
2276 end matchcontinue;
2277 end generateExtFunctionIncludeDirectoryFlags;
2278
2279 protected function getLinkerLibraryPaths"Builds search paths for the linker to find external libraries.
2280 Some libraries need special treatment.
2281 author: vwaurich TUD 2016-10"
2282 input String uri;
2283 input Absyn.Path path;
2284 input list<String> inLibs;
2285 output list<String> libPaths;
2286 protected
2287 String installationDir;
2288 algorithm
2289 503 installationDir := Settings.getInstallationDirectoryPath();
2290
2291 () := match(uri,path,inLibs)
2292 local
2293 case(_, _,{"-lWinmm"}) guard Autoconf.os=="Windows_NT"
2294 algorithm
2295 //Winmm has to be linked from the windows system but not from the resource directories.
2296 //This is a fix for M_DD since otherwise the dummy pthread.dll that breaks the built will be linked
2297 libPaths := {(installationDir + "/lib/" + Autoconf.triple + "/omc")};
2298 then ();
2299 case(, _,_)
2300 algorithm
2301 503 libPaths := {uri,
2302 uri + "/" + System.modelicaPlatform(),
2303 uri + "/" + System.openModelicaPlatform(),
2304 uri + "/" + System.openModelicaPlatformAlternative(),
2305 (Settings.getHomeDir(false) + "/.openmodelica/binaries/" + AbsynUtil.pathFirstIdent(path)),
2306 // Where an MSL-shaped build project forces its CMAKE_INSTALL_LIBDIR.
2307 (userCompiledBinariesDirectory(path) + "/Library/" + System.modelicaPlatform()),
2308 (installationDir + "/lib/"),
2309 (installationDir + "/lib/" + Autoconf.triple + "/omc")};
2310
2311 // A build project run for a wasm target installs beside, not over, the host build.
2312
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 503 times.
503 if isWasmSimCodeTarget() then
2313 ✗ libPaths := userCompiledBinariesDirectory(path) + "/" + wasmLibraryTriple ::
2314 userCompiledBinariesDirectory(path) + "/" + wasmLibraryTriple + "/Library/" + wasmLibraryTriple ::
2315 libPaths;
2316 end if;
2317
2318 if Autoconf.os == "Windows_NT" then
2319 libPaths := List.appendElt(installationDir + "/bin/", libPaths);
2320 end if;
2321
2322 then ();
2323 end match;
2324 end getLinkerLibraryPaths;
2325
2326 protected function generateExtFunctionLibraryDirectoryFlags
2327 "Process LibraryDirectory and IncludeDirectory"
2328 input Absyn.Program program;
2329 input Absyn.Path path;
2330 input SCode.Mod inMod;
2331 input list<String> inLibs;
2332 output list<String> outLibs;
2333 output list<String> installDirs;
2334 output Option<String> resources;
2335 algorithm
2336 (outLibs, installDirs, resources) := matchcontinue inLibs
2337 local
2338 String str, target, resourcesStr;
2339 list<String> libs, libs2;
2340 Boolean isLinux;
2341 case {} then ({}, {}, NONE());
2342 case libs
2343 algorithm
2344 str := matchcontinue inMod
2345 case _
2346 algorithm
2347
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
530 SCode.MOD(binding = SOME(Absyn.STRING(str))) := Mod.getUnelabedSubMod(inMod, "LibraryDirectory");
2348 then str;
2349 530 else "modelica://" + AbsynUtil.pathFirstIdent(path) + "/Resources/Library";
2350 end matchcontinue;
2351 530 str := ProgramUtil.getFullPathFromUri(program, str, false);
2352 503 resourcesStr := ProgramUtil.getFullPathFromUri(program, "modelica://" + AbsynUtil.pathFirstIdent(path) + "/Resources", false);
2353 isLinux := stringEq("linux",Autoconf.os);
2354 503 target := Flags.getConfigString(Flags.TARGET);
2355 // please, take care about ordering these libraries, the most specific should have the highest priority
2356 503 libs2 := getLinkerLibraryPaths(str, path, inLibs);
2357 503 libs := List.fold2(libs2, generateExtFunctionLibraryDirectoryFlags2, isLinux, target, libs);
2358 503 then (libs, listReverse(libs2), SOME(resourcesStr));
2359 else (inLibs, {}, NONE());
2360 end matchcontinue;
2361 end generateExtFunctionLibraryDirectoryFlags;
2362
2363 protected function generateExtFunctionLibraryDirectoryFlags2
2364 input String dir;
2365 input Boolean isLinux;
2366 input String target;
2367 input list<String> inLibs;
2368 output list<String> libs;
2369 algorithm
2370 // A wasm target loads modules by path (libPaths) instead of linking.
2371
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4024 times.
4024 if isWasmSimCodeTarget() then
2372 libs := inLibs;
2373 ✗ return;
2374 end if;
2375
1/2
✓ Branch 0 taken 4024 times.
✗ Branch 1 not taken.
4024 libs := if isLinux then "-Wl,-rpath=\"" + dir + "\""::inLibs else inLibs;
2376
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 4024 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
4024 libs := (if getGerneralTarget(target)=="msvc" then "/LIBPATH:\"" + dir + "\"" else "\"-L" + dir + "\"")::libs;
2377 end generateExtFunctionLibraryDirectoryFlags2;
2378
2379 protected function getGerneralTarget
2380 input String target;
2381 output String generalTarget;
2382 algorithm
2383
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5610 times.
5610 generalTarget := if (System.stringFind(target, "msvc") == 0) then "msvc" else target;
2384 end getGerneralTarget;
2385
2386
2387 protected function userCompiledBinariesDirectory
2388 input Absyn.Path path;
2389 output String str = Settings.getHomeDir(false)+"/.openmodelica/binaries/"+AbsynUtil.pathFirstIdent(path);
2390 end userCompiledBinariesDirectory;
2391
2392 constant String wasmLibraryTriple = "wasm32-wasip1";
2393
2394 protected function extLibraryBuildProjects
2395 "Build projects, most preferred first, relative to Resources. Only a CMake one
2396 can cross-compile, so only it can build the wasm module. Resources itself comes
2397 first: that is where the MSL puts the CMakeLists.txt a tool is meant to run."
2398 input String resources;
2399 input Boolean forWasm;
2400 output list<String> projects;
2401 protected
2402 list<String> dirs, cmakeProjects;
2403 algorithm
2404 ✗ dirs := list("BuildProjects/" + d for d in System.subDirectories(resources + "/BuildProjects"));
2405 ✗ if System.regularFileExists(resources + "/CMakeLists.txt") then
2406 dirs := "." :: dirs;
2407 end if;
2408 ✗ cmakeProjects := list(d for d guard
2409 System.regularFileExists(resources + "/" + d + "/CMakeLists.txt") in dirs);
2410 ✗ projects := if forWasm then cmakeProjects else
2411 listAppend(cmakeProjects, list(d for d guard
2412 not listMember(d, cmakeProjects) and
2413 System.regularFileExists(resources + "/" + d + "/autogen.sh") in dirs));
2414 end extLibraryBuildProjects;
2415
2416 protected function extLibraryBuildAttempted
2417 "Whether the build projects have already been run this session, and marks them
2418 run. A failed build installs nothing, so every further external function of the
2419 library would otherwise repeat it, copying the whole Resources tree each time."
2420 input String resources;
2421 input String name;
2422 input Boolean forWasm;
2423 output Boolean attempted;
2424 protected
2425 list<String> done;
2426 String key = resources + "\n" + name + "\n" + String(forWasm);
2427 algorithm
2428 ✗ done := getGlobalRoot(Global.extLibraryBuildIndex);
2429 ✗ attempted := listMember(key, done);
2430 ✗ if not attempted then
2431 ✗ setGlobalRoot(Global.extLibraryBuildIndex, key :: done);
2432 end if;
2433 end extLibraryBuildAttempted;
2434
2435 protected function extLibraryBuildCommand
2436 "Build and install one build project, run in an empty build directory for CMake
2437 and in the copied project directory for autotools."
2438 input Absyn.Path path;
2439 input Boolean forWasm;
2440 input String cmakeSourceDir "empty for an autotools project";
2441 output String cmd;
2442 protected
2443 String libdir, extra;
2444 algorithm
2445 ✗ libdir := userCompiledBinariesDirectory(path);
2446 ✗ if cmakeSourceDir <> "" then
2447 ✗ if forWasm then
2448 ✗ libdir := libdir + "/" + wasmLibraryTriple;
2449 // A wasm target loads a module rather than linking an archive.
2450 ✗ extra := " -DBUILD_SHARED_LIBS=ON \"-DCMAKE_TOOLCHAIN_FILE=" +
2451 Settings.getInstallationDirectoryPath() + "/share/omc/cmake/" +
2452 wasmLibraryTriple + ".cmake\"";
2453 else
2454 extra := "";
2455 end if;
2456 // How an MSL-shaped project asks for the tool's ModelicaUtilities.h.
2457 ✗ extra := extra + " \"-DMODELICA_UTILITIES_INCLUDE_DIR=" +
2458 Settings.getInstallationDirectoryPath() + "/include/omc/c\"";
2459 // -S/-B and `cmake --install` need a newer CMake than RHEL 8's 3.11.
2460 ✗ cmd := "cmake -DCMAKE_BUILD_TYPE=Release \"-DCMAKE_INSTALL_PREFIX=" +
2461 libdir + "\" -DCMAKE_INSTALL_LIBDIR=." + extra + " \"" + cmakeSourceDir +
2462 "\" && cmake --build . && cmake --build . --target install";
2463 else
2464 // TODO: Add $(host)
2465 ✗ cmd := "sh ./autogen.sh && ./configure --libdir='" + libdir + "' && make && make install";
2466 end if;
2467 end extLibraryBuildCommand;
2468
2469 protected function generateExtFunctionLibraryDirectoryPaths
2470 "Process LibraryDirectory and IncludeDirectory"
2471 input Absyn.Program program;
2472 input Absyn.Path path;
2473 input SCode.Mod inMod;
2474 output list<String> outLibs;
2475 algorithm
2476 outLibs := matchcontinue inMod
2477 local
2478 String str, platform1, platform2, platform3;
2479 list<String> libs;
2480 Boolean isLinux;
2481 case _
2482 algorithm
2483
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
608 SCode.MOD(binding = SOME(Absyn.STRING(str))) :=
2484 Mod.getUnelabedSubMod(inMod, "LibraryDirectory");
2485 ✗ str := ProgramUtil.getFullPathFromUri(program, str, false);
2486 ✗ platform1 := System.openModelicaPlatform();
2487 ✗ platform2 := System.openModelicaPlatformAlternative();
2488 ✗ platform3 := System.modelicaPlatform();
2489 isLinux := stringEq("linux",Autoconf.os);
2490 // please, take care about ordering these libraries, the most specific should go first (in reverse here)
2491 ✗ libs := generateExtFunctionLibraryDirectoryPaths2(true, str, isLinux, {} );
2492 ✗ libs := generateExtFunctionLibraryDirectoryPaths2(not stringEq(platform3,""), str + "/" + platform3, isLinux, libs);
2493 ✗ libs := generateExtFunctionLibraryDirectoryPaths2(not stringEq(platform2,""), str + "/" + platform2, isLinux, libs);
2494 ✗ libs := generateExtFunctionLibraryDirectoryPaths2(not stringEq(platform1,""), str + "/" + platform1, isLinux, libs);
2495 ✗ libs := generateExtFunctionLibraryDirectoryPaths2(isWasmSimCodeTarget(), str + "/wasm32-wasip1", isLinux, libs);
2496 then libs;
2497 case _
2498 algorithm
2499 608 str := "modelica://" + AbsynUtil.pathFirstIdent(path) + "/Resources/Library";
2500 608 str := ProgramUtil.getFullPathFromUri(program, str, false);
2501 581 platform1 := System.openModelicaPlatform();
2502 581 platform2 := System.openModelicaPlatformAlternative();
2503 581 platform3 := System.modelicaPlatform();
2504 isLinux := stringEq("linux",Autoconf.os);
2505 // please, take care about ordering these libraries, the most specific should go first (in reverse here)
2506 581 libs := generateExtFunctionLibraryDirectoryPaths2(true, str, isLinux, {} );
2507
1/4
✗ Branch 2 not taken.
✓ Branch 3 taken 581 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
581 libs := generateExtFunctionLibraryDirectoryPaths2(not stringEq(platform3,""), str + "/" + platform3, isLinux, libs);
2508
2/4
✓ Branch 2 taken 581 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 581 times.
581 libs := generateExtFunctionLibraryDirectoryPaths2(not stringEq(platform2,""), str + "/" + platform2, isLinux, libs);
2509
1/4
✗ Branch 2 not taken.
✓ Branch 3 taken 581 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
581 libs := generateExtFunctionLibraryDirectoryPaths2(not stringEq(platform1,""), str + "/" + platform1, isLinux, libs);
2510 581 libs := generateExtFunctionLibraryDirectoryPaths2(isWasmSimCodeTarget(), str + "/wasm32-wasip1", isLinux, libs);
2511 then libs;
2512 else {};
2513 end matchcontinue;
2514 end generateExtFunctionLibraryDirectoryPaths;
2515
2516
2517 protected function generateExtFunctionLibraryDirectoryPaths2
2518 input Boolean add;
2519 input String dir;
2520 input Boolean isLinux;
2521 input list<String> inLibs;
2522 output list<String> libs;
2523 algorithm
2524 libs := match (add, inLibs)
2525 local
2526 Boolean b;
2527 case (true, libs)
2528 algorithm
2529 1743 b := System.directoryExists(dir);
2530 1743 libs := List.consOnTrue(b, dir , libs);
2531 then libs;
2532 else inLibs;
2533 end match;
2534 end generateExtFunctionLibraryDirectoryPaths2;
2535
2536
2537 protected function getLibraryStringInMSVCFormat
2538 "Takes an Absyn.STRING describing a library and outputs a list
2539 of strings corresponding to it.
2540 Note: Normally only outputs a single string, but Lapack on MinGW is special."
2541 input Absyn.Exp exp;
2542 output list<String> strs;
2543 output list<String> names;
2544 algorithm
2545 (strs,names) := matchcontinue exp
2546 local
2547 String str;
2548
2549 // seems lapack can show on Lapack form or lapack (different case) (MLS revision 6155)
2550 // Lapack on MinGW/Windows is linked against f2c
2551 case Absyn.STRING(str) guard str=="Lapack" or str=="lapack"
2552 then ({"lapack_win32_MT.lib", "f2c.lib"}, {});
2553
2554 // omcruntime on windows needs linking with wsock and then some :)
2555 case Absyn.STRING("omcruntime")
2556 algorithm
2557 ✗ true := "Windows_NT" == Autoconf.os;
2558 strs := {"f2c.lib", "initialization.lib", "libexpat.lib", "math-support.lib", "meta.lib", "ModelicaExternalC.lib", "results.lib", "simulation.lib", "solver.lib", "sundials_kinsol.lib", "sundials_nvecserial.lib", "sundials_sunlinsolklu", "util.lib", "lapack_win32_MT.lib"};
2559 then
2560 (strs, {});
2561
2562 case Absyn.STRING("fmilib")
2563 then ({"fmilib.lib","shlwapi.lib"},{});
2564
2565 // A file is passed as it is, and if the string starts with a -, it's
2566 // probably a linker flag
2567 case Absyn.STRING(str)
2568 algorithm
2569 ✗ true := System.regularFileExists(str) or "-" == stringGetStringChar(str, 1);
2570 then ({str},{});
2571
2572 case Absyn.STRING(str)
2573 algorithm
2574 ✗ str := str + ".lib";
2575 then ({str},{});
2576
2577 else
2578 algorithm
2579 ✗ Error.addInternalError("Failed to process Library annotation for external function", sourceInfo());
2580 ✗ then fail();
2581 end matchcontinue;
2582 end getLibraryStringInMSVCFormat;
2583
2584 protected function getLibraryStringInGccFormat
2585 "Takes an Absyn.STRING describing a library and outputs a list
2586 of strings corresponding to it.
2587 Note: Normally only outputs a single string, but Lapack on MinGW is special."
2588 input Absyn.Exp exp;
2589 output list<String> strs;
2590 output list<String> names;
2591 algorithm
2592 (strs,names) := matchcontinue exp
2593 local
2594 String str;
2595 list<String> strs1, strs2, strs3, names1, names2, names3;
2596
2597 // Lapack is always included
2598 case Absyn.STRING("lapack") then ({},{});
2599 case Absyn.STRING("Lapack") then ({},{});
2600
2601 //pthreads is already linked under windows
2602 case Absyn.STRING("pthread") guard Autoconf.os=="Windows_NT"
2603 algorithm
2604 Error.addCompilerNotification("pthreads library is already available. It is not linked from the external library resource directory.\n");
2605 then ({},{});
2606
2607 //do not link rt.dll for Modelica Device Drivers as it is not needed under windows
2608 case Absyn.STRING("rt") guard Autoconf.os=="Windows_NT"
2609 algorithm
2610 Error.addCompilerNotification("rt library is not needed under Windows. It is not linked from the external library resource directory.\n");
2611 then ({},{});
2612
2613 //do not link Ws2_32.dll for Modelica Device Drivers as it is not needed under windows
2614 case Absyn.STRING("Ws2_32") guard Autoconf.os=="Windows_NT"
2615 algorithm
2616 Error.addCompilerNotification("Ws2_32 library is not needed under Windows. It is not linked from the external library resource directory.\n");
2617 then ({},{});
2618
2619 //user32 is already linked under windows
2620 case Absyn.STRING("User32") guard Autoconf.os=="Windows_NT"
2621 algorithm
2622 Error.addCompilerNotification("User32 library is already available. It is not linked from the external library resource directory.\n");
2623 then ({},{});
2624
2625 //winmm is a windows system lib
2626 case Absyn.STRING(str as "Winmm") guard Autoconf.os=="Windows_NT"
2627 algorithm
2628 str := "-l" + str;
2629 Error.addCompilerNotification("Winmm library is a windows system library. It is not linked from the external library resource directory.\n");
2630 then ({str},{});
2631
2632 //do not link X11.dll for Modelica Device Drivers as it is not needed under windows
2633 case Absyn.STRING("X11") guard Autoconf.os=="Windows_NT"
2634 algorithm
2635 Error.addCompilerNotification("X11 library is not needed under Windows. It is not linked from the external library resource directory.\n");
2636 then ({},{});
2637
2638 // The installed archive carries the MAT v7.3 paths, so a link line naming
2639 // it needs HDF5 too, ahead of the zlib that follows in the expansion below:
2640 // HDF5's deflate filter calls compress2.
2641 case Absyn.STRING("ModelicaMatIO") guard Autoconf.hdf5Libs <> ""
2642 then ({"-lModelicaMatIO", Autoconf.hdf5Libs},{});
2643
2644 case Absyn.STRING(str as "omcruntime")
2645 algorithm
2646 if "Windows_NT" == Autoconf.os then
2647 // omcruntime on windows needs linking with wsock and then some :)
2648 str := "-l" + str;
2649 strs := str :: "-lintl" :: "-liconv" :: "-lexpat" :: "-lsqlite3" :: "-ltre" :: "-lws2_32" :: "-lRpcrt4" :: "-lregex" :: {};
2650 else
2651 strs := Autoconf.systemLibs;
2652 end if;
2653 then (strs,{});
2654
2655 // One element per library, which the wasm-jit loads one by one.
2656 case Absyn.STRING("fmilib")
2657 259 then (if Autoconf.os=="Windows_NT" then {"-lfmilib","-lshlwapi"}
2658 elseif Autoconf.fmilibLibs == "" then {"-lfmilib"}
2659 else "-lfmilib" :: Util.stringSplitAtChar(Autoconf.fmilibLibs, " "),{});
2660
2661 case Absyn.STRING(str)
2662 algorithm
2663
3/4
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 861 times.
✓ Branch 3 taken 131 times.
✗ Branch 4 not taken.
992 if str=="ModelicaStandardTables" then
2664 // MSL 3.2.1 did not have the updated annotations...
2665 131 (strs1,names1) := getLibraryStringInGccFormat(Absyn.STRING("ModelicaIO"));
2666 131 (strs2,names2) := getLibraryStringInGccFormat(Absyn.STRING("ModelicaMatIO"));
2667 131 (strs3,names3) := getLibraryStringInGccFormat(Absyn.STRING("zlib"));
2668 131 strs := listAppend(strs1, listAppend(strs2, strs3));
2669 131 names := listAppend(names1, listAppend(names2, names3));
2670 else
2671 strs := {};
2672 names := {};
2673 end if;
2674 // If the string is a file, return it as it is
2675 // If the string starts with a -, it's probably -l or -L gcc flags
2676
4/6
✓ Branch 1 taken 978 times.
✓ Branch 2 taken 14 times.
✓ Branch 4 taken 978 times.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 978 times.
992 if System.regularFileExists(str) or "-" == stringGetStringChar(str, 1) then
2677 strs := str::strs;
2678 else
2679 978 strs := ("-l" + str)::strs;
2680 names := str::names;
2681 end if;
2682
2683 then (strs,names);
2684
2685 else
2686 algorithm
2687 ✗ Error.addInternalError("Failed to process Library annotation for external function", sourceInfo());
2688 ✗ then fail();
2689 end matchcontinue;
2690 end getLibraryStringInGccFormat;
2691
2692 protected function isWasmSimCodeTarget
2693 output Boolean isWasm = StringUtil.startsWith(Config.simCodeTarget(), "wasm");
2694 end isWasmSimCodeTarget;
2695
2696 protected function stripLibraryExtension
2697 "The base name of a library written for any target, so an annotation naming a host
2698 object file or shared library still identifies the wasm module."
2699 input String str;
2700 output String base = str;
2701 algorithm
2702 ✗ for ext in {".wasm", ".dylib", ".obj", ".dll", ".lib", ".so", ".a", ".o"} loop
2703 ✗ if StringUtil.endsWith(str, ext) then
2704 ✗ base := Util.removeLastNChar(str, stringLength(ext));
2705 ✗ return;
2706 end if;
2707 end for;
2708 end stripLibraryExtension;
2709
2710 protected function getLibraryStringInWasmFormat
2711 "The name of the wasm module implementing the library the Absyn.STRING describes.
2712 A wasm target has no linker: the annotation resolves to a PIC dylink module omc
2713 loads as-is, rather than to linker flags.
2714
2715 The gcc-format string follows it, so a native host running the wasm can fall back
2716 to the platform shared library for a function no wasm module implements."
2717 input Absyn.Exp exp;
2718 output list<String> strs;
2719 output list<String> names;
2720 algorithm
2721 (strs, names) := match exp
2722 local
2723 String str;
2724 list<String> host;
2725
2726 // In the runtime already: LAPACK/BLAS are in-wasm, and zlib is inside the
2727 // modules that use it.
2728 case Absyn.STRING("lapack") then ({},{});
2729 case Absyn.STRING("Lapack") then ({},{});
2730 case Absyn.STRING("blas") then ({},{});
2731 case Absyn.STRING("zlib") then ({},{});
2732 // The MSL's: the modules installed with it when there are, else the side
2733 // modules omc carries, never a platform library.
2734 case Absyn.STRING("ModelicaExternalC") then ({"ModelicaExternalC.wasm"},{});
2735 case Absyn.STRING("ModelicaStandardTables") then ({"ModelicaStandardTables.wasm"},{});
2736 case Absyn.STRING("ModelicaIO") then ({"ModelicaIO.wasm"},{});
2737 case Absyn.STRING("ModelicaMatIO") then ({"ModelicaMatIO.wasm"},{});
2738
2739 case Absyn.STRING(str)
2740 algorithm
2741 // Linker flags mean nothing here; only a library name can be resolved.
2742 ✗ if "-" == stringGetStringChar(str, 1) then
2743 strs := {};
2744 ✗ names := {};
2745 else
2746 ✗ (host, names) := getLibraryStringInGccFormat(exp);
2747 ✗ strs := (stripLibraryExtension(str) + ".wasm") :: host;
2748 end if;
2749 ✗ then (strs, names);
2750
2751 else
2752 algorithm
2753 ✗ Error.addInternalError("Failed to process Library annotation for external function", sourceInfo());
2754 ✗ then fail();
2755 end match;
2756 end getLibraryStringInWasmFormat;
2757
2758 protected function generateExtFunctionIncludesLibstr
2759 input String target;
2760 input SCode.Mod inMod;
2761 output list<String> outStringLst;
2762 output list<String> names;
2763 algorithm
2764 (outStringLst, names) := matchcontinue (if isWasmSimCodeTarget() then "wasm" else getGerneralTarget(target))
2765 local
2766 list<Absyn.Exp> arr;
2767 list<String> libs;
2768 list<list<String>> libsList, namesList;
2769 Absyn.Exp exp;
2770 case "wasm"
2771 algorithm
2772 ✗ SCode.MOD(binding = SOME(Absyn.ARRAY(arr))) :=
2773 Mod.getUnelabedSubMod(inMod, "Library");
2774 ✗ (libsList, namesList) := List.map_2(arr, getLibraryStringInWasmFormat);
2775 ✗ then
2776 (List.flatten(libsList), List.flatten(namesList));
2777 case "wasm"
2778 algorithm
2779 ✗ SCode.MOD(binding = SOME(exp)) :=
2780 Mod.getUnelabedSubMod(inMod, "Library");
2781 ✗ (libs,names) := getLibraryStringInWasmFormat(exp);
2782 then
2783 (libs,names);
2784 case "msvc"
2785 algorithm
2786 ✗ SCode.MOD(binding = SOME(Absyn.ARRAY(arr))) :=
2787 Mod.getUnelabedSubMod(inMod, "Library");
2788 ✗ (libsList, namesList) := List.map_2(arr, getLibraryStringInMSVCFormat);
2789 ✗ then
2790 (List.flatten(libsList), List.flatten(namesList));
2791 case "msvc"
2792 algorithm
2793 ✗ SCode.MOD(binding = SOME(exp)) :=
2794 Mod.getUnelabedSubMod(inMod, "Library");
2795 ✗ (libs,names) := getLibraryStringInMSVCFormat(exp);
2796 then
2797 (libs,names);
2798 case _
2799 algorithm
2800
5/8
✗ Branch 1 not taken.
✓ Branch 2 taken 541 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 541 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 541 times.
✓ Branch 7 taken 138 times.
✓ Branch 8 taken 403 times.
608 SCode.MOD(binding = SOME(Absyn.ARRAY(arr))) :=
2801 Mod.getUnelabedSubMod(inMod, "Library");
2802 403 (libsList, namesList) := List.map_2(arr, getLibraryStringInGccFormat);
2803 403 then
2804 (List.flatten(libsList), List.flatten(namesList));
2805 case _
2806 algorithm
2807
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 138 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 138 times.
205 SCode.MOD(binding = SOME(exp)) :=
2808 Mod.getUnelabedSubMod(inMod, "Library");
2809 138 (libs,names) := getLibraryStringInGccFormat(exp);
2810 then
2811 (libs,names);
2812 67 else ({},{});
2813 end matchcontinue;
2814 end generateExtFunctionIncludesLibstr;
2815
2816 protected function generateExtFunctionIncludesIncludestr
2817 input SCode.Mod inMod;
2818 output list<String> includes;
2819 algorithm
2820 includes := matchcontinue inMod
2821 local
2822 String inc, inc_1;
2823 Integer lineNumberStart;
2824 String str,fileName;
2825 case _
2826 algorithm
2827
4/8
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 120 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 120 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 120 times.
608 SCode.MOD(binding = SOME(Absyn.STRING(inc)), info = SOURCEINFO(fileName=fileName,lineNumberStart=lineNumberStart)) :=
2828 Mod.getUnelabedSubMod(inMod, "Include");
2829 120 str := "#line "+intString(lineNumberStart)+" \""+fileName+"\"";
2830 120 inc_1 := System.unescapedString(inc);
2831
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
120 includes := if /*Config.acceptMetaModelicaGrammar() or*/ Flags.isSet(Flags.GEN_DEBUG_SYMBOLS) then {str,inc_1} else {inc_1};
2832 then includes;
2833 else {};
2834 end matchcontinue;
2835 end generateExtFunctionIncludesIncludestr;
2836
2837 protected function generateExtFunctionDynamicLoad
2838 input SCode.Mod inMod;
2839 output Boolean outDynamicLoad;
2840 algorithm
2841 outDynamicLoad:= matchcontinue inMod
2842 local
2843 Boolean b;
2844 case _
2845 algorithm
2846
0/8
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
608 SCode.MOD(binding = SOME((Absyn.BOOL(b)))) :=
2847 Mod.getUnelabedSubMod(inMod, "DynamicLoad");
2848 then
2849 b;
2850 else false;
2851 end matchcontinue;
2852 end generateExtFunctionDynamicLoad;
2853
2854 public function getImplicitRecordConstructors
2855 "If a record instance is sent to a function we need to generate code for the
2856 record constructor even if it's not explicitly called, because the constructor
2857 is used by the generated code. This function checks the arguments of a
2858 function for these implicit record constructor calls and returns a list of all
2859 record constructors that are used."
2860 input list<DAE.Exp> inExpLst;
2861 output list<DAE.Exp> outExpLst;
2862 algorithm
2863 outExpLst := matchcontinue inExpLst
2864 local
2865 DAE.ComponentRef cref;
2866 Absyn.Path record_path;
2867 list<DAE.Exp> rest_expr;
2868 DAE.Exp record_cref;
2869 case {} then {};
2870 // A record component reference.
2871 case DAE.CREF(
2872 componentRef = cref,
2873 ty = (DAE.T_COMPLEX(
2874 complexClassType = ClassInf.RECORD(path = record_path)))) :: rest_expr
2875 algorithm
2876 // Make sure it has no subscripts, i.e. it's a component reference for
2877 // an entire record instance.
2878 ✗ {} := ComponentReference.crefLastSubs(cref);
2879 // Build a DAE.CREF from the record path.
2880 ✗ cref := ComponentReference.pathToCref(record_path);
2881 ✗ record_cref := Expression.crefExp(cref);
2882 ✗ rest_expr := getImplicitRecordConstructors(rest_expr);
2883 then record_cref :: rest_expr;
2884 case _ :: rest_expr
2885 algorithm
2886 ✗ rest_expr := getImplicitRecordConstructors(rest_expr);
2887 then rest_expr;
2888 end matchcontinue;
2889 end getImplicitRecordConstructors;
2890
2891 protected function getCalledFunctionsInFunctions "Goes through the given DAE, finds the given functions and collects
2892 the names of the functions called from within those functions"
2893 input list<Absyn.Path> paths;
2894 input HashTableStringToPath.HashTable inHt;
2895 input AvlTreePathFunction.Tree funcs;
2896 output HashTableStringToPath.HashTable outHt;
2897 algorithm
2898 outHt := match (paths, inHt)
2899 local
2900 list<Absyn.Path> rest;
2901 Absyn.Path path;
2902 HashTableStringToPath.HashTable ht;
2903
2904 case ({}, ht) then ht;
2905 case (path::rest, ht)
2906 algorithm
2907 8793 ht := getCalledFunctionsInFunction2(path, AbsynUtil.pathStringNoQual(path), ht, funcs);
2908 8789 ht := getCalledFunctionsInFunctions(rest, ht, funcs);
2909 then ht;
2910 end match;
2911 end getCalledFunctionsInFunctions;
2912
2913 public function getCalledFunctionsInFunction2 "Goes through the given DAE, finds the given function and collects
2914 the names of the functions called from within those functions"
2915 input Absyn.Path inPath;
2916 input String pathstr;
2917 input HashTableStringToPath.HashTable inHt "paths to not add";
2918 input AvlTreePathFunction.Tree funcs;
2919 output HashTableStringToPath.HashTable outHt "paths to not add";
2920 algorithm
2921 outHt := matchcontinue (inPath, inHt)
2922 local
2923 String str;
2924 Absyn.Path path;
2925 DAE.Function funcelem;
2926 list<Absyn.Path> calledfuncs, varfuncs;
2927 list<DAE.Element> els;
2928 HashTableStringToPath.HashTable ht;
2929
2930 case (_, ht)
2931 guard BaseHashTable.hasKey(pathstr, ht)
2932 then ht;
2933
2934 case (path, ht)
2935 algorithm
2936 1878 funcelem := DAEUtil.getNamedFunction(path, funcs);
2937 1874 els := DAEUtil.getFunctionElements(funcelem);
2938 // SimCodeFunction.Function reference variables are filtered out
2939 1874 varfuncs := List.fold(els, DAEUtil.collectFunctionRefVarPaths, {});
2940 1874 (_, (_, varfuncs)) := DAEUtil.traverseDAEElementList(els, Expression.traverseSubexpressionsHelper, (DAEUtil.collectValueblockFunctionRefVars, varfuncs));
2941 1874 (_, (_, (calledfuncs, _))) := DAEUtil.traverseDAEElementList(els, Expression.traverseSubexpressionsHelper, (matchNonBuiltinCallsAndFnRefPaths, ({}, varfuncs)));
2942 1874 ht := BaseHashTable.add((pathstr, path), ht);
2943 1874 ht := addDestructor(funcelem, ht);
2944 1874 ht := getCalledFunctionsInFunctions(calledfuncs, ht, funcs);
2945 then ht;
2946
2947 case (path, _)
2948 algorithm
2949
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 failure(DAEUtil.getNamedFunction(path, funcs));
2950 4 str := "function getCalledFunctionsInFunction2: Class " + pathstr + " not found in global scope.";
2951 4 Error.addInternalError(str, sourceInfo());
2952 4 then
2953 fail();
2954 end matchcontinue;
2955 end getCalledFunctionsInFunction2;
2956
2957 public function getCalledFunctionsInFunction
2958 "Goes through the given DAE, finds the given function and collects
2959 the names of the functions called from within those functions.
2960 Lives here (next to its helper getCalledFunctionsInFunction2) rather than in
2961 SimCodeFunction so the SimCodeFunction datatype package does not depend on
2962 this function package."
2963 input Absyn.Path path;
2964 input AvlTreePathFunction.Tree funcs;
2965 output list<Absyn.Path> outPaths;
2966 protected
2967 HashTableStringToPath.HashTable ht;
2968 algorithm
2969 152 ht := HashTableStringToPath.emptyHashTable();
2970 152 ht := getCalledFunctionsInFunction2(path,AbsynUtil.pathStringNoQual(path),ht,funcs);
2971 148 outPaths := BaseHashTable.hashTableValueList(ht);
2972 end getCalledFunctionsInFunction;
2973
2974 protected function addDestructor
2975 input DAE.Function func;
2976 input HashTableStringToPath.HashTable inHt;
2977 output HashTableStringToPath.HashTable outHt;
2978 algorithm
2979 outHt := match func
2980 local
2981 Absyn.Path path;
2982 case DAE.FUNCTION(type_=DAE.T_FUNCTION(funcResultType=DAE.T_COMPLEX(complexClassType=ClassInf.EXTERNAL_OBJ(path=path))))
2983 algorithm
2984 5 path := AbsynUtil.joinPaths(path,Absyn.IDENT("destructor"));
2985 5 then addDestructor2(path,AbsynUtil.pathStringNoQual(path),inHt);
2986 else inHt;
2987 end match;
2988 end addDestructor;
2989
2990 protected function addDestructor2
2991 input Absyn.Path path;
2992 input String pathstr;
2993 input HashTableStringToPath.HashTable inHt;
2994 output HashTableStringToPath.HashTable ht = inHt;
2995 algorithm
2996
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if not BaseHashTable.hasKey(pathstr, ht) then
2997 5 ht := BaseHashTable.add((pathstr, path), ht);
2998 end if;
2999 end addDestructor2;
3000
3001 protected function matchNonBuiltinCallsAndFnRefPaths "The extra argument is a tuple<list, list>; the second list is the list of variable
3002 names to filter out (so we don't add function references variables)"
3003 input DAE.Exp inExp;
3004 input tuple<list<Absyn.Path>, list<Absyn.Path>> itpl;
3005 output DAE.Exp outExp;
3006 output tuple<list<Absyn.Path>, list<Absyn.Path>> otpl;
3007 algorithm
3008 (outExp,otpl) := matchcontinue (inExp,itpl)
3009 local
3010 Absyn.Path path;
3011 list<Absyn.Path> acc, filter;
3012 case (DAE.CALL(path = path, attr = DAE.CALL_ATTR(builtin = false)), (acc, filter))
3013 algorithm
3014 8668 path := AbsynUtil.makeNotFullyQualified(path);
3015
2/2
✓ Branch 1 taken 166 times.
✓ Branch 2 taken 8502 times.
8668 false := List.isMemberOnTrue(path, filter, AbsynUtil.pathEqual);
3016 8502 then (inExp, (path::acc, filter));
3017 case (DAE.REDUCTION(reductionInfo = DAE.REDUCTIONINFO(path = path)), (acc, filter))
3018 algorithm
3019
2/2
✓ Branch 1 taken 123 times.
✓ Branch 2 taken 10 times.
133 false := List.isMemberOnTrue(path, {Absyn.IDENT("list"),Absyn.IDENT("listReverse"),Absyn.IDENT("array"),Absyn.IDENT("min"),Absyn.IDENT("max"),Absyn.IDENT("sum"),Absyn.IDENT("product")}, AbsynUtil.pathEqual);
3020
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 false := List.isMemberOnTrue(path, filter, AbsynUtil.pathEqual);
3021 10 then (inExp, (path::acc, filter));
3022 case (DAE.PARTEVALFUNCTION(path = path), (acc, filter))
3023 algorithm
3024 24 path := AbsynUtil.makeNotFullyQualified(path);
3025
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 20 times.
24 false := List.isMemberOnTrue(path, filter, AbsynUtil.pathEqual);
3026 20 then (inExp, (path::acc, filter));
3027 case (DAE.CREF(ty = DAE.T_FUNCTION_REFERENCE_FUNC(builtin = false)), (acc, filter))
3028 algorithm
3029 261 path := AbsynUtil.crefToPath(getCrefFromExp(inExp));
3030
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 261 times.
261 false := List.isMemberOnTrue(path, filter, AbsynUtil.pathEqual);
3031 261 then (inExp, (path::acc, filter));
3032 else (inExp,itpl);
3033 end matchcontinue;
3034 end matchNonBuiltinCallsAndFnRefPaths;
3035
3036 protected function aliasRecordDeclarations
3037 input SimCodeFunction.RecordDeclaration inDecl;
3038 input HashTableStringToPath.HashTable inHt;
3039 output SimCodeFunction.RecordDeclaration decl;
3040 output HashTableStringToPath.HashTable ht;
3041 algorithm
3042 (decl,ht) := match inDecl
3043 local
3044 list<SimCodeFunction.Variable> vars;
3045 Absyn.Path name;
3046 String str,sname;
3047 Option<String> alias;
3048 Boolean extConvert;
3049 case SimCodeFunction.RECORD_DECL_FULL(sname, _, name, vars, extConvert)
3050 algorithm
3051 4332 str := stringDelimitList(List.map(vars, variableString), "\n");
3052 4332 (alias,ht) := aliasRecordDeclarations2(str, name, inHt);
3053
2/2
✓ Branch 0 taken 1420 times.
✓ Branch 1 taken 2912 times.
5752 then (SimCodeFunction.RECORD_DECL_FULL(sname, alias, name, vars, extConvert),ht);
3054 else (inDecl,inHt);
3055 end match;
3056 end aliasRecordDeclarations;
3057
3058 protected function aliasRecordDeclarations2
3059 input String str;
3060 input Absyn.Path path;
3061 input HashTableStringToPath.HashTable inHt;
3062 output Option<String> alias;
3063 output HashTableStringToPath.HashTable ht;
3064 algorithm
3065 (alias,ht) := matchcontinue inHt
3066 local
3067 String aliasStr;
3068 case _
3069 algorithm
3070 4332 aliasStr := AbsynUtil.pathStringUnquoteReplaceDot(BaseHashTable.get(str, inHt),"_");
3071 then (SOME(aliasStr),inHt);
3072 else
3073 algorithm
3074 980 ht := BaseHashTable.add((str,path),inHt);
3075 then (NONE(),ht);
3076 end matchcontinue;
3077 end aliasRecordDeclarations2;
3078
3079 protected function variableString
3080 "The member as it is laid out in the struct: an array member is an array
3081 descriptor whatever its dimension sizes."
3082 input SimCodeFunction.Variable var;
3083 output String str;
3084 algorithm
3085 str := match var
3086 local
3087 DAE.ComponentRef name;
3088 DAE.Type ty;
3089 case SimCodeFunction.VARIABLE(name=name, ty=ty)
3090 43452 then TypesDump.unparseType(Types.arrayElementType(ty)) + "[" + intString(Types.numberOfDimensions(ty)) + "] " + ComponentReferenceBasics.printComponentRefStr(name);
3091 case SimCodeFunction.FUNCTION_PTR(name=str)
3092 ✗ then "modelica_fnptr " + str;
3093 end match;
3094 end variableString;
3095
3096 public function createMakefileParams
3097 input list<String> includes;
3098 input list<String> libs;
3099 input list<String> libPaths;
3100 input Boolean isFunction;
3101 input Boolean isFMU=false;
3102 output SimCodeFunction.MakefileParams makefileParams;
3103 protected
3104 String omhome, ccompiler, cxxcompiler, linker, exeext, dllext, cflags, ldflags, rtlibs, platform, compileDir;
3105 algorithm
3106
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 1486 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 1478 times.
1486 ccompiler := if stringEq(Config.simCodeTarget(),"JavaScript") then "emcc" else
3107 (if Flags.isSet(Flags.HPCOM) then System.getOMPCCompiler() else System.getCCompiler());
3108
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1486 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
1486 cxxcompiler := if stringEq(Config.simCodeTarget(),"JavaScript") then "emcc" else System.getCXXCompiler();
3109
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1486 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
1486 linker := if stringEq(Config.simCodeTarget(),"JavaScript") then "emcc" else System.getLinker();
3110
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1486 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
1486 exeext := if stringEq(Config.simCodeTarget(),"JavaScript") then ".js" else Autoconf.exeExt;
3111 dllext := Autoconf.dllExt;
3112 1486 omhome := Settings.getInstallationDirectoryPath();
3113 1486 omhome := System.trim(omhome, "\""); // Remove any quotation marks from omhome.
3114
2/2
✓ Branch 3 taken 1478 times.
✓ Branch 4 taken 8 times.
2964 cflags := System.getCFlags() + " " +
3115 (if Flags.isSet(Flags.HPCOM) then "-fopenmp" else "");
3116
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1486 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
1486 cflags := if stringEq(Config.simCodeTarget(),"JavaScript") then "-Os -Wno-warn-absolute-paths" else cflags;
3117 1486 ldflags := System.getLDFlags();
3118 // The Rust simulation runtime serves ParModelica/auto's own interface, so
3119 // linking the C++ one beside it would define PM_Model_create and friends twice.
3120
3/4
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1485 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
1486 if Flags.getConfigBool(Flags.PARMODAUTO) and not Config.simCodeRustRuntime() then
3121 ✗ ldflags := " " + Autoconf.parModelicaAutoLibs + " " + ldflags;
3122 end if;
3123 // A MetaModelica function library is dlopened into omc and hands values back
3124 // through omc's own vocabulary, so it links the runtime omc links.
3125
8/8
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 1338 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 112 times.
✓ Branch 5 taken 1171 times.
✓ Branch 6 taken 167 times.
✓ Branch 8 taken 45 times.
✓ Branch 9 taken 1126 times.
1486 rtlibs := if isFunction then (if Config.acceptMetaModelicaGrammar() then Autoconf.ldflags_runtime_mmc else Autoconf.ldflags_runtime)
3126 elseif isFMU then Autoconf.ldflags_runtime_fmu
3127 elseif Config.simCodeRustRuntime() then Autoconf.ldflags_runtime_sim_rust
3128 else Autoconf.ldflags_runtime_sim;
3129 1486 platform := System.modelicaPlatform();
3130 1486 compileDir := System.pwd() + Autoconf.pathDelimiter;
3131 1486 makefileParams := SimCodeFunction.MAKEFILE_PARAMS(ccompiler, cxxcompiler, linker, exeext, dllext,
3132 omhome, cflags, ldflags, rtlibs, includes, libs,libPaths, platform,compileDir);
3133 end createMakefileParams;
3134
3135 public
3136
3137 function codegenResetTryThrowIndex
3138 algorithm
3139 37948 setGlobalRoot(Global.codegenTryThrowIndex, {});
3140 end codegenResetTryThrowIndex;
3141
3142 function codegenPushTryThrowIndex
3143 input Integer i;
3144 protected
3145 list<Integer> lst;
3146 algorithm
3147 1174 lst := getGlobalRoot(Global.codegenTryThrowIndex);
3148 1174 setGlobalRoot(Global.codegenTryThrowIndex, i::lst);
3149 end codegenPushTryThrowIndex;
3150
3151 function codegenPopTryThrowIndex
3152 protected
3153 list<Integer> lst;
3154 algorithm
3155 1174 lst := getGlobalRoot(Global.codegenTryThrowIndex);
3156
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1174 times.
1174 _::lst := lst;
3157 1174 setGlobalRoot(Global.codegenTryThrowIndex, lst);
3158 end codegenPopTryThrowIndex;
3159
3160 function codegenPeekTryThrowIndex
3161 output Integer i;
3162 protected
3163 list<Integer> lst;
3164 algorithm
3165 3414 lst := getGlobalRoot(Global.codegenTryThrowIndex);
3166 i := match lst
3167 case i::_ then i;
3168 else -1;
3169 end match;
3170 end codegenPeekTryThrowIndex;
3171
3172 public function varIndex
3173 input SimCodeVar.SimVar var;
3174 output Integer index;
3175 algorithm
3176 ✗ SimCodeVar.SIMVAR(index=index) := var;
3177 end varIndex;
3178
3179 public function isParallelFunctionContext
3180 input SimCodeFunction.Context context;
3181 output Boolean outBool;
3182 algorithm
3183 outBool := match context
3184 20316 case SimCodeFunction.FUNCTION_CONTEXT() then context.is_parallel;
3185 else false;
3186 end match;
3187 end isParallelFunctionContext;
3188
3189 function twodigit
3190 input Integer i;
3191 output String outS;
3192 algorithm
3193 outS :=
3194 match i
3195 local String s;
3196 case _ guard i < 10
3197 algorithm
3198 126 s := intString(i);
3199 126 s := stringAppend("0", s);
3200 then
3201 s;
3202 349 else intString(i);
3203 end match;
3204 end twodigit;
3205
3206 public function generateSubPalceholders
3207 input DAE.ComponentRef cr;
3208 output String outdef;
3209 protected
3210 list<DAE.Dimension> dims;
3211 Integer nrdims;
3212 list<String> idxstrlst;
3213 algorithm
3214 ✗ dims := ComponentReferenceBasics.crefDims(cr);
3215 ✗ nrdims := listLength(dims);
3216 ✗ idxstrlst := List.map(List.intRange(nrdims),intString);
3217 ✗ outdef := stringDelimitList(List.threadMap(List.fill("i_", nrdims), idxstrlst, stringAppend), ",");
3218 end generateSubPalceholders;
3219
3220
3221 /* This functions are used to get/append cref prefixes in function contexts.The cref prefix is appended
3222 to all crefs generated. We use this to generate dependent names in some cases (for example when generating
3223 code for record constructors) so that every cref we generate while this is set has this prefix applied to it*/
3224 public function getCurrentCrefPrefix
3225 input SimCodeFunction.Context context;
3226 output String cref_pref;
3227 algorithm
3228 cref_pref := match context
3229 case SimCodeFunction.FUNCTION_CONTEXT(cref_pref, _) then cref_pref;
3230 ✗ else algorithm Error.addInternalError("Tried to get cref prefix from a non FUNCTION_CONTEXT() context. cref_pref is only avaiable in FUNCTION_CONTEXT.", sourceInfo()); then fail();
3231 end match;
3232 end getCurrentCrefPrefix;
3233
3234 public function appendCurrentCrefPrefix
3235 input SimCodeFunction.Context context;
3236 input String in_cref_pref;
3237 output SimCodeFunction.Context out_context;
3238 protected
3239 String cref_pref;
3240 Boolean prl;
3241 algorithm
3242 out_context := match context
3243
1/2
✓ Branch 1 taken 42939 times.
✗ Branch 2 not taken.
85878 case SimCodeFunction.FUNCTION_CONTEXT(cref_pref, prl) then SimCodeFunction.FUNCTION_CONTEXT(cref_pref + in_cref_pref, prl);
3244 ✗ else algorithm Error.addInternalError("Tried to append cref prefix from a non FUNCTION_CONTEXT() context. cref_pref is only avaiable in FUNCTION_CONTEXT.", sourceInfo()); then fail();
3245 end match;
3246 end appendCurrentCrefPrefix;
3247
3248 annotation(__OpenModelica_Interface="simcode_util");
3249 end SimCodeFunctionUtil;
3250