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 |