From: Tomas Cernaj on
Hello everyone,

is there any way to tell the Ada compiler that an Address attribute
should be constant? I want to use it for accessing fixed memory
locations, and without the Address attribute being constant the compiler
won't optimize away an indirect access.

I couldn't find anything in the RM or GNAT documentation... The point is
that I want to use the 'Address construct on the AVR target, which is an
8-bit processor, so the indirect access is quite expensive.

I suppose that was a bit unclear, so here's an example: :)
I have the following declarations in a package spec file:

type T_Type is array (0 .. 7) of Boolean;
pragma Pack (T_Type);
for T_Type'Size use 8;

package TA is new System.Address_To_Access_Conversions (T_Type);
X : constant access T_Type
:= TA.To_Pointer (System.Storage_Elements.To_Address (50));

Y : T_Type;
for Y'Address use System.Storage_Elements.To_Address (51);
pragma Import (Ada, Y);

Note that X is something like a "T_Type * const X" in C.
Compiling the following code

X (4) := True;
Y (5) := True;

with GNAT (gcc-4.2 -O -S) yields this assembler output (x86-64):

orb $16, 50 ; X (4) := True
movq testpkg__y(%rip), %rdx ; Y (5) := True
movzbl (%rdx), %eax
orl $32, %eax
movb %al, (%rdx)

That's because the compiler can not assume that Y'Address will not be
changed.

Thank you for your help,
Tomas
From: Samuel Tardieu on
>>>>> "Tomas" == Tomas Cernaj <tcernaj.WITHOUTTHIS(a)gmx.de> writes:

Tomas> That's because the compiler can not assume that Y'Address will
Tomas> not be changed.

Well, no, that's not the reason (Y'Address is obviously static and
constant). This is due to an unfortunate combination of three things:

a) because of RM13.3(19), no optimization can be done on Y based on
assumptions of no aliases

b) to implement this clause, GCC marks the implicitly defined pointer
type as volatile

c) when this implicitly defined pointer type is marked as volatile,
GCC generates code which does read+modify+write here at 3 separate
operations rather than using an atomic one

I think GNAT is overconservative concerning (b) as I do not think a
volatile behaviour is mandated here, and that (c) could generate a
better code but this is a separate issue from (b).

Sam
--
Samuel Tardieu -- sam(a)rfc1149.net -- http://www.rfc1149.net/
From: Samuel Tardieu on
>>>>> "Sam" == Samuel Tardieu <sam(a)rfc1149.net> writes:
>>>>> "Tomas" == Tomas Cernaj <tcernaj.WITHOUTTHIS(a)gmx.de> writes:

Tomas> That's because the compiler can not assume that Y'Address will
Tomas> not be changed.

Sam> Well, no, that's not the reason (Y'Address is obviously static
Sam> and constant). This is due to an unfortunate combination of three
Sam> things:

Sam> a) because of RM13.3(19), no optimization can be done on Y based
Sam> on assumptions of no aliases

Sam> b) to implement this clause, GCC marks the implicitly defined
Sam> pointer type as volatile

Sam> c) when this implicitly defined pointer type is marked as
Sam> volatile, GCC generates code which does read+modify+write here at
Sam> 3 separate operations rather than using an atomic one

Sam> I think GNAT is overconservative concerning (b) as I do not think
Sam> a volatile behaviour is mandated here, and that (c) could
Sam> generate a better code but this is a separate issue from (b).

I found a discussion about (b) dating from last September which
explains that a lot of Ada code assumes that pragma Volatile is
implicit and cannot be easily changed. So I asked about (c) on the GCC
developers mailing-list, as it may be a missed optimization.

Sam
--
Samuel Tardieu -- sam(a)rfc1149.net -- http://www.rfc1149.net/
From: Tomas Cernaj on
Thank you for your quick response. You've helped me a lot to sort things
out.

Actually I think there's two problems at hand:

1) the read/modify/write access

2) the indirect access

ad 1): As explained by Richard Kenner, the C construct "y |= 32" is by
definition equivalent to "y = y | 32", so R/M/W is perfectly OK. However,
writing "Y (5) := True" IMO means that we only want to set the
corresponding bit, no matter what the rest of the byte/word etc. looks
like.
I've tried this using a (volatile) bit field in C, and here again gcc
generates a R/M/W access. (compiler problem...?)

ad 2): I'm not quite sure if I've understood the concept of aliased types
you mentioned in (a)... :-|
Anyways, I modified the example in my first post to include "pragma
Volatile (T_Type);". Here's what gcc generates:

movzbl 50, %eax ; X (4) := True
orl $16, %eax
movb %al, 50
movq testpkg__y(%rip), %rdx ; Y (5) := True
movzbl (%rdx), %eax
orl $32, %eax
movb %al, (%rdx)

So X is accessed directly while Y is accessed indirectly. That's why I
thought it had something to do with Y'Address not being constant... (I
mean that whenever one uses the package where Y is declared one can still
change the value of Y'Address).

Am I missing a point?

Thanks,
Tomas
From: Samuel Tardieu on
>>>>> "Tomas" == Tomas Cernaj <tcernaj.WITHOUTTHIS(a)gmx.de> writes:

Tomas> So X is accessed directly while Y is accessed
Tomas> indirectly. That's why I thought it had something to do with
Tomas> Y'Address not being constant... (I mean that whenever one uses
Tomas> the package where Y is declared one can still change the value
Tomas> of Y'Address).

Tomas> Am I missing a point?

Yes: the fact that nobody else can change the value of Y'Address :)

Sam
--
Samuel Tardieu -- sam(a)rfc1149.net -- http://www.rfc1149.net/