Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Iteration count

559 views
Skip to first unread message

James Van Buskirk

unread,
Feb 12, 2020, 8:32:23 PM2/12/20
to
Is this program supposed to perform 0, 128, or infinity iterations of its
loop?

program test
use ISO_FORTRAN_ENV, only: INT8
implicit none
integer(INT8) x
do x = 0, 2**7-1
write(*,*) x
end do
end program test

David Billinghurst

unread,
Feb 12, 2020, 9:00:04 PM2/12/20
to
On Thursday, February 13, 2020 at 12:32:23 PM UTC+11, James Van Buskirk wrote:
> Is this program supposed to perform 0, 128, or infinity iterations of its
> loop?

Interesting. I would expect 0..127 = 128 iterations, with 2**7-1=127 calculated as a default integer then converted to an INT8.

ifort 2019 with /stand:f08 /warn:all agrees.

gfortran 7.4.0 with -Wall outputs
do x = 0, 2**7-1
1
Warning: DO loop at (1) is undefined as it overflows [-Wundefined-do-loop]

I think gfortran is wrong. I haven't time to refer to the standard right now.

David Billinghurst

unread,
Feb 12, 2020, 9:17:39 PM2/12/20
to
On Thursday, February 13, 2020 at 1:00:04 PM UTC+11, David Billinghurst wrote:

> I think gfortran is wrong. I haven't time to refer to the standard right now.

I have extended my lunch to read the F2008 standard. I think this is undefined behaviour so ... whatever. Section 8.1.6.6.1 says:

the following steps are performed in sequence.

(1) The initial parameter m1, the terminal parameter m2, and the incrementation parameter m3 are of type integer with the same kind type parameter as the do-variable. Their values are established by evaluating scalar-int-expr-1, scalar-int-expr-2, and scalar-int-expr 3, respectively, including, if necessary, conversion to the kind type parameter of the do-variable according to the rules for numeric conversion (Table 7.11). If scalar-int-expr 3 does not appear, m3 has the value 1. The value of m3 shall not be zero.

(2) The DO variable becomes de fined with the value of the initial parameter m1.

(3) The iteration count is established and is the value of the expression (m2+m1+m3)=m3, unless that value is negative, in which case the iteration count is 0.

Thus we have

integer(INT8) m1, m2, m3, iteration_count
m1 = 0
m2 = 2**7-1
m3 = 1
iteration_count = (m2-m1+m3)/m3

The INT8 expression (m2-m1+m3)/m3 overflows. Undefined behaviour.

David Billinghurst

unread,
Feb 12, 2020, 9:21:53 PM2/12/20
to
On Thursday, February 13, 2020 at 1:17:39 PM UTC+11, David Billinghurst wrote:
> (3) The iteration count is established and is the value of the expression (m2+m1+m3)=m3, unless that value is negative, in which case the iteration count is 0.

... is the value of the expression (m2-m1+m3)/m3 ...

steve kargl

unread,
Feb 12, 2020, 10:23:04 PM2/12/20
to
gfortran tells you that the behavior is undefined.

mobile:kargl[213] gfcx -o z -fdump-tree-original -Wall a.f90
a.f90:5:19:

5 | do x = 0, 2**7-1
| 1
Warning: DO loop at (1) is undefined as it overflows [-Wundefined-do-loop]

--
steve

ga...@u.washington.edu

unread,
Feb 13, 2020, 12:03:18 AM2/13/20
to
On Wednesday, February 12, 2020 at 6:17:39 PM UTC-8, David Billinghurst wrote:

(snip)

> Thus we have

> integer(INT8) m1, m2, m3, iteration_count
> m1 = 0
> m2 = 2**7-1
> m3 = 1
> iteration_count = (m2-m1+m3)/m3

> The INT8 expression (m2-m1+m3)/m3 overflows. Undefined behaviour.

As well as I know, yes, it is defined in terms of iteration count,
but then the compiler can figure out if it works in terms of the
values given. That is, loop until the loop variable is greater
than m2. As you can see, that will never happen.

Ev. Drikos

unread,
Feb 13, 2020, 3:16:39 AM2/13/20
to
In this case this program would have surprisingly different behavior:

program test
use ISO_FORTRAN_ENV, only: INT8
implicit none
integer(INT8) x, m1, mN, mS
m1 = 0
mN = 2**7-1
mS = 1
do x = m1, mN, mS

ga...@u.washington.edu

unread,
Feb 13, 2020, 7:16:15 AM2/13/20
to
The standard says, regardin INT8:

"The values of these default integer scalar constants shall be
those of the kind type parameters that specify an INTEGER type
whose storage size expressed in bits is 8, 16, 32, and 64
respectively."

It does not say that it requires a binary representation stored
in those bits. Since otherwise the standard allows any integer
radix greater than one, I don't see a restriction to radix 2.
Message has been deleted

Ron Shepard

unread,
Feb 13, 2020, 11:36:55 AM2/13/20
to
I am not following the distinction between this and the original code.
It seems like in all cases, the expressions are evaluated with default
integers, converted to INT8, and then the trip count is evaluated in
INT8 arithmetic. It is the computation of the trip count that overflows.

By comparison, if mN were evaluated as

mN = 2_INT8 ** 7_INT8 - 1_INT8

then the computation of mN itself would be undefined. But that's not
what happens, mN should be evaluated correctly and result in the value
127. You could put a write statement before the loop to check to see if
that is true.

The do loop could also be specified simply as

do x = 0_INT8, 127_INT8, 1_INT8

and the same undefined behavior should result. This avoids the red
herring of the computations and the conversions to INT8, and gets right
to the problem, the trip count computation.

Regarding the original question, the trip count should never, according
to the standard, result in 0 or infinity. It either results in 128 or it
fails, and in the latter case, it is undefined behavior. The standard
does not specify or put constraints on how it should fail, including
starting WWIII. Under no conditions would the standard require the
result to be 0 or infinity passes through the loop, those possibilities
are just the consequences of the undefined behavior case. The trip
count, 128, cannot be represented in INT8, so the result is undefined.
On most machines, the way do loops work is that a register is
initialized to the trip count value, 128 in this case if it were done
successfully, and it is decremented each pass through the loop until it
reaches 0. The do loop is *NOT* terminated when x exceeds mN. That is
the way C loops are implemented, but it is not the way fortran loops
work. Of course, the standard is vague enough so that all of the
implementation is "as if" it were done that way. And just to confuse
things, one possible allowed way to fail, in addition to WWIII, is for
it to work as intended and to execute 128 times.

After all that, I think this is the correct interpretation of the
standard. I would welcome any corrections.

$.02 -Ron Shepard

Ev. Drikos

unread,
Feb 13, 2020, 12:22:38 PM2/13/20
to
On 13/02/2020 6:36 PM, Ron Shepard wrote:
> On 2/13/20 2:16 AM, Ev. Drikos wrote:
>> On 13/02/2020 4:17 AM, David Billinghurst wrote:
>>> ...
>>
> I am not following the distinction between this and the original code.

I thought the distinction is obvious because ie gfortran-8.2 prints a
warning only for the original code and the executable loops for ever,
in contrast to my modified examples that loops exactly 128 times.

Is the meaning here why does it matter since the behavior is undefined?


>
> After all that, I think this is the correct interpretation of the
> standard. I would welcome any corrections.
>

I've no corrections.

Ev. Drikos

JCampbell

unread,
Feb 13, 2020, 7:39:57 PM2/13/20
to
Steve,

I compiled with gFortran 8.3.0 and it cycled indefinitely.
gfortran %prog%.f90 -o %prog%.exe

Including -Wall did provide a warning, but same result.

steve kargl

unread,
Feb 13, 2020, 8:22:13 PM2/13/20
to
Look up the phrase "undefined behavior". Luckily,
you did not start WW III.

--
steve



David Billinghurst

unread,
Feb 13, 2020, 9:48:16 PM2/13/20
to
On Friday, February 14, 2020 at 3:36:55 AM UTC+11, Ron Shepard wrote:
>
> After all that, I think this is the correct interpretation of the
> standard.

A good summary. I agree.

ga...@u.washington.edu

unread,
Feb 13, 2020, 10:42:38 PM2/13/20
to
On Thursday, February 13, 2020 at 5:22:13 PM UTC-8, steve kargl wrote:

(snip)

> Look up the phrase "undefined behavior". Luckily,
> you did not start WW III.

Unfortunately, one of the things that can happen with undefined
behavior is what you wished or hoped would happen.

robin....@gmail.com

unread,
Feb 14, 2020, 10:50:05 AM2/14/20
to
On Friday, February 14, 2020 at 3:36:55 AM UTC+11, Ron Shepard wrote:
In the general case, a trip count of zero is legal Fortran.
In such an event, the loop is not executed.

> It either results in 128 or it
> fails, and in the latter case, it is undefined behavior. The standard
> does not specify or put constraints on how it should fail, including
> starting WWIII. Under no conditions would the standard require the
> result to be 0 or infinity passes through the loop, those possibilities
> are just the consequences of the undefined behavior case. The trip
> count, 128, cannot be represented in INT8, so the result is undefined.
> On most machines, the way do loops work is that a register is
> initialized to the trip count value, 128 in this case if it were done
> successfully,

It can never be done successfully because 128 is a positive value,
and only values up to 127 can be represented correctly in an 8-bit byte.
In other words, 128 overflows on assignment.

Were the value 128 stored. it would then appear as -128 in a twos-
complement representation.

> and it is decremented each pass through the loop until it
> reaches 0. The do loop is *NOT* terminated when x exceeds mN.

In some compilers, it still is.

robin....@gmail.com

unread,
Feb 14, 2020, 10:55:19 AM2/14/20
to
That's probably because it implemetns loops the "old" way,
namely, setting the control variable with the initial value,
incrementing it after each time thru the loop, and testing
to see whether it has exceeded the limit value.
Of course, the "final" increment causes the control variable's
value to overflow, and to appear negative, and thus the
loop is re-entered ... and re-entered ...

robin....@gmail.com

unread,
Feb 14, 2020, 11:08:33 AM2/14/20
to
On Friday, February 14, 2020 at 3:36:55 AM UTC+11, Ron Shepard wrote:
Look, this is 2020. This problem arises because Fortran still
does not have integer overflow interrupt.

On the other hand, PL/I has been making use of hardware
checks for integer overflow since 1966. That's 50+ years ago.

BTW, to keep folks happy - those who wanted to iterate up to the
limit - whether it be 127, 32767, or 2147483747, or whatever,
IBM introduced another loop construct for PL/I, e.g.,

do cv = 1 upthru 127;

(where cv is a one-byte control variable).

Marshall Ward

unread,
Feb 14, 2020, 11:47:25 AM2/14/20
to
On Friday, 14 February 2020 10:50:05 UTC-5, robin...@gmail.com wrote:

>
> It can never be done successfully because 128 is a positive value,
> and only values up to 127 can be represented correctly in an 8-bit byte.
> In other words, 128 overflows on assignment.
>
> Were the value 128 stored. it would then appear as -128 in a twos-
> complement representation.
>

Does the standard require that the trip counter also be int8? It says that m1, m2, m3 are converted to the int8, the same kind as x, but the trip counter's kind is not stated. However, the value is given by the expression (m2 - m1 + m3) / m3, which is made up of int8 values.

If the expression is an int8 operation, then the trip counter cannot have a value of 128. But if it is interpreted as a mathematical expression, then a compiler could potentially iterate x from 0 to 127. Is that right?

Ron Shepard

unread,
Feb 14, 2020, 12:12:47 PM2/14/20
to
On 2/14/20 9:55 AM, robin....@gmail.com wrote:
>> I compiled with gFortran 8.3.0 and it cycled indefinitely.
>> gfortran %prog%.f90 -o %prog%.exe
> That's probably because it implemetns loops the "old" way,
> namely, setting the control variable with the initial value,
> incrementing it after each time thru the loop, and testing
> to see whether it has exceeded the limit value.
> Of course, the "final" increment causes the control variable's
> value to overflow, and to appear negative, and thus the
> loop is re-entered ... and re-entered ...

Could someone with this version of that compiler please post the
intermediate code for a do loop like this to verify this claim? I'm
skeptical, but I'm willing to be convinced with evidence.

$.02 -Ron Shepard

steve kargl

unread,
Feb 14, 2020, 12:30:55 PM2/14/20
to
'gfc8 -fdump-tree-original -c a.f90' yields

test ()
{
integer(kind=1) x;

x = 0;
while (1)
{
{
/* output stuff */
}
L.1:;
x = x + 1;
}
L.2:;
}

Changing the upper limit to 2**7-2, so m3 does not overflow, one gets

test ()
{
integer(kind=1) x;

x = 0;
while (1)
{
{
logical(kind=4) D.3764;

D.3764 = x == 127;
if (D.3764) goto L.2;
{
/* output stuff. */
}
L.1:;
x = x + 1;
}
}
L.2:;
}

Notice the jump to L2 is missing in the undefined behavior case.

--
steve

Ron Shepard

unread,
Feb 14, 2020, 12:44:26 PM2/14/20
to
On 2/14/20 9:50 AM, robin....@gmail.com wrote:
>> Regarding the original question, the trip count should never, according
>> to the standard, result in 0 or infinity.
> In the general case, a trip count of zero is legal Fortran.
> In such an event, the loop is not executed.

Yes, in general nonpositive trip counts are required to result in zero
passes through the loop body. When this was introduced in f77, it
replaced the previously undefined behavior in these situations. Namely,
some earlier compilers would always execute the loop once, while others
would skip over the loop body. Even modern compilers sometimes have
flags that enforce this convention to allow nonconforming codes to run
without modification.

But the expression (127-0+1)/1 is never, under any condition, required
by the standard to result in a nonpositive trip count. The only way it
can be anything other than 128 is for it to exceed the capability of the
machine, in which case the result is undefined. And that is what I said
in my previous post, as far as the standard is concerned, the code is
never required to produce either 0 or infinity passes through the loop.
If a compiler does that, it is an incidental consequence of the
undefined behavior.

Another feature of the trip-count idea is for loops like the following

N = 1
do I = 1, N
N = 3
write(*,*) I
enddo

The standard requires to trip count to be evaluated at the beginning of
the loop. It should evaluate to 1 in this case, and the loop body
should execute once. But if it behaved like a C loop, and compared I to
N every pass through the loop, then the loop body would execute 3 times.

On the other hand, if you want I to be compared to N each pass through
the loop, then

do while (I <= N)

does that. In this kind of loop, the programmer is free to modify both I
and N within the body, more like the C for loop behavior. Of course,
that is a modern fortran construct, it was not in f77 or earlier standards.

$.02 -Ron Shepard


ga...@u.washington.edu

unread,
Feb 14, 2020, 1:04:17 PM2/14/20
to
On Friday, February 14, 2020 at 7:55:19 AM UTC-8, robin...@gmail.com wrote:

(snip)

> That's probably because it implemetns loops the "old" way,
> namely, setting the control variable with the initial value,
> incrementing it after each time thru the loop, and testing
> to see whether it has exceeded the limit value.
> Of course, the "final" increment causes the control variable's
> value to overflow, and to appear negative, and thus the
> loop is re-entered ... and re-entered ...

As far as I know, much of the time compilers do that.

As long as the results satisfy the standard, it doesn't matter
how that is achieved. With constant m1, m2, m3, the compiler can
verify when the "old" way works.

Or, as I said before, undefined behavior includes doing what you
wanted it to do, even though the standard doesn't require it.

With an 8 bit I:

DO I=-128, 127
PRINT *,I
ENDDO

can legally print 256 values of I. Even more, as far as I know:

DO I=1, 10000
PRINT *,I
ENDDO

can legally print 10000 values of I. Even more, I believe it
can print values from 1 to 10000, though it could also print
the bit patterns that arise from storing those values into an 8 bit
variable, with the sign convention in use. Or almost any other 10000
values that it might choose or any other number of values.

It used to be common to keep the DO variable in a register and
never store it into the actual variable. Since Fortran 77, it is
required to store the appropriate termination value in the variable,
but the loop can still be done with it in a register.
(Fortran 66 leaves the DO variable undefined at normal loop end,
allowing for it not to change at all.)


ga...@u.washington.edu

unread,
Feb 14, 2020, 1:55:46 PM2/14/20
to
On Friday, February 14, 2020 at 9:44:26 AM UTC-8, Ron Shepard wrote:

(snip)
> Yes, in general nonpositive trip counts are required to result in zero
> passes through the loop body. When this was introduced in f77, it
> replaced the previously undefined behavior in these situations. Namely,
> some earlier compilers would always execute the loop once, while others
> would skip over the loop body. Even modern compilers sometimes have
> flags that enforce this convention to allow nonconforming codes to run
> without modification.

The early Fortran compilers, such as on the 704, tested at the
end of the loop. Later compilers did this to keep those programs
working. It is supposed to be that the BXLE instruction was added
to IBM S/360 to support this. (Unverified rumor.)


> But the expression (127-0+1)/1 is never, under any condition, required
> by the standard to result in a nonpositive trip count. The only way it
> can be anything other than 128 is for it to exceed the capability of the
> machine, in which case the result is undefined. And that is what I said
> in my previous post, as far as the standard is concerned, the code is
> never required to produce either 0 or infinity passes through the loop.
> If a compiler does that, it is an incidental consequence of the
> undefined behavior.

> Another feature of the trip-count idea is for loops like the following

> N = 1
> do I = 1, N
> N = 3
> write(*,*) I
> enddo

> The standard requires to trip count to be evaluated at the beginning of
> the loop. It should evaluate to 1 in this case, and the loop body
> should execute once. But if it behaved like a C loop, and compared I to
> N every pass through the loop, then the loop body would execute 3 times.

I was trying to find in the standard that it specifically allows
changing N during the loop, or specifically disallows it. I don't
see either way, but the explanations are complicated by mixing in
the explanation for DO CONCURRENT.

It is specifically not allowed to change the DO variable.

> On the other hand, if you want I to be compared to N each pass through
> the loop, then

> do while (I <= N)

> does that. In this kind of loop, the programmer is free to modify both I
> and N within the body, more like the C for loop behavior. Of course,
> that is a modern fortran construct, it was not in f77 or earlier standards.

Note that this case allows modifying I and N.

Modifying your loop above:

N = 1
do I = 1, N
I = 0
write(*,*) I
enddo


Even though the loop count is precomputed as 1, this one is
still undefined behavior, modifying I.

In this case, 1, infinity, or any other number of iterations
are allowed.

As you compared to C above, note that C does allow changing
the loop variable inside the loop. That is, the loop variable
is not special in the way it is in Fortran.


robin....@gmail.com

unread,
Feb 14, 2020, 4:58:27 PM2/14/20
to
I think that you will find that it's illegal, and that
compilers will report an illegal construct.

> In this case, 1, infinity, or any other number of iterations
> are allowed.

Probably not, as it won't get to execution.

robin....@gmail.com

unread,
Feb 14, 2020, 5:02:08 PM2/14/20
to
On Saturday, February 15, 2020 at 5:55:46 AM UTC+11, ga...@u.washington.edu wrote:
> On Friday, February 14, 2020 at 9:44:26 AM UTC-8, Ron Shepard wrote:
>
> (snip)
> > Yes, in general nonpositive trip counts are required to result in zero
> > passes through the loop body. When this was introduced in f77, it
> > replaced the previously undefined behavior in these situations. Namely,
> > some earlier compilers would always execute the loop once, while others
> > would skip over the loop body. Even modern compilers sometimes have
> > flags that enforce this convention to allow nonconforming codes to run
> > without modification.
>
> The early Fortran compilers, such as on the 704, tested at the
> end of the loop. Later compilers did this to keep those programs
> working. It is supposed to be that the BXLE instruction was added
> to IBM S/360 to support this. (Unverified rumor.)

Whether that's true or not, the BCTR instruction is a better and faster
way to go back to the head of the loop body, or to terminate the loop.

JCampbell

unread,
Feb 14, 2020, 7:30:31 PM2/14/20
to
On Saturday, February 15, 2020 at 5:04:17 AM UTC+11, ga...@u.washington.edu wrote:
> can legally print 256 values of I. Even more, as far as I know:
>
> DO I=1, 10000
> PRINT *,I
> ENDDO
>
> can legally print 10000 values of I.

Well, No, with gFortran 8.3.0, this produces a compile error using minimal compile options :
C:\Tmp\TEST\loop_i3.f90(11) : error - Arithmetic overflow converting INTEGER(4) to INTEGERcolumn 1 at (1). This check can be disabled with the option '-fno-range-check'
Interesting that the example " do x = 0, 2**7-1" did not produce this or any warning without -Wall

Fortunately, the other examples mentioned of pre F77 DO approaches do not work, such as:
N = 1
do I = 1, N
N = 3
write(*,*) I
enddo

and
N = 1
do I = 1, N
I = 0
write(*,*) I
enddo

While these DO examples with int8 x look contrived, failures with int16 or int32 x did occur, and when int64 was not available, these were annoying problems.

Ron Shepard

unread,
Feb 15, 2020, 1:34:43 AM2/15/20
to
On 2/14/20 12:04 PM, ga...@u.washington.edu wrote:
> With an 8 bit I:
>
> DO I=-128, 127
> PRINT *,I
> ENDDO
>
> can legally print 256 values of I.

What exactly does "can" mean in this context? The trip-count expression
cannot be evaluated, so the behavior is undefined. If by "can" you mean
that 256 values might be printed right before WWIII is started, then I
think you would be right, as that is one possible result of the
undefined behavior.

$.02 -Ron Shepard

Ron Shepard

unread,
Feb 15, 2020, 1:44:30 AM2/15/20
to
On 2/14/20 6:30 PM, JCampbell wrote:
> Fortunately, the other examples mentioned of pre F77 DO approaches do not work, such as:
> N = 1
> do I = 1, N
> N = 3
> write(*,*) I
> enddo

This one is standard conforming and should work, which means the loop
body is executed once.

[...]
> While these DO examples with int8 x look contrived, failures with int16 or int32 x did occur, and when int64 was not available, these were annoying problems.

I remember the first time I tried to execute a do loop over 2**32 in
length. I used a 64-bit integer do variable, but that wasn't enough. It
took me a few tries to figure out what was wrong and how to fix it.

$.02 -Ron Shepard

robin....@gmail.com

unread,
Feb 15, 2020, 6:53:51 AM2/15/20
to
On Saturday, February 15, 2020 at 3:47:25 AM UTC+11, Marshall Ward wrote:
> On Friday, 14 February 2020 10:50:05 UTC-5, r.....@gmail.com wrote:
>
> >
> > It can never be done successfully because 128 is a positive value,
> > and only values up to 127 can be represented correctly in an 8-bit byte.
> > In other words, 128 overflows on assignment.
> >
> > Were the value 128 stored. it would then appear as -128 in a twos-
> > complement representation.
> >
>
> Does the standard require that the trip counter also be int8?
> It says that m1, m2, m3 are converted to the int8, the same kind as x,
> but the trip counter's kind is not stated.

That's right: according to the 2018 draft, the kind is not stated.
But the overriding consideration is the fact that in the expression
(m2 - m1 + m3) / m3,
all the entities are int8 (as you pointed out).
Consequently, the result is int8.
The conclusion is that the value 128 cannot be stored, as you say.

> However, the value is given by the expression (m2 - m1 + m3) / m3, which is made up of int8 values.
>
> If the expression is an int8 operation, then the trip counter cannot have a value of 128. But if it is interpreted as a mathematical expression, then a compiler could potentially iterate x from 0 to 127. Is that right?

As a corollary to the above, if the DO statement specifies something
like
do x = -127, 127
then the trip counter would theoretically be 257 -- which is more than double
the maximum value that can be stored in an int8.

Could this be an oversight of the designers?
At least
do x = -127, 126
evaluated the old way would have worked (viz, set control variable to -127,
test for the value exceeding 126, execute loop body,
increment control variable, branch back to the test, and so on.

The DO runs into the same problem for int16 and int32 [with
corresponding values for the initial and final values].

Ron Shepard

unread,
Feb 15, 2020, 9:18:48 AM2/15/20
to
On 2/15/20 5:53 AM, robin....@gmail.com wrote:
> Could this be an oversight of the designers?
> At least
> do x = -127, 126
> evaluated the old way would have worked (viz, set control variable to -127,
> test for the value exceeding 126, execute loop body,
> increment control variable, branch back to the test, and so on.

I think the decision was by design, but I don't know the arguments pro
and con. As you point out, the trip count only allows do loops as large
as the positive side of the signed integer model in fortran. If fortran
had unsigned integers, then I expect the trip count would have been
formally expressed that way to get that extra factor of 2 in loop length.

The decision to convert the trip count expression to the kind of the
loop variable was probably directed to the case where the loop variable
has more precision than the default integer precision. Say a 32-bit loop
variable where the default integers are 16-bit. Nowadays, it might be a
64-bit integer with 32-bit default. This discussion has been about going
the other direction, a small loop variable with large default integer. I
have never actually had a problem like that, so it is somewhat a
contrived situation.

$.02 -Ron Shepard

Ev. Drikos

unread,
Feb 15, 2020, 1:23:00 PM2/15/20
to
Possibly buggy, an older version does this:

test ()
{
integer(kind=1) x;

x = 0;
while (1)
{
{
logical(kind=4) D.1889;

{
/* output stuff */
}
L.1:;
D.1889 = x == 127;
x = x + 1;
if (D.1889) goto L.2;
}
}
L.2:;
}


FortranFan

unread,
Feb 15, 2020, 7:01:34 PM2/15/20
to
On Saturday, February 15, 2020 at 9:18:48 AM UTC-5, Ron Shepard wrote:

> .. Nowadays, it might be a
> 64-bit integer with 32-bit default. This discussion has been about going
> the other direction, a small loop variable with large default integer. I
> have never actually had a problem like that, so it is somewhat a
> contrived situation.
> ..

Indeed. From a practical point-of-view, the comment above "Nowadays, it might be a 64-bit integer with 32-bit default" is an issue of concern with some of the teams I work with, where the datasets of interest are larger than what can enumerated using Fortran's "32-bit default" for integers.

That's why suggestions like the one in the link below need to pursued in Fortran:
https://github.com/j3-fortran/fortran_proposals/issues/78

I think the proposal therein which is for "Program-specified default KIND for constants" will be very useful- take a look at the example in the proposal and the DO loop in it:

Example:
--------
This is just to show how it works, it is too trivial to show much
advantage.

Program sum_tan_prefix
Default Integer (Kind=Selected_Int_Kind(18))
Default Real (Kind=Selected_Real_Kind(15))
Real,Allocatable :: x(:)
Print *,'Input vector length N'
Read *, n
If (n<2) Stop 'Don''t be silly.'
Allocate(x(n))
Print *,'Input vector with',Size(x),'values in degrees'
Read *,x
tmp = 0
Print *,'SUM_TAN_PREFIX results'
Do i=1,Size(x)
tmp = tmp + Tan(x(i)*3.1415926535897932384/180)
Print *,i,x
End Do
End Program

JCampbell

unread,
Feb 15, 2020, 10:43:56 PM2/15/20
to
I am finding some variation in the way "do i = m1,m2" vs "do i = m1,m2,m3"
The first appears to use a test "if ( i > m2 ) exit" and overflows for int8
The second appears to use a do_trip_count of optional kind, which 2 compilers treat differently.

I presume there is some flexibility in the standard as to what the compiler does. ( has this changed since F90? )

for : DO i = m1,m2,m3
where i,m1,m2,m3 are kind=int8
We have the assumption that do_trip_count = (m2 - m1 + m3) / m3
and potentially the kind for this trip count is the same "int8" (or higher kind ?)

My testing suggests that for gFortran this is not always the case,
as DO i = m1,m2 may not use a trip_count (and fails for if ( i > 127_1 ) exit

I used the following test program for 4 test cases:

program test_do
use ISO_FORTRAN_ENV, only: INT8,INT16
implicit none
integer(INT8) i,n,i1,i2,inc
integer(INT16) count, test
!
do test = 1,4
write (*,*) ' '
n = 3
select case (test)
case (1,2)
i1 = 0
i2 = 2**7-1
inc = 1
case (3)
i1 = -120
i2 = 120
inc = 1
case (4)
i1 = 120
i2 = -120
inc = -1
end select
!
! do i = 0, n
! do i = 1,1000
count = 0
if ( test==1) then
write (*,*) 'first test with count safety',i1,i2
do i = i1,i2
n = 1
i2 = 1
count = count+1
if ( count > 3000 ) exit
end do ! i
else
write (*,*) 'test',test,' with count safety',i1,i2,inc
do i = i1,i2,inc
n = 1
i2 = 1
count = count+1
if ( count > 3000 ) exit
end do ! i
end if
write(*,*) 'i =',i,' count =',count
end do ! test
!
end program test_do
(note: test code adapted from earlier cases)

My gFortran ( F08 compiler ? ) test produces:
Driving: gfortran loop_i3.f90 -o loop_i3.exe -v -l gfortran
Target: x86_64-w64-mingw32
Thread model: win32
gcc version 8.3.0 (GCC)
COLLECT_GCC_OPTIONS='-o' 'loop_i3.exe' '-v' '-mtune=generic' '-march=x86-64'

first test with count safety 0 127
i = -72 count = 3001

test 2 with count safety 0 127 1
i = -128 count = 128

test 3 with count safety -120 120 1
i = 121 count = 241

test 4 with count safety 120 -120 -1
i = -121 count = 241

for gFortran
1: do i = 0_1,127_1 never sees i(_1) > 127 to exit (does not appear to use loop count)
2: do i = 0_1,127_1,1_1 has a loop count of 128
3: do i = -120_1,120_1,1_1 has a loop count of 241
4: do i = 120_1,-120_1,-1_1 has a loop count of 241
ie the loop count is not int8

However for FTN95 Ver 8.40 (32-bit F95 compiler)
[FTN95/Win32 Ver. 8.40.0 Copyright (c) Silverfrost Ltd 1993-2018]

0004) integer(INT8) i,n,i1,i2,inc
WARNING - 242: Variable N has been given a value but never used
NO ERRORS, 1 WARNING [<TEST_DO> FTN95 v8.40.0]
Creating executable: c:\Tmp\TEST\lgotemp@.exe
Program entered

first test with count safety 0 127
i = -72 count = 3001

test 2 with count safety 0 127 1
i = 0 count = 0

test 3 with count safety -120 120 1
i = -120 count = 0

test 4 with count safety 120 -120 -1
i = 120 count = 0

1: do i = 0_1,127_1 never sees i = 128 to exit (does not appear to use loop count)
2: do i = 0_1,127_1,1_1 has a loop count of 0
3: do i = -120_1,120_1,1_1 has a loop count of 0
4: do i = 120_1,-120_1,-1_1 has a loop count of 0
ie the loop count appears to be int8

Conclusion
for "do i = m1,m2", it does not appear to be managed via a loop count, but a test if i>m2
There is some flexibility in the way that "do i = m1,m2,m3" is implemented, specifically for the kind of the loop count.

What might be the case if we had integer(int64) :: m1,m2,m3 ?

ga...@u.washington.edu

unread,
Feb 15, 2020, 11:51:12 PM2/15/20
to
On Saturday, February 15, 2020 at 7:43:56 PM UTC-8, JCampbell wrote:
> I am finding some variation in the way "do i = m1,m2"
> vs "do i = m1,m2,m3"
> The first appears to use a test "if ( i > m2 ) exit" and
> overflows for int8
> The second appears to use a do_trip_count of optional kind,
> which 2 compilers treat differently.

> I presume there is some flexibility in the standard as to what
> the compiler does. ( has this changed since F90? )

In comp.lang.c, this is called the "as if" rule.

If it gives the result that the standard requires, in all cases where
the standard requires it, then it is fine.

In the case of m3=1, and I suspect for most positive m3 (constant
so that the compiler knows it is positive), it is fairly easy to
do it, as previously noted, the old way. This is especially true
using a wider type than the actual DO variable. (For example, when
it is kept in a register.)

I suspect that is also true when m3 is negative.

When m3 is a variable, I might expect compilers to compute the
loop count as described. Otherwise, it isn't so easy to get all
the cases to work. I might have known compilers to generate two
loops and a test for the sign if m3, but only for small loops.

> for : DO i = m1,m2,m3
> where i,m1,m2,m3 are kind=int8
> We have the assumption that do_trip_count = (m2 - m1 + m3) / m3
> and potentially the kind for this trip count is the same "int8" (or higher kind ?)

> My testing suggests that for gFortran this is not always the case,
> as DO i = m1,m2 may not use a trip_count (and fails for if ( i > 127_1 )
> exit

As noted, in cases where the trip count overflows, undefined behavior
means that the compiler can do anything. It can be an infinite loop,
or loop the number of times that it might do "the old way".
These are interesting. In this case, presumably, the compiler
does not know that values at compile time (some optimizing compilers
might be good enough to figure this out), so treats them as variables.

You might try the do i=1_1,127_1 case, where it terminates
properly with a loop count, but not with 8 bit signed arithmetic
waiting for 128. Note that one of the examples showing the internal
form from gfortran tests for 127 before incrementing.
As previously noted, the 0,127 case is undefined behavior,
but the 1,127 case is not. It has to get the 1,127 case right.

> What might be the case if we had integer(int64) :: m1,m2,m3 ?

Don't try:

integer(int64): i

do i=1,huge(i)
enddo

Well, some compilers will optimize away the whole loop,
so maybe try something else.

ga...@u.washington.edu

unread,
Feb 16, 2020, 12:16:01 AM2/16/20
to
On Saturday, February 15, 2020 at 6:18:48 AM UTC-8, Ron Shepard wrote:

(snip)

> The decision to convert the trip count expression to the kind of the
> loop variable was probably directed to the case where the loop variable
> has more precision than the default integer precision. Say a 32-bit loop
> variable where the default integers are 16-bit. Nowadays, it might be a
> 64-bit integer with 32-bit default. This discussion has been about going
> the other direction, a small loop variable with large default integer. I
> have never actually had a problem like that, so it is somewhat a
> contrived situation.

Well, I think it is that Fortran always, at least in theory, does
arithmetic with the appropriate size.

In C, arithmetic expressions are always evaluated after converting
any integer type smaller than int up to int. This makes sense on most
machines, where registers are int sized. Unsigned types smaller than
int also promote to int. I believe that this gives the desired result
more often than Fortran's doing arithmetic in the appropriate size.

The C rules for mixing signed and unsigned do confuse people,
though, I suspect more than the Fortran rules.

robin....@gmail.com

unread,
Feb 16, 2020, 7:31:52 AM2/16/20
to
The 0,127 case is one that needs to work. It is more likely
to arise in practice than the 1,127 case.

urba...@comcast.net

unread,
Feb 16, 2020, 8:59:37 AM2/16/20
to
I would like to see there be a "NONE" option as well, perhaps
DEFAULT INTEGER(KIND=NONE)
or
EXPLICIT
that would mean that all constants require a KIND be specified as well, and that no automatic propogation occur. This would require extra work by the programmer, not less -- but would ensure that kind was always considered.

Gary Scott

unread,
Feb 16, 2020, 11:01:29 AM2/16/20
to
Hmm, don't think I like that. I'd prefer that people just learn and
understand the fairly simple type, kind, and conversion rules.

Ev. Drikos

unread,
Feb 17, 2020, 6:56:00 AM2/17/20
to
On 16/02/2020 05:43, JCampbell wrote:
> ...
>
> However for FTN95 Ver 8.40 (32-bit F95 compiler)
> [FTN95/Win32 Ver. 8.40.0 Copyright (c) Silverfrost Ltd 1993-2018]
>
> 0004) integer(INT8) i,n,i1,i2,inc
> WARNING - 242: Variable N has been given a value but never used
> NO ERRORS, 1 WARNING [<TEST_DO> FTN95 v8.40.0]
> Creating executable: c:\Tmp\TEST\lgotemp@.exe
> Program entered
> ...

Just tried to compile this program with Silverfrost FTN95 Ver 8.50
Personal Edition but the module ISO_FORTRAN_ENV cannot be found.

Does one need to specify extra arguments or use ie business edition?


Ev. Drikos


Dick Hendrickson

unread,
Feb 17, 2020, 1:33:43 PM2/17/20
to
On 2/15/20 5:53 AM, robin....@gmail.com wrote:
> On Saturday, February 15, 2020 at 3:47:25 AM UTC+11, Marshall Ward wrote:
>> On Friday, 14 February 2020 10:50:05 UTC-5, r.....@gmail.com wrote:
>>
>>>
>>> It can never be done successfully because 128 is a positive value,
>>> and only values up to 127 can be represented correctly in an 8-bit byte.
>>> In other words, 128 overflows on assignment.
>>>
>>> Were the value 128 stored. it would then appear as -128 in a twos-
>>> complement representation.
>>>
>>
>> Does the standard require that the trip counter also be int8?
>> It says that m1, m2, m3 are converted to the int8, the same kind as x,
>> but the trip counter's kind is not stated.
>
> That's right: according to the 2018 draft, the kind is not stated.
> But the overriding consideration is the fact that in the expression
> (m2 - m1 + m3) / m3,
> all the entities are int8 (as you pointed out).
> Consequently, the result is int8.


I'm not sure that the result must be int8. F2008 says "The iteration
count is established and is the value of the expression (m2 - m1
+m3)/m3" But, look at the font, the ms are in normal text font, not
Fortran font (check the examples nearby in notes or syntax rules). Much
the same as in, e.g., the COS function where "the result is ...
approximation to cos(X)." "COS" is a Fortran thing, "cos" is a
mathematical thing.

I'm pretty sure there was an interpretation request, many years ago,
about whether or not defining text formulas are intended to be Fortran
expressions or mathematical expressions and the answer was mathematical.

Dick Hendrickson

ga...@u.washington.edu

unread,
Feb 17, 2020, 3:19:46 PM2/17/20
to
On Monday, February 17, 2020 at 10:33:43 AM UTC-8, Dick Hendrickson wrote:
> On 2/15/20 5:53 AM, robin....@gmail.com wrote:

(snip)
> > That's right: according to the 2018 draft, the kind is not stated.
> > But the overriding consideration is the fact that in the expression
> > (m2 - m1 + m3) / m3,
> > all the entities are int8 (as you pointed out).
> > Consequently, the result is int8.

> I'm not sure that the result must be int8. F2008 says "The iteration
> count is established and is the value of the expression (m2 - m1
> +m3)/m3" But, look at the font, the ms are in normal text font, not
> Fortran font (check the examples nearby in notes or syntax rules). Much
> the same as in, e.g., the COS function where "the result is ...
> approximation to cos(X)." "COS" is a Fortran thing, "cos" is a
> mathematical thing.

That is an interesting way to say it. Since m1, m2, and m3 have a kind,
though, they are obviously Fortran values, since mathematical values
don't have a kind.

Otherwise, the only time you really need the trip count to get things
right is when m3 is a variable, especially when the sign is not known.

When m3 is constant, it is easy to generate appropriate loop increment
(positive or negative) and test conditions. (Allowing for the test
before increment case.)

robin....@gmail.com

unread,
Feb 17, 2020, 6:41:41 PM2/17/20
to
On Tuesday, February 18, 2020 at 7:19:46 AM UTC+11, ga...@u.washington.edu wrote:
> On Monday, February 17, 2020 at 10:33:43 AM UTC-8, Dick Hendrickson wrote:
> > On 2/15/20 5:53 AM, r.....@gmail.com wrote:
>
> > > That's right: according to the 2018 draft, the kind is not stated.
> > > But the overriding consideration is the fact that in the expression
> > > (m2 - m1 + m3) / m3,
> > > all the entities are int8 (as you pointed out).
> > > Consequently, the result is int8.
>
> > I'm not sure that the result must be int8. F2008 says "The iteration
> > count is established and is the value of the expression (m2 - m1
> > +m3)/m3" But, look at the font, the ms are in normal text font, not
> > Fortran font (check the examples nearby in notes or syntax rules). Much
> > the same as in, e.g., the COS function where "the result is ...
> > approximation to cos(X)." "COS" is a Fortran thing, "cos" is a
> > mathematical thing.
>
> That is an interesting way to say it. Since m1, m2, and m3 have a kind,
> though, they are obviously Fortran values, since mathematical values
> don't have a kind.
>
> Otherwise, the only time you really need the trip count to get things
> right is when m3 is a variable,

How so? It doesn't matter whether m3 is a constant or a variable.

> especially when the sign is not known.

The sign is always known, even when m3 is a variable.

robin....@gmail.com

unread,
Feb 17, 2020, 6:49:37 PM2/17/20
to
On Tuesday, February 18, 2020 at 5:33:43 AM UTC+11, Dick Hendrickson wrote:
> On 2/15/20 5:53 AM, r.....@gmail.com wrote:
> > On Saturday, February 15, 2020 at 3:47:25 AM UTC+11, Marshall Ward wrote:
> >> On Friday, 14 February 2020 10:50:05 UTC-5, r.....@gmail.com wrote:
> >>
> >>>
> >>> It can never be done successfully because 128 is a positive value,
> >>> and only values up to 127 can be represented correctly in an 8-bit byte.
> >>> In other words, 128 overflows on assignment.
> >>>
> >>> Were the value 128 stored. it would then appear as -128 in a twos-
> >>> complement representation.
> >>>
> >>
> >> Does the standard require that the trip counter also be int8?
> >> It says that m1, m2, m3 are converted to the int8, the same kind as x,
> >> but the trip counter's kind is not stated.
> >
> > That's right: according to the 2018 draft, the kind is not stated.
> > But the overriding consideration is the fact that in the expression
> > (m2 - m1 + m3) / m3,
> > all the entities are int8 (as you pointed out).
> > Consequently, the result is int8.
>
>
> I'm not sure that the result must be int8. F2008 says "The iteration
> count is established and is the value of the expression (m2 - m1
> +m3)/m3" But, look at the font, the ms are in normal text font, not
> Fortran font (check the examples nearby in notes or syntax rules). Much
> the same as in, e.g., the COS function where "the result is ...
> approximation to cos(X)." "COS" is a Fortran thing, "cos" is a
> mathematical thing.

Well, math formula or Fortran expression or not,
Silverfrost FTN95 cannot handle it when there are 128 or more
iterations.

In any case,
do i = -2147483647, 2147483647, 1
will usually have problems with the iteration count model.
Likewise
do i = -2147483648, 2147483646, 1
etc

JCampbell

unread,
Feb 17, 2020, 8:24:09 PM2/17/20
to
Silverfrost FTN95 is a F95 compiler, so I supply my own ISO_FORTRAN_ENV module for compatibility.
I thought it interesting that FTN95 appears to apply KIND to the do_loop_count, while gFortran does not. For gFortran, I did not test if count was default kind or int64, so int32 or int64 loops could be a problem.

There is clearly some interpretation in how i>m2 or do_loop_count is applied so using DO loops of the types tested is not robust coding. (ie m2 = huge(i) or do_count >= huge(i) ) I would suggest that setting m2 >= huge(i) is not a smart idea ( should be an automatic compiler warning where possible. )

ga...@u.washington.edu

unread,
Feb 17, 2020, 9:00:33 PM2/17/20
to
On Monday, February 17, 2020 at 3:41:41 PM UTC-8, robin...@gmail.com wrote:

(snip, I wrote)

> > That is an interesting way to say it. Since m1, m2, and m3 have a kind,
> > though, they are obviously Fortran values, since mathematical values
> > don't have a kind.

> > Otherwise, the only time you really need the trip count to get things
> > right is when m3 is a variable,

> How so? It doesn't matter whether m3 is a constant or a variable.

When it is constant, the sign is known at compile time, and it
is easy to generate appropriate tests. If the sign is not known
at compile time, but a trip count is computed, then it is also easy
to do the tests. But without a trip count, the loop test is more
complicated. For small loops, the test time is a significant part
of the loop, and especially if branch prediction doesn't figure it out.

> > especially when the sign is not known.

> The sign is always known, even when m3 is a variable.

The sign is known at compile time when it is constant, or
with an exceptional optimizer.

robin....@gmail.com

unread,
Feb 18, 2020, 8:48:51 PM2/18/20
to
On Tuesday, February 18, 2020 at 1:00:33 PM UTC+11, ga...@u.washington.edu wrote:
> On Monday, February 17, 2020 at 3:41:41 PM UTC-8, robin...@gmail.com wrote:
>
> (snip, I wrote)
>
> > > That is an interesting way to say it. Since m1, m2, and m3 have a kind,
> > > though, they are obviously Fortran values, since mathematical values
> > > don't have a kind.
>
> > > Otherwise, the only time you really need the trip count to get things
> > > right is when m3 is a variable,
>
> > How so? It doesn't matter whether m3 is a constant or a variable.
>
> When it is constant, the sign is known at compile time, and it
> is easy to generate appropriate tests.

Obviously.

> If the sign is not known
> at compile time, but a trip count is computed, then it is also easy
> to do the tests. But without a trip count, the loop test is more
> complicated.

Only trivially. A test is required on the sign.

> For small loops, the test time is a significant part
> of the loop,

Not so. For the IBM/360 and later models,
the loop instruction can be BCTR, which is fast.

> and especially if branch prediction doesn't figure it out.

> > > especially when the sign is not known.
>
> > The sign is always known, even when m3 is a variable.
>
> The sign is known at compile time when it is constant,

Obviously. But it is also known at run time, when a
trivial test on the sign is required.

ga...@u.washington.edu

unread,
Feb 18, 2020, 9:26:30 PM2/18/20
to
On Tuesday, February 18, 2020 at 5:48:51 PM UTC-8, robin...@gmail.com wrote:

(snip, I wrote)
> > If the sign is not known
> > at compile time, but a trip count is computed, then it is also easy
> > to do the tests. But without a trip count, the loop test is more
> > complicated.

> Only trivially. A test is required on the sign.

Write the sign considering loop code in your favorite
assembly language. Be sure to consider pipelining and
branch (mis)prediction.

> > For small loops, the test time is a significant part
> > of the loop,

> Not so. For the IBM/360 and later models,
> the loop instruction can be BCTR, which is fast.

BCTR works well with a trip count, or for the case of
a loop going down to 0. For others, it doesn't help much.
But I thought you were arguing against a loop count.

By the way, it is known that for some IBM processors,
that BXLE predicts branch taken, and BXH predicts branch
not taken, independent of the position at the top or
bottom of a loop. Depending on how you write loops,
either can be used at the top or bottom, independent
of the sign of m3, if the sign of m3 is known at compile
time.

Otherwise, for the variable m3 case, some compilers generate
two loops, one for positive and one for negative m3, each
appropriately optimized. This is especially important for those
with static branch prediction.

robin....@gmail.com

unread,
Feb 18, 2020, 10:59:43 PM2/18/20
to
On Wednesday, February 19, 2020 at 1:26:30 PM UTC+11, ga...@u.washington.edu wrote:
> On Tuesday, February 18, 2020 at 5:48:51 PM UTC-8, r.......@gmail.com wrote:
>
> (snip, I wrote)
> > > If the sign is not known
> > > at compile time, but a trip count is computed, then it is also easy
> > > to do the tests. But without a trip count, the loop test is more
> > > complicated.
>
> > Only trivially. A test is required on the sign.
>
> Write the sign considering loop code in your favorite
> assembly language. Be sure to consider pipelining and
> branch (mis)prediction.

Please confine your comments to something that is relevant.
Compared to the time to execute the loop body, the test is
INSIGNIFICANT.
Compared to the time to execute the set-up code, it is
INSIGNIFICANT.
The set-up code is executed ONCE for the entire loop.
If you think that you can measure the extra time taken
for the test, go ahead.

> > > For small loops, the test time is a significant part
> > > of the loop,
>
> > Not so. For the IBM/360 and later models,
> > the loop instruction can be BCTR, which is fast.
>
> BCTR works well with a trip count, or for the case of
> a loop going down to 0.

BCTR can work for any number of trips. It is not restricted to
a maximum of 2147483647 for the count. For more trips, the
register can be set up with an appropriate negative value,
because the value can wrap round to positive.

> For others, it doesn't help much.

Rubbish.

> But I thought you were arguing against a loop count.

I was pointing out that the FORTRAN definition and implementation
is inadequate.

> By the way, it is known that for some IBM processors,
> that BXLE predicts branch taken, and BXH predicts branch
> not taken, independent of the position at the top or
> bottom of a loop. Depending on how you write loops,
> either can be used at the top or bottom, independent
> of the sign of m3, if the sign of m3 is known at compile
> time.

BXLE and BXH are not really useful instructions for loop control,
and take up valuable register space. (they tie up 3 GPRs.)

> Otherwise, for the variable m3 case, some compilers generate
> two loops,

What a waste! Two loops are unnecessary. Only the setup
is different to handle the two cases, with a single loop body.

ga...@u.washington.edu

unread,
Feb 19, 2020, 2:16:41 AM2/19/20
to
On Tuesday, February 18, 2020 at 7:59:43 PM UTC-8, robin...@gmail.com wrote:

(snip)
> Please confine your comments to something that is relevant.
> Compared to the time to execute the loop body, the test is
> INSIGNIFICANT.
> Compared to the time to execute the set-up code, it is
> INSIGNIFICANT.
> The set-up code is executed ONCE for the entire loop.
> If you think that you can measure the extra time taken
> for the test, go ahead.

The slowest things in modern processors are mispredicted
conditional branches. Anything that makes the loop test more
complicated, slows down the loop.

robin....@gmail.com

unread,
Feb 19, 2020, 6:54:56 AM2/19/20
to
What's difficult about the concept?

The loop setup is done ONCE and ONLY once.

The execution time for the loop greatly exceeds the setup time.
Even if the loop is executed only once.

The branch f

James Van Buskirk

unread,
Feb 21, 2020, 5:39:51 AM2/21/20
to
wrote in message
news:b620d944-e38c-40d6...@googlegroups.com...
I remember an FFT code I wrote in assembly language where the
inner loops were triangular and the CPU wasn't smart enough to
predict their branches. About half the CPU time was due to
mispredicted branches. Not as bad as TLB thrashing, but it made
the algorithm unusable on that processor.

ga...@u.washington.edu

unread,
Feb 21, 2020, 7:00:33 PM2/21/20
to
On Friday, February 21, 2020 at 2:39:51 AM UTC-8, James Van Buskirk wrote:
> wrote in message
> news:b620d944-e38c-40d6...@googlegroups.com...

(snip)

> I remember an FFT code I wrote in assembly language where the
> inner loops were triangular and the CPU wasn't smart enough to
> predict their branches. About half the CPU time was due to
> mispredicted branches. Not as bad as TLB thrashing, but it made
> the algorithm unusable on that processor.

TLB thrashing is reminding me of a discussion on the number of
pages a single VAX instruction can reference, and so the minimum
number of TLB entries.

It seems that there is a six address instruction ADDP6.
With indirect addressing, each operand can reference two pages,
plus the page with the instruction, so 13 entries? I haven't
thought about this for a while, so maybe it is even more.

Oh, yes, each operand can cross a page boundary, so could reference
two pages. Maybe the indirect address can also cross a page boundary,
so 19 or 25 entries?

Instruction can cross a page boundary, so 20 or 26.

Ron Shepard

unread,
Feb 22, 2020, 12:04:21 PM2/22/20
to
On 2/17/20 12:33 PM, Dick Hendrickson wrote:
>> That's right: according to the 2018 draft, the kind is not stated.
>> But the overriding consideration is the fact that in the expression
>>     (m2 - m1 + m3) / m3,
>> all the entities are int8 (as you pointed out).
>> Consequently, the result is int8.
>
>
> I'm not sure that the result must be int8.  F2008 says "The iteration
> count is established and is the value of the expression (m2 - m1
> +m3)/m3"  But, look at the font, the ms are in normal text font, not
> Fortran font (check the examples nearby in notes or syntax rules).  Much
> the same as in, e.g., the COS function where "the result is ...
> approximation to cos(X)."  "COS" is a Fortran thing, "cos" is a
> mathematical thing.

This is an interesting observation. If this is correct, then what
exactly are the consequences? Does it mean that a compiler that does not
execute the loop 128 times is nonconforming?

$.02 -Ron Shepard

Ron Shepard

unread,
Feb 22, 2020, 12:34:13 PM2/22/20
to
On 2/16/20 6:31 AM, robin....@gmail.com wrote:
>> As previously noted, the 0,127 case is undefined behavior,
>> but the 1,127 case is not. It has to get the 1,127 case right.
> The 0,127 case is one that needs to work. It is more likely
> to arise in practice than the 1,127 case.

Are you suggesting that the language specification should be changed to
*REQUIRE* the 0,127 case to work?

It is possible for loops like

do I = -128, 127

and

do I = 127, -128, -1

to work correctly if the language specification required the test on the
variable I to occur before the final increment.

It does seem that there are many situations that look like they might
fail, but are required to work. For example a loop like

do I = 126, 127

or perhaps

do I = 126, 127, 2

might fail if the compiler implements a test on the variable I after the
last increment. But both of these cases should work correctly if
executed as trip counts, and I think the standard requires this behavior
in those cases.

I have never really been bothered by the current language specification
in which the loop behavior is determined by the trip count. I know that
reduces the maximum loop count by a factor of 2 compared to the
alternative approach, but it is a simple rule for the programmer to
remember.

$.02 -Ron Shepard

ga...@u.washington.edu

unread,
Feb 22, 2020, 3:05:19 PM2/22/20
to
On Saturday, February 22, 2020 at 9:34:13 AM UTC-8, Ron Shepard wrote:

(snip)

> It does seem that there are many situations that look like they might
> fail, but are required to work. For example a loop like
>
> do I = 126, 127
>
> or perhaps
>
> do I = 126, 127, 2
>
> might fail if the compiler implements a test on the variable I after the
> last increment. But both of these cases should work correctly if
> executed as trip counts, and I think the standard requires this behavior
> in those cases.
>
> I have never really been bothered by the current language specification
> in which the loop behavior is determined by the trip count. I know that
> reduces the maximum loop count by a factor of 2 compared to the
> alternative approach, but it is a simple rule for the programmer to
> remember.

The standard doesn't say much about INT8, other than mentioning
storage size, presumably the result of the STORAGE_SIZE function.

Even if it does mean a binary representation, that still allows for
sign magnitude or ones' complement, so the lower limit might be 127.

But it could also be, for example, a BCD representation with only
one digit and sign, or any other base with a binary representation.

For STORAGE_SIZE, the standard says:

"This is intended to be the size in memory that an object takes
when it is stored; this might differ from the size it takes during
expression handling (which might be the native register size) or
when stored in a file. If an object is never stored in memory but
only in a register, this function nonetheless returns the size it
would take if it were stored in memory."

STORAGE_SIZE also includes any padding necessary for an array
element, so might be more than the actual scalar value.

Nowhere does that suggest a binary representation.

C_INT8_T would include the C restrictions on types, which pretty
much require a binary representation, but still allow for sign magnitude
and ones' complement.



JCampbell

unread,
Feb 22, 2020, 8:53:35 PM2/22/20
to
Interesting that the final release of gFortran Ver 7.5 does make reference to DO loops where m2 = huge(i). ( I hope this extends into versions 8,9 and 10 )
https://gcc.gnu.org/gcc-7/changes.html

The example appears to relate to default integer, rather than int8, so I am wondering what would be the result for other integer kinds.
Is there any reference for the loop count kind required in the standard ?
Or should the programmer manage this uncertainty ?

edmondo.g...@gmail.com

unread,
Feb 24, 2020, 10:03:33 AM2/24/20
to
I have used many times the fact that the test is after the increment of the loop variable to check if the exit of the loop occur naturlly or there was an exit instruction. Like:

do i = 1, N
...
if (condition) exit
...
end do
if (i>N) then ! loop completed
...
endif

I think it is standard conforming but tell me if I were wrong.

Il giorno sabato 22 febbraio 2020 18:34:13 UTC+1, Ron Shepard ha scritto:

Ron Shepard

unread,
Feb 24, 2020, 12:55:24 PM2/24/20
to
On 2/24/20 9:03 AM, edmondo.g...@gmail.com wrote:
> I have used many times the fact that the test is after the increment of the loop variable to check if the exit of the loop occur naturlly or there was an exit instruction. Like:
>
> do i = 1, N
> ...
> if (condition) exit
> ...
> end do
> if (i>N) then ! loop completed
> ...
> endif
>
> I think it is standard conforming but tell me if I were wrong.

When N == huge(I), then the after-loop test cannot work correctly,
otherwise it is correct and standard conforming, even when the loop body
itself was implemented by the compiler with a trip count rather than my
incrementing I. It is a separate issue whether the loop is executed the
correct number of times, this depends on how the expression
(m2-m1+m3)/m3 is evaluated or mimicked. That is the situation being
discussed in this thread, when N == huge(I), when is the loop required
to be executed the correct number of times.

BTW, before f77, that after-loop test would not have been standard
conforming. The way I remember this issue, the value of the loop
variable upon successful execution was not defined before that, it was
only defined if the loop body had been exited before the full loop count.

$.02 -Ron Shepard

Dick Hendrickson

unread,
Feb 24, 2020, 1:14:14 PM2/24/20
to
I don't think there are practical consequences. Compiler writers try to
do the right thing. Sometimes they miss.

The standard doesn't impose any rules on the size or complexity of a
program that must be executed. So a compiler that doesn't execute the
loop 128 times isn't nonconforming, no matter what the integer precision
is. I think it's just a quality of implementation issue.

Dick Hendrickson

ga...@u.washington.edu

unread,
Feb 24, 2020, 9:35:20 PM2/24/20
to
On Monday, February 24, 2020 at 9:55:24 AM UTC-8, Ron Shepard wrote:

(snip)

> When N == huge(I), then the after-loop test cannot work correctly,
> otherwise it is correct and standard conforming, even when the loop body
> itself was implemented by the compiler with a trip count rather than my
> incrementing I. It is a separate issue whether the loop is executed the
> correct number of times, this depends on how the expression
> (m2-m1+m3)/m3 is evaluated or mimicked. That is the situation being
> discussed in this thread, when N == huge(I), when is the loop required
> to be executed the correct number of times.

It isn't so hard to make the test work, as someone noted from the
gfortran generated code, which is to test, increment, and then branch
on the results of the test. In addition, you need a test at the top,
to not enter the loop under appropriate conditions, if that isn't
known at compile time.

> BTW, before f77, that after-loop test would not have been standard
> conforming. The way I remember this issue, the value of the loop
> variable upon successful execution was not defined before that, it was
> only defined if the loop body had been exited before the full loop count.

Yes, Fortran 66 says that the loop variable is undefined on normal exit.
Many compilers I know keep the value in a register and never store
it in the actual variable. Fortran 66 also allows only positive going
loops (m3>0), also m1>0 and m2>=m1. Some compilers allowed more than
that as an extension, but the IBM compilers I know keep those requirements
in the case of constants.


Ron Shepard

unread,
Feb 25, 2020, 2:16:03 AM2/25/20
to
On 2/24/20 8:35 PM, ga...@u.washington.edu wrote:
> Yes, Fortran 66 says that the loop variable is undefined on normal exit.
> Many compilers I know keep the value in a register and never store
> it in the actual variable. Fortran 66 also allows only positive going
> loops (m3>0), also m1>0 and m2>=m1. Some compilers allowed more than
> that as an extension, but the IBM compilers I know keep those requirements
> in the case of constants.

Only simple variables or literal constants were allowed, no expressions
and no parameters, which were also introduced only later in f77. The
m2>=m1 condition in f66 is why some compilers still have a "one-trip"
option. Since the m2<m1 situation was not defined by the standard,
different compilers treated it differently, some always executing the
loop body at least once.

$.02 -Ron Shepard

robin....@gmail.com

unread,
Feb 25, 2020, 6:31:46 AM2/25/20
to
On Tuesday, February 25, 2020 at 1:35:20 PM UTC+11, ga...@u.washington.edu wrote:
> On Monday, February 24, 2020 at 9:55:24 AM UTC-8, Ron Shepard wrote:
>
> (snip)
>
> > When N == huge(I), then the after-loop test cannot work correctly,
> > otherwise it is correct and standard conforming, even when the loop body
> > itself was implemented by the compiler with a trip count rather than my
> > incrementing I. It is a separate issue whether the loop is executed the
> > correct number of times, this depends on how the expression
> > (m2-m1+m3)/m3 is evaluated or mimicked. That is the situation being
> > discussed in this thread, when N == huge(I), when is the loop required
> > to be executed the correct number of times.
>
> It isn't so hard to make the test work, as someone noted from the
> gfortran generated code, which is to test, increment, and then branch
> on the results of the test. In addition, you need a test at the top,

The test does not need to be at the top of the loop.
It does need to be executed before loop entry, however.
The initial value, the test, and the increment can he
physically placed at the end of the loop.

> to not enter the loop under appropriate conditions, if that isn't
> known at compile time.
>
> > BTW, before f77, that after-loop test would not have been standard
> > conforming. The way I remember this issue, the value of the loop
> > variable upon successful execution was not defined before that, it was
> > only defined if the loop body had been exited before the full loop count.
>
> Yes, Fortran 66 says that the loop variable is undefined on normal exit.
> Many compilers I know keep the value in a register and never store
> it in the actual variable.

They would need to store the value if the loop variable is
passed as an argument to a procedure, and if it is in COMMON.

ga...@u.washington.edu

unread,
Feb 25, 2020, 12:46:45 PM2/25/20
to
On Monday, February 24, 2020 at 11:16:03 PM UTC-8, Ron Shepard wrote:

(I wrote)
The simple variables and constants, needed a temporary variable
if you needed something else, didn't bother me so much as the
restrictions on the I/O list of WRITE statements.

Again no expressions, though whole arrays and array elements
were allowed, but not constants. So lots of temporary variables
for those. I remember WATFIV with many Fortran 77 features
already in 1973, I suspect to test them out before the standard.

Allowing expressions in I/O lists was at the time my favorite
new feature.

I remember using unformatted WRITE statements, which sometimes
needed to write constants, and so variables with the right value.
0 new messages