Version 1.3 of ai05s/ai05-0009-1.txt
!standard 9.10(1) 07-05-20 AI05-0009-1/03
!class binding interpretation 06-03-21
!status work item 06-03-21
!status received 06-02-20
!priority Medium
!difficulty Hard
!qualifier Error
!subject Confirming rep. clauses and independence
!summary
The incorporation of confirming representation clauses has
semantic implications for independent addressability.
Two new pragmas (Independent and Independent_Components) to allow a user
to specify that the components of an object or type should be
independently addressable. Additionally, objects or types that have a
convention (other than Ada) specified by an interfacing pragma have
been added to the kinds of representation items that impact
independent addressability.
!question
9.10(1) says that two nonoverlapping objects are independently addressable unless one or
more representation clauses are specified for them. AI95-0291-2 says that confirming
representation clauses don't change the representation of items, so it seems weird that
they can affect independent addressibility. Is this intended? (No.)
!recommendation
Modify 9.10 to identify only non-confirming representations as those
that can cause dependent addressability. Modify to include
convention as an item that can cause an object to be dependent
(exclude convention Ada) for a representation. Change dependent
addressability from implementation defined to unspecified.
Add pragmas Independent and Independent_Components to C.6. Independent
applies to components of record types; Independent_Components
applies to components of arrays or anonymous array objects.
Also update the AARM notes in 13.1 (8.v, 8.w; 8.gg, 8.hh) to add the
new pragmas independent and independent components.
!wording
Modify 9.10 (1) to read:
If two different objects, including nonoverlapping parts of the same
object, are independently addressable, they can be manipulated
concurrently by two different tasks without synchronization.
Normally, any two nonoverlapping objects are independently addressable.
However, if a non-confirming representation item is used to specify
packing, record layout, Component_Size, or a convention other than Ada,
then the independent addressability of the object (and subcomponents)
is unspecified.
Add or modify C.6 as follows:
Add to Syntax
pragma Independent (
[Entity => ] local_name
{,[Component =>] component_local_name});
Pragma Independent_Components(array_local_name);
An independent component is a component to which a pragma Independent
or pragma Independent_Components applies.
Modify Name Resolution
The local_name in an Atomic or Volatile pragma shall resolve to denote
either an object_declaration, a non-inherited component_declaration,
or a full_type_declaration. The local_name in an Independent pragma shall
resolve to denote a full_type_declaration of a record_type_definition; the
component_local_name shall resolve to denote a non-inherited component
of the full_type_declaration. The array_local_name in an
Atomic_Components, Volatile_Components or Independent_Components
pragma shall ...
Add to Legality Rules
It is illegal to apply a pragma Independent or Independent_Components
to an independent component when the component is not independently
addressable.
If a pragma Independent or Independent_Components applies to a generic
formal type, then the actual type must have independent components.
Add to Static Semantics
An independent component is independently addressable.
!discussion
The problem to be addressed is demonstrated by the following (on a
byte addressable target):
A : array (1..4) of character;
for A'Component_Size use 8;
The components of A are no longer independent, which allows different
encodings of the following statements:
A (1) := <char>;
A (4) := <char>;
Independent Sequence:
Store <char> to A (1)
Store <char> to A (4)
Dependent Sequence:
Load 32-bit register with A
Set MSB to <char>
Set LSB to <char>
Store 32-bit register to A
The dependent sequence is disallowed when pragma Independent_Components
applies to A on the byte addressable machine; on a word addressable
machine the pragma would be rejected because each component of
A is not independently addressable.
9.10 (1)
Including non-confirming removes semantics associated with confirming
representations. Convention was added to allow dependent addressability
for conventions other than Ada.
C.6
Introduces the new pragmas, defining independent to be applicable to
all record types, except arrays which will require Independent_Components.
Pragma independent and Independent_Components are similar to Volatile and
Atomic in that only a single entity name is accepted with the pragma
(conflicts with 13.1 (5/1, 6/1)).
The minutes from Albuquerque identify that pragma independent_components
should be considered for all composite types; however, there is no way
to remove independence for the components of tasks or protected types,
so the pragma was not allowed for tasks and protected types.
ACATS Tests
ACATS tests can be generated that would verify the rejection of the pragmas
for all but bit-addressable architectures (TBD). The verification of code
generation is target dependent and probably can't be effectively tested.
!appendix
[Note: This thread originally branched off of the discussion in AI-447. Mail preceding
this one can be found there. - Editor]
From: Pascal Leroy
Sent: Friday, February 17, 2006 6:34 AM
> Indeed. I actually think that there should be a rule that the
> compiled accept all confirming representation clauses, which
> is not necessarily the case.
There is actually an IA to that effect in Ada 2005, see 13.1(21.1). Of
course, with dope and dynamic stuff and so on this cannot be a
requirement. But this IA is intended to nudge implementers in the right
direction.
****************************************************************
From: Robert Dewar
Sent: Friday, February 17, 2006 7:04 AM
Good, I had missed that. I agree IA is fine here (as I have commented
in the past, IA is often stronger than a requirement, since it is to
be interpreted informally -- to me all documentation requirements would
be stronger if they were IA :-))
****************************************************************
From: Robert A. Duff
Sent: Friday, February 17, 2006 7:10 AM
> > Indeed. I actually think that there should be a rule that the
> > compiled accept all confirming representation clauses, which
> > is not necessarily the case.
>
> There is actually an IA to that effect in Ada 2005, see 13.1(21.1). Of
> course, with dope and dynamic stuff and so on this cannot be a
> requirement. But this IA is intended to nudge implementers in the right
> direction.
21.1/2 {AI95-00291-02} A confirming representation item should be supported.
This is not "mere" Implementation Advice. It is "Recommended Level of
Support", so the "should" becomes "shall" in the SP Annex.
I wonder if that was the intent. The AARM says:
Wording Changes from Ada 95
...
28.n/2 {AI95-00291-02} Added wording to define confirming representation
items, and to suggest that they should always be supported.
This is not just a wording change, and does not merely "suggest".
I don't understand the "with dope and dynamic stuff" part of your comment
above (which echoes the sentiment in the AARM):
21.a.1/2 To be honest: A confirming representation item might not be
possible for some entities. For instance, consider an unconstrained
array. The size of such a type is implementation-defined, and might
not actually be a representable value, or might not be static.
The way I read para 21.1 is: if you write a confirming representation clause
(confirming some aspect of rep), then the compiler has to accept it. It does
not claim that there is a way to confirm every aspect of everything
(e.g. sizes of non-static stuff). You cannot, for example, specify that you
want a twos complement little endian representation for an integer, even if
that would be confirming. So I don't see any dishonesty that the "To be
honest" needs to address.
****************************************************************
From: Randy Brukardt
Sent: Friday, February 17, 2006 2:07 PM
> This is not just a wording change, and does not merely "suggest".
This is a BI, so it wasn't documented as an extension. I've just finished
going over the entire set of BIs and changing that (with a marker so it's
possible to tell the difference between BI and Amendment extensions,
incompatibilities, and the like), but I managed to miss this one. (It's
likely that I missed others as well, feel free to point them out.)
We felt that this was always the intent of Ada, it just wasn't written down.
(I'm not aware of any compiler that would violate this rule - Janus/Ada
doesn't implement all rep. items to the Recommended Level of Support, but it
allows confirming ones on all of them.)
...
> The way I read para 21.1 is: if you write a confirming representation clause
> (confirming some aspect of rep), then the compiler has to accept
> it. It does not claim that there is a way to confirm every aspect of
> everything (e.g. sizes of non-static stuff). You cannot, for example,
> specify that you
> want a twos complement little endian representation for an integer, even if
> that would be confirming. So I don't see any dishonesty that the "To be
> honest" needs to address.
That's one way to read it, but I thought there was enough possibility for
confusion that it was worth reiterating it. It's easy to read it as meaning
that there must be a way to write a confirming item (I read it that way
every time, I agree your reading makes more sense, but I *still* read it the
other way.) I suppose the AARM note could be classified as a Ramification or
some such, but it still seems iffy to me.
****************************************************************
From: Robert Dewar
Sent: Friday, February 17, 2006 1:44 PM
> The way I read para 21.1 is: if you write a confirming representation clause
> (confirming some aspect of rep), then the compiler has to accept it. It does
> not claim that there is a way to confirm every aspect of everything
> (e.g. sizes of non-static stuff). You cannot, for example, specify that you
> want a twos complement little endian representation for an integer, even if
> that would be confirming. So I don't see any dishonesty that the "To be
> honest" needs to address.
Hmm, suppose my compiler is very clever, and figures out it can overlap
two components of a record because they are never used at the same time,
how do I confirm that.
Suppose that my compiler has 'Size be some value, but does not follow
the IA/requirements that come with this in the RM, then a confirming
rep clause says too much.
Suppose that my compiler by default allows two fields in the same
byte to be accessed independently different tasks, because it
figures this is safe, if I write an implicit rep clause, then I
treat on the independence land mine.
[this is fun!]
Suppose a compiler figures out that it can store an object of type
Integer in 8 bits, because no larger value is stored, can I really
specify a size of 8 bits for the object?
Suppose a compiler uses different representations for local and
global objects, what's the 'Size of the type in that case? Whatever
the answer, a confirming rep clause will mess things up.
How can I confirm the layout of a record with dynamic fields, well
perhaps pragma Pack might do it, can pragma Pack ever be considered
to be a confirming rep clause (I think not).
If I store biased types in some cases, do you really want me to be able
to force it in all cases.
Suppose I align a type in different ways in different cases. In this
case 'Alignment will return the lowest value, but specifying this
lowest value will force this value in all cases, is that confirming?
This should have been IA, not a requirement, in my view.
****************************************************************
From: Randy Brukardt
Sent: Friday, February 17, 2006 2:22 PM
> This should have been IA, not a requirement, in my view.
The requirement is as Bob described it: "*IF* you can write a confirming
rep. item, then it shall be supported.". It's not a requirement to always be
able to write a confirming rep. item.
In most of your examples, you can't write a confirming rep. item (because
there are multiple sizes, the size isn't known, the item has properties not
described by a rep. item, etc.) So there is no problem, the requirement
means nothing.
In the rest, you are giving different semantics to items that don't have a
rep. item to those that do. It was the sense of the ARG that having such
constructs was in very bad taste. It was *precisely* the intent of the ARG
to (implicitly) ban such things in an implementation that claims to follow
the Recommended Level of Support. (I say that because we spent a lot of
effort changing any rule in the Standard that even seemed to imply that
could be the case.)
So, I don't see that there is any problem with a requirement here.
Implementers have a lot of leaway in defining the default representation, so
it shouldn't be a problem to skirt the rule if necessary.
P.S. See, Bob, why we need the To Be Honest?? :-)
****************************************************************
From: Robert Dewar
Sent: Friday, February 17, 2006 2:29 PM
> In most of your examples, you can't write a confirming rep. item (because
> there are multiple sizes, the size isn't known, the item has properties not
> described by a rep. item, etc.) So there is no problem, the requirement
> means nothing.
Actually in almost all the cases I gave, you *can* write a confirming rep
item. It just does not confirm exactly.
> In the rest, you are giving different semantics to items that don't have a
> rep. item to those that do
THe RM does this! If you don't have a rep clause, then you are guaranteed
independence. But if you give a confirming rep clause you are no longer
guaranteed independence. Has this changed in 2005? If so, what language
changed this.
****************************************************************
From: Pascal Leroy
Sent: Monday, February 20, 2006 2:17 AM
This didn't change, and it was an oversight as far as I can tell. It
seems to me that we should have added "nonconfirming" to the last sentence
of 9.10(1). This can always be done later by an AI: it won't affect the
code generated by compilers.
****************************************************************
From: Robert Dewar
Sent: Monday, February 20, 2006 5:49 AM
It definitely can affect the generated code.
It immediately occurred to me, it would surprise me if there were
not other similar consequences. This is a very delicate area.
One problem for example: There is nothing now to stop a compiler
from doing things quite differently for rep'ed and non-rep'ed
stuff. Just because you think you have specified all the visible
standard attributes does not mean you have specified enough.
Also now you are giving real semantics to the notion of a confirming
rep clause, and I don't see how that is possible. After all the
compiler can change its defaults at any time. It seems really
awkward in a formal requirements sense to talk about what the
compiler *would have* done. Also how do you know you are confirming
all the attributes. And how is this testable?
This seems a quagmire to me, better to put this in implementation
advice, where we do not have to worry about formal definition. In
fact the whole business of confirming rep clauses would have been
better as IA.
****************************************************************
From: Robert Dewar
Sent: Monday, February 20, 2006 7:15 AM
One really worrisome thing here. If you are going to start ascribing
real semantics to confirming rep clauses, then the compiler has to be
able to recognize confirming rep clauses. That's really hard. It would
mean major new circuitry for us to figure this out, something like
laying out the type with and without rep clauses to see if it came
out the same - UGH!
****************************************************************
From: Pascal Leroy
Sent: Monday, February 20, 2006 9:17 AM
True, we'd have to do the same.
On the other hand, doesn't it bother you that if I write:
type T is new String;
for T'Component_Size use 8;
my program becomes mysteriously nonportable because of 9.10(1)? This
doesn't seem to be helpful to users...
****************************************************************
From: Robert Dewar
Sent: Monday, February 20, 2006 10:35 AM
Well it is not mysteriously nonportable, it is just that you
can't count on independence for strings, something I have always
known, and which is critical on some word addressed architectures
like the old alpha.
Standard.String is packed, so definitely any program expecting
dependence is seriously non-portable! So your example is not
a good one, T lacks independence before you even give a
component size.
If I do
type T is array (Positive) of Character;
then on the old Alpha, you have to allocate 32-bits/character.
If you say
for T'Component_Size use 8;
then everything is fine, you get 8-bit characters but you
lose independence.
****************************************************************
From: Randy Brukardt
Sent: Monday, February 20, 2006 8:22 PM
> This didn't change, and it was an oversight as far as I can tell. It
> seems to me that we should have added "nonconfirming" to the last sentence
> of 9.10(1). This can always be done later by an AI: it won't affect the
> code generated by compilers.
I agree. We spent a lot of time going thought Section 13 and eliminating any
wording that implied any dependence on the existence of confirming rep.
clauses. We didn't look anywhere else, probably because we bought the
fiction that they don't affect semantics. :-) Anything that implies
otherwise is a mistake, and it should be fixed ASAP. Sounds like a candidate
for AI05-00001.
****************************************************************
From: Randy Brukardt
Sent: Monday, February 20, 2006 8:36 PM
> One really worrisome thing here. If you are going to start ascribing
> real semantics to confirming rep clauses, then the compiler has to be
> able to recognize confirming rep clauses. That's really hard. It would
> mean major new circuitry for us to figure this out, something like
> laying out the type with and without rep clauses to see if it came
> out the same - UGH!
It seems to me that you have this bass-ackwards.
A confirming rep. clause has no semantics; it's what the compiler would have
done anyway. (Independence is one of the things that the compiler has to "do
anyway"). A non-confirming rep. clause *might* have semantics. But it's not
necessary to apply semantics just because there is a rep. clause (you don't
have go out of your way to make things not independent, for example). T'Size =
16 might not be confirming, but it still is independent, for instance.
A few days ago, you talked about "almost confirming" rep. clauses. Such a thing
is not possible; either it is confirming, or it is not. If T'Size = 16, then
for T'Size use 16; is confirming. Period. And whether or not the rep. clause is
given is semantically neutral.
If you need to know if a rep. clause is confirming, there is something wrong
with your default representations. In a new compiler, you fix the defaults, you
don't stand on your head. Now, I realize that compatibility reasons might mean
that you need to stand on your head, but the cause of that is bad taste in
existing choices. We wanted to strongly discourage those choices, and the
harder you have to work to make them, the more successful we were. ;-)
****************************************************************
From: Robert Dewar
Sent: Monday, February 20, 2006 9:18 PM
>> One really worrisome thing here. If you are going to start ascribing
>> real semantics to confirming rep clauses, then the compiler has to be
>> able to recognize confirming rep clauses. That's really hard. It would
>> mean major new circuitry for us to figure this out, something like
>> laying out the type with and without rep clauses to see if it came
>> out the same - UGH!
>
> It seems to me that you have this bass-ackwards.
Yes, well I see how it may seem that way if you have not really
carefully thought out the issues, in which case the "requirement"
of allowing confirming rep clauses may seem like a no-brainer.
> A confirming rep. clause has no semantics; it's what the compiler would have
> done anyway. (Independence is one of the things that the compiler has to "do
> anyway").
Sorry Randy, that's plain wrong, a compiler does not have to provide
independence if a rep clause is present. That's the way the language is.
That means that the compiler does not have to generate code ensuring
independence if a rep clause is present. On some machines, it takes
extra code to guarantee independence in the default case.
The idea that independence has to provided if a rep clause is confirming
is really difficult since you need a way to test this predicate, and
certainly in our compiler there is easy way to do this.
I suspect that some people may have an over-naive view of code
generation for modern processors here ...
> A non-confirming rep. clause *might* have semantics. But it's not
> necessary to apply semantics just because there is a rep. clause (you don't
> have go out of your way to make things not independent, for example). T'Size
> = 16 might not be confirming, but it still is independent, for instance.
Might we perhaps remind ourselves of what 9.10 actually says:
However, if packing, record layout, or Component_Size is specified for
a given composite object, then it is implementation defined whether
or
not two nonoverlapping parts of that composite object are
independently addressable.
It is not *all* rep clauses that have this effect, and in particular,
specifying 'Size for a type does NOT give you permission to compromise
independent addressability for record components or stand alone objects.
If you have a record type, then it is mandatory to ensure independent
addressability unless a pragma Pack is given, or a record layout is
given. Similarly for an array, it is mandatory to ensure independent
addressability unless a pragma Pack is given, or a component clause
is given.
Note incidentally that this means that a compiler MUST reject
type R is array (0 .. 31) of Boolean;
for R'Size use 32;
XR : R;
for XR'Size use 32;
unless it has a way of independently addressing bits (in other
words, the IA of 13.3(53):
53 A Size clause on a composite subtype should not affect the internal
layout of components.
often becomes a requirement in practice because of the rules on
independent addressability.
The rules on independent addressability have powerful effects, it
is important to bear them in mind whenever you are discussing rep
clauses.
> A few days ago, you talked about "almost confirming" rep. clauses. Such a
> thing is not possible; either it is confirming, or it is not. If T'Size =
> 16, then for T'Size use 16; is confirming. Period. And whether or not the
> rep. clause is given is semantically neutral.
Actually again, this is NOT the semantics of the language as it
stands today (Ada 95). Specifying 'Size officially affects only
packing and unchecked conversion, so if by default have 'Size of 16 for
a type for which no 'Size is specified, then all you are saying
is that you will pack it this way if you can, and that UC will
work for 16 bits.
But look at the Ada 95 RM ... we have the following IA, that
applies *ONLY* if a Size clause is *explicitly* given:
50 If the Size of a subtype is specified, and allows for efficient
independent addressability (see 9.10) on the target architecture,
then the Size of the following objects of the subtype should equal
the Size of the subtype:
51 Aliased objects (including components).
52 Unaliased components, unless the Size of the component is
determined by a component_clause or Component_Size clause.
So suddenly a "confirming" rep clause for the type brings these
two IA paras into play where they were not in play before.
If you find that odd, all i can say is that is the way the
language is. I did not write this section, I am just a reader
reading what is there.
> If you need to know if a rep. clause is confirming, there is something wrong
> with your default representations.
No, that's just wrong, if a rep clause is given you do NOT have
to generate less efficient code to ensure independence! In fact
in Ada 95, given an "obvious" confirming rep clause is a way of
telling the compiler: don't bother with independence. You can
change this (in an incompatible way) in Ada 2005 of course, but
a) you had better realize you are doing so (looks like the critical
issue of independence was not even discussed).
b) if you make incomaptibilities you had better justify them
c) you had better make sure that things are easily implementable
These requirements interact, and it looks like more thought is
needed for all three.
I would just remove the stuff about confirming rep clauses. It
has either no effect, or it has effects that are possibly
detrimental.
In other words, you put this there because you think it will
have some useful effect for some existing or future compilers.
Just *why* do you think a compiler might *not* allow a
"confirming" rep clause?
I don't see the answer to this question. Looks to me like this
new requirement was put in as something obvious (a la Randy
mail that I am replying to here), and was not carefully
enough thought out.
If you want an example of efficiency of code generation, consider
X : String (1 .. 4);
X (1) := Ascii.Nul;
X (3) := Ascii.Nul;
it is just fine to generate a word load, followed by an AND,
followed by a word store in this case, since independence
is not required. But if I do
type S is array (Positive range <>) of Character;
X : S (1 .. 4)
then if I choose (as many compilers would) to still store
the characters in 8-bit bytes, the above combination would
not be valid, since for this type data independence is
required.
But if I add the "confirming" rep clause
for S'Component_Size use 8;
Now I can generate the load/and/store sequence since
data independence is no longer required.
Again, I didn't write this, I am just a reader, and
that's what the Ada 95 RM says.
****************************************************************
From: Robert Dewar
Sent: Monday, February 20, 2006 9:25 PM
> I agree. We spent a lot of time going thought Section 13 and eliminating any
> wording that implied any dependence on the existence of confirming rep.
> clauses. We didn't look anywhere else, probably because we bought the
> fiction that they don't affect semantics. :-) Anything that implies
> otherwise is a mistake, and it should be fixed ASAP. Sounds like a candidate
> for AI05-00001.
I look forward to the reading the suggested fix, I don't see
one that does not introduce incompatibilities.
****************************************************************
From: Randy Brukardt
Sent: Monday, February 20, 2006 10:18 PM
> > A confirming rep. clause has no semantics; it's what the compiler would have
> > done anyway. (Independence is one of the things that the compiler has to "do
> > anyway").
>
> Sorry Randy, that's plain wrong, a compiler does not have to provide
> independence if a rep clause is present. That's the way the language is.
Yes, but that's the bug. We don't require it for any other representation
property, and it is a clear oversight that that it was missed here.
> That means that the compiler does not have to generate code ensuring
> independence if a rep clause is present. On some machines, it takes
> extra code to guarantee independence in the default case.
That seems like a very bad design for a machine, at least for Ada. :-) If
you have to use extra code by default, pretty much everything will get
weighted down with that code. On all of the machines I'm aware of, it's just
a space vs. time trade-off, and there is a solution (not necessarily
optimal) that doesn't require extra code.
> The idea that independence has to provided if a rep clause is confirming
> is really difficult since you need a way to test this predicate, and
> certainly in our compiler there is easy way to do this.
I presume you meant "*no* easy way". I understand, but again this seems like
a singularly bad machine to run Ada on. It would only be usable in an
environment with strict, unbreakable coding rules; while such exist, they
aren't the norm for programming of any sort.
...
> Might we perhaps remind ourselves of what 9.10 actually says:
>
> However, if packing, record layout, or Component_Size is specified for
> a given composite object, then it is implementation defined whether or
> not two nonoverlapping parts of that composite object are
> independently addressable.
>
> It is not *all* rep clauses that have this effect, and in particular,
> specifying 'Size for a type does NOT give you permission to compromise
> independent addressability for record components or stand alone objects.
Right, but remember that this rule is wrong; at a least it should say
"non-confirming" like all other rules for rep. clauses.
...
> > A few days ago, you talked about "almost confirming" rep. clauses. Such a
> > thing is not possible; either it is confirming, or it is not. If T'Size =
> > 16, then for T'Size use 16; is confirming. Period. And whether or not the
> > rep. clause is given is semantically neutral.
>
> Actually again, this is NOT the semantics of the language as it
> stands today (Ada 95).
We're not talking about Ada 95; we're talking about Ada 2005. Ada 95 had
lots of problems with these rules, they've been fixed. Moreover, the AIs in
question are BIs; they apply to Ada 95 as well as Ada 2005.
...
> But look at the Ada 95 RM ... we have the following IA, that
> applies *ONLY* if a Size clause is *explicitly* given:
>
> 50 If the Size of a subtype is specified, and allows for efficient
> independent addressability (see 9.10) on the target architecture,
> then the Size of the following objects of the subtype should equal
> the Size of the subtype:
Again, this was changed by AI-51: "is specified, and" was dropped. This
applies to all sizes.
> > If you need to know if a rep. clause is confirming, there is something wrong
> > with your default representations.
>
> No, that's just wrong, if a rep clause is given you do NOT have
> to generate less efficient code to ensure independence! In fact
> in Ada 95, given an "obvious" confirming rep clause is a way of
> telling the compiler: don't bother with independence.
That's a horribly kludgy usage, and precisely the sort of thing that we
wanted to get rid of. If that means that the default objects all have to
take 64-bits, so be it. (Although I seriously doubt that would be the case
on any commonly used processors.)
...
> In other words, you put this there because you think it will
> have some useful effect for some existing or future compilers.
> Just *why* do you think a compiler might *not* allow a
> "confirming" rep clause?
Mainly because it appears useless to them. User need to know that it is safe
to confirm the representation of the type, and that it isn't going to have
some bizarre side-effects (such as the loss of independence).
Moreover, implementers tend not to do work that's useless. It's important
for them to know that confirming rep. clauses aren't useless.
> I don't see the answer to this question. Looks to me like this
> new requirement was put in as something obvious (a la Randy
> mail that I am replying to here), and was not carefully
> enough thought out.
>
> If you want an example of efficiency of code generation, consider
>
> X : String (1 .. 4);
>
> X (1) := Ascii.Nul;
> X (3) := Ascii.Nul;
>
> it is just fine to generate a word load, followed by an AND,
> followed by a word store in this case, since independence
> is not required. But if I do
>
> type S is array (Positive range <>) of Character;
> X : S (1 .. 4)
>
> then if I choose (as many compilers would) to still store
> the characters in 8-bit bytes, the above combination would
> not be valid, since for this type data independence is
> required.
If you don't have byte operations, the default component size for this array
cannot be 8. It has to be 16 or 32 or whatever. Or you have to provide
independence all of the time (and I agree that's too expensive).
But are there any such machines in use today? The old Alphas are, well, old,
and everything else I can think of has 8 bit operations.
> But if I add the "confirming" rep clause
>
> for S'Component_Size use 8;
>
> Now I can generate the load/and/store sequence since
> data independence is no longer required.
And then there is no problem, because this isn't confirming on this machine.
> Again, I didn't write this, I am just a reader, and
> that's what the Ada 95 RM says.
And it's clearly wrong. A rep. clause like the above should never, ever
change the semantics.
In any case, I agree that we need to give careful consideration to changing
this rule, because it might cause a real hardship. (Although I'd like to see
concrete examples of code that causes trouble on particular processors.) One
solution would be to have an independent way to specify "independence", so
kludges like expecting a confirming clause to have a semantic meaning aren't
necessary. Sure sounds like an AI05.
****************************************************************
From: Robert Dewar
Sent: Monday, February 20, 2006 10:52 PM
> Right, but remember that this rule is wrong; at a least it should say
> "non-confirming" like all other rules for rep. clauses.
Yes, but that is incompatible and has severe implementation consequences
because it is hard to check the predicate confirming. Why?
Well if we have a record type, the only way we know what the default
representation is is to lay it out with no rep clauses. So you are
in practice suggesting that we lay it out twice whenever there is
a rep clause, once to see the default layout, once to see the
layout with the rep clause, to see if they are the same.
The rules for layout of records in the default case are extremely
complex and ABI dependent. Not all the machines in the world are
simple minded as the x86 when it comes to alignment (though for
efficiency, you want to align things on the x86 far more than
is usually done).
> That's a horribly kludgy usage, and precisely the sort of thing that we
> wanted to get rid of. If that means that the default objects all have to
> take 64-bits, so be it. (Although I seriously doubt that would be the case
> on any commonly used processors.)
I think you just don't know enough processors well enough :-). Just as
we take shared generics into serious consideration even though almost
all Ada 95 compilers do not try to do universal sharing, we certainly
must take architectures other than the x86 into effect, and casually
causing major incompatibilties with these architectures and announcing
"so be it" is casual beyond belief to me.
>> If you want an example of efficiency of code generation, consider
>>
>> X : String (1 .. 4);
>>
>> X (1) := Ascii.Nul;
>> X (3) := Ascii.Nul;
>>
>> it is just fine to generate a word load, followed by an AND,
>> followed by a word store in this case, since independence
>> is not required. But if I do
>>
>> type S is array (Positive range <>) of Character;
>> X : S (1 .. 4)
>>
>> then if I choose (as many compilers would) to still store
>> the characters in 8-bit bytes, the above combination would
>> not be valid, since for this type data independence is
>> required.
>
> If you don't have byte operations, the default component size for this array
> cannot be 8. It has to be 16 or 32 or whatever. Or you have to provide
> independence all of the time (and I agree that's too expensive).
Please read more carefully, we are of COURSE talking about a machine
with byte operations here. hat's the WHOLE POINT of this example. Indeed
just think of it as an example for the x86.
Code where you do not have to worry about independence
mov eax,w
and eax,0xff00ff00
mov w,eax
Code where you have to worry about independence
sub al,al
mov w+0,al
mov w+2,al
Now which sequence is faster depends of course on the state
of the multiple pipelines and the store buffer (things that
a modern optiming compiler worries about).
For type String, you can choose either sequence
For type S with no Pack, you can only use the second sequence
For type S with a pack, you can choose either sequence
It is *EXACTLY* intentional that pragma Pack give this kind
of freedom! That's why the independence rule is there (for
more about independence and its consequences, see Norm
Schulman's PhD thesis [NYU, me as the advisor])
> But are there any such machines in use today? The old Alphas are, well, old,
> and everything else I can think of has 8 bit operations.
You don't know general architectures very well, there are a number of
DSP chips and other special purpose chips with odd word lengths! That's
why we put a pragma Pack on String, knowing that it destroyed independence.
As for the "old" alphas, there are plenty around, and any serious
compiler that is intended for general use on the alpha must accomodate
this architecture.
>> But if I add the "confirming" rep clause
>>
>> for S'Component_Size use 8;
>>
>> Now I can generate the load/and/store sequence since
>> data independence is no longer required.
>
> And then there is no problem, because this isn't confirming on this machine.
We are talking about a byte addressed machine. I think you fired off
your response too quickly here, please reread this example carefully.
It applies for instance to the x86.
>> Again, I didn't write this, I am just a reader, and
>> that's what the Ada 95 RM says.
>
> And it's clearly wrong. A rep. clause like the above should never, ever
> change the semantics.
Make up things as you go along if you like, but of COURSE rep clauses
can change the semantics in Ada 95. Do you really think the pragma Pack
on String is there for any other reason than to change the semantics?
> In any case, I agree that we need to give careful consideration to changing
> this rule, because it might cause a real hardship. (Although I'd like to see
> concrete examples of code that causes trouble on particular processors.) One
> solution would be to have an independent way to specify "independence", so
> kludges like expecting a confirming clause to have a semantic meaning aren't
> necessary. Sure sounds like an AI05.
As I said, we put the pragma Pack in in Standard precisely because of
the independence issue. This pragma could have a comment:
pragma Pack (String);
-- ensure a component size of 8 if possible, even at the expense of
-- losing independence.
A separate way of controlling independence was certainly considered, but
rightly rejected as over-complex.
I really think this entire issue has been addressed without sufficient
thought, and it seems a mess to me. The original formulation of Ada 95
Size/Alignment stuff is a bit of a mess anyway, this seems to make it
worse.
****************************************************************
From: Randy Brukardt
Sent: Monday, February 20, 2006 11:37 PM
...
> > And it's clearly wrong. A rep. clause like the above should never, ever
> > change the semantics.
>
> Make up things as you go along if you like, but of COURSE rep clauses
> can change the semantics in Ada 95. Do you really think the pragma Pack
> on String is there for any other reason than to change the semantics?
A pragma Pack can never be confirming, because the "pack" aspect is not one
that anything has by default.
> > In any case, I agree that we need to give careful consideration to changing
> > this rule, because it might cause a real hardship. (Although I'd like to see
> > concrete examples of code that causes trouble on particular processors.) One
> > solution would be to have an independent way to specify "independence", so
> > kludges like expecting a confirming clause to have a semantic meaning aren't
> > necessary. Sure sounds like an AI05.
>
> As I said, we put the pragma Pack in in Standard precisely because of
> the independence issue. This pragma could have a comment:
>
> pragma Pack (String);
> -- ensure a component size of 8 if possible, even at the expense of
> -- losing independence.
>
> A separate way of controlling independence was certainly considered, but
> rightly rejected as over-complex.
Well, pragma Pack is never confirming, so it would in fact be good enough
for this purpose.
My example was Component_Size, which is a different kettle of fish. And yes,
in the absence of pragma Pack/"pragma lose independence", I think that
independence ought to be maintained.
> I really think this entire issue has been addressed without sufficient
> thought, and it seems a mess to me. The original formulation of Ada 95
> Size/Alignment stuff is a bit of a mess anyway, this seems to make it
> worse.
Sorry, but any more thought on those AIs wasn't going to lead anywhere. I
think most of us feel our heads were about to explode when AI-51 was finally
finished! Perhaps we would have had different conclusions had you been
involved in the meeting discussions, but you weren't, and we didn't.
****************************************************************
From: Pascal Leroy
Sent: Tuesday, February 21, 2006 2:29 AM
> > Right, but remember that this rule is wrong; at a least it should say
> > "non-confirming" like all other rules for rep. clauses.
>
> Yes, but that is incompatible...
I must be a bonehead, but I don't see the incompatibility here.
Adding "nonconfirming" to 9.10(1) would guarantee independence in *more*
cases. I am sure that there are many programs out there that depend on
independence, and *removing* independence in some situations would not be
acceptable. However I cannot imagine that a program would depend on
non-independence (unless it were erroneous).
Now of course it could mean generating a less efficient instruction
sequence in the new circumstances where you have to guarantee
independence. But we don't worry about this: the code generated by a
compiler can change at the drop of a hat (in particular, at every new
release) and we are not in the business of counting the number of cycles
that it takes to perform some operations.
Incidentally, I don't understand why 9.10(1) doesn't mention pragma
Convention. Consider an array of 4 characters. On an old Alpha, as you
explained, it would have to be laid out with components occupying 32 bits.
But if you put a pragma Convention (C) on the array, I would expect the
components to use 8 bits. (I see that the C standard doesn't specify the
size of char, but I am pretty sure that most of the C code out there
assumes that it's 8 bits.)
****************************************************************
From: Robert Dewar
Sent: Tuesday, February 21, 2006 8:02 AM
> My example was Component_Size, which is a different kettle of fish. And yes,
> in the absence of pragma Pack/"pragma lose independence", I think that
> independence ought to be maintained.
Gosh, you are now proposing a different semantics between
type X is array (0 .. 31) of Boolean;
pragma Pack (X);
and
type X is array (0 .. 31) of Boolean;
for X'Component_Size use 1;
and furthermore you are suggesting that the latter should maintain
independence.
That would be *hugely* incompatible, since it would require, on all
common architectures, that the latter very common construction should
be rejected. You cannot be serious, you must have said something you
did not mean.
If you are just musing about a language that is not Ada, then what
you say may make sense, though I would do it exactly the other way
round. I would not make independence the default, since accessing
components of a single composite object is the unusual case, which
can use commenting in any case, so I would have a
pragma Independent_Access (type);
with the meaning that the layout of type must accomodate access to
different components by independent tasks.
> Sorry, but any more thought on those AIs wasn't going to lead anywhere. I
> think most of us feel our heads were about to explode when AI-51 was finally
> finished!
If you feel your head is about to explode, you probably have got
things wrong, and you need more work. You should feel comfortable
with something when it is finished, not disturbed by it.
Anyway, this problem with independence is a significant bug, and I
see no reasonable proposal to fix it that is not either very hard
to implement on some compilers, or incompatible, so I don't see a
way out. I suggest someone finds something, you can't just add a
new feature to Ada 2005 that is wrong in this kind of way without
at least some idea that it can be fixed. Otherwise better to leave
it out, and put it back when you figure out how. After all, this
particular rule, about confirming rep clauses, is not addressing
some real problem, so why generate real problems with a new
requirement that is not in any sense urgent, and which has not
been completely thought through.
In practice of course, this is not that serious. There is plenty
of stuff in the RM that makes no sense that implementors and users
and the ACATS tests ignore, and this stuff does not cause any
significant problems, since it is ignored. I am sure this new
rule will also be essentially ignored by existing compilers.
Still it seems unnecessary to add useless things to the standard.
****************************************************************
From: Robert Dewar
Sent: Tuesday, February 21, 2006 8:17 AM
> Now of course it could mean generating a less efficient instruction
> sequence in the new circumstances where you have to guarantee
> independence. But we don't worry about this: the code generated by a
> compiler can change at the drop of a hat (in particular, at every new
> release) and we are not in the business of counting the number of cycles
> that it takes to perform some operations.
No, but we are in the business of not requiring changes to the code
generator without a lot of thought, and some idea that this is a benefit.
And as I have pointed out before, giving specific semantics to the
notion of a confirming rep clause is a potential implementation
earthquake, since at least in the case of GNAT, there is simply
no easy way to tell if a rep clause is or is not confirming.
> Incidentally, I don't understand why 9.10(1) doesn't mention pragma
> Convention. Consider an array of 4 characters. On an old Alpha, as you
> explained, it would have to be laid out with components occupying 32 bits.
> But if you put a pragma Convention (C) on the array, I would expect the
> components to use 8 bits. (I see that the C standard doesn't specify the
> size of char, but I am pretty sure that most of the C code out there
> assumes that it's 8 bits.)
I agree, that's a bug, probably the understanding is that pragma
convention is equivalent to a component size or record rep clause.
But it should be stated.
Presumably pragma Convention (Ada) would be exempted, or is this
another way to tell the compiler you do not care out independence :-)
****************************************************************
From: Randy Brukardt
Sent: Tuesday, February 21, 2006 2:36 PM
Robert Dewar write:
> Randy Brukardt wrote:
>
> > My example was Component_Size, which is a different kettle of fish. And yes,
> > in the absence of pragma Pack/"pragma lose independence", I think that
> > independence ought to be maintained.
>
> Gosh, you are now proposing a different semantics between
>
> type X is array (0 .. 31) of Boolean;
> pragma Pack (X);
>
> and
>
> type X is array (0 .. 31) of Boolean;
> for X'Component_Size use 1;
>
> and furthermore you are suggesting that the latter should maintain
> independence.
No, no, no. The X'Component_Size is not going to be confirming on any common
architecture, so it clearly isn't going to require independence. (If it is
confirming, then the default implementation *can* guarentee independence,
and then it should here, too, and again there is no problem.)
Now, if you had stuck with your original example:
type X is array (0 .. 31) of Character;
pragma Pack (X);
and
type X is array (0 .. 31) of Character;
for X'Component_Size use 8;
Then you are exactly right; the latter should maintain independence, while
the former doesn't have to. That just follows from the "no semantics for
confirming rep. clauses" rules - and it's an easy rule to remember.
> > Sorry, but any more thought on those AIs wasn't going to lead anywhere. I
> > think most of us feel our heads were about to explode when AI-51 was finally
> > finished!
>
> If you feel your head is about to explode, you probably have got
> things wrong, and you need more work. You should feel comfortable
> with something when it is finished, not disturbed by it.
The problem is that it is hugely difficult to come to agreement on these
issues; the solution is just fine. But getting everybody on board to even a
relatively trivial issue is very painful work. We even considered no
solution at all (essentially the anarchy solution), but that isn't
considered acceptable politically.
If I was starting a new language (as you put it), I'd blow away the entire
definitions of Size, etc. and start over with something that actually makes
sense (on the line of the GNAT 'Object_Size). But we're not doing that.
Given the options, somebodies ox is going to get gored (or at least
injured).
In any case, you seem to be ignoring the critical point, which is a
usability issue. Do you agree or disagree with the statement "users should
be able to add confirming rep. clauses without changing the semantics of
their program"?
Now, it seems to me that the discussion has pointed out one important point:
determining if a record rep. clause is confirming is very difficult, so if
there is a real need to do that, we need to look at exempting it from any
such requirement. But making that determination for most rep. clauses is
reasonably easy, so there needs to be no exception for them.
****************************************************************
From: Robert Dewar
Sent: Tuesday, February 21, 2006 2:37 PM
> Now, if you had stuck with your original example:
>
> type X is array (0 .. 31) of Character;
> pragma Pack (X);
>
> and
>
> type X is array (0 .. 31) of Character;
> for X'Component_Size use 8;
To me it is plain horrible to introduce a fundamental
difference between the pragma Pack and the component
size clause here (given that the Pack must result in
a component size of 8).
> In any case, you seem to be ignoring the critical point, which is a
> usability issue. Do you agree or disagree with the statement "users should
> be able to add confirming rep. clauses without changing the semantics of
> their program"?
I think that is fine as implementation advice. I think it is a
horrible error as a requirement, but still I think most compilers
will just ignore it, and no one will notice the difference.
>
> Now, it seems to me that the discussion has pointed out one important point:
> determining if a record rep. clause is confirming is very difficult, so if
> there is a real need to do that, we need to look at exempting it from any
> such requirement. But making that determination for most rep. clauses is
> reasonably easy, so there needs to be no exception for them.
It is not so easy to tell if a component clause if confirming or not,
since laying out arrays is highly target dependent, so the determination
happens deep in the target dependent area. Again, we would have to
introduce the idea of laying out the type twice, just to see if the
component clause was confirming.
****************************************************************
From: Pascal Leroy
Sent: Wednesday, February 22, 2006 3:32 AM
> > type X is array (0 .. 31) of Character;
> > pragma Pack (X);
> >
> > and
> >
> > type X is array (0 .. 31) of Character;
> > for X'Component_Size use 8;
>
> To me it is plain horrible to introduce a fundamental
> difference between the pragma Pack and the component size
> clause here (given that the Pack must result in a component
> size of 8).
This might represent Dewar's interpretation, but it is not borne out by
13.2, which talks about "storage minimization". Consider the case of an
array that has dope. It would be very sensible for pragma Pack to affect
the layout of dope *and* components, causing the dope to be compressed
somehow. On the other hand the Component_Size clause would only affect
the components, not the dope.
The above array probably doesn't have dope, but for an unconstrained array
(eg, String) there might be a significant different between Pack and
Component_Size.
> > Now, it seems to me that the discussion has pointed out one important
> > point: determining if a record rep. clause is confirming is very
> > difficult, so if there is a real need to do that, we need to look at
> > exempting it from any such requirement. But making that determination
> > for most rep. clauses is reasonably easy, so there needs to be no
> > exception for them.
>
> It is not so easy to tell if a component clause if confirming
> or not, since laying out arrays is highly target dependent,
> so the determination happens deep in the target dependent
> area.
It is not so easy for alignment either: in our implementation the choice
of size and alignment are intertwined, and the size is clearly affected by
a record representation clause. So if we believe that confirming
representation clauses have to be neutral (I do) then we have to bite the
bullet, we cannot exempt some of them.
> Again, we would have to introduce the idea of laying
> out the type twice, just to see if the component clause was
> confirming.
As I said earlier we would have to do the same, but somehow it doesn't
seem too bad . In our implementation it wouldn't take more than a couple
of days. Time well spent if you ask me compared to, say, Unicode support.
(As usual with implementations, YMMV.)
****************************************************************
From: Robert Dewar
Sent: Wednesday, February 22, 2006 5:58 AM
> This might represent Dewar's interpretation, but it is not borne out by
> 13.2, which talks about "storage minimization". Consider the case of an
> array that has dope. It would be very sensible for pragma Pack to affect
> the layout of dope *and* components, causing the dope to be compressed
> somehow. On the other hand the Component_Size clause would only affect
> the components, not the dope.
Well I don't know about "very sensible", since (a) I can't imagine any
such scheme that makes sense, and (b) of course as you note below this
array does not have any "dope". Let us just say it is conceivable.
But since "dope" is semantically invisible, I don't think the above
makes any sense at all, a compiler is free to compress or uncompress
the dope regardless of the presence or absence of either rep clause.
But the distinction that Randy was suggesting was that there was a
substantial *semantic* difference between the two cases. Let's look
at a very exact case
type X is array (0 .. 31) of Character;
pragma Pack (X);
In randy's suggested interpretation, this does not guarantee
independence.
type X is array (0 .. 31) of Character;
for X'Component_Size use 8;
Now, assuming that Standard.String'Component_Size is 8, Randy
says this should guarantee independence (and that's something
that a real semantic test can be written for).
That's what I object to. A formal semantic difference between
these two rep clauses, which have always been equivalent in
Ada 95.
> It is not so easy for alignment either: in our implementation the choice
> of size and alignment are intertwined, and the size is clearly affected by
> a record representation clause. So if we believe that confirming
> representation clauses have to be neutral (I do) then we have to bite the
> bullet, we cannot exempt some of them.
Well as long as there is no significant semantic effect, I don't see
the difficulty
>> Again, we would have to introduce the idea of laying
>> out the type twice, just to see if the component clause was
>> confirming.
>
> As I said earlier we would have to do the same, but somehow it doesn't
> seem too bad . In our implementation it wouldn't take more than a couple
> of days. Time well spent if you ask me compared to, say, Unicode support.
> (As usual with implementations, YMMV.)
This would be a real mess in GNAT, we just wouldn't do it. It would
represent weeks of work, may be more, to completely change the
way types are layed out. That's because the layout occurs very late
in the back end, and we would have to alter the entire interface
between the back end and front end.
Note that Ada is obviously designed to allow this late layout of
composite objects (that's why things like record_type'Size are
not static when they perfectly well could be from a semantic
point of view when the record has all static layout).
Actually regarding the Unicode support, we have customers taking full
advantage of this Ada 2005 feature right now (we have fully implemented
this for a while).
To me, to go through this (much more difficult) implementation effort
just to deal with this independence glitch would be a major nonsense,
which would benefit absolutely no users at all.
So adding "non-confirming" to the independence paragraph is not a minor
fix, it is a major change at the last moment, which I find entirely
unacceptable.
****************************************************************
From: Tucker Taft
Sent: Wednesday, February 22, 2006 5:41 PM
This topic feels a bit overblown to me.
We are mostly talking about the issue of independence,
and I would expect that for a given representation,
either the load/stores are independent or they aren't.
I would be surprised that if you had two types
with identical representations, that an implementation
would provide independence for one but not for the other
simply because there was no rep. clause on one but
there was on the other. There are a finite number
of Ada implementations, and it is unlikely to increase
any time soon. Do any implementations actually go out
of there way to provide independence for a given
representation *only* when there are no rep. clauses?
Seems like most of us have plenty of better things to do.
****************************************************************
From: Robert Dewar
Sent: Wednesday, February 22, 2006 9:10 PM
You might equally ask whether implementations go out
of their way to reject confirming rep clauses, and
the answer is no, they do not.
Either we are talking about crafting the language
in a way that makes sense for all reasonable
implementations, in which case we have to worry
about the independence issue (I gave a perfectly
reasonable example of a case in which a compiler
might generate different code depending on whether
independence is require, you can easily find other
examples.
Or we are taking a pragmatic view wrt existing
compilers, in which case the whole business of
mentioning confirming rep clauses is junk. If
there are any existing compilers that reject
confirming rep clauses, the RM is not likely
to make them change their implementation anyway!
****************************************************************
From: Robert Dewar
Sent: Wednesday, February 22, 2006 9:13 PM
> Do any implementations actually go out
> of there way to provide independence for a given
> representation *only* when there are no rep. clauses?
> Seems like most of us have plenty of better things to do.
That's exactly the wrong way round. You have to go
out of your way to guarantee independence. The back
end is in the business of combining instructions to
reduce the instruction count, and the point of
independence is to prevent such combining.
I have no idea whether the GCC back end can do
combinations that are troublesome in practice.
It is almost impossible to make absolute
statements about what the optimizer will do,
since it works with the machine description
in a goal driven way, and figuring out all
possible outcomes is infeasible.
****************************************************************
From: Randy Brukardt
Sent: Wednesday, February 22, 2006 9:31 PM
Out of curiosity, how do you guarantee independence when it is required by
the language for such a backend? On the face of it, it would seem
incompatible with Ada.
****************************************************************
From: Tucker Taft
Sent: Thursday, February 23, 2006 9:03 AM
>> Do any implementations actually go out
>> of there way to provide independence for a given
>> representation *only* when there are no rep. clauses?
>> Seems like most of us have plenty of better things to do.
>
> That's exactly the wrong way round. You have to go
> out of your way to guarantee independence.
Isn't that what my question is asking? Do any
implementations make an effort to guarantee independence?
Or do they just rely on choosing default
representations that they presume will provide it?
> ... The back
> end is in the business of combining instructions to
> reduce the instruction count, and the point of
> independence is to prevent such combining.
Combining is not really a problem for independence.
For independence the key is that you don't store
more bits than you need to. Loading more is OK.
(This is not about atomicness, which is a separate
discussion.)
But the real question is does GNAT make an effort
to prevent storing more bits than necessary,
or do they just presume that if the machine has
instructions for storing 16-bit values
directly, that that is what the backend will do?
I suspect that most implementations where the
back end and front end are supported by separate
organizations, that there is an implicit understanding
that overlong stores won't be used unless there is
no choice.
> I have no idea whether the GCC back end can do
> combinations that are troublesome in practice.
> It is almost impossible to make absolute
> statements about what the optimizer will do,
> since it works with the machine description
> in a goal driven way, and figuring out all
> possible outcomes is infeasible.
I don't think it is combinations. It is overlong
stores. And a troublesome overlong store is one
that also requires a load and a mask.
In any case, the real question is whether GNAT is doing
something special to guarantee independence
for the default representation?
****************************************************************
From: Randy Brukardt
Sent: Thursday, February 23, 2006 4:37 PM
As usual, Tucker has more clearly stated my question. It seems that usually
independence is something that you would expect out of a back-end, not
something you would need to ask for. Of course, a front-end creator could be
wrong about that assumption, but it seems likely that they wouldn't find
that out until there was a bug report...
****************************************************************
From: Robert Dewar
Sent: Thursday, February 23, 2006 6:08 PM
> Isn't that what my question is asking? Do any
> implementations make an effort to guarantee independence?
> Or do they just rely on choosing default
> representations that they presume will provide it?
Well I would not trust this presumption. I don't know
what goes on in the back end here, but would not be
completely surprised to find out that we *did* have
some independence bugs in some strange cases, which
would need fixing (but would not be hard to fix).
> Combining is not really a problem for independence.
> For independence the key is that you don't store
> more bits than you need to. Loading more is OK.
> (This is not about atomicness, which is a separate
> discussion.)
Right, and the combiner is clever enough to know
that it can store more bits if it loads them first.
After all it has to do this kind of thing all the
time.
Actually it is quite interesting to worry about
whether there are independence bugs in the
back end, there might be!
> I suspect that most implementations where the
> back end and front end are supported by separate
> organizations, that there is an implicit understanding
> that overlong stores won't be used unless there is
> no choice.
I don't think there is any such implicit understanding
in gcc, not that I know of anyway.
> I don't think it is combinations. It is overlong
> stores. And a troublesome overlong store is one
> that also requires a load and a mask.
But lots of sequences require load-more-than-you-need
mask, store-more-than-you-need. This is after all the
routine code for dealing with packed bit arrays.
>
> In any case, the real question is whether GNAT is doing
> something special to guarantee independence
> for the default representation?
I don't know, and the actual question might be
whether GNAT needs to do something special with
the GCC 4 optimizer (which we have not fully
integrated yet, but which already caused us
trouble -- e.g. it was helpfully eliminating
'Valid tests because it assumed that things
were valid :-))
So I think the likely scenario is that as the
optimizer improves, we find we *do* need to do
more to guarantee independence even if we don't
now. That's easy enough to do (providing we
don't have to evaluate the is-confirming
predicate, which I discussed the other day,
and our back end folks agreed that this would
be really difficult to do).
****************************************************************
From: Robert Dewar
Sent: Thursday, February 23, 2006 7:10 PM
I think this thread does show that the proper solution for
independence would indeed be a pragma (though as I said before,
I think you want the default to be no independence, and a pragma
that guarantees independence -- of course pragma Atomic_Comonents
is often enough to achieve what you want).
****************************************************************
From: Pascal Leroy
Sent: Friday, February 24, 2006 1:39 AM
I agree. The fact that specifying the representation affects
independence, and does so in a non-portable way, is poor language design.
Incidentally, this discussion has convinced me that confirming
representation clauses are not the essence of the problem: if I specify a
component size of 64 bits for an array of characters, chances are that
this won't be confirming and chances are that it won't affect independence
(YMMV).
Why don't we provide a way for the user to clearly express her intent?
Representation items specify the representation, period. If an algorithm
depends on independence (or doesn't depend on independence -- what the
default should be is a different discussion) it should state it
explicitly, irrespective of representation items.
This would make the code much more readable, because you would not have to
interpret the *absence* of a representation item as implying independence.
And it would also improve safety and portability, because a combination of
representation items and independence requirements that could not be
satisfied would be rejected, instead of silently becoming erroneous.
****************************************************************
From: Robert Dewar
Sent: Friday, February 24, 2006 5:22 AM
> Why don't we provide a way for the user to clearly express her intent?
> Representation items specify the representation, period. If an algorithm
> depends on independence (or doesn't depend on independence -- what the
> default should be is a different discussion) it should state it
> explicitly, irrespective of representation items.
I strongly agree with this, although it is formally an incompatible
change. So here is a form in which it is compatible:
pragma Independent_Components (type_local_NAME);
This pragma specifies that independence must be guaranteed for
the given type, even if a representation clause is present. The
compiler must reject the pragma if it is not possible to guarantee
independence for the type given the representation clauses present.
If no representation clauses are present, then the default
representation that is chosen must be such that the compiler
can guarantee independence by default. For such types, the
use of pragma Independent_Components has no effect (but may
still be useful as clear documentation that separate tasks
may access separate components in an asynchronous manner.
>
> This would make the code much more readable, because you would not have to
> interpret the *absence* of a representation item as implying independence.
> And it would also improve safety and portability, because a combination of
> representation items and independence requirements that could not be
> satisfied would be rejected, instead of silently becoming erroneous.
Right, a better formulation would be to require the pragma even
if there are no rep clauses present, but that's a significantly
incompatible change.
Of course compilers could simply refrain from taking advantage
of this incompatibility if they were concerned about compatibility
issues, but still, from a formal point of view, it would be a
an incompatible change, and therefore contentious.
The change, even in the compatible form I give here, solves the
issue of conforming rep clauses, because the rule would simply be
that a set of conforming rep clauses must include the independence
pragma (of course you could leave it out if you were not interested
in separate task access).
****************************************************************
From: Bibb Latting
Sent: Monday, November 6, 2006 5:21 PM
While working on this AI, I had the following questions regarding
both the text of the AI and what should or shouldn't be included:
9.10 (1)
How about removing implementation defined from this paragraph.
Something along the lines of:
"However, representation items such as packing and record layout may
prevent a subcomponent of an object from being independently
addressable."
9.10 (16 and 17)
Should the implementation advice attempt to include update of any
implementation data such as array doping or other hidden data?
Should some documentation recommendation be added that identifies
those elementary values, if any, that are not suitable for use with
multiple tasks?
Dependently Addressable Objects
Should an implementation permission be given to allow generation of
an instruction sequence which might break inter-task synchronization
when an object is not independently addressable?
High Integrity
Are there any appropriate restrictions applicable for "pragma
Independent_Components". Specifically, should D.7, Tasking
Restrictions; D.13.1, The "Ravenscar" profile, and H.4 High Integrity
Restrictions contain a restriction to prevent the use of
"Independent_Components"?
Privacy
Using independent addressing as the default synchronization method
causes a dreadful headache when considering privacy. Might the
introduction of a "Pragma Independent" as some sort of recursive
application of pragma Independent_Components partially mitigate this
problem?
Initialized Discriminates
The behavior of assignment to initialized discriminates is
problematic here; should initialized discriminates be explicitly
excluded from those objects which are independently addressable?
Should an initialized discriminate be cause to reject a pragma
Independent_Components?
Independent Addressability
Should pragma Independent_Components cause rejection of elementary
components which are independently addressable, but can not be
updated using an indivisible operation?
Should a pragma be provided to assure thread-safe elementary object
representation and instruction selection (as opposed to the
flexibility associated with independent addressability)?
Memory Segment Allocation
What relevance, if any, does segment allocation have with regards to
inter-task data sharing (a segment can be "local" or "shared" on
some architectures), particularly on multi-processor systems? Is
there a default that needs to be addressed?
Notes
13.1 (21.1) was selected for implementation advice for confirming
representations to avoid implementation advice for each item
(e.g. 13.1 (21.1) recommends a confirming representation for pragma
pack, which is considered to be non-confirming). 9.10 was discarded
as an appropriate location because of the unnecessary forward
reference to a confirming representation.
****************************************************************
From: Randy Brukardt
Sent: Tuesday, November 7, 2006 6:59 PM
> While working on this AI, I had the following questions regarding
> both the text of the AI and what should or shouldn't be included:
>
> 9.10 (1)
>
> How about removing implementation defined from this paragraph.
> Something along the lines of:
>
> "However, representation items such as packing and record layout may
> prevent a subcomponent of an object from being independently
> addressable."
Why? "implementation-defined" means it is supposed to be documented somehow.
That means users have a way to find out what happens. Granted, using the new
pragma it probably better than depending on implementation-defined behavior.
But I think we want to make as little change here as possible (we don't want
to break existing programs).
> 9.10 (16 and 17)
>
> Should the implementation advice attempt to include update of any
> implementation data such as array doping or other hidden data?
I don't know how you could do that. Objects are independent unless the
language says that they don't have to be, so any hidden stuff also has to be
independent. And we almost never talk about implementation artifacts: the
implementation is supposed to handle those correctly. If the objects aren't
independent, then any dope wouldn't need to be, either.
> Should some documentation recommendation be added that identifies
> those elementary values, if any, that are not suitable for use with
> multiple tasks?
Robert Dewar will say that documentation requirements are junk. Besides,
your question doesn't make sense. Independent addressability merely says
that two tasks can access *different* objects (inc. components) without
interference. That surely must be possible for all types in the absence of
representation items. (Just put one Boolean per byte, for instance.) We
expect compilers to get this right.
> Dependently Addressable Objects
>
> Should an implementation permission be given to allow generation of
> an instruction sequence which might break inter-task synchronization
> when an object is not independently addressable?
We always have to talk in terms of two objects when we're talking about
independently addressable. It seems like you might be confusing independent
addressibility with Atomic. The language seems clear that if two objects are
not independently addressible, then the tasks might need some explicit
synchronization to access them. I don't see that anything about this has
anything to do with "instruction sequences" (that's Atomic). If I'm wrong,
perhaps an example of the problem would help.
> High Integrity
>
> Are there any appropriate restrictions applicable for "pragma
> Independent_Components". Specifically, should D.7, Tasking
> Restrictions; D.13.1, The "Ravenscar" profile, and H.4 High Integrity
> Restrictions contain a restriction to prevent the use of
> "Independent_Components"?
Huh again? Why would you *not* want Independent_Components, as it prevents
dependencies not shown in the source code. It might be nice to have a
restriction to flag things that are *not* independently addressable -- but
that surely was an issue in Ada 95, and it wasn't considered important
enough to bother with.
> Privacy
>
> Using independent addressing as the default synchronization method
> causes a dreadful headache when considering privacy. Might the
> introduction of a "Pragma Independent" as some sort of recursive
> application of pragma Independent_Components partially mitigate this
> problem?
Huh again? Independent addressibility is *not* a synchronization method!!
That's Atomic (see C.6). It merely says that things will work as expected,
when two tasks access *different* objects. When an objects/components are
not independently addressable, then there can be interference between them
even if they are semantically separate.
For instance, if we have:
type Rec is record
B1, B2 : Boolean;
end record;
pragma Independent_Components (Rec);
Obj : Rec;
then if task T1 accesses Obj.B1, and task T2 accesses Obj.B2, no
synchronization is needed. OTOH, if we replaced Independent_Components by
Pack, then there is no guarantee that T1 and T2 can access the two
components of Obj without trouble. (This is more interesting with arrays,
but I'm giving the example as a record because it is easier to write and
understand.)
> Initialized Discriminates
>
> The behavior of assignment to initialized discriminates is
> problematic here; should initialized discriminates be explicitly
> excluded from those objects which are independently addressable?
>
> Should an initialized discriminate be cause to reject a pragma
> Independent_Components?
I don't see any reason that initialized discriminants have any bearing on
this at all. Please explain with an example.
> Independent Addressability
>
> Should pragma Independent_Components cause rejection of elementary
> components which are independently addressable, but can not be
> updated using an indivisible operation?
Indivisible operations are those for Atomic. You're thinking of
Atomic_Components again. The only reason I can think of for rejecting
Independent_Components is if another rep. clause requires a mask-and-store
implementation:
type Arr is (1..8) of Boolean;
for Arr'Component_Size use 1;
pragma Independent_Components (Arr); -- Reject this.
But if the components are large and require multiple instructions, that's
not a problem so long as the memory cells in question are separate from any
other objects cells.
> Should a pragma be provided to assure thread-safe elementary object
> representation and instruction selection (as opposed to the
> flexibility associated with independent addressability)?
That sounds like pragma Atomic and Atomic_Components. Or did you have
something else in mind?
> Memory Segment Allocation
>
> What relevance, if any, does segment allocation have with regards to
> inter-task data sharing (a segment can be "local" or "shared" on
> some architectures), particularly on multi-processor systems? Is
> there a default that needs to be addressed?
That level of detail is usually left up to the implementer. Atomic is an
exception, but we're not talking about that here.
> Notes
>
> 13.1 (21.1) was selected for implementation advice for confirming
> representations to avoid implementation advice for each item
> (e.g. 13.1 (21.1) recommends a confirming representation for pragma
> pack, which is considered to be non-confirming). 9.10 was discarded
> as an appropriate location because of the unnecessary forward
> reference to a confirming representation.
I'm not sure what this means. There shouldn't need to be any new advice
about confirming representations. The bug in 9.10 was that confirming rep.
clauses had a semantic effect, we don't want that ever to be true. For all
representation items, a confirming clause should be supported (if such a
thing can be written -- which isn't necessarily possible, because we don't
have a pragma Unpack to specify the absence of pragma Pack, for one
example). There is no exception to this rule! We're surely not going to
distribute some goofy rules about independent addressibility all over the
standard.
****************************************************************
From: Robert Dewar
Sent: Sunday, May 20, 2007 10:01 PM
> Modify to identify only non-confirming representations as those
> that can cause dependent addressability. Modify to include
> convention as an item that can cause an object to be dependent
> (exclude convention Ada) for a representation. Change dependent
> addressability from implementation defined to unspecified.
I don't think this is tenable. What on earth is the semantic
definition of a confirming representation clause. After all
there is nothing in the standard that prevents a compiler
from basing the representation of an item on the phases
of the moon, or the MD-5 checksum of the program (the latter
ensuring that the would-be default representation is changed
by adding "confirming rep clauses". Also it may simply not
be possible from a formal point of view to specify a confirming
rep clause, e.g. suppose that an array is by default stored
in some sparse hash table form, and only has a meaningful
component size if one is specified, or if the component size
is queried. etc etc.
At most this could be implementation advice
I do not see why convention should possibly affect independence
>
> AARM 13.1 (8.v, 8.w; 8.gg, 8.hh)
>
> Add independent and independent components, respectively.
>
> C.6
>
> Add pragmas Independent and Independent_Components. Independent
> applies to components of record types; Independent_Components
> applies to components of arrays or anonymous array objects.
The pragmas make good sense indeed. And with the pragmas the whole
business of trying to specify what is meant by a confirming rep
clause disappears.
****************************************************************
From: Randy Brukardt
Sent: Monday, May 21, 2006 12:25 AM
...
> What on earth is the semantic
> definition of a confirming representation clause.
It's in 13.1(18.2/2):
A representation item that specifies an aspect of representation that would
have been chosen in the absence of the representation item is said to be
confirming.
The recommended level of support 13.1(21.1/2) is that confirming items (if
they can be written, see below) always be supported.
Next question. ;-)
> After all
> there is nothing in the standard that prevents a compiler
> from basing the representation of an item on the phases
> of the moon, or the MD-5 checksum of the program (the latter
> ensuring that the would-be default representation is changed
> by adding "confirming rep clauses". Also it may simply not
> be possible from a formal point of view to specify a confirming
> rep clause, e.g. suppose that an array is by default stored
> in some sparse hash table form, and only has a meaningful
> component size if one is specified, or if the component size
> is queried. etc etc.
Recommended level of support is always implementation advice.
In any case, we had this discussion right here on the ARG list back in
February of 2006. Then, you said:
> Indeed. I actually think that there should be a rule that the
> compiled accept all confirming representation clauses, which
> is not necessarily the case.
To which it was pointed out that there indeed is such a rule in Ada 2005.
Note that further discussion (and an AARM note) points out that it might not
be possible to write a confirming rep. clause; the rule is intended to be
read such that if you *can* write such a clause, then it must be accepted.
It's also intended that a confirming representation item never have a
semantic effect. We changed all of the chapter 13 rules to make that true;
we missed this one on chapter 9. Since the "representation choosen by
implementation by default" has to be independent anyway, this change can't
have any semantic effect on a correct compiler. It just means that if you
confirm a component size (for one example), you don't lose independence as a
side-effect.
Remember that independent components is the default; you don't need advice
that the default remains true!
The pragmas are needed so that you can force independence even when giving
non-confirming representation items like Pack. (And if independence can't be
maintained, then the program is illegal.)
...
> I do not see why convention should possibly affect independence
Pascal brought that up. He suggested that "I don't understand why 9.10(1)
doesn't mention pragma Convention. Consider an array of 4 characters. On
an old Alpha, as you explained, it would have to be laid out with components
occupying 32 bits. But if you put a pragma Convention (C) on the array, I
would expect the components to use 8 bits. (I see that the C standard
doesn't specify the size of char, but I am pretty sure that most of the C
code out there
assumes that it's 8 bits.)".
Bibb is just trying to write the AI as the ARG agreed at the last meeting.
Hope this helps.
****************************************************************
From: Robert Dewar
Sent: Tuesday, May 22, 2007 2:15 PM
> Recommended level of support is always implementation advice.
Not if Annex C is in effect
>
> In any case, we had this discussion right here on the ARG list back in
> February of 2006. Then, you said:
>
>> Indeed. I actually think that there should be a rule that the
>> compiled accept all confirming representation clauses, which
>> is not necessarily the case.
This is reasonable if there are no special semantics associated
with this.
> To which it was pointed out that there indeed is such a rule in Ada 2005.
>
> Note that further discussion (and an AARM note) points out that it might not
> be possible to write a confirming rep. clause; the rule is intended to be
> read such that if you *can* write such a clause, then it must be accepted.
And that's fine
> It's also intended that a confirming representation item never have a
> semantic effect. We changed all of the chapter 13 rules to make that true;
> we missed this one on chapter 9. Since the "representation choosen by
> implementation by default" has to be independent anyway, this change can't
> have any semantic effect on a correct compiler. It just means that if you
> confirm a component size (for one example), you don't lose independence as a
> side-effect.
I find it awkward and confusing to have this rule. I think it better to
rely on the new pragmas. After all we are changing the language right
now. In Ada 2005, writing a confirming rep clause clearly does kill
independence (even if this was not intended), so it has to be fixed,
and the clean way of fixing it is with the pragmas in any case. It is
a good thing to emphasize independence as a property rather than relying
on the default behavior.
It's a pity that we don't have a way of turning off independence by
default. Probably implementations should add a configuration pragma
that has this effect, relying on the new pragmas to add it back where
needed (this would avoid having to unpack things just in case
independence was required).
Remember that in Ada 83, we just did not think this out properly at
all (this was the huge change at the last minute in the printers
proof that dealt with independence at all).
The pragmas are a MUCH cleaner solution
> Pascal brought that up. He suggested that "I don't understand why 9.10(1)
> doesn't mention pragma Convention. Consider an array of 4 characters. On
> an old Alpha, as you explained, it would have to be laid out with components
> occupying 32 bits. But if you put a pragma Convention (C) on the array, I
> would expect the components to use 8 bits. (I see that the C standard
> doesn't specify the size of char, but I am pretty sure that most of the C
> code out there
> assumes that it's 8 bits.)".
OK, that makes sense
>
> Bibb is just trying to write the AI as the ARG agreed at the last meeting.
Well it's no big deal in fact, none of this independence stuff is
anything any implementor gives a thought to (it just falls out :-))
****************************************************************
From: Randy Brukardt
Sent: Tuesday, May 22, 2007 3:02 PM
> Well it's no big deal in fact, none of this independence stuff is
> anything any implementor gives a thought to (it just falls out :-))
I agree. And it is not really testable (a test which tries to generate a
independence failure might very well work for many other reasons even if the
independence is wrong). So, after choosing default representations
appropriately, pretty much this is something worth worrying about only if
there is a bug report from a customer (for instance, if a code generator
gets too aggressive combining instructions).
****************************************************************
Questions? Ask the ACAA Technical Agent