chapel-lang/chapel — pull request #315 by ronawho (2014-09-05 19:52:30+00:00)
Title: Add V2 of "C for loops"

Generate C style for loops for all iterators that forward to any range
iterator, not just the bounded+non-stride one. This includes arrays as
DefaultRectangular now forwards to a range iterator.

V1 of c for loops gave us c style for loops for the bounded+non-strided range
iterator. This brings us c style for loops for all range iterators and cleans
up the implementation of the c for loop primitive.

The primitive used to be: __primitive("C for loop", i, start, end, stride)

Now it is: __primitive("C for loop", initExpr, testExpr, incrExpr) where the
init, test, and incr can be symExprs, or other primitives.

This allows us to create arbitrary c for loops in the modules. Previously the
loops were forced to be a certain form by the compiler. They were turned into:
__primitive("C for loop", {i=start}, {i<=end}, {i=i+stride})

and there was no way to change the <= relational operator or specify the stride
expr, etc. This makes C for loops look uglier in the modules, but it cleans up
code in the compiler, and allows c for loops to be flexible. This seems like
the cleanest way to do this without changing the language to accept something
like:
__primitive("C for loop", {i=start}, {i<=end}, {i=i+stride})

directly in the modules.

In order to support this, the C for loop primitives and build.cpp had to be
adjusted to use the new form. There is also a new function isRelationalOperater
which is used at codegen time for c for loops.

Using the new form of c for loops the bounded+strided and unbounded range
iterators now use the c for loop primitive too.

C for loops were also switched to use the op= and assign operators. We didn't
use them before because of the ref temps they introduced, but the ref temp
elimination patch that went in recently allowed us to switch.

We also noticed that loops over an array didn't turn into c for loops.
"for a in Array" still generated a while loop. This is because of an old
optimization in DefaultRectangular that explicitly used a while loop instead of
forwarding to the range iterator. Brad sent me patch to correct this that
had a loop of the form:

for j in 0..size-1 {
yield theData(i);
i += step;
}

This created clean c for loops but it leaves you with two induction variables
and the backend compiler seemed unable to eliminate one of them. Ideally we
just want something like:
for i in 0..size-1 by step {
yield theData(i);
}

but then you forward to a less optimized iterator (where the c for loop uses the
!= relational operator instead of <=.)

To get around this I added a posStrideIter. It is an optimized iterator for when
you know the stride is positive. It is not intended to be used by users, but is
instead a stepping stone to give us a performant loop for positively strided
ranges until we have a more robust way to assert that the stride is positive at
compile time. While this is far from an ideal solution it's ok for now.