Version 1.6 of ais/ai-00173.txt

Unformatted version of ais/ai-00173.txt version 1.6
Other versions for file ais/ai-00173.txt

!standard 13.03 (16)          03-08-01 AI95-00173/01
!class binding interpretation 96-11-16
!status No Action (11-0-0) 04-06-17
!status work item 98-03-17
!status received 96-11-16
!priority Low
!difficulty Hard
!subject Optimizations and the use of 'Address
!summary
Suppose an execution accesses the same storage twice, at least one of the accesses modifies the storage, and at least one of the accesses is based on an address value. Then the behavior of the execution is unspecified unless at least one of the following conditions holds:
o Each of the accesses is the update or examination of a volatile object.
o Each of the accesses is the update or examination of an object that is
aliased, imported, or exported, is of a by-reference type, or has an address specified by an address clause; and both objects are of the same type.
!question
Common optimization techniques, applied to source code that makes undisciplined use of 'Address, can result in object code with surprising behavior. Under what circumstances are optimizations required to preserve the effects resulting from examining or modifying variables through their addresses?
!response
An access to an object is "based on an address value" if either of the following holds:
o The object is part of an object whose address is specified by an address
clause.
o The object is part of an object designated by an access value that was
generated by an instance of System.Address_To_Access conversions.
Suppose an execution accesses the same storage twice, at least one of the accesses modifies the storage, and at least one of the accesses is based on an address value. Then the behavior of the execution is unspecified unless at least one of the following conditions holds:
o Each of the accesses is the update or examination of a volatile object.
o Each of the accesses is the update or examination of an object that is
aliased, imported, or exported, is of a by-reference type, or has an address specified by an address clause; and both objects are of the same type.
!discussion
A naive approach would be to allow only optimizations valid in the presence of arbitrary aliasing. This approach is impractical because the possibility of arbitrary aliasing is so prevalent that many innocuous optimizations would be inhibited. Consider the following example:
package Pkg is type Integer_Pointer is access all Integer; type Float_Pointer is access all Float; F: aliased Float; end Pkg;
with System.Address_To_Access_Conversions; package Access_Integer_Conversions is new System.Address_To_Access_Conversions(Integer);
with Pkg; use Pkg; procedure Proc1(IP: in Integer_Pointer; FP: in Float_Pointer) is begin IP.all := IP.all + 1; FP.all := FP.all + 1.0; end Proc1;
with Pkg, Access_Integer_Conversions, Proc1; use Pkg, Access_Integer_Conversions; procedure Proc2 is Object_Pointer_To_F: Object_Pointer := To_Pointer(F'Address); Integer_Pointer_To_F: Integer_Pointer := Integer_Pointer(Object_Pointer_To_F); Float_Pointer_To_F: Float_Pointer := F'access; begin Proc1(Integer_Pointer_To_F, Float_Pointer_To_F); end Proc2;
Conventional instruction-scheduling techniques could generate code for Proc1 that loads IP.all into a general register, then loads FP.all into a floating-point register, then adds one to each register, then stores each register. However, as Proc2 demonstrates, it is possible for IP.all and FP.all to overlap, in which case this scheduling of instructions produces a result different from the result of executing the two assignment statements in order. Nonetheless, it would be unreasonable to prohibit a scheduling that interleaves instructions from the two assignment statements in Proc1. A separately compiled subprogram like Proc1 is most likely to be part of a program that does no address manipulation, so that IP.all and FP.all cannot possibly overlap. (6.2(12), on aliasing of subprogram parameters, does not apply in this case; it is not the formal parameters, but the objects they designate, that are aliased.) In contrast, given the procedure
with Pkg; use Pkg; procedure Proc3 (IP1, IP2: in Integer_Pointer) is begin IP1.all := IP1.all + 1; IP2.all := IP2.all + 1; end Proc3;
it is prudent to assume that IP1 and IP2 may be equal, and thus inhibit any optimization that depends on IP1.all and IP2.all occupying disjoint storage.
Our goal is to produce a set of rules that is simple enough to be easily understood, makes common usages safe by default, provides the programmer with a means to make uncommon usages safe, and inhibits relatively few optimizations.
We allow an optimizer to assume that addresses are used in a type-safe manner. That is, potential aliasing between variables of different types need not be considered when determining whether an optimization is safe. A programmer knowingly using addresses to view the same storage as belonging to two different types can (and should) make both views volatile or atomic to inhibit reordering. (This requires implementation support for the shared-variable-control pragmas defined in the Systems Programming annex.) For example, a programmer who knows that Integer_Pointer and Float_Pointer values may designate overlapping objects could use the following version of package Pkg:
package Pkg is type Volatile_Integer is new Integer; pragma Volatile(Volatile_Integer); type Volatile_Float is new Float; pragma Volatile(Volatile_Float); type Integer_Pointer is access all Volatile_Integer; type Float_Pointer is access all Volatile_Float; F: aliased Volatile_Float; end Pkg;
C.6(20) states, "The external effect of a program (see 1.1.3) is defined to include each read and update of a volatile or atomic object." Therefore, 1.1.3(15) inhibits optimizations that reorder reads or updates of such objects.
13.3(16) recommends the following level of support for the Address attribute:
X'Address should produce a useful result if X is an object that is aliased or of a by-reference type, or is an entity whose Address has been specified.
AARM 13.3(16.b) asserts, "An implementation need not go to any trouble to make Address work in other cases," and this is nearly true. However, 13.3(19) adds the following condition to the recommended level of support:
If the address of an object is specified, or it is imported or exported, then the implementation should not perform optimizations based on assumptions of no aliases.
Thus this interpretation restricts optimizations only in cases where the Standard guarantees the existence of a "useful" address, and in the case of imported or exported objects.
13.7.2(5) defines the behavior of address-to-access conversions as follows:
To_Pointer(X'Address) is equal to X'Unchecked_Access for an X that allows Unchecked_Access. To_Pointer(Null_Address) returns null. For other addresses, the behavior is unspecified.
The Standard provides no guarantees about the behavior of a program that invokes To_Pointer with a value that is not the address of an object X of the type denoted by the generic formal type Object. Since the semantics of type-unsafe address-to-access conversions are already unpredictable, there is nothing to be gained for the programmer by insisting that optimizations preserve the semantics of programs containing such conversions.
The Standard does not attach any such unpredictability to the type-unsafe use of address clauses. For example, the Standard would seem to require Proc1 to be compiled in such a way that it can be invoked as follows and still behave as if its two assignment statements were executed in sequence:
with Pkg, Access_Integer_Conversions, Proc1; use Pkg, Access_Integer_Conversions; procedure Proc2 is I: Integer; for I'Address use F'Address; Integer_Pointer_To_F: Integer_Pointer := I'access; Float_Pointer_To_F: Float_Pointer := F'access; begin Proc1(Integer_Pointer_To_F, Float_Pointer_To_F); end Proc2;
For the reasons explained earlier, this requirement overly restricts the optimizations that may be applied when compiling Proc1. Therefore, we do not require optimizations to preserve the semantics of any program containing type-unsafe use of addresses, except as required by volatile objects.
(It is the treatment of type-safety violations arising from address clauses in the same manner as type-safety violations arising from address-to-access conversions that makes this interpretation a binding interpretation. Otherwise, it would be a ramification of the rules in the Standard.)
!appendix

!section 13.3(16)
!subject Optimizations and the use of 'Address
!reference RM95 13.3(16)
!reference RM95 13.7.1(6)
!from Tucker Taft  96-11-06
!reference 1996-5743.a Tucker Taft 1996-11-6>>
!discussion

If one tries to do relatively aggressive optimization, then
undisciplined use of 'Address can cause havoc.  Unfortunately,
the RM does not provide any guidelines for what is "undisciplined"
use of 'Address.  13.3(16) says that 'Address should produce
a "useful" value for certain cases (including all by-reference
types), and *specifying* the 'Address of an object should disable
certain optimizations.  However, there is no guidance to the
user or the implementor as to what should be the effect of referencing
the 'Address attribute on an object.

Particularly nasty cases occur when a local record or array
is passed as an IN parameter to a function, and the function
simply returns (or stores into a global) the 'Address of the
parameter.  Any stores through the address returned by such
a function could have mysterious and unexpected side-effects
on the pointed-to record or array.  Unless an optimizer gives
up all attempts to optimize uses of record or array components,
it must presume that such mysterious side-effects don't happen.

This leads to some set of restrictions on the use of 'Address
and on stores through an address.  Perhaps the RM should include
a proposed set of restrictions, or at least allow implementations
to impose restrictions on the use of values produced by 'Address.

Here is one possible set of restrictions:

 First, some context:
    We are only worried here about objects that are updated
    by code that makes use only of the object's address, rather
    than via an Ada name that denotes the object.

    There are two interesting points: one where the 'Address
    attribute reference appears; and the other where the actual
    update-via-address takes place.

 Here are the proposed restrictions:

    If an object is going to be updated via its address,
    then at the point of the 'Address, the prefix must
    denote a variable view of the object, and at the point
    of the update, the object must still exist.

    If the point of the 'Address and the point of the
    update-via-address are not in the same subprogram, then
    there must be no reference, by a normal Ada name, to the value of
    the object between the point at which the 'Address is
    taken and the point at which the update-via-address occurs.

Violating any of these restrictions can lead to erroneous execution.

The point of these restrictions is so that the optimizer can
effectively treat a variable whose 'Address is taken as volatile
throughout the subprogram where the 'Address explicitly occurs,
and that the eventual update-via-address can be seen as just
a deferred effect of taking the 'Address (by disallowing references
to the value between the 'Address and the update).

Comments?

-Tuck

****************************************************************

!section 13.3(16)
!subject Optimizations and the use of 'Address
!reference RM95 13.3(16)
!reference RM95 13.7.1(6)
!from Tucker Taft  96-11-06
!reference 1996-5743.a Tucker Taft 1996-11-6
!reference 96-5744.a Norman H. Cohen 96-11-7>>
!discussion

> Here are the proposed restrictions:
>
> If an object is going to be updated via its address,
> then at the point of the 'Address, the prefix must
> denote a variable view of the object, and at the point
> of the update, the object must still exist.
>
> If the point of the 'Address and the point of the
> update-via-address are not in the same subprogram, then
> there must be no reference, by a normal Ada name, to the value of
> the object between the point at which the 'Address is
> taken and the point at which the update-via-address occurs.

I'm not convinced these rules do the trick.  In a case like

   package Global_Data is
      A: Integer;
         -- NOT declared aliased, but its 'Address is
         --   taken by the caller of P.
   end Global_Data;

   with System.Address_To_Access_Conversions;
   package Integer_Pointer_Conversions is
      new System.Address_To_Access_Conversions (Integer);

   with Integer_Pointer_Conversions;
   use Integer_Pointer_Conversions;
   with Global_Data;
   procedure P (Address_Of_A: in System.Address) is
      Pointer_To_A: constant Object_Pointer :=
                       To_Pointer(Address_Of_A);
      B: Integer;
   begin
      [stuff having nothing to do with A or B];
      Pointer_To_A.all := 0;
      B := Global.A;
      ...
   end P;

the programmer appears to have obeyed the rules, but I see nothing to
prevent the compiler from scheduling the assignment to B before the
update-through-address of A, thus surprising the programmer.  (Of course
similar examples can be constructed with the global scalar replaced by a
composite passed as a by-reference parameter.)

-- Norman

****************************************************************

!section 13.3(16)
!subject Optimizations and the use of 'Address
!reference RM95 13.3(16)
!reference RM95 13.7.1(6)
!reference 1996-5743.a Tucker Taft 1996-11-6
!reference 1996-5744.a Norman Cohen 1996-11-7
!from Tucker Taft  96-11-07
!reference 1996-5746.a Tucker Taft 1996-11-7>>
!discussion

> > Here are the proposed restrictions:
> >
> > If an object is going to be updated via its address,
> > then at the point of the 'Address, the prefix must
> > denote a variable view of the object, and at the point
> > of the update, the object must still exist.
> >
> > If the point of the 'Address and the point of the
> > update-via-address are not in the same subprogram, then
> > there must be no reference, by a normal Ada name, to the value of
> > the object between the point at which the 'Address is
> > taken and the point at which the update-via-address occurs.
>
> I'm not convinced these rules do the trick.  In a case like
>
>    package Global_Data is
>       A: Integer;
>          -- NOT declared aliased, but its 'Address is
>          --   taken by the caller of P.
>    end Global_Data;
>
>    with System.Address_To_Access_Conversions;
>    package Integer_Pointer_Conversions is
>       new System.Address_To_Access_Conversions (Integer);
>
>    with Integer_Pointer_Conversions;
>    use Integer_Pointer_Conversions;
>    with Global_Data;
>    procedure P (Address_Of_A: in System.Address) is
>       Pointer_To_A: constant Object_Pointer :=
>                        To_Pointer(Address_Of_A);
>       B: Integer;
>    begin
>       [stuff having nothing to do with A or B];
>       Pointer_To_A.all := 0;
>       B := Global.A;
>       ...
>    end P;
>
> the programmer appears to have obeyed the rules, but I see nothing to
> prevent the compiler from scheduling the assignment to B before the
> update-through-address of A, thus surprising the programmer.  (Of course
> similar examples can be constructed with the global scalar replaced by a
> composite passed as a by-reference parameter.)

It looks like there is another relevant "point" in the equation, namely
the point where the conversion from 'Address back to an access value
takes place, relative to where the update takes place.
I would presume that if the optimizer "sees" this conversion from
Address to access value it can presume that something is fishy, and
perhaps take appropriate precautions (though tracking where that value
wonders may not be easy).

However, if that conversion appears deep inside some function,
then the optimizer has no clue that the access value through which
it is storing is a "dangerous" one.

One possible additional requirement is that the subprogram where the
update-via-address takes place may not have *any* reference to the
value of the variable via a normal Ada name.  This would solve the
above problem, presumably, but then we get into what happens if
there is inlining of code, or interprocedural "optimization"
(destruction?).

Here is one possible alternative for the second paragraph:

    Any update-via-address must occur before the subprogram
    containing the 'Address returns, and the only references
    to the value of the variable by a normal Ada name before
    the subprogram returns must be within the subprogram itself,
    and not in some subprogram it calls.

But that is perhaps too limiting...

Any other suggestions?

Perhaps the above is sufficient to cover cases where the
object is not marked "aliased" or "Volatile" or "exported."

It basically lets you take 'Address of a parameter for the purpose
of updating it before you return, even if the actual corresponding
to the parameter is not aliased, volatile, or exported.  For globals
whose 'Address is taken, aliased, Volatile, or Export would be required.

> -- Norman

-Tuck

****************************************************************

!section 13.3(16)
!subject Optimizations and the use of 'Address
!reference RM95 13.3(16)
!reference RM95 13.7.1(6)
!reference 1996-5743.a Tucker Taft 1996-11-6
!reference 1996-5744.a Norman Cohen 1996-11-7
!reference 1996-5746.a Tucker Taft 1996-11-7
!from Norman Cohen  96-11-07
!reference 96-5747.a Norman H. Cohen 96-11-7>>
!discussion

> Any other suggestions?

The straightforward rule would be that it is erroneous to update a variable
by its address and refer to the variable by its Ada name in the same
program, unless the variable is marked volatile (by one of the pragmas
Volatile, Atomic, Volatile_Components, or Atomic_Components).  It does not
suffice for the variable to be marked aliased:  An aggressive optimizer
could note that there are no local updates through access-to-T and deduce
that references to objects of type T can be safely moved.

Formally, this is a glaring upward incompatibility.  In practical terms,
due to the unpredictable nature of erroneous execution, existing compilers
can continue to do what they are now doing and existing code, even if it
becomes formally erroneous, will continue to behave (or misbehave) as it
always did, at least until the code is recompiled by a more aggressively
optimizing compiler.

****************************************************************

!section 13.3(16)
!subject Optimizations and the use of 'Address
!reference RM95 13.3(16)
!reference RM95 13.7.1(6)
!reference 1996-5743.a Tucker Taft 1996-11-6
!reference 1996-5744.a Norman Cohen 1996-11-7
!reference 1996-5746.a Tucker Taft 1996-11-7
!reference 1996-5747.a Norman Cohen 1996-11-7
!from Tucker Taft 96-11-07
!reference 1996-5749.a Tucker Taft 1996-11-7>>
!discussion

> > Any other suggestions?
>
> The straightforward rule would be that it is erroneous to update a variable
> by its address and refer to the variable by its Ada name in the same
> program, unless the variable is marked volatile (by one of the pragmas
> Volatile, Atomic, Volatile_Components, or Atomic_Components).  It does not
> suffice for the variable to be marked aliased:  An aggressive optimizer
> could note that there are no local updates through access-to-T and deduce
> that references to objects of type T can be safely moved.

Yes, it seems like Volatile or Ex/Import is required for globals
whose 'Address is going to be taken (Ex/Import does the job thanks
to 13.3(19)).

However, for non-globals, this seems too draconian, since there is no way
to apply Volatile or Export/Import to a formal parameter.  I think
something like the restriction I proposed in my second message would work,
namely that if 'Address is taken in a subprogram, and the variable is not
Volatile/Ex/Imported, then the update-via-address must occur before
the subprogram returns, and any value references by Ada name must be
restricted to the subprogram where the 'Address explicitly occurs.

> Formally, this is a glaring upward incompatibility.  In practical terms,
> due to the unpredictable nature of erroneous execution, existing compilers
> can continue to do what they are now doing and existing code, even if it
> becomes formally erroneous, will continue to behave (or misbehave) as it
> always did, at least until the code is recompiled by a more aggressively
> optimizing compiler.

I don't think that is acceptable, given the common use of 'Address on
a formal parameter for doing otherwise relatively portable binary I/O.

-Tuck

****************************************************************

!section 13.3(16)
!subject Optimizations and the use of 'Address
!reference RM95 13.3(16)
!reference RM95 13.7.1(6)
!reference 1996-5743.a Tucker Taft 1996-11-6
!reference 1996-5744.a Norman Cohen 1996-11-7
!reference 1996-5746.a Tucker Taft 1996-11-7
!reference 1996-5747.a Norman Cohen 1996-11-7
!reference 1996-5749.a Tucker Taft 1996-11-7
!from Norman Cohen 96-11-07
!reference 96-5751.a Norman H. Cohen 96-11-7>>
!discussion

> > Formally, this is a glaring upward incompatibility.  In practical terms,
> > due to the unpredictable nature of erroneous execution, existing compilers
> > can continue to do what they are now doing and existing code, even if it
> > becomes formally erroneous, will continue to behave (or misbehave) as it
> > always did, at least until the code is recompiled by a more aggressively
> > optimizing compiler.
>
> I don't think that is acceptable, given the common use of 'Address on
> a formal parameter for doing otherwise relatively portable binary I/O.

Does this use involve updating an object through its address and then
examining it through its Ada name?

****************************************************************

!section 13.3(16)
!subject Optimizations and the use of 'Address
!reference RM95 13.3(16)
!reference RM95 13.7.1(6)
!reference 1996-5743.a Tucker Taft 1996-11-6
!from Randy Brukardt 96-11-07
!reference 96-5752.a Randy Brukardt  96-11-7>>
!discussion

>If one tries to do relatively aggressive optimization, then=20
>undisciplined use of 'Address can cause havoc.  Unfortunately,
>the RM does not provide any guidelines for what is "undisciplined"
>use of 'Address.  13.3(16) says that 'Address should produce
>a "useful" value for certain cases (including all by-reference
>types), and *specifying* the 'Address of an object should disable
>certain optimizations.  However, there is no guidance to the
>user or the implementor as to what should be the effect of referencing
>the 'Address attribute on an object.

I agree with your note this far, but then you get much too complicated.

I have always viewed the RM as saying that the only 'Addresses which =
have
to work are those specified in 13.3(16).  Other ones may produce a =
result,
but optimization may make that result useless.  We changed our manual
to stress that to users years ago (that was one of the first Ada 95 =
changes
made to our documentation).

I don't think there is any special optimizations needed for aliased, =
by-reference, or specified types, since they already are handled =
specially by
optimizers.  'Address on them will work as expected.

I see little reason that the language should guarentee more.

Of course, as a practical matter, compilers will support more so as not =
to
make existing Ada 83 code fail to work.  However, that is not a language
issue -- Ada 83 compilers were very inconsistent on this point.  I know =
that
some other compilers (not ours) could not take 'Address of constants or
some local variables when optimization was on.  (We implemented special
code for those cases in order to make them to work).  Thus, any Ada 83
code using 'Address was not portable to other Ada compilers anyway.  I
don't think it would be benefical to Ada to require some compilers to =
support
more 'Address uses.

In my view, 'Address (as a query) should have been an obsolecent feature
anyway.  Just about every use of it would be better handled with =
stronger
typing using 'Access or 'Unchecked_Access.  It wasn't made such because
specification of it is still useful.  I think it is crazy to waste much =
time (or
especially implementation effort) trying to figure out how it ought to =
work in
the face of optimization.

                        Randy.

****************************************************************

!section 13.3(16)
!subject Optimizations and the use of 'Address
!reference RM95 13.3(16)
!reference RM95 13.7.1(6)
!reference 1996-5743.a Tucker Taft 1996-11-6
!reference 1996-5752.a Randy Brukardt 1996-11-7
!from Tucker Taft 96-11-7
!reference 1996-5753.a Tucker Taft 1996-11-7>>
!discussion

> ...
> I agree with your note this far, but then you get much too complicated.
>
> I have always viewed the RM as saying that the only 'Addresses which =
> have
> to work are those specified in 13.3(16).  Other ones may produce a =
> result,
> but optimization may make that result useless.  We changed our manual
> to stress that to users years ago (that was one of the first Ada 95 =
> changes
> made to our documentation).
>
> I don't think there is any special optimizations needed for aliased, =
> by-reference, or specified types, since they already are handled =
> specially by
> optimizers.  'Address on them will work as expected.
>
> I see little reason that the language should guarantee more.

Even if we limit ourselves to aliased and by-reference, many aggressive
optimizers will be flumoxed if the update-via-address occurs in a random
place.  Are you saying that every local object of a by-reference type
is trashed by any subprogram call?  That seems a bit overly pessimistic.

Similarly, just being aliased seems insufficient, since Ada-oriented
optimizers could normally presume that an aliased object of type
T could only be altered by an assignment through an access-to-T.
There is nothing precluding converting the 'Address of an aliased
object to an access-to-T1, and storing through that.

In any case, it seems we need a stronger statement in the RM
saying that storing through a value produced by 'Address has
implementation-defined effects.  It would be ideal if we could
also provide guidance to implementors and users as to what should normally
be safe to do with 'Address, and what would often be unsafe.

> ...
>                       Randy.

-Tuck

****************************************************************

!section 13.3(16)
!subject Optimizations and the use of 'Address
!reference RM95 13.3(16)
!reference RM95 13.7.1(6)
!reference 1996-5743.a Tucker Taft 1996-11-6
!reference 1996-5752.a Randy Brukardt 1996-11-7
!reference 1996-5753.a Tucker Taft 1996-11-7
!from Randy Brukardt 1996-11-8
!reference 96-5755.a Randy Brukardt  96-11-8>>
!discussion

>Even if we limit ourselves to aliased and by-reference, many aggressive
>optimizers will be flumoxed if the update-via-address occurs in a random
>place.  Are you saying that every local object of a by-reference type
>is trashed by any subprogram call?  That seems a bit overly pessimistic.

Our optimizer assumes EVERYTHING is trashed by any subprogram call.
(Yes, I'm a pessimist by nature.)  Obviously, that's too conservative.  For
Ada 83, where unrestricted use of 'Address was common, it really could
be necessary.  For Ada 95, I would like to see 'Address discouraged
enough that it would be safe to trust that non-aliased (non-volitile, too, I
suppose) local variables aren't trashed.

For me, to tell more, the compiler has to interprocedural optimizations.  That
is especially true since our compiler system allows drop-in assembler
routines, which of course don't necessarily follow any Ada rules.

I realize that my position is essentially equivalent to "aggressive optimization
= incorrect optimization", a minority position at best.  I have always objected
to changing the users code in ways that they can detect (which puts me
into a small minority) -- but, hey I'm in Ada, so I'm ALREADY in a small
minority.  If I wanted to be in the mainstream, I'd be struggling to learn JAVA
now.  :-)

>Similarly, just being aliased seems insufficient, since Ada-oriented
>optimizers could normally presume that an aliased object of type
>T could only be altered by an assignment through an access-to-T.
>There is nothing precluding converting the 'Address of an aliased
>object to an access-to-T1, and storing through that.

I suppose that an optimizer could presume that, although that is more
information than the vast majority of optimizers have.  It would be nice if Ada
was sufficiently strong to justify the investment to build Ada-95-only
optimizers
and code generators from the ground up -- they'd turn out a whole lot better
than the stuff that is out there.  As it is, I expect that most of the Ada 95
systems will use technology that is very similar to their Ada 83 technology,
which would prevent much use of information specific to Ada 95 (like
that of general access types).

>In any case, it seems we need a stronger statement in the RM
>saying that storing through a value produced by 'Address has
>implementation-defined effects.  It would be ideal if we could
>also provide guidance to implementors and users as to what should normally
>be safe to do with 'Address, and what would often be unsafe.

Right.  My position is that doing anything with 'Address is unsafe (other than
specifying it).  Use 'Access if you want to be safe.

                Randy.

****************************************************************

>From the minutes of the November 1997 ARG meeting:

There was discussion about the optimization capabilities of C and
FORTRAN compilers in handling address operators.  Arguably compilers
effectively optimize around dereferencing of such address values.  Ada
should allow this as well.

Bob, who wrote the paragraph 13.3(16), said that the user was on her
own if she applied 'Address to an object that was not aliased.  First,
the object might not be addressable at all. Second, optimizations
should be allowed to keep non-aliased objects in registers thereby
making 'Address undefined, or cache their value, rendering the use of
the obtained address rather useless.  It would take much more effort
by the compiler to determine non-aliased objects to which 'Address is
applied in order to avoid optimizations that involve this object. (In
fact, such determination is impossible for global variables and their
components).  The wording is currently loose enough to permit the
continued use of 'Address in legacy Ada83 code, while still not
preventing optimizations.

Tuck is proposing some additional restrictions beyond 13.3(16) to
enable subprograms to apply 'Address to a formal parameter, that may
be a part of legacy code.  It's too late to permit the user specify a
formal parameter with the aliased keyword.  Hmmm ... how about creating
a calling convention where formal parameters are aliased???  Not
really.

The group is leaning towards no action or a confirming paragraph
13.3(16), except Tuck's point that using 'Address provides a
language-defined method for violating the type rules.  Several people
feel that this hole should be highlighted as implementation-defined.
Namely, the user who accesses an object both through 'Address and
through its name is courting trouble and must be disciplined to "poke"
the object through 'Address in a type safe manner.

It was observed that "volatile" assures the actuality of values in
memory and will defeat all optimizations regarding the object.
"Aliased" should have the semantics that the compiler should at least
be allowed to assume type-safeness, i.e., an assignment to a
dereferenced "access to T" can only affect objects of type T, no
matter how the access value was obtained.  For any other conversions
of addresses to access types, the user is guaranteed nothing.

Norm will dig into this AI and complete a write-up that handles the
optimization and type safety concerns from the meeting.

****************************************************************

From: 	Norman H Cohen[SMTP:ncohen@us.ibm.com]
Sent: 	Thursday, April 30, 1998 12:58 PM

The discussion of AI-173 omits the Venn diagram that Tuck drew, which I think
is the key to the solution.  Here is the same hierarchy, presented as a tree:

Address-taken objects
(includes subtrees below +
 X for which X'Address is written locally)
   |
   +---------aliased objects of type T1
   |         (includes subtrees below+
   |          declared aliased+
   |          designated by general access types)
   |             |
   |             +-----objects of type T1 designated
   |             |        by pool-specific type A11
   |             |
   |             +-----objects of type T1 designated
   |                      by pool-specific type A12
   |
   +---------aliased objects of type T2
             (includes subtrees below+
              declared aliased+
              designated by general access types)
                 |
                 +-----objects of type T2 designated
                 |        by pool-specific type A21
                 |
                 +-----objects of type T2 designated
                           by pool-specific type A22

Suppose each object is placed in the innermost applicable Venn-diagram circle,
or the applicable tree node farthest from the root.  Then assignment to a
variable in a given category should force the compiler to regard all objects
placed in the same category, in enclosing categories, and in enclosed
categories to be regarded as potentially modified.  (In the AI, of course, I
have to word that from the point of view of the programmer rather than the
compiler.)

-- Norman
****************************************************************

Editor's note:

The priority of this AI was changed based on ARG discussion in November 2000.

****************************************************************

From: Robert Dewar
Sent: Wednesday, July 16, 2003  10:36 AM

The RM says

   19  If the Address of an object is specified, or it is imported or
       exported, then the implementation should not perform optimiza-
       tions based on assumptions of no aliases.

Now for sure this does not mean what it says (which is that the compiler must
stop ALL optimization based on aliasing EVERYWHERE in the generated code if
a SINGLE address clause is used).

So it means something about assumptions for this particular variable. What
exactly is not allowed (we sort of know intuitively if we are compiler
writers, but it is far from clear semantically, and in this case friendly
reading is not really sufficient).

What about

    A : Integer;
    B : Integer;
    for B'Address use A'Address;

Well it sure seems like we want to stop optimization in both directions,
but the RM statement probably only affects code generation for references
to B and not for A.

In GNAT we make A and B implicitly volatile in the above situation (for
code generation purposes, not for legality purposes, which raises issues
of lack of protection when passing parameters etc -- the kind of protection
that officially volatile objects are provided).

Actually the sequence above is not required to be accepted, instead we
need to write

   A : Integer;
   A_Address : constant Address := A'Address;
   B : Integer;
   for B'Address use A_Address;

Well now it's getting a bit harder to fish out the fact that we should not
have any optimization on A. GNAT goes this far, but obviously the overlay
can be "disguised" further than this in a manner we would not detect (e.g.
by using many different constants defined in terms of one another).

****************************************************************

From: Tucker Taft
Sent: Wednesday, July 16, 2003  11:28 AM

Aliasing is generally symmetric (though not
transitive).  That is, if B is potentially aliased
with A, then A is potentially aliased with B.

So I think a reasonable reading is that when
the address for B is specified by an expression
or imported, then the compiler should not assume
it is an "independent" variable, and in fact might
be aliased with other things.  Now which other things?
I suppose anything whose address it might share.  By
default, that would mean everything whose address was
taken or which was exported or whose 'Access might
have been converted to Address.

I agree that some clarification is in order, in any case.
I can see that just making B volatile by itself would
not solve the problem.  But if you are using a backend
that handles C, this seems straightforward, since I presume
that "under the covers" you are effectively declaring
an implicit pointer-to-int object B__Addr, and defining
B as equivalent to *B__Addr.  B__Addr is initialized with
the expression given in the address clause.

A typical C backend will survive that and will make an
appropriate determination of what *B__Addr might
be aliased with.

****************************************************************

From: Robert Dewar
Sent: Wednesday, July 16, 2003  12:05 PM

The easiest way to say this precisely would be to say that it was implicitly
volatile, but in fact this is a bit confusing because we would not require
all the volatile rules to be met.

Also, this seems to miss my point, which is whether you want to have
constraints on A. In other words, if B is changed, should the compiler "see" a
change in the value of A.

Note that the use of address clauses to overlay two variables is in my
experience one of the most common uses of address clauses, and is precisely
the case in which the symmetrical treatment of aliasing for (suppression of)
optimization purposes makes sense, so that is why it is perhaps worth
addressing specially.

****************************************************************

From: Tucker Taft
Sent: Wednesday, July 16, 2003  1:26 PM

We often use address clauses in the run-time to effect a default
initialization on some "raw storage" whose address is passed
into a routine.  In this case, the aliasing is between two
objects of potentially different types, one being effectively
a storage array (properly aligned, hopefully), and the other
some higher level Ada (usually record) type.

I don't particularly like the implicitly volatile semantics; that
seems more like an implementation approach.  The key thing
is that at the semantic level, the address used in an address
clause can be pretty much anything, and the compiler is supposed
to do the "right thing."  If the compiler can track the address-value used
in the address clause, and it "knows" where it points, then it need
not treat the object as implicitly volatile, but rather can treat
it more like a renaming.  If it does not know where the address
"came from," then it has to make more pessimistic assumptions in
terms of what it might be aliased with, but this never seems to
go to the point of "volatility," though an implementation might
choose that approach for pragmatic reasons.  But just making
it volatile doesn't solve the problem, unless all possible objects
whose address might have been used to produce the value used
in the address clause are also marked volatile, which seems like
a lot of distributed overhead for just having one variable with
an address clause.

****************************************************************

From: Robert Dewar
Sent: Wednesday, July 16, 2003  2:41 PM

I agree with this.

But I am still concerned about the other way round issue.

****************************************************************

From: Erhard Ploedereder
Sent: Wednesday, July 16, 2003  1:35 PM

> Also, this seems to miss my point, which is whether you want to have
> constraints on A. In other words, if B is changed, should the compiler "see"
> a change in the value of A.

In terms of a language rule, this would be very nasty. Since there are no
restrictions on the nature of <expression> (there are only implementation
permissions to restrict), the address clause can refer to
pretty much anything with the consequence that most variables would have to
be treated as potentially aliased in the vicinity of accesses to the
address-spec'ed variable.

I suspect that Tuck's implementation model under separate compilation has
precisely this effect for all global variables, even if <expression> is
static and "nice". (Yes, there is an argument of semantic closure making
the info available -- from private parts, too ?? -- but how do I convince
my code generator?)

Unfortunately, current wording seems to imply that model.

It is a pretty heavy price to pay for a capability that hopefully is
almost never used (I mean overlay by means of address specs, so that
the aliasing matters.)

Parameter aliasing problems in general are considered bounded errors, RM
6.2.(12). Why aliasing problems due to address or linkname overlay should be
treated differently, is a bit beyond me.  (Well, I happen to believe that
Ada83 was right for once -- in making overlays via address clauses
erroneous, nowadays known as bounded error.)

****************************************************************

From: Erhard Ploedereder
Sent: Wednesday, July 16, 2003  1:49 PM

A small PS, so I am not being misunderstood...

> almost never used (I mean overlay by means of address specs, so that
> the aliasing matters.)

The "never used" referred to the "aliasing matters".

As in the parameter aliasing problem, "matters" means that you use
alternate access paths for reading and writing, where both paths still
exist and are being in use (so that the assumption of "no aliasing"
would actually affect the results of the program).

****************************************************************

From: Robert Dewar
Sent: Wednesday, July 16, 2003  2:43 PM

We have cases all the time where aliasing matters. Users have reported our
failure to avoid optimization here in some marginal cases as bugs :-)

****************************************************************

From: Robert Dewar
Sent: Wednesday, July 16, 2003  2:48 PM

> Parameter aliasing problems in general are considered bounded errors, RM
> 6.2.(12). Why aliasing problems due to address or linkname overlay should be
> treated differently, is a bit beyond me.  (Well, I happen to believe that
> Ada83 was right for once -- in making overlays via address clauses
> erroneous, nowadays known as bounded error.)

I disagree, legacy code is full of the use of address clauses to achieve
overlayh. Many programmers find it more convenient and natural than the
use of unchecked conversion (Fortran COMMON and COBOL REDEFINES are of
course precedents for this kind of usage).

It is a bit silly for the official definition to ignore actual usage, so making
it impl defined is definitely a step forward.

The question is in the direct kind of case that I gave:

   A : Integer;
   B : Float;
   for B'Address use A'Address;

should the compiler understand that A and B are aliased? In other words, if
one of them is assigned to, then the other one has changed.

If a pedantic viewpoint leads to answering No, then you are simply creating
a tension between the language definition and actual implementations (certainly
we know from experience that once we started doing better aliasing analysis
in teh transition from GCC 2 to GCC 3, several users complained about wrong
results, and we have to go to quite a bit of effort to make things "work"
again (yes you can explain to users that their code is wrong, but you only
do this if you are really stuck :-)

****************************************************************

From: Randy Brukardt
Sent: Wednesday, July 16, 2003  1:59 PM

> What about
>
>     A : Integer;
>     B : Integer;
>     for B'Address use A'Address;
>
> Well it sure seems like we want to stop optimization in both directions,
> but the RM statement probably only affects code generation for references
> to B and not for A.

My reading of the intent of 13.3(16) is that the use of 'Address on objects
that aren't declared aliased (explicitly or implicitly) is not expected to
work properly in the face of optimizations. So I would say that the intent
of 13.3(19) is that it only applies to the object with the address clause
(it implicitly gives it "aliased").

So in the above case, there are no guarantees on A. If you had written
instead:

    A : aliased Integer;
    B : Integer;
    for B'Address use A'Address;

Then clearly both A and B are aliased as far the optimizer is concerned.

Now, I realize that this doesn't fit well with Ada 83 practice, but
compilers are always allowed to go beyond the standard. And if they do,
THEY, not the ARG, has to figure out what it means.

This is an area I think Ada 95 got right, in that it allows limited
overlaying of objects by address clauses, but only if both objects are
appropriately declared (so the compiler has no surprises). And other
overlays are not guaranteed to work. It's unfortunate that the Ada 83
practice of not marking objects referenced by the 'Address attribute hasn't
been discouraged more forcefully. (We're as guilty as any implementor here.)

****************************************************************

From: Robert Dewar
Sent: Wednesday, July 16, 2003  1:59 PM

> Now, I realize that this doesn't fit well with Ada 83 practice, but
> compilers are always allowed to go beyond the standard. And if they do,
> THEY, not the ARG, has to figure out what it means.

Not so fast. Implementation Advice is in the business of going "beyond the
[normative] standard". Remember that this whole thread is about what 13.3(9)
is trying to suggest!

> It's unfortunate that the Ada 83
> practice of not marking objects referenced by the 'Address attribute hasn't
> been discouraged more forcefully. (We're as guilty as any implementor here.)

Er, we are not in the business of forcefully discouraging our users, we are
in the business of meeting their needs. Of course we will not go so far as
to deliberately not conform to the standard, but short of that, user needs
come ahead of language lawyer aesthetic opinions :-)

****************************************************************

From: Randy Brukardt
Sent: Wednesday, July 16, 2003  8:14 PM

But in the case the "user need" is to avoid typing "aliased". I can hardly
find that to be a major problem; it's not like the fixed point operators
(for instance), where the workaround is obnoxious. In this case, the
workaround is trivial.

I'm well aware the problem will still occur in legacy code, and that most of
us will probably continue to support it in some way. But I think NEW code
should be "encouraged" to be correct; probably with warnings on 'Address
used on non-aliased objects and more documentation of the issues. And I
certainly don't think the standard should get into 'inferring' aliasing as
you suggest; it is much too hard to describe and implement. And given that
13.3(19) is a REQUIREMENT for most implementations, I am strongly opposed to
expanding it as you suggest. (Remember, this is "Recommended Level of
Support, which is required by Annex C).

I don't disagree that the wording is pretty vague, and clearly it should
state that it only means for the object and it subcomponents that has the
address clause. But that's as far as the language should go.

****************************************************************

From: Robert Dewar
Sent: Wednesday, July 16, 2003  9:21 PM

I don't see this. Using the keyword aliased is not enough to say that something
is aliased with something of some other type entirely. What's your point here?
Aliased just deals with whether typed pointers to the object caqn be created.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, July 16, 2003  9:47 PM

The point of 13.3(16) is that you cannot portably take 'Address of an object
that is not declared to be aliased. And that 'Address must work sensibly on
an object that is aliased. To me, at least, that means that optimization
must take into account the possibility of overlaying with anything.

Thus, a compiler cannot use type information to eliminate possible aliasing
for an aliased object unless it can prove that no 'Address can be taken of
the object (which of course also includes foreign language calls).

We pretty much "turn off" optimization of aliased objects, and we certainly
don't use type information for them. (Of course, that's partly because we
only have very limited type information available in the optimizer in the
first place.) If we had more type information, we'd use it only for locals,
because only those could be proven to be safe.

That's actually a lot more aggressive than our Ada 83 compiler; for that we
assumed that all objects were aliased unless they were copy parameters or we
could prove that they weren't aliased. (We tried more aggressive rules, but
they always had problems with address clauses, and we ended up going back.)

The converse point, of course, is that a compiler is allowed to do any
assumption of non-aliasing that it pleases on an object that is none of:
    by-reference type;
    aliased;
    or has an address clause or pragma Import.

I think this is right, as it gives the proper balance of control and
optimization. (It would be nice to have "degrees" of aliasedness, but it
hardly seems worth the complication.)

****************************************************************

From: Robert Dewar
Sent: Wednesday, July 16, 2003 10:46 PM

> The point of 13.3(16) is that you cannot portably take 'Address of an object
> that is not declared to be aliased. And that 'Address must work sensibly on
> an object that is aliased. To me, at least, that means that optimization
> must take into account the possibility of overlaying with anything.

If this is more than an unfounded opinion, please quote justification

> Thus, a compiler cannot use type information to eliminate possible aliasing
> for an aliased object unless it can prove that no 'Address can be taken of
> the object (which of course also includes foreign language calls).

Again, how do you figure this?

> We pretty much "turn off" optimization of aliased object

Well that's pretty pessimistic, perhaps this pessimistic view of alias analysis
leads you to what I consider the above non-obvious viewpoints.

These kind of undocumented, unsupportable "assumptions" make me think that it
is definitely important for the IA in the RM to state what it means.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, July 16, 2003  11:18 PM

It's a 'founded' opinion. :-) Optimization cannot change the meaning of a
legal Ada program unless the standard gives a specific permission to do so.
I see no such permission in terms of 'Address and optimizations in the
standard, with the exception of unaliased objects. In particular, the
erroneousness of overlaying was removed from Ada 95; thus it must work and
optimization cannot 'break' it.

Now it certainly is true that the AARM never says this, and perhaps the
intent was different. But this is certainly the model I took away from the
DR meetings where all of the implications of the model were discussed.

If you think that some other rule is implied by the standard, then I think
the onus is on you to point it out, not on me to prove that it doesn't
exist! And if you want to propose some other rule, please feel free to do
so -- now is the time.

> > We pretty much "turn off" optimization of aliased object
>
> Well that's pretty pessimistic, perhaps this pessimistic view of alias
> analysis leads you to what I consider the above non-obvious viewpoints.
>
> These kind of undocumented, unsupportable "assumptions" make me think that
> it is definitely important for the IA in the RM to state what it means.

My only assumption is that unless there is a language rule to the contrary,
in the standard mode, a program should operate the same whether or not
optimization is applied. I consider that the fundamental rule of
optimization, and breaking it is almost never worth it (as you are finding
out). While a few customers might find some (unlikely to be critical) extra
performance, the vendor ends up with a lot of additional support headaches.

The "assumption" that you ought to be able to do aggressive optimizations in
the face of explicitly declared aliasing is the one that seems to be
undocumented and unsupportable. Where is the language rule that allows that?

Of course, I'm not aware of any Ada vendors that considers their optimizer
to be part of the standard mode, so the whole question is irrelevant in
practice. Vendors should do something that makes sense to their customers,
because they will anyway.

****************************************************************

From: Robert Dewar
Sent: Thursday, July 17, 2003  5:39 AM

What does work mean?>

For example, in C if you use pointer conversion to point to two different
types, that definitely does NOT "work" in the sense you mean according
to the C standard.

In the Ada standard, there simply is not enough detail to determine that
unlike the case in C, you are guaranteed for things to "work". For one
thing what "works" means is definitely implementation defined, it has
to be in semantic terms.

> Now it certainly is true that the AARM never says this, and perhaps the
> intent was different. But this is certainly the model I took away from the
> DR meetings where all of the implications of the model were discussed.

Well what the AARM says has no force in any case, we are talking about teh
ARM here, and really the above sentence is my whole point. If the ARM intends
to say something useful here, it should say what it means. We cannot depend
on what Randy has "taken away from DR meetings" to understand Ada :-)

****************************************************************

From: Randy Brukardt
Sent: Thursday, July 17, 2003  11:07 AM

> What does work mean?>
>
> For example, in C if you use pointer conversion to point to two different
> types, that definitely does NOT "work" in the sense you mean according
> to the C standard.
>
> In the Ada standard, there simply is not enough detail to determine that
> unlike the case in C, you are guaranteed for things to "work". For one
> thing what "works" means is definitely implementation defined, it has
> to be in semantic terms.

You're right of course. I thought about that this morning, and concluded
that in the case of different types, the behavior has to be unspecified in
language terms. (That is, the implementation does whatever it does. It
certainly isn't implementation-defined, because that would require
documentation, and I'm pretty sure we don't want to have to document what
every possible combination of types results in!)

My personal opinion is that the optimizer shouldn't change the behavior of
the implementation, because that reduces surprises (and "optimizer fear")
and thus support costs. But that obviously is just an opinion, as it
certainly is the case that the implementation can do something different and
still be unspecified.

In the case you gave though:

  X : aliased Integer;
  Y : aliased Integer;
  for Y'address use X'address;

There is clear semantics in the language, and I see no justification for
  X := 4;
  if Y = 4 then -- Better take this branch.
not working, optimizer or no.

So, in your example replying to Jean-Pierre:

>  X : Integer;
>  Y : aliased Integer;

>the compiler can (and GNAT does) make use of the fact that X and Y cannot
>be aliased.

That's only true if Y doesn't have any occurrences of Y'Address. If Y is a
global, you can't prove that in general.

> > Now it certainly is true that the AARM never says this, and perhaps the
> > intent was different. But this is certainly the model I took away from the
> > DR meetings where all of the implications of the model were discussed.
>
> Well what the AARM says has no force in any case, we are talking about teh
> ARM here, and really the above sentence is my whole point. If the ARM intends
> to say something useful here, it should say what it means. We cannot depend
> on what Randy has "taken away from DR meetings" to understand Ada :-)

I originally said "RM and AARM" here, and edited it out because it seemed
redunant.

And I don't argue that 13.3(19) is unnecessarily vague (it needs to say "the
object" - it certainly can't mean the world); and there ought to be more
AARM notes for 13.3(16) to explain the model (mine or whichever).

****************************************************************

From: Robert Dewar
Sent: Thursday, July 17, 2003  12:45 PM

> My personal opinion is that the optimizer shouldn't change the behavior of
> the implementation, because that reduces surprises (and "optimizer fear")
> and thus support costs. But that obviously is just an opinion, as it
> certainly is the case that the implementation can do something different and
> still be unspecified.

That's a HUGE restriction on an optimizer. It would tend to fix the order
of evaluation of expressions, and as a result limit schedulability. And in
the case of uninitialized variables, it is a very heavy cost to restrict
them from being in registers.

****************************************************************


From: Jean-Pierre Rosen
Sent: Wednesday, July 16, 2003  2:25 AM

> The question is in the direct kind of case that I gave:
>
>    A : Integer;
>    B : Float;
>    for B'Address use A'Address;
>
> should the compiler understand that A and B are aliased? In other words, if
> one of them is assigned to, then the other one has changed.

I liked the idea that the compiler is not forced to consider A as aliased,
*unless* it is declared with the aliased keyword.
After all, requiring A to be declared aliased is just telling the truth to
both the compiler and the human reader!

****************************************************************

From: Robert Dewar
Sent: Thursday, July 17, 2003  6:08 AM

possibly, but please note that this does not help that much. Saying something
is aliased in Ada merely allows you to take access values of the object, it
does NOT say that the object is potentially aliased with everything else of
its type, let alone with everything of other types. For instance, in

  X : Integer;
  Y : alised Integer;

the compiler can (and GNAT does) make use of the fact that X and Y cannot
be aliased. This is true even for:

  X : aliased Integer;
  Y : aliased Integer;

It is still the case that X and Y cannot be aliased.

... in the absence of an address clause, and that's the whole point here.

If we now say

  for Y'Address use X'Address;

the question is how this changes the aliasing assumptions.

It seems clear from the current IA language, that the compiler should now
assume that Y can be aliased with X. It is not so clear that it can be
aliased with anything else.

It is FAR from clear that X must be assumed to be aliased with Y.

I really don't see what it buys you to say that the aliasing assumption is
changed by the aliased keyword during processing of the address clause.
It makes the implementation slightly more complicated, and means that the
typical Ada 83 usage will still not "work", so any reasonable compiler is
going to try to make this "work" without the aliased keyword anyway. Randy
apparently does this easily, because his compiler basically doesn't do much
with aliasing optimziations anyway.

The reason that we are focusing attention is that GCC 3, unlike GCC 2 does
very careful aliasing analysis, and after all this is one area in which Ada
is superior to C, so it is worth studying exactly what we intend compilers
to be able to do.

****************************************************************

From: Erhard Ploedereder
Sent: Thursday, July 17, 2003  8:08 AM

> I disagree, legacy code is full of the use of address clauses to achieve
> overlayh. Many programmers find it more convenient and natural than the
> use of unchecked conversion (Fortran COMMON and COBOL REDEFINES are of
> course precedents for this kind of usage).

I am not disagreeing with that. However, in terms of usage, there is quite a
difference between code of the form:

somewhere:
     A : Integer;
     B : Integer;
     for B'Address use A'Address;

-----
somewhere else:
     -- A unread, unassigned
     B := 7;
     A = 7 ?

and

     ... := some word-sized usage of A, so it may be cached in a register;
         or some assignment to A of compile-time propagatable values
     B := 7;
     A = 7  ?

Only in the second case will compilers be tempted to ignore the aliasing in
ontoward ways; unless you go for serious inter-procedural analysis,
straightline code of the first kind will work as expected, i.e. always yield
true.

Now, while I certainly understand the motivation for the first case, i.e.,
avoid casting as part of memory management or some such, the number of cases
where the second idiom is used ought to be much smaller. It is a very hefty
penalty (see below) to have the optimization restriction to make the second
example work as the user expects.

And if an implementer feels that this should work, well, nothing in the
standard hinders him to disable the optimization. To place the restriction
on all implementers, on the other hand, is bitter.

In terms of actually defining language semantics for it (or defining an
individual implementation strategy without resorting to the most general
model of (over)estimating potential aliasing), have fun with stuff like

    A: some_array_of_my_type;

    type Acc is access My_Type;
-----
    B: My_2ndType;
    for B'address use A(J)'Address;

    C: aliased My_Type;
    for C'Address use A(I)'Address;

    C1: aliased My_Type;  -- !! (or even without the aliased, using
                                 casting later on)

    X: Acc;
    X := C'Access; X:= C1'Access;

    D: My_3rdType:
    for D'Address use X.all'Address;

with these variables declared in various places, with their address specs
in private parts, and the X assignment in some body, and then somewhere

    B := 5;
    D := 7;
    B=D? , B=C?   -- presuming I=J
    C1 = 7?
(Not without enforcing that no caching in registers takes place for all
 the variables involved.)

A language semantics would need to give an answer to this example and I know
of no implementation model that would not make all global variables and some
locals potentially aliased with X'all.

An implementation is allowed to simply eliminate the example by posing a
restriction that address specs need to be static or suitably simple to allow
for decidability of aliasing at compile-time.

Or the language puts the decidability restrictions in place; that's fine,
too.

But to require an "all potential aliasing considered" from every
implementation, without restrictions, seems unreasonable to me.

****************************************************************

From: Tucker Taft
Sent: Thursday, July 17, 2003  11:54 AM

I think one way we could bound the problem is require
that the possibility of "unorthodox" aliasing need only
be of concern to the implementation when the original
stand-alone object declaration is denoted (directly
or via a rename).  If the object is passed as a by-reference
parameter, we can't really expect that
all by-reference parameters be treated as though they
had their address specified.  That seems excessive.

So as a worst case, any assignment to a part of an object
using a name that denotes an object declaration with an
associated address clause, must be considered to kill
everything.  Of course if the compiler is smarter, it
can know that certain objects have never had their
address taken, etc.  Similarly, such an object must be
killed by an assignment to anything else.

That seems simple enough for a compiler to implement, and
many compilers can do better than that.

Secondly, once a part of such an object is passed by
reference, the programmer must ensure that the program obeys
the normal rules having to do with aliasing.

The only remaining issue might be whether compilers are required
to pass parts of such objects by copy if pass-by-copy is permitted.
That seems too fierce a requirement (though that is what we
require for volatile objects that are not of a volatile type).
Hence, I would recommend that if it *could* be passed by reference,
then the normal parameter aliasing rules apply, putting the burden
back on the programmer.

The basic philosophy is then that the burden is on the compiler
when a name is used that denotes (directly or indirectly) an
object declaration with an address clause, and the burden is
on the programmer if a part of such an object is passed as
a might-be-by-reference parameter (following the rules in 6.2(12)).

****************************************************************

From: Robert I. Eachus
Sent: Thursday, July 17, 2003  12:20 PM

Robert Dewar wrote:

>Er, we are not in the business of forcefully discouraging our users, we are
>in the business of meeting their needs. Of course we will not go so far as
>to deliberately not conform to the standard, but short of that, user needs
>come ahead of language lawyer aesthetic opinions :-)
>
That is--or should be--true of the ARG as well. Our coustomers are the
potential users of Ada. And if the ARG fails to meet the needs of some
subset of them, Ada is less widely used.

So what IS the need in this case, and how can the ARG act to meet it? I
strongly agree with Robert Dewar that taking the address of something
should have a langauge-defined semantic effect. I also agree that the
scope of that effect can and should be limited.

How to balance these? Well, I know what I need and often depend on,
sometimes with a slight feeling of sin. Let me give examples and
proposed scopes:

type T is record
TC: Integer;
...
end record;
-- any type passed by reference. (Note: I did not say, required to be
passed by reference. The compiler knows what it is doing, so there is no
"additional" burden to the wider scope. In fact probably the opposite.)

function F (TP: T) return Foo is
Local: T;
for Local'Address use TP'Address;
begin... end F;

I don't need (or particularly want) every component of Local to be
treated as volitile. I do want and need for every assignment to Local.TC
to be treated as used when end F; is reached. We can have the argument
about what is required to have happened when this exception or that is
raised when discussing some other section. For this issue though, we can
restrict the discussion to non-predefined exceptions and raise
statements, which tend to be the exceptions I care about anyway The
"write-back" of Local.TC should also happen when an exception is raised.

What about references to TP.TC inside F? If there is an assignment to
Local.TC, the programmer is on his own, and should expect it. Of course,
if the programmer says:

Local_Int: Integer;
for Local_Int'Address use TP.TC;

...the programmer's expectations could be different. So it seems that
any rule should be stated in terms of local scopes, and of objects whose
Address has been taken, but not components of that object. I guess that
I would sort of as a reasonable compromise treat the 'local scope' of a
package spec for this purpose as the package itself, its body, and any
children and or subunits. If a programmer is binding a varible to a
particular (hardware) location, he should be using Volitile as well. And
if someone wants to take an address in a relatively global scope such as
the main program, he can pay the optimization penalty.

Pragma Inline should not affect the rules. We should try in this case to
hold to the precept that most pragmas do not affect the meaning of a
program.

****************************************************************

From: Robert I. Eachus
Sent: Thursday, July 17, 2003  12:29 PM

Tucker and I litterally crossed in the e-mail on this. Tucker's approach
and mine to limiting the excess are different, but as far as I am
concerned that just shows that this really is an issue that the ARG
should resolve. Some standardized reasonable limit on the potential
effect of taking an address is needed, but assuming away everything is
not a programmer-friendly option.

****************************************************************

From: Robert A. Duff
Sent: Thursday, July 17, 2003  1:40 PM

Whatever the rules are, there should be zero distributed overhead.
That is, the compiler has to know what to do based on the Address
clauses it can see, and not on some Address clauses that might exist
in some other compilation unit.

I suppose this might be obvious to everybody on this list, but I thought
I'd just put in my $0.02.  I don't have anything useful to say, beyond
what various folks have already said.  I probably wrote the RM paragraph
in question, and the reason it's so vague is probably that I didn't know
what I was talking about at the time.

Randy said:

> > My personal opinion is that the optimizer shouldn't change the behavior of
> > the implementation, because that reduces surprises (and "optimizer fear")
> > and thus support costs. But that obviously is just an opinion, as it
> > certainly is the case that the implementation can do something different and
> > still be unspecified.

And Robert Dewar replied:

> That's a HUGE restriction on an optimizer. It would tend to fix the order
> of evaluation of expressions, and as a result limit schedulability. And in
> the case of uninitialized variables, it is a very heavy cost to restrict
> them from being in registers.

Randy's requirement can easily be achieved, with no cost in run-time
speed, simply by always compiling in optimized mode.  ;-)

P.S. Is it time for my usual admonishment to include who said what,
when quoting (as I goodly did above, but often forget to do)?  ;-)
I even goodly distinguished "Dewar" from various other Roberts around
the place, such as me.

****************************************************************

From: Robert Dewar
Sent: Thursday, July 17, 2003  4:34 PM

> I strongly agree with Robert Dewar that taking the address of something
> should have a langauge-defined semantic effect. I also agree that the
> scope of that effect can and should be limited.

Note that this is stronger than what I asked for. I am quite happy for this
to be implementation advice, I would just like it to be IA that made sense
and that everyone interpreted the same way.

One point that seems to be getting lost in what I am saying (especially in
Tuck's last msg) is that I think the following two should be equivalent

   A : Integer;
   B : Integer;

   for B'Address use A'Address;

and

   B : Integer;
   A : Integer;
   for A'Address use B'Address;

I don't see a basis for asymmetrical treatment here. Either A and B are
aliased and the compiler knows about it, or they are not.

Note that in a case like this it is absolutely unnecessary to throw up your
hands and decide that either or both variables can be arbitrarily aliased
to anything. On the contrary, they are only aliased to one another and
nothing else.

This is an argument *against* requiring aliased keywords, since the use of
such keywords greatly increases the aliased sets involved.

****************************************************************

From: Tucker Taft
Sent: Thursday, July 17, 2003  4:34 PM

I agree that a particular compiler could treat them symmetrically,
but I fear the effort involved in trying to define this in the
reference manual.  Compilers are always allowed to be smarter,
if the effect is equivalent (the old "as if" rule).  In this case,
the compiler pretty much sees everything, and what you have is
the moral equivalent of a rename.  But I can't imagine using
an Address clause for something as simple as this.  There is
always something else going on, such as viewing a piece of
"raw storage" as a particular higher level type, or perhaps
using it to default reinitialize an existing object, or whatever.

It is rarely equivalent to a simple rename, and so it seems silly
to put much effort into specifying the semantics in that
case.

What I was suggesting was a "worst case" semantics, where
any assignment to the address-specified object kills everything,
and it is in turn killed by any assignment to anything else.
But this would *not* apply when referring to the object
via a by-reference parameter.

And of course compilers could do better if they have tracked
the possible values of the expression used in the address clause,
and can thereby narrow down the number of possible aliases.

****************************************************************

From: Robert Dewar
Sent: Thursday, July 17, 2003  5:10 PM

> But I can't imagine using
> an Address clause for something as simple as this.  There is
> always something else going on, such as viewing a piece of
> "raw storage" as a particular higher level type, or perhaps
> using it to default reinitialize an existing object, or whatever.

Yes, of course in practice the two types will usually be different, although
we have seen instances of address clauses that were renames, so a more
realistic example is:

     A : Integer;
     B : String (1 .. 4);

> I agree that a particular compiler could treat them symmetrically,
> but I fear the effort involved in trying to define this in the
> reference manual.

Then I think it is better that the reference manual say nothing. The idea
of asymmetrical alias sets is just too confusing. Why not just remove the
dubious implementation advice since we don't really know what it means.
I see no reason in trying to pin down precisely one side of this, if the
other side is left to cause surprising results.

Here would be Robert's first half baked attempt at more useful IA here.


  If an address clause causes an object to be aliased with other objects
  in the program, than changes to these other objects should be reflected
  in the value of the object with the address clause. In the simple case
  where an address clause is used to overlay two variables, as in

       A : Integer;
       B : Float;
       for B'Address use A'Address;

  then the implementation should recognize that A and B are aliased, and
  changes to either one should be reflected in the other.

Note this is IA, so we are not trying to be semantically precise here, just
to get something that we can read in a friendly manner and all end up with
at least roughly the same understanding :-)

****************************************************************

From: Tucker Taft
Sent: Thursday, July 17, 2003  5:55 PM

Robert Dewar wrote:
> ...
> > I agree that a particular compiler could treat them symmetrically,
> > but I fear the effort involved in trying to define this in the
> > reference manual.
>
> Then I think it is better that the reference manual say nothing. The idea
> of asymmetrical alias sets is just too confusing.

The aliasing relationship is still "symmetric" in the sense that
B is aliased with A (and everything else) and
A (and everything else) is aliased with B.

...
> Here would be Robert's first half baked attempt at more useful IA here.
...

I would still like to limit this to cases where the object with the
Address clause is being referred to "directly" as opposed to via
a by-reference parameter.

****************************************************************

From: Robert Dewar
Sent: Thursday, July 17, 2003 10:32 PM

> The aliasing relationship is still "symmetric" in the sense that
> B is aliased with A (and everything else) and
> A (and everything else) is aliased with B.

But that is absurdly pessimistic and unnecessary in this case. I certainly
don't want IA that implies this very poor implementation.

****************************************************************

From: Robert I. Eachus
Sent: Thursday, July 17, 2003  6:11 PM

>Note that this is stronger than what I asked for. I am quite happy for this
>to be implementation advice, I would just like it to be IA that made sense
>and that everyone interpreted the same way.

I didn't intented to overstate your position. It is just hard to say
"the reference manual should say something sensible about this case so
we can all implement it the same way" and fit it in one clause. (And of
course, that is still a simplification.)

A different way of stating my opinion is, "The Rosen trick must work." I
don't know how much Ada code out there depends on the Rosen trick. Since
most of it probably gets that way by using an implementation defined
random-number generator I am not all that worried about compiler
suddenly deciding not to compile those packages correctly.

>One point that seems to be getting lost in what I am saying (especially in
>Tuck's last msg) is that I think the following two should be equivalent
>
>   A : Integer;
>   B : Integer;
>
>   for B'Address use A'Address;
>
>and
>
>   B : Integer;
>   A : Integer;
>   for A'Address use B'Address;
>
>I don't see a basis for asymmetrical treatment here. Either A and B are
>aliased and the compiler knows about it, or they are not.
>
>Note that in a case like this it is absolutely unnecessary to throw up your
>hands and decide that either or both variables can be arbitrarily aliased
>to anything. On the contrary, they are only aliased to one another and
>nothing else.
>
>This is an argument *against* requiring aliased keywords, since the use of
>such keywords greatly increases the aliased sets involved.

Agreed. It would be like requiring the aliasing keyword for parameters.
We all know, and compilers all know that parameters create aliasing. But
that is a far cry from assuming that every value that might be passed as
a parameter is aliased to every object of the same type.

****************************************************************

From: Robert I. Eachus
Sent: Thursday, July 17, 2003  9:51 PM

Now we are getting down to the nitty-gritty. Why do you object to this
case, which may be the one I see as vital. But I wouldn't say that it is
the aliasing that occurs with a by-reference parameter we are protecting
here, it is the subsequent aliasing by an address clause. From my
previous example:

type T is record
TC: Integer;
...
end record;

function F (TP: T) return Foo is
Local: T;
for Local'Address use TP'Address;
begin... end F;

-- Let me add a call:

TO: T:
Foo_Obj: Foo;
...
Foo_Obj := F(TO);

I want to say that Local is an alias for TP, and TP is an alias for
Local, and that the (only IMHO) important synchronization points are at
the creation of local and the exit from the scope of F. The fact that
inside the call, Local is also an alias of TO is interesting, but I
would rush to the barracades if an ACATS test tried to check if the
transitive aliasing worked, especially if type T was potentially call by
reference but not required to be.

The aliasing between Local and TP on the other hand should always hold
even if F were a procedure and TP passed by value return. (We could then
spend a few minutes discussing an implementation specific pragma that
guaranteed by reference semantics for parameters where the RM doesn't
specify, or the copy back with call by value on a function call. But
that should almost be outside the ARG's scope.)

****************************************************************


Questions? Ask the ACAA Technical Agent