Skip to content

Commit

Permalink
Implement support for implicit iteration ranges (#7323)
Browse files Browse the repository at this point in the history
  • Loading branch information
perost committed Mar 24, 2021
1 parent dfb3a7a commit eff0130
Show file tree
Hide file tree
Showing 20 changed files with 557 additions and 42 deletions.
16 changes: 0 additions & 16 deletions .CI/compliance-newinst.failures
@@ -1,15 +1,7 @@
ModelicaCompliance.Algorithms.For.ImplicitBoolIterator
ModelicaCompliance.Algorithms.For.ImplicitEnumIterator
ModelicaCompliance.Algorithms.For.ImplicitIntegerIterator
ModelicaCompliance.Algorithms.For.ImplicitIteratorEqRange
ModelicaCompliance.Algorithms.For.ImplicitMultiIterator
ModelicaCompliance.Algorithms.For.ImplicitMultiMixedIterator
ModelicaCompliance.Algorithms.For.MixedImplExplIterator
ModelicaCompliance.Algorithms.For.RealRange
ModelicaCompliance.Algorithms.For.ShadowedIterator
ModelicaCompliance.Algorithms.For.StringRange
ModelicaCompliance.Arrays.Functions.Conversion.DimConversionMatrix
ModelicaCompliance.Arrays.Functions.Reductions.Deduce
ModelicaCompliance.Classes.Declarations.Long.QuotedIdentifiers.?abfnrtv
ModelicaCompliance.Classes.Enumeration.EnumUnspecified
ModelicaCompliance.Classes.Predefined.AttributeStateSelectInvalidAlways
Expand Down Expand Up @@ -86,14 +78,6 @@ ModelicaCompliance.Connections.Restrictions.SizeScalarInvalid
ModelicaCompliance.Connections.Stream.StreamConnectorMissingFlow
ModelicaCompliance.Connections.Stream.StreamConnectorMultiFlow
ModelicaCompliance.Connections.Stream.StreamOutsideConnector
ModelicaCompliance.Equations.For.BoolRange
ModelicaCompliance.Equations.For.ImplicitBoolIterator
ModelicaCompliance.Equations.For.ImplicitEnumIterator
ModelicaCompliance.Equations.For.ImplicitIntegerIterator
ModelicaCompliance.Equations.For.ImplicitIteratorEqRange
ModelicaCompliance.Equations.For.ImplicitMultiIterator
ModelicaCompliance.Equations.For.ImplicitMultiMixedIterator
ModelicaCompliance.Equations.For.MixedImplExplIterator
ModelicaCompliance.Functions.Calls.Vectorization.VectorizationMultiInputIllegal
ModelicaCompliance.Functions.Derivative.PartialDerivative
ModelicaCompliance.Functions.HigherOrder.PartialApplication3
Expand Down
16 changes: 0 additions & 16 deletions .CI/compliance.failures
@@ -1,15 +1,7 @@
ModelicaCompliance.Algorithms.For.ImplicitBoolIterator
ModelicaCompliance.Algorithms.For.ImplicitEnumIterator
ModelicaCompliance.Algorithms.For.ImplicitIntegerIterator
ModelicaCompliance.Algorithms.For.ImplicitIteratorEqRange
ModelicaCompliance.Algorithms.For.ImplicitMultiIterator
ModelicaCompliance.Algorithms.For.ImplicitMultiMixedIterator
ModelicaCompliance.Algorithms.For.MixedImplExplIterator
ModelicaCompliance.Algorithms.For.RealRange
ModelicaCompliance.Algorithms.For.ShadowedIterator
ModelicaCompliance.Algorithms.For.StringRange
ModelicaCompliance.Arrays.Functions.Conversion.DimConversionMatrix
ModelicaCompliance.Arrays.Functions.Reductions.Deduce
ModelicaCompliance.Classes.Declarations.Long.QuotedIdentifiers.?abfnrtv
ModelicaCompliance.Classes.Enumeration.EnumUnspecified
ModelicaCompliance.Classes.Predefined.AttributeStateSelectInvalidAlways
Expand Down Expand Up @@ -86,14 +78,6 @@ ModelicaCompliance.Connections.Restrictions.SizeScalarInvalid
ModelicaCompliance.Connections.Stream.StreamConnectorMissingFlow
ModelicaCompliance.Connections.Stream.StreamConnectorMultiFlow
ModelicaCompliance.Connections.Stream.StreamOutsideConnector
ModelicaCompliance.Equations.For.BoolRange
ModelicaCompliance.Equations.For.ImplicitBoolIterator
ModelicaCompliance.Equations.For.ImplicitEnumIterator
ModelicaCompliance.Equations.For.ImplicitIntegerIterator
ModelicaCompliance.Equations.For.ImplicitIteratorEqRange
ModelicaCompliance.Equations.For.ImplicitMultiIterator
ModelicaCompliance.Equations.For.ImplicitMultiMixedIterator
ModelicaCompliance.Equations.For.MixedImplExplIterator
ModelicaCompliance.Functions.Calls.Vectorization.VectorizationMultiInputIllegal
ModelicaCompliance.Functions.Derivative.PartialDerivative
ModelicaCompliance.Functions.HigherOrder.PartialApplication3
Expand Down
20 changes: 16 additions & 4 deletions OMCompiler/Compiler/NFFrontEnd/NFCall.mo
Expand Up @@ -1891,12 +1891,14 @@ protected
InstNode iter;
algorithm
for i in inIters loop
if isNone(i.range) then
Error.assertion(false, getInstanceName() + ": missing support for implicit iteration range", sourceInfo());
fail();
if isSome(i.range) then
range := Inst.instExp(Util.getOption(i.range), outScope, context, info);
else
// Use an empty expression to indicate that the range is missing and
// needs to be deduced during typing.
range := Expression.EMPTY(Type.UNKNOWN());
end if;

range := Inst.instExp(Util.getOption(i.range), outScope, context, info);
(outScope, iter) := Inst.addIteratorToScope(i.name, outScope, info);
outIters := (iter, range) :: outIters;
end for;
Expand Down Expand Up @@ -1933,6 +1935,11 @@ protected

for i in call.iters loop
(iter, range) := i;

if Expression.isEmpty(range) then
range := Typing.deduceIterationRangeExp(Expression.CALL(call), iter, info);
end if;

(range, iter_ty, iter_var, iter_pur) := Typing.typeIterator(iter, range, next_context, is_structural);

if is_structural then
Expand Down Expand Up @@ -1992,6 +1999,11 @@ protected

for i in call.iters loop
(iter, range) := i;

if Expression.isEmpty(range) then
range := Typing.deduceIterationRangeExp(Expression.CALL(call), iter, info);
end if;

(range, _, iter_var, iter_pur) := Typing.typeIterator(iter, range, context, structural = false);
variability := Variability.variabilityMax(variability, iter_var);
purity := Variability.purityMin(purity, iter_pur);
Expand Down
27 changes: 27 additions & 0 deletions OMCompiler/Compiler/NFFrontEnd/NFDimension.mo
Expand Up @@ -341,6 +341,17 @@ public
end match;
end sizeExp;

function lowerBoundExp
input Dimension dim;
output Expression exp;
algorithm
exp := match dim
case BOOLEAN() then Expression.BOOLEAN(false);
case ENUM() then Expression.makeEnumLiteral(dim.enumType, 1);
else Expression.INTEGER(1);
end match;
end lowerBoundExp;

function expIsLowerBound
"Returns true if the expression represents the lower bound of a dimension."
input Expression exp;
Expand All @@ -354,6 +365,22 @@ public
end match;
end expIsLowerBound;

function upperBoundExp
input Dimension dim;
output Expression exp;
algorithm
exp := match dim
local
Type ty;

case INTEGER() then Expression.INTEGER(dim.size);
case BOOLEAN() then Expression.BOOLEAN(true);
case ENUM(enumType = ty as Type.ENUMERATION())
then Expression.makeEnumLiteral(ty, listLength(ty.literals));
case EXP() then dim.exp;
end match;
end upperBoundExp;

function expIsUpperBound
"Returns true if the expression represents the upper bound of the given dimension."
input Expression exp;
Expand Down
5 changes: 5 additions & 0 deletions OMCompiler/Compiler/NFFrontEnd/NFRangeIterator.mo
Expand Up @@ -86,6 +86,7 @@ public
local
Integer istart, istep, istop;
Real rstart, rstep, rstop;
Boolean bstart, bstop;
Type ty;
list<String> literals;
Absyn.Path path;
Expand Down Expand Up @@ -113,6 +114,10 @@ public
stop = Expression.REAL(rstop))
then REAL_RANGE(rstart, 1.0, 0, Util.realRangeSize(rstart, 1.0, rstop));

case Expression.RANGE(start = Expression.BOOLEAN(bstart),
stop = Expression.BOOLEAN(bstop))
then ARRAY_RANGE(list(Expression.BOOLEAN(b) for b in bstart:bstop));

case Expression.RANGE(start = Expression.ENUM_LITERAL(ty = ty, index = istart),
step = NONE(),
stop = Expression.ENUM_LITERAL(index = istop))
Expand Down
20 changes: 20 additions & 0 deletions OMCompiler/Compiler/NFFrontEnd/NFSubscript.mo
Expand Up @@ -49,6 +49,8 @@ public
import Dimension = NFDimension;
import NFPrefixes.{Variability, Purity};
import NFCeval.EvalTarget;
import NFInstNode.InstNode;
import ComponentRef = NFComponentRef;

import Subscript = NFSubscript;

Expand Down Expand Up @@ -181,6 +183,24 @@ public
end match;
end isScalarLiteral;

function isIterator
input Subscript sub;
input InstNode iterator;
output Boolean res;
protected
ComponentRef cref;
algorithm
res := match sub
case UNTYPED(exp = Expression.CREF(cref = cref))
then InstNode.refEqual(iterator, ComponentRef.node(cref));

case INDEX(index = Expression.CREF(cref = cref))
then InstNode.refEqual(iterator, ComponentRef.node(cref));

else false;
end match;
end isIterator;

function isEqual
input Subscript subscript1;
input Subscript subscript2;
Expand Down
158 changes: 152 additions & 6 deletions OMCompiler/Compiler/NFFrontEnd/NFTyping.mo
Expand Up @@ -2609,12 +2609,11 @@ algorithm

if isSome(eq.range) then
SOME(e1) := eq.range;
e1 := typeIterator(eq.iterator, e1, context, structural = true);
else
Error.assertion(false, getInstanceName() + ": missing support for implicit iteration range", sourceInfo());
fail();
e1 := deduceIterationRangeEq(eq, eq.iterator, info);
end if;

e1 := typeIterator(eq.iterator, e1, context, structural = true);
next_context := InstContext.set(context, NFInstContext.FOR);
body := list(typeEquation(e, next_context) for e in eq.body);
then
Expand Down Expand Up @@ -2847,12 +2846,11 @@ algorithm

if isSome(st.range) then
SOME(e1) := st.range;
e1 := typeIterator(st.iterator, e1, context, structural = false);
else
Error.assertion(false, getInstanceName() + ": missing support for implicit iteration range", sourceInfo());
fail();
e1 := deduceIterationRangeStmt(st, st.iterator, info);
end if;

e1 := typeIterator(st.iterator, e1, context, structural = false);
next_context := InstContext.set(context, NFInstContext.FOR);
body := typeStatements(st.body, next_context);
then
Expand Down Expand Up @@ -3270,5 +3268,153 @@ algorithm
end if;
end typeReinit;

function deduceIterationRangeEq
input Equation eq;
input InstNode iterator;
input SourceInfo info;
output Expression iterationRange;
protected
list<tuple<ComponentRef, Integer>> crefs;
algorithm
crefs := Equation.foldExp(eq, function collectIteratorCrefs(iterator = iterator), {});
iterationRange := deduceIterationRange(crefs, iterator, info);
end deduceIterationRangeEq;

function deduceIterationRangeStmt
input Statement stmt;
input InstNode iterator;
input SourceInfo info;
output Expression iterationRange;
protected
list<tuple<ComponentRef, Integer>> crefs;
algorithm
crefs := Statement.foldExp(stmt, function collectIteratorCrefs(iterator = iterator), {});
iterationRange := deduceIterationRange(crefs, iterator, info);
end deduceIterationRangeStmt;

function deduceIterationRangeExp
input Expression exp;
input InstNode iterator;
input SourceInfo info;
output Expression iterationRange;
protected
list<tuple<ComponentRef, Integer>> crefs;
algorithm
crefs := Expression.fold(exp, function collectIteratorCrefs2(iterator = iterator), {});
iterationRange := deduceIterationRange(crefs, iterator, info);
end deduceIterationRangeExp;

function deduceIterationRange
"Deduces the range of an iterator given a list of crefs and dimension indices
that the iterator was used to index."
input list<tuple<ComponentRef, Integer>> crefs;
input InstNode iterator;
input SourceInfo info;
output Expression iterationRange;
protected
tuple<ComponentRef, Integer> range_cr;
ComponentRef cr;
Integer dim_index;
Dimension dim;
Expression start_exp, stop_exp;
algorithm
// The iterator needs to be used in a subscript somewhere to be able to deduce it.
if listEmpty(crefs) then
Error.addSourceMessage(Error.IMPLICIT_ITERATOR_NOT_FOUND_IN_LOOP_BODY,
{InstNode.name(iterator)}, info);
fail();
end if;

// Check that the dimensions are all the same.
range_cr := List.reduce(crefs, function deduceIterationRange2(info = info));
(cr, dim_index) := range_cr;

// Deduced iteration range is 1:size(cr, dim_index)
dim := Type.nthDimension(InstNode.getType(ComponentRef.node(cr)), dim_index);
start_exp := Dimension.lowerBoundExp(dim);
stop_exp := Dimension.endExp(dim, cr, dim_index);
iterationRange := Expression.RANGE(Type.UNKNOWN(), start_exp, NONE(), stop_exp);
end deduceIterationRange;

function collectIteratorCrefs
"Traverses an expression and return a list of crefs that the given iterator
was used as a subscript in, as well as the index of the dimension that the
subscripts are indexing."
input Expression exp;
input InstNode iterator;
input output list<tuple<ComponentRef, Integer>> crefs;
algorithm
crefs := Expression.fold(exp, function collectIteratorCrefs2(iterator = iterator), crefs);
end collectIteratorCrefs;

function collectIteratorCrefs2
"Helper function to collectIteratorCrefs, collects the iterator crefs in an
expression."
input Expression exp;
input InstNode iterator;
input output list<tuple<ComponentRef, Integer>> crefs;
protected
ComponentRef cref;
Integer index;
list<Subscript> subs;
algorithm
() := match exp
case Expression.CREF(cref = cref)
algorithm
while ComponentRef.isCref(cref) loop
(cref, subs) := ComponentRef.stripSubscripts(cref);
index := 1;

for sub in subs loop
if Subscript.isIterator(sub, iterator) then
crefs := (cref, index) :: crefs;
end if;

index := index + 1;
end for;

cref := ComponentRef.rest(cref);
end while;
then
();

else ();
end match;
end collectIteratorCrefs2;

function deduceIterationRange2
"Helper function to deduceIterationRange, check that two dimensions are the same."
input tuple<ComponentRef, Integer> range1;
input tuple<ComponentRef, Integer> range2;
input SourceInfo info;
output tuple<ComponentRef, Integer> range = range2;
protected
ComponentRef cref1, cref2;
Integer index1, index2;
InstNode node1, node2;
Dimension dim1, dim2;
algorithm
(cref1, index1) := range1;
(cref2, index2) := range2;
node1 := ComponentRef.node(cref1);
node2 := ComponentRef.node(cref2);

// Skip the check if they refer to the same dimension.
if index1 == index2 and InstNode.refEqual(node1, node2) then
return;
end if;

// The crefs are probably untyped here, so use the type of the instance nodes instead.
dim1 := Type.nthDimension(InstNode.getType(node1), index1);
dim2 := Type.nthDimension(InstNode.getType(node2), index2);

if not Dimension.isEqualKnown(dim1, dim2) then
Error.addSourceMessage(Error.INCOMPATIBLE_IMPLICIT_RANGES,
{String(index1), ComponentRef.toString(cref1),
String(index2), ComponentRef.toString(cref2)}, info);
fail();
end if;
end deduceIterationRange2;

annotation(__OpenModelica_Interface="frontend");
end NFTyping;

0 comments on commit eff0130

Please sign in to comment.