Skip to content

Commit

Permalink
[NF] Improved parameter evaluation analysis.
Browse files Browse the repository at this point in the history
- Avoid evaluating parameters that are non-final or depend on non-final
  parameters when Evaluate=true or -d=evaluateAllParameters is used.
- Evaluate parameters that are both fixed and final if their bindings
  are also fixed and final.
- Propagate finalness from modifiers to components, to better exploit
  the above optimization.

Belonging to [master]:
  - OpenModelica/OMCompiler#2990
  - OpenModelica/OpenModelica-testsuite#1144
  • Loading branch information
perost authored and OpenModelica-Hudson committed Mar 22, 2019
1 parent 050a820 commit 3b38d7b
Show file tree
Hide file tree
Showing 6 changed files with 328 additions and 27 deletions.
18 changes: 18 additions & 0 deletions Compiler/NFFrontEnd/NFBinding.mo
Expand Up @@ -605,6 +605,24 @@ public
end match;
end mapExp;

function containsExp
input Binding binding;
input PredFunc predFn;
output Boolean res;

partial function PredFunc
input Expression exp;
output Boolean res;
end PredFunc;
algorithm
res := match binding
case UNTYPED_BINDING() then Expression.contains(binding.bindingExp, predFn);
case TYPED_BINDING() then Expression.contains(binding.bindingExp, predFn);
case FLAT_BINDING() then Expression.contains(binding.bindingExp, predFn);
case CEVAL_BINDING() then Expression.contains(binding.bindingExp, predFn);
else false;
end match;
end containsExp;
end Binding;

annotation(__OpenModelica_Interface="frontend");
Expand Down
2 changes: 1 addition & 1 deletion Compiler/NFFrontEnd/NFComponent.mo
Expand Up @@ -826,7 +826,7 @@ uniontype Component
return;
end if;

fixed := fixed and Expression.isTrue(Binding.getTypedExp(binding));
fixed := fixed and Expression.isTrue(Binding.getExp(binding));

end getFixedAttribute;

Expand Down
163 changes: 141 additions & 22 deletions Compiler/NFFrontEnd/NFExpression.mo
Expand Up @@ -3814,34 +3814,13 @@ public
algorithm
res := match cref
case ComponentRef.CREF()
then subscriptsContains(cref.subscripts, func) or
then Subscript.listContainsExp(cref.subscripts, func) or
crefContains(cref.restCref, func);

else false;
end match;
end crefContains;

function subscriptsContains
input list<Subscript> subs;
input ContainsPred func;
output Boolean res;
algorithm
for s in subs loop
res := match s
case Subscript.UNTYPED() then contains(s.exp, func);
case Subscript.INDEX() then contains(s.index, func);
case Subscript.SLICE() then contains(s.slice, func);
else false;
end match;

if res then
return;
end if;
end for;

res := false;
end subscriptsContains;

function listContains
input list<Expression> expl;
input ContainsPred func;
Expand Down Expand Up @@ -3911,6 +3890,146 @@ public
end match;
end callContains;

function containsShallow
input Expression exp;
input ContainsPred func;
output Boolean res;
algorithm
res := match exp
case CREF() then crefContainsShallow(exp.cref, func);
case ARRAY() then listContainsShallow(exp.elements, func);

case MATRIX()
algorithm
res := false;

for row in exp.elements loop
if listContainsShallow(row, func) then
res := true;
break;
end if;
end for;
then
res;

case RANGE()
then func(exp.start) or
Util.applyOptionOrDefault(exp.step, func, false) or
func(exp.stop);

case TUPLE() then listContainsShallow(exp.elements, func);
case RECORD() then listContainsShallow(exp.elements, func);
case CALL() then callContainsShallow(exp.call, func);

case SIZE()
then Util.applyOptionOrDefault(exp.dimIndex, func, false) or
func(exp.exp);

case BINARY() then func(exp.exp1) or func(exp.exp2);
case UNARY() then func(exp.exp);
case LBINARY() then func(exp.exp1) or func(exp.exp2);
case LUNARY() then func(exp.exp);
case RELATION() then func(exp.exp1) or func(exp.exp2);
case IF() then func(exp.condition) or func(exp.trueBranch) or func(exp.falseBranch);
case CAST() then func(exp.exp);
case UNBOX() then func(exp.exp);

case SUBSCRIPTED_EXP()
then func(exp.exp) or Subscript.listContainsExpShallow(exp.subscripts, func);

case TUPLE_ELEMENT() then func(exp.tupleExp);
case RECORD_ELEMENT() then func(exp.recordExp);
case PARTIAL_FUNCTION_APPLICATION() then listContains(exp.args, func);
case BOX() then func(exp.exp);
else false;
end match;
end containsShallow;

function crefContainsShallow
input ComponentRef cref;
input ContainsPred func;
output Boolean res;
algorithm
res := match cref
case ComponentRef.CREF()
then Subscript.listContainsExpShallow(cref.subscripts, func) or
crefContainsShallow(cref.restCref, func);

else false;
end match;
end crefContainsShallow;

function listContainsShallow
input list<Expression> expl;
input ContainsPred func;
output Boolean res;
algorithm
for e in expl loop
if func(e) then
res := true;
return;
end if;
end for;

res := false;
end listContainsShallow;

function callContainsShallow
input Call call;
input ContainsPred func;
output Boolean res;
algorithm
res := match call
local
Expression e;

case Call.UNTYPED_CALL()
algorithm
res := listContainsShallow(call.arguments, func);

if not res then
for arg in call.named_args loop
(_, e) := arg;

if func(e) then
res := true;
break;
end if;
end for;
end if;
then
res;

case Call.ARG_TYPED_CALL()
algorithm
for arg in call.arguments loop
(e, _, _) := arg;

if func(e) then
res := true;
return;
end if;
end for;

for arg in call.named_args loop
(_, e, _, _) := arg;

if func(e) then
res := true;
return;
end if;
end for;
then
false;

case Call.TYPED_CALL() then listContainsShallow(call.arguments, func);
case Call.UNTYPED_ARRAY_CONSTRUCTOR() then func(call.exp);
case Call.TYPED_ARRAY_CONSTRUCTOR() then func(call.exp);
case Call.UNTYPED_REDUCTION() then func(call.exp);
case Call.TYPED_REDUCTION() then func(call.exp);
end match;
end callContainsShallow;

function arrayFirstScalar
"Returns the first scalar element of an array. Fails if the array is empty."
input Expression arrayExp;
Expand Down
134 changes: 130 additions & 4 deletions Compiler/NFFrontEnd/NFInst.mo
Expand Up @@ -1407,6 +1407,10 @@ algorithm
attr := mergeRedeclaredComponentAttributes(Util.getOption(originalAttr), attr, node);
end if;

if not attr.isFinal and Modifier.isFinal(mod) then
attr.isFinal := true;
end if;

// Create the untyped component and update the node with it. We need the
// untyped component in instClass to make sure everything is scoped
// correctly during lookup, but the class node the component should have
Expand Down Expand Up @@ -3185,21 +3189,21 @@ algorithm

case Component.UNTYPED_COMPONENT(binding = binding, condition = condition)
algorithm
// @adrpo: if Evaluate=true make the parameter a structural parameter
// only make it a structural parameter if is not constant, duh!, 1071 regressions :)
if c.attributes.variability == Variability.PARAMETER and
(Component.getEvaluateAnnotation(c) or evalAllParams) then
if isStructuralComponent(c, c.attributes, binding, node, evalAllParams) then
markStructuralParamsComp(c, node);
end if;

// Parameters used in array dimensions are structural.
for dim in c.dimensions loop
markStructuralParamsDim(dim);
end for;

// Parameters that determine the size of a component binding are structural.
if Binding.isBound(binding) then
markStructuralParamsExpSize(Binding.getUntypedExp(binding));
end if;

// Parameters used in a component condition are structural.
if Binding.isBound(condition) then
markStructuralParamsExp(Binding.getUntypedExp(condition));
end if;
Expand All @@ -3223,6 +3227,128 @@ algorithm
end match;
end updateImplicitVariabilityComp;

function isStructuralComponent
input Component component;
input Component.Attributes compAttrs;
input Binding compBinding;
input InstNode compNode;
input Boolean evalAllParams;
output Boolean isStructural;
protected
Boolean is_fixed;
algorithm
if compAttrs.variability <> Variability.PARAMETER then
// Only parameters can be structural.
isStructural := false;
elseif evalAllParams or Component.getEvaluateAnnotation(component) then
// If -d=evaluateAllParameters is set or the parameter has an Evaluate=true
// annotation we should probably evaluate the parameter, which we do by
// marking it as structural.
if not Component.getFixedAttribute(component) then
// Except non-fixed parameters.
isStructural := false;
elseif Binding.isUnbound(compBinding) then
// Except parameters with no bindings.
if not evalAllParams then
// Print a warning if a parameter has an Evaluate=true annotation but no binding.
Error.addSourceMessage(Error.UNBOUND_PARAMETER_EVALUATE_TRUE,
{InstNode.name(compNode)}, InstNode.info(compNode));
end if;

isStructural := false;
elseif isBindingNotFixed(compBinding, requireFinal = false) then
// Except parameters that depend on non-fixed parameters.
isStructural := false;
else
// All other parameters are considered structural in this case.
isStructural := true;
end if;
elseif Component.isFinal(component) and Component.getFixedAttribute(component) then
// If a parameter is fixed and final we might also want to evaluate it,
// since its binding can't be modified. But only if all parameters it
// depends on are also fixed and final.
if Binding.isUnbound(compBinding) or isBindingNotFixed(compBinding, requireFinal = true) then
isStructural := false;
else
isStructural := true;
end if;
else
isStructural := false;
end if;
end isStructuralComponent;

function isBindingNotFixed
input Binding binding;
input Boolean requireFinal;
input Integer depth = 1;
output Boolean isNotFixed;
algorithm
if depth > 4 then
isNotFixed := true;
return;
end if;

isNotFixed := match binding
case Binding.UNTYPED_BINDING()
then isExpressionNotFixed(binding.bindingExp, requireFinal, depth);

else false;
end match;
end isBindingNotFixed;

function isExpressionNotFixed
input Expression exp;
input Boolean requireFinal;
input Integer depth;
output Boolean isNotFixed;
algorithm
isNotFixed := match exp
local
InstNode node;
Component c;
Variability var;
Expression e;

case Expression.CREF()
algorithm
node := ComponentRef.node(exp.cref);

if InstNode.isComponent(node) then
c := InstNode.component(node);
var := Component.variability(c);

if var <= Variability.STRUCTURAL_PARAMETER then
isNotFixed := false;
elseif var == Variability.PARAMETER and
(not requireFinal or Component.isFinal(c)) and
Component.getFixedAttribute(c) then
isNotFixed := isBindingNotFixed(Component.getBinding(c), requireFinal, depth + 1);
else
isNotFixed := true;
end if;
else
isNotFixed := true;
end if;
then
isNotFixed or
Expression.containsShallow(exp,
function isExpressionNotFixed(requireFinal = requireFinal, depth = depth));

case Expression.SIZE()
algorithm
if isSome(exp.dimIndex) then
isNotFixed := isExpressionNotFixed(Util.getOption(exp.dimIndex), requireFinal, depth);
else
isNotFixed := false;
end if;
then
isNotFixed;

else Expression.containsShallow(exp,
function isExpressionNotFixed(requireFinal = requireFinal, depth = depth));
end match;
end isExpressionNotFixed;

function markStructuralParamsDim
input Dimension dimension;
algorithm
Expand Down
10 changes: 10 additions & 0 deletions Compiler/NFFrontEnd/NFModifier.mo
Expand Up @@ -479,6 +479,16 @@ public
end match;
end isEach;

function isFinal
input Modifier mod;
output Boolean isFinal;
algorithm
isFinal := match mod
case MODIFIER(finalPrefix = SCode.FINAL()) then true;
else false;
end match;
end isFinal;

function map
input output Modifier mod;
input FuncT func;
Expand Down

0 comments on commit 3b38d7b

Please sign in to comment.