Currently we create a looping structure which is executed to traverse an array and transfer it one element at a time. This works, but is not too efficient. We could improve this by converting the implied do loops into the appropriate array descriptor and call transfer_array.
The two cases are:
real, dimension(10) :: a
write(10,'(10f8.3)') (a(i), i=1,10)
struct array1_real(kind=4) parm.4;
parm.4.dtype = 281;
parm.4.dim.lbound = 1;
parm.4.dim.ubound = 10;
parm.4.dim.stride = 1;
parm.4.data = (void *) &a;
parm.4.offset = -1;
_gfortran_transfer_array (&dt_parm.3, &parm.4, 4, 0);
i = 1;
if (i <= 10)
_gfortran_transfer_real (&dt_parm.3, &a[(integer(kind=8)) i + -1], 4);
D.958 = i == 10;
i = i + 1;
if (D.958) goto L.3;
The former is needed to simplify asynchronous I/O where we need to be able to convey to the I/O thread the task to be done and not the actual code to do the looping.
Putting it another way, if the implied loop has 10000 count. We need to pass that count to the I/O routines, so they can take it and run with it.
(In reply to comment #0)
> real, dimension(10) :: a
> write(10,'(10f8.3)') a
> write(10,'(10f8.3)') (a(i), i=1,10)
The problem is, this isn't possible in the most generic case:
write(10,'(10f8.3)') (a(i**-2*i+13), i=1,10)
OK, I see your point. Would it be possible to create a hidden iterator function that could be called internally by the I/O library to return the index into the array?
In the meantime, I am thinking through a different approach for aio that avoids the issue here.
> In the meantime, I am thinking through a different approach for aio that avoids
> the issue here.
Yes it would - use gfc_conv_expr_descriptor to convert the expression and pass the resulting array descriptor. For the cases that you are concerned with, this would be a temporary. However, gfortran_transfer array would be used and the io itself taken out of the loop. Obviously, this would only work for a WRITE operation and gfc_conv_subref_array_arg would have to be used for a READ - as in the existing code in gfc_trans_transfer.
In fact, I believe that the exsting code in gfc_trans_transfer would be able to handle iterator expressions, were they passed to it. However, the frontend does this scalarization; see io.c(match_io_element):2396 onwards. This builds up a DO loop and a call to EXEC_TRANSFER for each element. Where there is only one element, you will get what you want by turning the iterator expression into an EXPR_ARRAY and writing the gfc_code to pass that to EXEC_TRANSFER. I think that it should be a very straightforward job.
Best of luck!
I have a method figured out for async I/O that will handle things as they are now, However, it would greatly improve the situation if we fix this implied do loop business.
Depending how much ground we want to cover, this
can be tricky.
Off my head, I can think of the following examples:
(a(i), i=1,10) --> a(1:10)
(a(i), i=1,10,2) --> a(1:10:2)
(a(2*i), i=1,10) --> a(2:20:2)
((a(i,j), i=1,10), j=1,2) --> a(1:10,1:20)
((a(i,j), j=1,2), i=1,10) --> no equivalent
((a(i,j), j=1,2) --> a(i,1:2)
(a(i,2*i), i=1,10) --> no equivalent
(a(i**2), i=1,10) --> no equivalent