CVS difference for ai12s/ai12-0128-1.txt

Differences between 1.5 and version 1.6
Log of other versions for file ai12s/ai12-0128-1.txt

--- ai12s/ai12-0128-1.txt	2015/07/14 02:29:41	1.5
+++ ai12s/ai12-0128-1.txt	2015/10/10 00:02:38	1.6
@@ -48,69 +48,84 @@
 
 !wording
 
-Add after C.6(8.1/4): [Static Semantics]
+Append to the list of C.6 aspects:
 
-For a volatile object, the following representation aspect can be specified:
+   Whole_Object_Reference - The type of aspect Whole_Object_Reference
+   is Boolean.
 
-Exact_Size_Only
-   The type of aspect Exact_Size_Only is Boolean. An object with aspect
-   Exact_Size_Only having the value True is called an *exact size object*.
-   For an exact size object, all loads and stores of the object shall be
-   implemented by accessing exactly the bits of the object and no others.
+Append after C.6(8.3):
+  A "whole object reference" type is one for which the aspect
+  Whole_Object_Reference is true. A "whole object reference" object
+  (including a component) is one for which the Whole_Object_Reference
+  aspect is true, or an object of a whole object reference type.
+
+Move Static Semantics section (which is currently empty) ahead of
+Legality rules section. In the Static Semantics section add:
+
+  All reads of or writes to any part of a "whole object reference" object shall
+  be implemented by reading or writing the entire object.
+  Notwithstanding any rule to the contrary, no subcomponents of a
+  "whole object reference" object are independently addressable.
+
+  Implementation Note:
+
+  For example, if a 32-bit record object has 4 components, each occupying
+  one byte, then an assignment to one of those components might normally be
+  implemented on some target machines via some sort of store_byte instruction;
+  the "whole object reference" aspect indicates that instead a 32-bit
+  read-modify-write must be performed. That read-modify-write need not
+  be atomic, although the read and the write must each separately be
+  atomic if the object is atomic. This aspect is intended for use in
+  supporting memory-mapped devices on some targets.
+
+  As another example, consider a "whole object reference" object having
+  two or more nonoverlapping volatile subcomponents. A read of or write to any
+  part of the object will read, write, or possibly both read and write
+  the entire object, notwithstanding the other rules given in this section
+  about accessing volatile objects. This is similar to other target-dependent
+  cases where reading or writing one component necessarily involves reading
+  and/or writing neighboring storage and that neighboring storage
+  happens to overlap a volatile object.
+
+Modify the last sentence of C.6(13.2):
+   Corresponding rules apply to volatile objects and types
+   {, and to whole object reference objects and types }.
+
+Append at the end of the legality rules section (after C/6(13.2)):
+
+   The Whole_Object_Reference aspect shall not be specified for an
+   elementary entity.
+   If a subcomponent of a "whole object reference" object is passed as
+   the actual parameter in a call then the formal parameter shall
+   allow pass by copy (and, at run-time, the parameter shall be
+   passed by copy).
+   No subcomponent of a "whole object reference" object shall
+   used as an actual for a generic formal of mode in out.
+   No part of a "whole object reference" entity shall have
+   components which are specified to be independently addressable.
+   No part of a "whole object reference" entity shall be
+   aliased, limited, tagged, discriminated, or private, or
+   subject to a dynamic index constraint.
+
+AARM note:
+   We want to ensure that no view of any part of a whole object reference
+   object can ever be aliased. We also want to eliminate any issues
+   associated with implicit reading of discriminants.
+
+Discussion:
+   Just as atomic implies volatile, should "whole object" imply
+   volatile? Should it imply atomic? If the latter, then the "if the
+   object is atomic" wording above needs to be changed.
 
-   When this aspect is directly
-   specified, the aspect_definition shall be a static expression. If not
-   specified, this aspect is False.
 
-AARM Ramification: This aspect makes the Implementation Advice a requirement
-on the specified object (which will have no effect on most implementations,
-which are following the advice anyway). Note that this wording does NOT say
-"as a whole"; this rule applies to ALL accesses of the object and accesses
-which may require some other implementation are illegal (see below).
 
-Add after C.6(13.2/3): [Legality Rules]
 
-It is illegal to specify aspect Exact_Size_Only to have the value True for
-an object if the implementation cannot support the exact access required
-by the aspect.
-
-AARM Discussion: On most implementations, this will mean that the size of
-the object will have to be a multiple of the storage unit size.
-
-The name of an exact size object shall not be used as the prefix of a slice,
-indexed_component, or selected_component.
-
-AARM Reason: Such a component access will necessarily be volatile, and
-almost always would require access in a different (smaller) size than
-the object as a whole. To make the implementation easier, we disallow
-all component access to such objects.
-
-An exact size object shall not have a part which is a discriminated record.
-
-AARM Reason: A discriminant check would be an implicit component access
-just like the ones banned by the previous rule.
-
-An exact size object shall not be the actual to a generic *in out* parameter.
-An exact size object shall not be the prefix for the Access
-or Unchecked_Access attribute.
-
-AARM Reason: Inside the generic, the restrictions on access would not be known
-and thus enforced. If passed as an actual to a generic *in* parameter, a copy
-would be made. Similarly, the designated type for an access type would not
-enforce the restrictions on access to an exact size object.
-
-Add after C.6(20.a):
-
-AARM To Be Honest:
-    For an volatile-but-not-atomic object, multiple (divisible) operations may
-    be needed to implement a single read or write in the program. That might
-    include one or more reads in the case of writing some by not all bits of
-    a machine scalar. On the other hand, for an atomic object, all operations
-    have to be indivisible, so the operations should do exactly what is
-    specified in the code.
-
 !discussion
 
+[Editor's note: The discussion below is based on the proposal of version
+/03 of this AI. Version /04 didn't update it, so it doesn't exactly
+match the proposal.]
+
 The problem isn't really C.6(15). C.6(8/3) says that the subcomponents of
 a volatile object are also volatile. (Recall that atomic objects are also
 volatile.) The same rule that is supposed to help us then causes problems,
@@ -1868,7 +1883,7 @@
 From: Robert Dewar
 Sent: Saturday, March 21, 2015  8:57 AM
 
-We have had continued problems with people trying to use pragma Atomic for 
+We have had continued problems with people trying to use pragma Atomic for
 mapping memory-mapped variables. There are two problems
 
 a) Atomic does not guarantee that read/write references use a single
@@ -1892,18 +1907,18 @@
 From: Randy Brukardt
 Sent: Saturday, March 21, 2015  8:29 PM
 
-> We have had continued problems with people trying to use pragma Atomic 
+> We have had continued problems with people trying to use pragma Atomic
 > for mapping memory-mapped variables.
 
 This problem was reported to Ada-Comment last July. AI12-0128-1 was created to
 (potentially) address it.
 
 > There are two problems
-> 
-> a) Atomic does not guarantee that read/write references use a single 
-> instruction to access *ALL* the bits of the object, as is often 
-> expected and required. It is allowable (and most certainly GNAT takes 
-> advantage of this) to access e.g. a single field in an atomic record 
+>
+> a) Atomic does not guarantee that read/write references use a single
+> instruction to access *ALL* the bits of the object, as is often
+> expected and required. It is allowable (and most certainly GNAT takes
+> advantage of this) to access e.g. a single field in an atomic record
 > with a byte load instruction even if the record is a word.
 
 It's more than "allowed". It's strongly recommended, because the components
@@ -1912,7 +1927,7 @@
 
 A load or store of a volatile object whose size is a multiple of
 System.Storage_Unit and whose alignment is nonzero, should be implemented by
-accessing exactly the bits of the object and no others. 
+accessing exactly the bits of the object and no others.
 
 This is advice in name only; the only reason we didn't make it a requirement
 was that we couldn't find any way to say that normatively.
@@ -1924,9 +1939,9 @@
 Right. That I wasn't able to convince the person who reported it, so I didn't
 make much effort to bring this AI to the attention of the full ARG.
 
-> We just implemented pragma/aspect Volatile_Full_Access which is just 
-> like Volatile except that it guarantees that every read/write access 
-> to an object with this aspect reads or writes all the bits in a single 
+> We just implemented pragma/aspect Volatile_Full_Access which is just
+> like Volatile except that it guarantees that every read/write access
+> to an object with this aspect reads or writes all the bits in a single
 > instruction.
 
 On what does it work? Only on an object, or anywhere that Volatile can be used?
@@ -1937,8 +1952,8 @@
 to making another kind of volatile). Of course, I don't think anyone else ever
 commented on that. Either way works.
 
-> I suspect this new aspect is really what 99% of programmers trying to 
-> do memory mapped I/O really want, and may be worth considering for 
+> I suspect this new aspect is really what 99% of programmers trying to
+> do memory mapped I/O really want, and may be worth considering for
 > addition to the language.
 
 Something certainly should be added to the language. Your suggestion is probably
@@ -1951,7 +1966,7 @@
 The external effect of a program (see 1.1.3) is defined to include each read
 and update of a volatile or atomic object. The implementation shall not
 generate any memory reads or updates of atomic or volatile objects other than
-those specified by the program. 
+those specified by the program.
 
 This doesn't make any sense for volatile bit-mapped components, whether or not
 exact size is being required. In such a case, a read is necessary before a
@@ -1972,5 +1987,93 @@
     code.
 
 Going to be fun. ;-)
+
+****************************************************************
+
+From: Steve Baird
+Sent: Friday, October 9, 2015  5:56 PM
+
+This AI was part of my Madrid homework. [This is version /04 of the AI.]
+This is a preliminary attempt so that we have something concrete to discuss and
+(most likely) modify. See also the GNAT-defined Volatile_Full_Access pragma and
+aspect.
+
+****************************************************************
+
+From: Randy Brukardt
+Sent: Friday, October 9, 2015  7:00 PM
+
+Steve and I had an extensive private e-mail correspondence on this topic. Here
+are some thoughts from the correspondence not covered in the AI:
+
+(1) Since the problem is accessing hardware registers, it seems strange to
+separate the solution from Volatile. In all real uses, Volatile would be
+required as well as Whole_Object_Reference. (Why would anyone care how memory is
+read or written when the compiler can arbitrarly change it anyway??) And in that
+case, the requirements of Whole_Object_Reference would conflict with the
+requirements on a Volatile object (since components of a volatile object are
+also Volatile). In particular, the read-modify-write cycle violates C.6(20), and
+size violates IA C.6(22/2). That suggests an integrated solution (like Robert's
+last aspect, Volatile_Full_Access) might work better.
+
+(2) C.6(20) is broken for non-aligned or not multiple of storage-element sizes
+components, regardless of this new AI. Steve views that as an issue for a
+different AI, but I disagree. We surely want C.6(20) to apply to objects that
+have are both Whole_Object_Reference and Volatile, but the read before a write
+appears to be banned by the text. Since we have to fix it here in order to
+actually solve the problem, we should fix here for all cases (especially as they
+are all related to memory-mapped register access).
+
+I made a stab updating the C.6(20) wording:
+
+The external effect of a program (see 1.1.3) is defined to include each read and
+update of a volatile or atomic object. The implementation shall not generate any
+memory reads or updates of atomic or volatile objects {whose size is a multiple
+of the size of a machine scalar and is aligned properly for that machine scalar}
+other than those specified by the program. {A similar rule applies for reads or
+writes of an entire Whole_Object_Reference object.} {For other volatile objects,
+an update specified by the program may generate a read before an update, but no
+other updates or reads shall be generated other than those specified by the
+program.}
+
+AARM Ramification: "Specified by the program" includes reads or updates
+implicitly specified by the program. For instance, the default initialization of
+an object without an explicit initialization is considered specified by the
+program. Similarly, reads and updates caused by the (implicit) finalization of
+an object are considered specified by the program.
+
+I'm not sure this covers everything needed. (Note that there is a Bairdian note
+applied to the end, as Steve wondered about volatile controlled types, and that
+led me to wonder about implicit reads and writes in general. They certainly
+ought to be mentioned, if the types involved aren't restricted.)
+
+Steve noted that we could restrict what types are allowed to be Volatile, but
+that isn't the model that was used for Ada 95 and Ada 2012, so such a
+restriction would be incompatible with existing practice.
+
+[Note: I used "machine scalar" rather than "storage element" to account for
+machines on which the storage element is not directly addressable. The U2200 I
+worked on in the late 1990s was like that; while it had byte pointers (for the C
+compiler), they didn't translate into usual machine instructions - they
+implicitly used a read/modify/write set of instructions, as the actual
+addressable unit was a 36-bit word.]
+
+(3) One could argue that C.6(20) is not broken because the Dewar rule says that
+read-before-write is implied in the source code for components that aren't
+directly modifiable by hardware instructions. In that case, there is no problem
+at all, as the only other issue is C.6(22/2), and as Implementation Advice,
+implementations can ignore it when it causes issues. I reject this line of
+thinking both because the IA C.6(22/2) really was intended as a requirement (but
+we thought it was too undefined to write that way) and because it is too
+misleading to programmers to have the text of the Standard say something other
+than the actual rules.
+
+(4) It's unclear to me as to whether a Whole_Object_Reference object should be
+allowed to be Atomic. As Steve notes in his write-up, the read-modify-write
+cycle would not be atomic as a whole, just the read and the write. That's
+misleading to a programmer, which probably would expect an indivisible update.
+Making the whole cycle indivisible would almost certainly require expensive
+locking (especially on a multicore machine). But perhaps it is OK to leave this
+to the individual implementations??
 
 ****************************************************************

Questions? Ask the ACAA Technical Agent