OMCompiler/Compiler/NBackEnd/Util/NBReplacements.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 uniontype NBReplacements | ||
| 37 | "file: NBReplacements.mo | ||
| 38 | package: NBReplacements | ||
| 39 | description: | ||
| 40 | Replacements consists of a mapping between variables and expressions, the first binary tree of this type. | ||
| 41 | To eliminate a variable from an equation system a replacement rule varname->expression is added to this | ||
| 42 | datatype. | ||
| 43 | To be able to update these replacement rules incrementally a backward lookup mechanism is also required. | ||
| 44 | For instance, having a rule a->b and adding a rule b->c requires to find the first rule a->b and update it to | ||
| 45 | a->c. This is what the second binary tree is used for. | ||
| 46 | " | ||
| 47 | |||
| 48 | protected | ||
| 49 | // rename self import | ||
| 50 | import Replacements = NBReplacements; | ||
| 51 | |||
| 52 | // OF imports | ||
| 53 | import Absyn; | ||
| 54 | |||
| 55 | // NF imports | ||
| 56 | import Binding = NFBinding; | ||
| 57 | import Call = NFCall; | ||
| 58 | import ComponentRef = NFComponentRef; | ||
| 59 | import Expression = NFExpression; | ||
| 60 | import NFInstNode.InstNode; | ||
| 61 | import InstContext = NFInstContext; | ||
| 62 | import NFFunction.Function; | ||
| 63 | import SimplifyExp = NFSimplifyExp; | ||
| 64 | import Statement = NFStatement; | ||
| 65 | import Subscript = NFSubscript; | ||
| 66 | import Type = NFType; | ||
| 67 | import Typing = NFTyping; | ||
| 68 | import Variable = NFVariable; | ||
| 69 | |||
| 70 | // Backend imports | ||
| 71 | import BVariable = NBVariable; | ||
| 72 | import NBEquation.{EqData, Equation, EquationPointers}; | ||
| 73 | import Inline = NBInline; | ||
| 74 | import Slice = NBSlice; | ||
| 75 | import Solve = NBSolve; | ||
| 76 | import StrongComponent = NBStrongComponent; | ||
| 77 | import NBVariable.{VarData, VariablePointers}; | ||
| 78 | |||
| 79 | // Util | ||
| 80 | import StringUtil; | ||
| 81 | |||
| 82 | public | ||
| 83 | // ========================================================================= | ||
| 84 | // COMPONENT REFERENCE REPLACEMENT | ||
| 85 | // ========================================================================= | ||
| 86 | |||
| 87 | function single | ||
| 88 | "performs a single replacement" | ||
| 89 | input output Expression exp "Replacement happens inside this expression"; | ||
| 90 | input Expression old "Replaced by new"; | ||
| 91 | input Expression new "Replaces old"; | ||
| 92 | protected | ||
| 93 | function traverse | ||
| 94 | input output Expression exp; | ||
| 95 | input Expression old; | ||
| 96 | input Expression new; | ||
| 97 | algorithm | ||
| 98 |
2/2✓ Branch 1 taken 168 times.
✓ Branch 2 taken 97 times.
|
265 | exp := if Expression.isEqual(exp, old) then new else exp; |
| 99 | end traverse; | ||
| 100 | algorithm | ||
| 101 | 93 | exp := Expression.map(exp, function traverse(old = old, new = new)); | |
| 102 | end single; | ||
| 103 | |||
| 104 | function simple | ||
| 105 | "creates simple replacement rules for alias removal" | ||
| 106 | input list<StrongComponent> comps; | ||
| 107 | input UnorderedMap<ComponentRef, Expression> replacements; | ||
| 108 | algorithm | ||
| 109 |
2/2✓ Branch 0 taken 1936 times.
✓ Branch 1 taken 1105 times.
|
3041 | for comp in comps loop |
| 110 | 1936 | addSimple(comp, replacements); | |
| 111 | end for; | ||
| 112 | end simple; | ||
| 113 | |||
| 114 | function addSimple | ||
| 115 | "ToDo: More cases!" | ||
| 116 | input StrongComponent comp; | ||
| 117 | input UnorderedMap<ComponentRef, Expression> replacements; | ||
| 118 | algorithm | ||
| 119 | () := match comp | ||
| 120 | local | ||
| 121 | ComponentRef varName; | ||
| 122 | Equation solvedEq; | ||
| 123 | Solve.Status status; | ||
| 124 | Expression replace_exp; | ||
| 125 | |||
| 126 | case StrongComponent.SINGLE_COMPONENT() algorithm | ||
| 127 | // solve the equation for the variable | ||
| 128 | 1920 | varName := BVariable.getVarName(comp.var); | |
| 129 | 1920 | (solvedEq, status, _) := Solve.solveBody(Pointer.access(comp.eqn), varName); | |
| 130 |
1/2✓ Branch 0 taken 1920 times.
✗ Branch 1 not taken.
|
1920 | if status == NBSolve.Status.EXPLICIT then |
| 131 | // apply all previous replacements on the RHS | ||
| 132 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 1920 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1920 times.
|
1920 | SOME(replace_exp) := Equation.getRHS(solvedEq); |
| 133 | 1920 | replace_exp := Expression.map(replace_exp, function applySimpleExp(replacements = replacements)); | |
| 134 | 1920 | replace_exp := SimplifyExp.simplifyDump(replace_exp, true, getInstanceName()); | |
| 135 | // add the new replacement rule | ||
| 136 | 1920 | addInputArgTpl((varName, replace_exp) , replacements, true); | |
| 137 | else | ||
| 138 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because strong component cannot be solved explicitly: " + StrongComponent.toString(comp)}); | |
| 139 | ✗ | fail(); | |
| 140 | end if; | ||
| 141 | then (); | ||
| 142 | |||
| 143 | case StrongComponent.SLICED_COMPONENT() algorithm | ||
| 144 | // solve the equation for the variable | ||
| 145 | 16 | varName := BVariable.getVarName(Slice.getT(comp.var)); | |
| 146 | 16 | (solvedEq, status, _) := Solve.solveBody(Pointer.access(Slice.getT(comp.eqn)), varName); | |
| 147 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | if status == NBSolve.Status.EXPLICIT then |
| 148 | // apply all previous replacements on the RHS | ||
| 149 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
|
16 | SOME(replace_exp) := Equation.getRHS(solvedEq); |
| 150 | 16 | replace_exp := Expression.map(replace_exp, function applySimpleExp(replacements = replacements)); | |
| 151 | 16 | replace_exp := SimplifyExp.simplifyDump(replace_exp, true, getInstanceName()); | |
| 152 | // add the new replacement rule | ||
| 153 | 16 | addInputArgTpl((varName, replace_exp) , replacements, true); | |
| 154 | else | ||
| 155 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because strong component cannot be solved explicitly: " + StrongComponent.toString(comp)}); | |
| 156 | ✗ | fail(); | |
| 157 | end if; | ||
| 158 | then (); | ||
| 159 | |||
| 160 | else algorithm | ||
| 161 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because strong component is not simple: " + StrongComponent.toString(comp)}); | |
| 162 | ✗ | then fail(); | |
| 163 | end match; | ||
| 164 | end addSimple; | ||
| 165 | |||
| 166 | function applySimple | ||
| 167 | "Used for alias removal. | ||
| 168 | This should be applied before partitioning. Otherwise all systems have to be checked for jacobians | ||
| 169 | and hessians on which this also has to be applied. Can be applied on single jacobians and hessians | ||
| 170 | while removing simple equations on them." | ||
| 171 | input output EqData eqData; | ||
| 172 | input output VarData varData; // bindings | ||
| 173 | input UnorderedMap<ComponentRef, Expression> replacements "rules for replacements are stored inside here"; | ||
| 174 | protected | ||
| 175 | list<tuple<ComponentRef, Expression>> entries; | ||
| 176 | ComponentRef aliasCref; | ||
| 177 | Expression replacement; | ||
| 178 | Pointer<Variable> var_ptr; | ||
| 179 | Variable var; | ||
| 180 | algorithm | ||
| 181 | // do nothing if replacements are empty | ||
| 182 |
2/2✓ Branch 1 taken 287 times.
✓ Branch 2 taken 93 times.
|
380 | if UnorderedMap.isEmpty(replacements) then return; end if; |
| 183 | 186 | eqData := EqData.mapExp(eqData, function applySimpleExp(replacements = replacements), SOME(function applySimpleCref(replacements = replacements))); | |
| 184 | |||
| 185 | // apply on bindings (is this necessary?) | ||
| 186 | varData := match varData | ||
| 187 | case VarData.VAR_DATA_SIM() algorithm | ||
| 188 | 186 | varData.variables := VariablePointers.map(varData.variables, function applySimpleVar(replacements = replacements)); | |
| 189 | 186 | varData.aliasVars := VariablePointers.map(varData.aliasVars, function applySimpleVar(replacements = replacements)); | |
| 190 | then varData; | ||
| 191 | case VarData.VAR_DATA_JAC() algorithm | ||
| 192 | ✗ | varData.variables := VariablePointers.map(varData.variables, function applySimpleVar(replacements = replacements)); | |
| 193 | then varData; | ||
| 194 | case VarData.VAR_DATA_HES() algorithm | ||
| 195 | ✗ | varData.variables := VariablePointers.map(varData.variables, function applySimpleVar(replacements = replacements)); | |
| 196 | then varData; | ||
| 197 | end match; | ||
| 198 | |||
| 199 | // update alias variable bindings | ||
| 200 | 93 | entries := UnorderedMap.toList(replacements); | |
| 201 |
2/2✓ Branch 0 taken 2030 times.
✓ Branch 1 taken 93 times.
|
2123 | for entry in entries loop |
| 202 | 2030 | (aliasCref, replacement) := entry; | |
| 203 | 2030 | var_ptr := BVariable.getVarPointer(aliasCref, sourceInfo()); | |
| 204 | 2030 | var := Pointer.access(var_ptr); | |
| 205 | 2030 | var.binding := Binding.update(var.binding, replacement); | |
| 206 | 2030 | Pointer.update(var_ptr, var); | |
| 207 | end for; | ||
| 208 | end applySimple; | ||
| 209 | |||
| 210 | function applySimpleExp | ||
| 211 | "Needs to be mapped with Expression.map()" | ||
| 212 | input output Expression exp "Replacement happens inside this expression"; | ||
| 213 | input UnorderedMap<ComponentRef, Expression> replacements "rules for replacements are stored inside here"; | ||
| 214 | algorithm | ||
| 215 | exp := match exp | ||
| 216 | local | ||
| 217 | Expression res; | ||
| 218 | ComponentRef stripped; | ||
| 219 | list<Subscript> subs; | ||
| 220 | |||
| 221 | case Expression.CREF() algorithm | ||
| 222 |
2/2✓ Branch 1 taken 11820 times.
✓ Branch 2 taken 25153 times.
|
36973 | if UnorderedMap.contains(exp.cref, replacements) then |
| 223 | // the cref (with subscripts) is found in replacements | ||
| 224 | 11820 | res := UnorderedMap.getOrFail(exp.cref, replacements); | |
| 225 | else | ||
| 226 | // try to strip the subscripts and see if that cref occurs | ||
| 227 | 25153 | stripped := ComponentRef.stripSubscriptsAll(exp.cref); | |
| 228 |
2/2✓ Branch 1 taken 210 times.
✓ Branch 2 taken 24943 times.
|
25153 | if UnorderedMap.contains(stripped, replacements) then |
| 229 | 210 | subs := ComponentRef.subscriptsAllWithWholeFlat(exp.cref); | |
| 230 | 210 | res := UnorderedMap.getOrFail(stripped, replacements); | |
| 231 | 210 | res := Expression.applySubscripts(subs, res, true); | |
| 232 | else | ||
| 233 | // do nothing | ||
| 234 | res := exp; | ||
| 235 | end if; | ||
| 236 | end if; | ||
| 237 | then res; | ||
| 238 | else exp; | ||
| 239 | end match; | ||
| 240 | end applySimpleExp; | ||
| 241 | |||
| 242 | function applySimpleCref | ||
| 243 | "Needs to be used as funcCref in Equation.map() to replace crefs that appear | ||
| 244 | as direct ComponentRef arguments (e.g. the state variable of a reinit statement)." | ||
| 245 | input output ComponentRef cref; | ||
| 246 | input UnorderedMap<ComponentRef, Expression> replacements; | ||
| 247 | protected | ||
| 248 | Expression replacement; | ||
| 249 | algorithm | ||
| 250 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 402 times.
|
402 | if UnorderedMap.contains(cref, replacements) then |
| 251 | ✗ | replacement := UnorderedMap.getOrFail(cref, replacements); | |
| 252 | cref := match replacement | ||
| 253 | ✗ | case Expression.CREF() then replacement.cref; | |
| 254 | else cref; | ||
| 255 | end match; | ||
| 256 | end if; | ||
| 257 | end applySimpleCref; | ||
| 258 | |||
| 259 | function applySimpleVar | ||
| 260 | "applys replacement on the variable binding expression" | ||
| 261 | input output Variable var; | ||
| 262 | input UnorderedMap<ComponentRef, Expression> replacements "rules for replacements are stored inside here"; | ||
| 263 | algorithm | ||
| 264 | var := match var | ||
| 265 | local | ||
| 266 | Binding binding; | ||
| 267 | case Variable.VARIABLE(binding = binding as Binding.TYPED_BINDING()) algorithm | ||
| 268 | 5488 | binding.bindingExp := Expression.map(binding.bindingExp, function applySimpleExp(replacements = replacements)); | |
| 269 | 2744 | var.binding := binding; | |
| 270 | then var; | ||
| 271 | else var; | ||
| 272 | end match; | ||
| 273 | end applySimpleVar; | ||
| 274 | |||
| 275 | function replaceVarPtr | ||
| 276 | "replaces a pointer if there is a name replacement in the map" | ||
| 277 | input output Pointer<Variable> var_ptr; | ||
| 278 | input UnorderedMap<ComponentRef, ComponentRef> replacements; | ||
| 279 | protected | ||
| 280 | Option<ComponentRef> cref; | ||
| 281 | algorithm | ||
| 282 | ✗ | cref := UnorderedMap.get(BVariable.getVarName(var_ptr), replacements); | |
| 283 | ✗ | if isSome(cref) then | |
| 284 | ✗ | var_ptr := BVariable.getVarPointer(Util.getOption(cref), sourceInfo()); | |
| 285 | end if; | ||
| 286 | end replaceVarPtr; | ||
| 287 | |||
| 288 | function simpleToString | ||
| 289 | input UnorderedMap<ComponentRef, Expression> replacements; | ||
| 290 | output String str = ""; | ||
| 291 | protected | ||
| 292 | list<tuple<ComponentRef, Expression>> entries; | ||
| 293 | String constStr="", aliasStr="", nonTrivialStr=""; | ||
| 294 | ComponentRef key; | ||
| 295 | Expression value; | ||
| 296 | algorithm | ||
| 297 | 14 | entries := UnorderedMap.toList(replacements); | |
| 298 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 14 times.
|
40 | for entry in entries loop |
| 299 | 26 | (key, value) := entry; | |
| 300 |
2/2✓ Branch 1 taken 16 times.
✓ Branch 2 taken 10 times.
|
26 | if Expression.isConstNumber(value) then |
| 301 | // constant alias | ||
| 302 | 16 | constStr := constStr + "\t" + ComponentRef.toString(key) + "\t ==> \t" + Expression.toString(value) + "\n"; | |
| 303 | elseif not Expression.isTrivialCref(value) then | ||
| 304 | // non trivial alias | ||
| 305 | 6 | nonTrivialStr := nonTrivialStr + "\t" + ComponentRef.toString(key) + "\t ==> \t" + Expression.toString(value) + "\n"; | |
| 306 | else | ||
| 307 | // trivial alias | ||
| 308 | 4 | aliasStr := aliasStr + "\t" + ComponentRef.toString(key) + "\t ==> \t" + Expression.toString(value) + "\n"; | |
| 309 | end if; | ||
| 310 | end for; | ||
| 311 | 14 | str := str + StringUtil.headline_4("[dumprepl] Constant Replacements:") + constStr; | |
| 312 | 14 | str := str + StringUtil.headline_4("[dumprepl] Trivial Alias Replacements:") + aliasStr; | |
| 313 | 14 | str := str + StringUtil.headline_4("[dumprepl] Nontrivial Alias Replacements:") + nonTrivialStr; | |
| 314 | end simpleToString; | ||
| 315 | |||
| 316 | // ========================================================================= | ||
| 317 | // FUNCTION BODY REPLACEMENT | ||
| 318 | // ========================================================================= | ||
| 319 | |||
| 320 | function replaceFunctions | ||
| 321 | "replaces all function calls in the replacements map with their body expressions, | ||
| 322 | if possible." | ||
| 323 | input output EqData eqData; | ||
| 324 | input VariablePointers variables; | ||
| 325 | input UnorderedMap<Absyn.Path, Function> replacements; | ||
| 326 | protected | ||
| 327 | UnorderedMap<Expression, Expression> prev_replacements = UnorderedMap.new<Expression>(Expression.hash, Expression.isEqual); | ||
| 328 | algorithm | ||
| 329 | // do nothing if replacements are empty | ||
| 330 |
2/2✓ Branch 1 taken 514 times.
✓ Branch 2 taken 55 times.
|
569 | if UnorderedMap.isEmpty(replacements) then return; end if; |
| 331 | 55 | eqData := EqData.mapExp(eqData, function applyFuncExp(replacements = replacements, prev_replacements = prev_replacements, variables = variables)); | |
| 332 | end replaceFunctions; | ||
| 333 | |||
| 334 | function applyFuncExp | ||
| 335 | "Needs to be mapped with Expression.map()" | ||
| 336 | input output Expression exp "Replacement happens inside this expression"; | ||
| 337 | input UnorderedMap<Absyn.Path, Function> replacements "rules for replacements are stored inside here"; | ||
| 338 | input UnorderedMap<Expression, Expression> prev_replacements "previously found replacements that need not be done again"; | ||
| 339 | input VariablePointers variables; | ||
| 340 | algorithm | ||
| 341 | exp := match exp | ||
| 342 | local | ||
| 343 | Call call; | ||
| 344 | Function fn; | ||
| 345 | UnorderedMap<ComponentRef, Expression> local_replacements; | ||
| 346 | list<ComponentRef> input_crefs; | ||
| 347 | ComponentRef local_cref; | ||
| 348 | Option<Expression> binding_exp_opt; | ||
| 349 | Expression binding_exp, body_exp, res_exp; | ||
| 350 | |||
| 351 | case Expression.CALL(call = call as Call.TYPED_CALL(fn = fn)) guard(UnorderedMap.contains(fn.path, replacements)) algorithm | ||
| 352 | // check if the function was previously replaced | ||
| 353 | res_exp := match UnorderedMap.get(exp, prev_replacements) | ||
| 354 | case SOME(res_exp) then res_exp; | ||
| 355 | else algorithm | ||
| 356 | // use the function from the tree, in case it was changed | ||
| 357 | 336 | fn := UnorderedMap.getOrFail(fn.path, replacements); | |
| 358 | |||
| 359 | // map all the inputs to the arguments and add to local replacement map | ||
| 360 | 336 | local_replacements := UnorderedMap.new<Expression>(ComponentRef.hash, ComponentRef.isEqual); | |
| 361 |
4/4✓ Branch 0 taken 629 times.
✓ Branch 1 taken 336 times.
✓ Branch 2 taken 629 times.
✓ Branch 3 taken 336 times.
|
965 | input_crefs := list(ComponentRef.fromNode(node, InstNode.getType(node)) for node in fn.inputs); |
| 362 | // ToDo: rather use the function slots for this? | ||
| 363 |
2/2✓ Branch 1 taken 629 times.
✓ Branch 2 taken 336 times.
|
965 | for tpl in List.zip(input_crefs, call.arguments) loop |
| 364 | 629 | addInputArgTpl(tpl, local_replacements, false); | |
| 365 | end for; | ||
| 366 | |||
| 367 | // add replacement rules for local (protected) variables | ||
| 368 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 336 times.
|
337 | for local_node in fn.locals loop |
| 369 | 1 | local_cref := ComponentRef.fromNode(local_node, InstNode.getType(local_node)); | |
| 370 | 1 | binding_exp_opt := InstNode.getBindingExpOpt(local_node); | |
| 371 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
|
1 | if isSome(binding_exp_opt) then |
| 372 | // replace binding expression with already gathered input replacements | ||
| 373 | 1 | binding_exp := Expression.map(Util.getOption(binding_exp_opt), function applySimpleExp(replacements = local_replacements)); | |
| 374 | else | ||
| 375 | // add a "wild" binding. This will result in unused outputs being ignored. | ||
| 376 | binding_exp := Expression.CREF(Type.UNKNOWN(), ComponentRef.WILD()); | ||
| 377 | end if; | ||
| 378 | 1 | addInputArgTpl((local_cref, binding_exp), local_replacements, false); | |
| 379 | end for; | ||
| 380 | |||
| 381 | // get the expression from function body (fails if its not a single replacable assignment) | ||
| 382 | 336 | body_exp := Function.getSingleBodyExp(fn); | |
| 383 | // replace input withs arguments in expression | ||
| 384 | 336 | body_exp := Expression.map(body_exp, function applySimpleExp(replacements = local_replacements)); | |
| 385 | // if any of the inputs had an undetermined size, retype the new body | ||
| 386 |
2/2✓ Branch 1 taken 43 times.
✓ Branch 2 taken 293 times.
|
336 | if not List.all(input_crefs, ComponentRef.sizeKnown) then |
| 387 | 43 | body_exp := Typing.typeExp(body_exp, NFInstContext.RHS, sourceInfo(), true); | |
| 388 | end if; | ||
| 389 | |||
| 390 | // combine binaries and simplify | ||
| 391 | 336 | body_exp := SimplifyExp.combineBinaries(body_exp); | |
| 392 | 336 | body_exp := SimplifyExp.simplifyDump(body_exp, true, getInstanceName()); | |
| 393 | |||
| 394 | // replace body with possible nested functions | ||
| 395 | 336 | res_exp := Expression.map(body_exp, function applyFuncExp(replacements = replacements, prev_replacements = prev_replacements, variables = variables)); | |
| 396 | |||
| 397 | // wrap all event triggering expressions in noEvent() if the function is not supposed to trigger events | ||
| 398 |
1/2✓ Branch 0 taken 336 times.
✗ Branch 1 not taken.
|
336 | if not fn.attributes.generateEvents then |
| 399 | 336 | res_exp := Expression.fakeMap(res_exp, wrapEvents); | |
| 400 | end if; | ||
| 401 | |||
| 402 | // add the new replacement to the map | ||
| 403 | 336 | UnorderedMap.add(exp, res_exp, prev_replacements); | |
| 404 | |||
| 405 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 336 times.
|
336 | if Flags.isSet(Flags.DUMPBACKENDINLINE) then |
| 406 | ✗ | print("[" + getInstanceName() + "] Inlining: " + Expression.toString(exp) + "\n"); | |
| 407 | ✗ | print("-- Result: " + Expression.toString(body_exp) + "\n\n"); | |
| 408 | end if; | ||
| 409 | then res_exp; | ||
| 410 | end match; | ||
| 411 | then res_exp; | ||
| 412 | |||
| 413 | else exp; | ||
| 414 | end match; | ||
| 415 | end applyFuncExp; | ||
| 416 | |||
| 417 | function addInputArgTpl | ||
| 418 | "adds an input to argument replacement and also adds | ||
| 419 | all record children replacements." | ||
| 420 | input tuple<ComponentRef, Expression> tpl; | ||
| 421 | input UnorderedMap<ComponentRef, Expression> replacements; | ||
| 422 | input Boolean lowered_lhs "true if the LHS has properly lowered (backend) crefs"; | ||
| 423 | protected | ||
| 424 | ComponentRef cref; | ||
| 425 | Expression arg; | ||
| 426 | list<Expression> children_args; | ||
| 427 | list<ComponentRef> children, tmp; | ||
| 428 | Call call; | ||
| 429 | Function fn; | ||
| 430 | algorithm | ||
| 431 | 3392 | (cref, arg) := tpl; | |
| 432 | 3392 | UnorderedMap.add(cref, arg, replacements); | |
| 433 | |||
| 434 | // also try to add record children replacements (throw error if impossible?) | ||
| 435 |
2/2✓ Branch 0 taken 2039 times.
✓ Branch 1 taken 1353 times.
|
3392 | children := if lowered_lhs then BVariable.getRecordChildrenCref(cref) else ComponentRef.getRecordChildren(cref); |
| 436 |
2/2✓ Branch 0 taken 3160 times.
✓ Branch 1 taken 232 times.
|
3392 | if not listEmpty(children) then |
| 437 | children_args := match arg | ||
| 438 | |||
| 439 | // if the argument is a cref, get its children | ||
| 440 | case Expression.CREF() algorithm | ||
| 441 | 200 | tmp := BVariable.getRecordChildrenCref(arg.cref); | |
| 442 |
4/4✓ Branch 0 taken 495 times.
✓ Branch 1 taken 200 times.
✓ Branch 2 taken 495 times.
✓ Branch 3 taken 200 times.
|
695 | then list(recordChildArg(child) for child in tmp); |
| 443 | |||
| 444 | // if it is a basic record, take its elements | ||
| 445 | 8 | case Expression.RECORD() then arg.elements; | |
| 446 | ✗ | case Expression.TUPLE() then arg.elements; | |
| 447 | |||
| 448 | // if the argument is a record constructor, map it to its attributes | ||
| 449 | case Expression.CALL(call = call as Call.TYPED_CALL(fn = fn)) algorithm | ||
| 450 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
|
24 | if Function.isDefaultRecordConstructor(fn) then |
| 451 | ✗ | children_args := call.arguments; | |
| 452 | elseif Function.isNonDefaultRecordConstructor(fn) then | ||
| 453 | // ToDo: this has to be mapped correctly with the body. | ||
| 454 | // for non default record constructors its not always the | ||
| 455 | // case that inputs map 1:1 to attributes | ||
| 456 | ✗ | children_args := call.arguments; | |
| 457 | else | ||
| 458 | 24 | children_args := Expression.getRecordElements(arg); | |
| 459 | end if; | ||
| 460 | then children_args; | ||
| 461 | |||
| 462 | ✗ | else Expression.getRecordElements(arg); | |
| 463 | end match; | ||
| 464 | |||
| 465 | // check if children and children_args can be mapped to one another | ||
| 466 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 232 times.
|
232 | if List.compareLength(children, children_args) == 0 then |
| 467 |
2/2✓ Branch 1 taken 826 times.
✓ Branch 2 taken 232 times.
|
1058 | for child_tpl in List.zip(children, children_args) loop |
| 468 | 826 | addInputArgTpl(child_tpl, replacements, lowered_lhs); | |
| 469 | end for; | ||
| 470 | end if; | ||
| 471 | end if; | ||
| 472 | end addInputArgTpl; | ||
| 473 | |||
| 474 | function recordChildArg | ||
| 475 | "constant record children are replaced by their literal binding, since constants | ||
| 476 | are not assigned at runtime and are only referenced after inlining." | ||
| 477 | input ComponentRef child; | ||
| 478 | output Expression exp = Expression.fromCref(child); | ||
| 479 | protected | ||
| 480 | Pointer<Variable> var_ptr; | ||
| 481 | Variable var; | ||
| 482 | Option<Expression> binding; | ||
| 483 | algorithm | ||
| 484 |
2/2✓ Branch 1 taken 45 times.
✓ Branch 2 taken 450 times.
|
495 | if listEmpty(ComponentRef.subscriptsAllFlat(child)) then |
| 485 | 450 | var_ptr := BVariable.getVarPointer(child, sourceInfo()); | |
| 486 |
1/2✓ Branch 1 taken 450 times.
✗ Branch 2 not taken.
|
450 | if BVariable.isConst(var_ptr) then |
| 487 | ✗ | var := Pointer.access(var_ptr); | |
| 488 | ✗ | binding := Binding.typedExp(var.binding); | |
| 489 | ✗ | if isSome(binding) and Expression.isLiteral(Util.getOption(binding)) then | |
| 490 | ✗ | exp := Util.getOption(binding); | |
| 491 | end if; | ||
| 492 | end if; | ||
| 493 | end if; | ||
| 494 | end recordChildArg; | ||
| 495 | |||
| 496 | function wrapEvents | ||
| 497 | input output Expression exp; | ||
| 498 | algorithm | ||
| 499 | exp := match exp | ||
| 500 | case Expression.IF() algorithm | ||
| 501 | // wrap the condition in noEvent() if it does not have a noEvent() yet | ||
| 502 | exp.condition := match exp.condition | ||
| 503 | 10 | case Expression.CALL() guard(Expression.isCallNamed(exp.condition, "noEvent")) then exp.condition; | |
| 504 | 7 | else Expression.CALL(Call.makeTypedCall( | |
| 505 | fn = NFBuiltinFuncs.NO_EVENT, | ||
| 506 | args = {exp.condition}, | ||
| 507 | variability = Expression.variability(exp.condition), | ||
| 508 | purity = NFPrefixes.Purity.PURE)); | ||
| 509 | end match; | ||
| 510 | 17 | exp.trueBranch := Expression.mapShallow(exp.trueBranch, wrapEvents); | |
| 511 | 17 | exp.falseBranch := Expression.mapShallow(exp.falseBranch, wrapEvents); | |
| 512 | then exp; | ||
| 513 | |||
| 514 | // wrap all relations in noEvent() | ||
| 515 | case Expression.RELATION() algorithm | ||
| 516 | 4 | then Expression.CALL(Call.makeTypedCall( | |
| 517 | fn = NFBuiltinFuncs.NO_EVENT, | ||
| 518 | args = {exp}, | ||
| 519 | variability = Expression.variability(exp), | ||
| 520 | purity = NFPrefixes.Purity.PURE)); | ||
| 521 | |||
| 522 | // wrap all logical binaries in noEvent() | ||
| 523 | case Expression.LBINARY() algorithm | ||
| 524 | ✗ | then Expression.CALL(Call.makeTypedCall( | |
| 525 | fn = NFBuiltinFuncs.NO_EVENT, | ||
| 526 | args = {exp}, | ||
| 527 | variability = Expression.variability(exp), | ||
| 528 | purity = NFPrefixes.Purity.PURE)); | ||
| 529 | |||
| 530 | // wrap all logical unaries in noEvent() | ||
| 531 | case Expression.LUNARY() algorithm | ||
| 532 | ✗ | then Expression.CALL(Call.makeTypedCall( | |
| 533 | fn = NFBuiltinFuncs.NO_EVENT, | ||
| 534 | args = {exp}, | ||
| 535 | variability = Expression.variability(exp), | ||
| 536 | purity = NFPrefixes.Purity.PURE)); | ||
| 537 | |||
| 538 | 5616 | else Expression.mapShallow(exp, wrapEvents); | |
| 539 | end match; | ||
| 540 | end wrapEvents; | ||
| 541 | |||
| 542 | annotation(__OpenModelica_Interface="nbackend"); | ||
| 543 | end NBReplacements; | ||
| 544 |