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

custom assignment for tr15581 derived type

47 views
Skip to first unread message

amgarching

unread,
Sep 16, 2011, 9:15:49 AM9/16/11
to
Hi, All,

I am not quite sure what is hidden behind a custom
assignment according the fortran sematics. Is this

x = array_expression

translated directly into

call assign_t_1(x, array_expression)

or should I rather imagine

rhs = array_expression
call assign_t_1(x, rhs)

The code that inspired me is below.
Works with Intel fails with Gfortran 4.3.2.

Alexei



module m

type :: t
real, allocatable :: c(:)
end type

interface assignment(=)
module procedure assign_t_1
end interface

contains

subroutine assign_t_1(a, b)
implicit none
type(t), intent(out) :: a
real, intent(in) :: b(:)
! *** end of interface ***

a = t(b)
end subroutine assign_t_1

end module

program prog
use m
implicit none

type(t) :: x

x = t([1.0, 2.0, 3.0])

print *, "x%c =", x%c

x = [10.0, 20.0, 30.0]

print *, "x%c =", x%c

x = [10.0, 20.0, 30.0, 40.0]

print *, "x%c =", x%c

! FIXME: is this supposed to work?
x = x%c * 10.0

print *, "x%c =", x%c
end program

steve

unread,
Sep 16, 2011, 10:14:44 AM9/16/11
to
On Sep 16, 6:15 am, amgarching <alexei.matv...@gmail.com> wrote:
>
> The code that inspired me is below.
> Works with Intel fails with Gfortran 4.3.2.
>

You forgot to define the meaning of "Works"
and "fails". You also forgot to mention the
version of the Intel compiler. And more
importantly, why are you using a 3 year old
compiler that just might have a bug that
may have been fixed sometime in the past
3 years?

--
steve

amgarching

unread,
Sep 16, 2011, 10:52:24 AM9/16/11
to
On Sep 16, 4:14 pm, steve <kar...@comcast.net> wrote:
> On Sep 16, 6:15 am, amgarching <alexei.matv...@gmail.com> wrote:
>
>
>
> > The code that inspired me is below.
> > Works with Intel fails with Gfortran 4.3.2.

When compiled with Intel 11.1 the program terminates
normally and produces the output:

$ ./a.out
x%c = 1.000000 2.000000 3.000000
x%c = 10.00000 20.00000 30.00000
x%c = 10.00000 20.00000 30.00000 40.00000
x%c = 100.0000 200.0000 300.0000 400.0000

>
> You forgot to define the meaning of "Works"
> and "fails".  You also forgot to mention the
> version of the Intel compiler.  And more
> importantly, why are you using a 3 year old
> compiler that just might have a bug that
> may have been fixed sometime in the past
> 3 years?

It must have been fixed (if it were a bug and not an unspecified
behavior). Indeed with Gfortran 4.4 the output is identical.
A workaround is obvious. But I hoped for an enlightening
discussion to understand the rules to tell legal and illegal code
apart.

I know that aliasing should be avoided and

call assign(x, x)

may even produce a warning with some compilers telling that the
same argument is associated both with intent(in) and intent(out)
parameters. On the other hand

x = x

must be legal in a sane setup. So what is actually happening
if assignment is redefined?

Alexei

Richard Maine

unread,
Sep 16, 2011, 11:04:38 AM9/16/11
to
amgarching <alexei....@gmail.com> wrote:

> I am not quite sure what is hidden behind a custom
> assignment according the fortran sematics. Is this
>
> x = array_expression
>
> translated directly into
>
> call assign_t_1(x, array_expression)
>
> or should I rather imagine
>
> rhs = array_expression
> call assign_t_1(x, rhs)

The second form is closer. More precisely, the standard defines it as

call assign_t_1(x,(array_expression))

Note the parens. Specifically, from 12.3.2.1.2 of f2003

"A defined assignment is treated as a reference to the subroutine,
with the left-hand side as the first argument and the right-hand
side enclosed in parentheses as the second argument)."

The parens have an effect much like that of your second form. This makes
defined assignment act like intrinsic assignment in that the RHS is
conceptually evaluated before any changes are made to the LHS. I say
"conceptually" because there can be obvious optimizations in skipping
the extra copy in cases where it doesn't matter.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain

Richard Maine

unread,
Sep 16, 2011, 11:08:18 AM9/16/11
to
amgarching <alexei....@gmail.com> wrote:

> I know that aliasing should be avoided and

Well, that's a common overgeneralization. Aliasing is fine in some
cases. It is only when you modify things that are aliased that trouble
arises.

>
> call assign(x, x)
>
> may even produce a warning with some compilers telling that the
> same argument is associated both with intent(in) and intent(out)
> parameters.

But

call assign(x,(x))

is fine. See my other post from just a minute or so ago.

glen herrmannsfeldt

unread,
Sep 16, 2011, 2:23:06 PM9/16/11
to
Richard Maine <nos...@see.signature> wrote:

(snip regarding defined assignment and aliasing)

> Note the parens. Specifically, from 12.3.2.1.2 of f2003

> "A defined assignment is treated as a reference to the subroutine,
> with the left-hand side as the first argument and the right-hand
> side enclosed in parentheses as the second argument)."

> The parens have an effect much like that of your second form. This makes
> defined assignment act like intrinsic assignment in that the RHS is
> conceptually evaluated before any changes are made to the LHS. I say
> "conceptually" because there can be obvious optimizations in skipping
> the extra copy in cases where it doesn't matter.

But how does the compiler know, in general, it is one of the
cases that doesn't matter? For an internal procedure, I suppose
the compiler could look inside and maybe figure it out. For
external or module procedure, though, it would be harder.

It would seem, then, much more likely than for ordinary assignment
that the compiler would use a temporary array.

-- glen

Steve Lionel

unread,
Sep 16, 2011, 3:38:17 PM9/16/11
to
On 9/16/2011 2:23 PM, glen herrmannsfeldt wrote:
> But how does the compiler know, in general, it is one of the
> cases that doesn't matter? For an internal procedure, I suppose
> the compiler could look inside and maybe figure it out. For
> external or module procedure, though, it would be harder.

The compiler has to recognize that it is dealing with a defined
assignment and look to see if there is any possibility of overlap
between the left and right sides. If it can prove that there isn't,
then it can optimize by not making a copy of the right-hand side. Many
compilers already do this sort of thing with regular assignments. That
the assignment is implemented by a procedure call is not important.

--
Steve Lionel
Developer Products Division
Intel Corporation
Merrimack, NH

For email address, replace "invalid" with "com"

User communities for Intel Software Development Products
http://software.intel.com/en-us/forums/
Intel Software Development Products Support
http://software.intel.com/sites/support/
My Fortran blog
http://www.intel.com/software/drfortran

Refer to http://software.intel.com/en-us/articles/optimization-notice
for more information regarding performance and optimization choices in
Intel software products.

glen herrmannsfeldt

unread,
Sep 16, 2011, 9:57:22 PM9/16/11
to
Steve Lionel <steve....@intel.invalid> wrote:
> On 9/16/2011 2:23 PM, glen herrmannsfeldt wrote:
>> But how does the compiler know, in general, it is one of the
>> cases that doesn't matter? For an internal procedure, I suppose
>> the compiler could look inside and maybe figure it out. For
>> external or module procedure, though, it would be harder.

> The compiler has to recognize that it is dealing with a defined
> assignment and look to see if there is any possibility of overlap
> between the left and right sides. If it can prove that there isn't,
> then it can optimize by not making a copy of the right-hand side. Many
> compilers already do this sort of thing with regular assignments. That
> the assignment is implemented by a procedure call is not important.

I was thinking about cases where the order matters, but if done
in the appropriate order no temporary is needed.

If there is no possible overlap, then the compiler should know.

Now, consider:

x(1:99)=x(2:100)

-- glen

amgarching

unread,
Sep 17, 2011, 9:31:08 AM9/17/11
to

> The second form is closer. More precisely, the standard defines it as

Thanks, This is the kind of confirmation I was hoping for.

I assume that the ruling that intent(out) allocatable components
be deallocated upon

a = whatever

translated to "call assign(a, (whatever))" is irrelevant then.
But doing a manual

call assign(a, a)

with "a" having allocatable component is illegal, right?

Dick Hendrickson

unread,
Sep 17, 2011, 11:08:47 AM9/17/11
to
Right. It's pretty much illegal for any arguments, allocatable or not.

From 12.5.2.13 of F2008

"(1) Action that aff ects the allocation status of the entity or a
subobject thereof shall be taken through the dummy argument.

(3) Action that a ffects the value of the entity or any subobject of
it shall be taken only through the dummy argument unless [POINTER and
TARGET exceptions]."

The basic rule is that dummy arguments that are somehow associated with
each other can't be changed.

Dick Hendrickson

Richard Maine

unread,
Sep 17, 2011, 11:30:14 AM9/17/11
to
amgarching <alexei....@gmail.com> wrote:

> > The second form is closer. More precisely, the standard defines it as

> I assume that the ruling that intent(out) allocatable components
> be deallocated upon
>
> a = whatever
>
> translated to "call assign(a, (whatever))" is irrelevant then.
> But doing a manual
>
> call assign(a, a)
>
> with "a" having allocatable component is illegal, right?

Right, as DIck explains. But then

call asign(a,(a))

is fine and is exactly equivalent to the assignment statement. WIth the
parens, the second actual argument is no longer a. It is an expression.
The expression is pretty trivial and has the same value as a, but it
isn't the same thing as a. The allocatable component of the intent(out)
argument *DOES* get deallocated in both the assignment statement form
and the call form. But that deallocation happens after the evaluation of
the expression in the second argument.

Steve Lionel

unread,
Sep 19, 2011, 12:17:24 PM9/19/11
to
On 9/16/2011 9:57 PM, glen herrmannsfeldt wrote:
> Steve Lionel<steve....@intel.invalid> wrote:
>> The compiler has to recognize that it is dealing with a defined
>> assignment and look to see if there is any possibility of overlap
>> between the left and right sides. If it can prove that there isn't,
>> then it can optimize by not making a copy of the right-hand side. Many
>> compilers already do this sort of thing with regular assignments. That
>> the assignment is implemented by a procedure call is not important.
>
> I was thinking about cases where the order matters, but if done
> in the appropriate order no temporary is needed.

Since in the case of defined assignment, the compiler does not control
the order, it would need to be pessimistic in this regard.
>
> If there is no possible overlap, then the compiler should know.
>
> Now, consider:
>
> x(1:99)=x(2:100)

If this was not a defined assignment, then I would expect a modern
optimizing compiler to recognize cases that can be done as simple memory
copies in whichever order was needed. But for defined assignment, it's
much more complex to analyze and such analysis would need to be later in
the compilation process with inlining and such. I'd expect fewer such
cases to optimize.
0 new messages