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

Weird behaviour with intent

2 views
Skip to first unread message

jel...@gmail.com

unread,
Jan 4, 2007, 3:23:39 AM1/4/07
to
Hi all,

I've found a strange behaviour when passing the same array portion as
both intent(inout) and intent(in) arguments. Is this normal or should I
report a compiler bug? Is it legal code anyway?

Consider this test Fortran 90 program:

!================================
program test
implicit none
integer, dimension(3,3) :: n
n(:,1)=(/1,2,3/)
n(:,2)=(/1,2,3/)
n(:,3)=(/1,2,3/)
write(6,*) n(:,1)
call sub(n(:,1),n(:,1))
write(6,*) n(:,1)

n(:,1)=(/1,2,3/)
n(:,2)=(/1,2,3/)
n(:,3)=(/1,2,3/)
write(6,*) n(1,:)
call sub(n(1,:),n(1,:))
write(6,*) n(1,:)

contains
subroutine sub(a,b)
implicit none
integer, dimension(3), intent(inout) :: a
integer, dimension(3), intent(in) :: b
a=(/4,5,6/)
end subroutine
end program test
!================================

The program just calls the subroutine twice, once with a column of n,
once with a row. The expected output (for me) is:

1 2 3
4 5 6
1 1 1
4 5 6

i.e., the subroutine changes the argument to (/4,5,6/) anyway. I get
this expected output with Intel's compiler (version 9.1), but with GNU
fortran (version 4.3.0 20061223) I get:

1 2 3
4 5 6
1 1 1
1 1 1

that is, the subroutine works as expected when called with a column,
but not when called with a row. This same behaviour happens with ifort
if the subroutine is defined outside the program, outside any module
and with no interface block.

As I said, is this normal?

Thanks

Joost

unread,
Jan 4, 2007, 3:46:27 AM1/4/07
to
> I've found a strange behaviour when passing the same array portion as
> both intent(inout) and intent(in) arguments. Is this normal or should I
> report a compiler bug? Is it legal code anyway?

I think the program is standard conforming (especially since b is not
referenced in sub), and that it illustrates a bug in gfortran and g95.

Joost

glen herrmannsfeldt

unread,
Jan 4, 2007, 4:00:44 AM1/4/07
to
jel...@gmail.com wrote:


> I've found a strange behaviour when passing the same array portion as
> both intent(inout) and intent(in) arguments. Is this normal or should I
> report a compiler bug? Is it legal code anyway?

It looks suspicious to me. One would have to read the standard pretty
carefully, but in the row case it could be that the calling program
generates a copy of the array before the call, and copies back after
the call. It might be that it can do that even for an intent(in)
argument. Since b does not need a copy, the copy back overwrites a.


(snip)

> call sub(n(:,1),n(:,1))

(snip)

> call sub(n(1,:),n(1,:))
> write(6,*) n(1,:)

> contains
> subroutine sub(a,b)
> implicit none
> integer, dimension(3), intent(inout) :: a
> integer, dimension(3), intent(in) :: b
> a=(/4,5,6/)
> end subroutine
> end program test

(snip)

Herman D. Knoble

unread,
Jan 4, 2007, 7:51:25 AM1/4/07
to
Your program runs and displays expected results if:

1) Using Lahey or Salford compilers.

2) Or since argument/dummy argument b is not used, remove
the second argument/dummy argument and g95 will also
display the expected results.

Skip Knoble

On 4 Jan 2007 00:23:39 -0800, jel...@gmail.com wrote:

-|Hi all,
-|
-|I've found a strange behaviour when passing the same array portion as
-|both intent(inout) and intent(in) arguments. Is this normal or should I
-|report a compiler bug? Is it legal code anyway?
-|
-|Consider this test Fortran 90 program:
-|
-|!================================
-|program test
-| implicit none
-| integer, dimension(3,3) :: n
-| n(:,1)=(/1,2,3/)
-| n(:,2)=(/1,2,3/)
-| n(:,3)=(/1,2,3/)
-| write(6,*) n(:,1)
-| call sub(n(:,1),n(:,1))
-| write(6,*) n(:,1)
-|
-| n(:,1)=(/1,2,3/)
-| n(:,2)=(/1,2,3/)
-| n(:,3)=(/1,2,3/)
-| write(6,*) n(1,:)
-| call sub(n(1,:),n(1,:))
-| write(6,*) n(1,:)
-|
-| contains
-| subroutine sub(a,b)
-| implicit none
-| integer, dimension(3), intent(inout) :: a
-| integer, dimension(3), intent(in) :: b
-| a=(/4,5,6/)
-| end subroutine
-|end program test
-|!================================
-|
-|The program just calls the subroutine twice, once with a column of n,
-|once with a row. The expected output (for me) is:
-|
-| 1 2 3
-| 4 5 6
-| 1 1 1
-| 4 5 6
-|
-|i.e., the subroutine changes the argument to (/4,5,6/) anyway. I get
-|this expected output with Intel's compiler (version 9.1), but with GNU
-|fortran (version 4.3.0 20061223) I get:
-|
-| 1 2 3
-| 4 5 6
-| 1 1 1
-| 1 1 1
-|
-|that is, the subroutine works as expected when called with a column,
-|but not when called with a row. This same behaviour happens with ifort
-|if the subroutine is defined outside the program, outside any module
-|and with no interface block.
-|
-|As I said, is this normal?
-|
-|Thanks

Gordon Sande

unread,
Jan 4, 2007, 9:00:36 AM1/4/07
to
On 2007-01-04 04:23:39 -0400, jel...@gmail.com said:

> Hi all,
>
> I've found a strange behaviour when passing the same array portion as
> both intent(inout) and intent(in) arguments. Is this normal or should I
> report a compiler bug? Is it legal code anyway?
>
> Consider this test Fortran 90 program:
>
> !================================
> program test
> implicit none
> integer, dimension(3,3) :: n
> n(:,1)=(/1,2,3/)
> n(:,2)=(/1,2,3/)
> n(:,3)=(/1,2,3/)
> write(6,*) n(:,1)
> call sub(n(:,1),n(:,1))
> write(6,*) n(:,1)
>
> n(:,1)=(/1,2,3/)
> n(:,2)=(/1,2,3/)
> n(:,3)=(/1,2,3/)
> write(6,*) n(1,:)
> call sub(n(1,:),n(1,:))

The a and b arguements of sub will be aliased for these calls.
The intent ( in ) for b is interesting but that is a statement
about the intended use by the programmer. The aliasing rules
would still require that neither a nor b be redefined in sub.

Or at least that is my limited understanding of the interaction
between this new fangled feature of intent and the golden oldie
rules about aliasing. Namely the aliasing rules still have full
force.

Since the code is nonstandard there is no correct answer.

If my understnding is an overly strict (urban superstition)
interpretation of the rules I would like to be corrected.
It does have the merit of being fail safe.

Dick Hendrickson

unread,
Jan 4, 2007, 12:13:06 PM1/4/07
to
jel...@gmail.com wrote:
> Hi all,
>
> I've found a strange behaviour when passing the same array portion as
> both intent(inout) and intent(in) arguments. Is this normal or should I
> report a compiler bug? Is it legal code anyway?
>
> Consider this test Fortran 90 program:
>
> !================================
> program test
> implicit none
> integer, dimension(3,3) :: n
> n(:,1)=(/1,2,3/)
> n(:,2)=(/1,2,3/)
> n(:,3)=(/1,2,3/)
> write(6,*) n(:,1)
> call sub(n(:,1),n(:,1))
The standard is crystal clear about this case. You're doing a bad
thing. :( When a subroutine is called with two arguments that are
storage associated and overlap each other, neither one of them can
be changed in the called subroutine. This is to allow an argument
passing mechanism known as copy-in/copy-out. (There are some exceptions
for pointers and partial overlap, but that doesn't apply here.)

For this particular call, since both arrays are in contiguous storage,
many compilers just pass the "base" address of the array section and
don't bother with a copy-in/copy-out.

> write(6,*) n(:,1)
>
> n(:,1)=(/1,2,3/)
> n(:,2)=(/1,2,3/)
> n(:,3)=(/1,2,3/)
> write(6,*) n(1,:)
> call sub(n(1,:),n(1,:))

In this case, the array sections are not contiguous in memory and many
compilers will make a contiguous copy and pass the base address of the
new temporary copy. On return, they will copy-out the temp into the
original array sections. As Murphy's law guarantees, they do the copy
in the "wrong" order for what you are trying to do.

Dick Hendrickson

Richard E Maine

unread,
Jan 4, 2007, 12:17:51 PM1/4/07
to
Gordon Sande <g.s...@worldnet.att.net> wrote:

> On 2007-01-04 04:23:39 -0400, jel...@gmail.com said:

> > I've found a strange behaviour when passing the same array portion as
> > both intent(inout) and intent(in) arguments. Is this normal or should I
> > report a compiler bug? Is it legal code anyway?

[code elided]

> The a and b arguements of sub will be aliased for these calls.
> The intent ( in ) for b is interesting but that is a statement
> about the intended use by the programmer. The aliasing rules
> would still require that neither a nor b be redefined in sub.

...


> Since the code is nonstandard there is no correct answer.

Gordon's understanding is correct. The code is nonstandard. Some people
overstate the restriction in question by saying that aliasing is
disallowed. Aliasing is allowed, but there are restrictions on it. One
of those restrictions is that you may not modify the value of either of
the aliased variables. Thus there is no correct answer and the compilers
are free to do anything they want with it. This is not an error that
compilers are required to catch. Nor is it an error that I'd expect most
compilers to be able to catch.

As Gordon notes, the intent attributes do not change this. Intent(n)
does *NOT* translate to "make a copy and don't copy back out". (The 2003
value attribute basically does translate to that. It was originally
introduced as a C interop feature, but has enough uses independent of C
interop that its main description is not in the C interop section.) Nor
does it matter that b is unused.

As to why some compilers work as expected and other fail... Well, I
suspect it is a matter of optimization. In general, optimization is more
likely to cause problems with buggy code. But in this particular case,
there is are simple optimizations that would avoid problems. Some
compilers might do variants of those optimizations. In particular,
passing a non-contiguous array slice (such as a row) here is likely to
cause copy-in/copy-out. Such copy-in/copy-out is one of the things that
the standard is explicitly written to allow; it is also sometimes the
source of behavior that can be surprising. (Or conversely, in other
situations, the lack of copy-in/copy-out can result in behavior that
might seem surprising to some.)

I suspect that some compilers avoid the copy out here, possibly because
of the intent(in), or possibly because of b being unused (in which case,
even the copy in could be avoided). It seems an obvious enough
optimization provided that the compiler has the right information at the
right time to do it. However, the standard does *NOT* require this
optimization. Failure to do the optimization does not constitute a
compiler bug in terms of implementing the standard (though it might
indicate that the compiler has room to improve its optimization). The
bug here is in the code.

As an aside, I'll note that I often recommend using assumed shape dummy
arrays instead of explicit shape ones. There are tradeoffs involved, and
there isn't enough data here to adequately judge the real application.
(This code is obviously not directly from a real app, but instead was
done just to demonstrate the issue - and very well done, I might add. If
this were a compiler bug, the vendor would be very happy with this test
case, which simply and clearly illustrates the issue at hand. Perhaps
the vendors whose compilers did not give the expected results might
still like this test - not because it illustrates a bug, but because it
illustrates a lack of optimization - at least that's my guess.) Anyway,
back to my recommendation. One of the advantages of assumed shape
dummies is that you will not get copy-in/copy-out. Well, often that is a
performance advantage - counterexamples exist. Note that assumed shape
would not make this code standard conforming and it would not
technically guarantee that the compiler wouldn't do copy-in/copy-out. It
is just that I seriously doubt that any compiler would do
copy-in/copy-out by default in that situation. (There exist compilers
with options to force such copying for cases where it can help instead
of hurt, but that doesn't tend to be the default).

--
Richard Maine | Good judgment comes from experience;
email: my first.last at org.domain| experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain

Greg Lindahl

unread,
Jan 4, 2007, 2:17:28 PM1/4/07
to
In article <1hrer10.1rpjzoetyakxkN%nos...@see.signature>,

Richard E Maine <nos...@see.signature> wrote:

> This is not an error that
> compilers are required to catch. Nor is it an error that I'd expect most
> compilers to be able to catch.

This is true, however, we have an option to our compiler which says
"don't assume that arguments don't alias." It has several friends, and
when a customer sees a wrong answer, the first thing we do (or the
customer does, if they've read the docs) is compile with all of these
options, which will quickly lead them to the type of bug.

We added this option after we noticed that the Polyhedron benchmarks
contained one example of illegal aliasing. (It's fixed now.)

-- greg
(employed by, not speaking for, QLogic/PathScale)

jel...@gmail.com

unread,
Jan 5, 2007, 4:05:45 AM1/5/07
to
Richard E Maine wrote:

> Gordon's understanding is correct. The code is nonstandard.
>

> [snip]

Thanks for your detailed explanation and thanks to all who replied. So
I was doing something wrong. As you said, the code is not the actual
code I was using, but a simplification. In the real app, I have a
subroutine which takes a point (in 3D) and a vector, the point is
modified and the vector is not; in some calls I want to use the
subroutine with the same point as a vector, and then the problem
appears. It seems I have to create a copy anyway.

paul.rich...@gmail.com

unread,
Jan 5, 2007, 5:16:05 AM1/5/07
to

Richard
...snip...

>
> optimization. Failure to do the optimization does not constitute a
> compiler bug in terms of implementing the standard (though it might
> indicate that the compiler has room to improve its optimization).
>
...snip...

> case, which simply and clearly illustrates the issue at hand. Perhaps
> the vendors whose compilers did not give the expected results might
> still like this test - not because it illustrates a bug, but because it
> illustrates a lack of optimization - at least that's my guess.)

Yes, indeed to both points. Tobias Burnus has posted this missing
optimisation as gcc PR30374 and I am regression testing a fix for
gfortran. He also posted PR30373 to flag the desirability of detecting
aliassing.

Thanks to all those who contributed to this thread.

Paul Thomas

robin

unread,
Jan 15, 2007, 7:38:11 AM1/15/07
to
"glen herrmannsfeldt" <g...@ugcs.caltech.edu> wrote in message
news:0ZCdnXxQauFEXAHY...@comcast.com...

> jel...@gmail.com wrote:
>
> > I've found a strange behaviour when passing the same array portion as
> > both intent(inout) and intent(in) arguments. Is this normal or should I
> > report a compiler bug? Is it legal code anyway?
>
> It looks suspicious to me. One would have to read the standard pretty
> carefully, but in the row case it could be that the calling program
> generates a copy of the array before the call, and copies back after
> the call. It might be that it can do that even for an intent(in)
> argument. Since b does not need a copy, the copy back overwrites a.

There won't necessarily be a copy back, since argument b is intent (in).


0 new messages