!topic LSN on Alignment Attribute and Clauses !key LSN-1071 on Alignment Attribute and Clauses !reference RM9X-13.3(36-40);4.0 !reference 93-3190.a Antoine Bertier 93-10-20 !reference 93-3192.a Tucker Taft 93-10-21 !reference 93-3213.a Antoine Bertier 93-10-28 !from Bob Duff $Date: 94/02/16 16:15:42 $ $Revision: 1.8 $ !discussion The definition of the Alignment attribute in 13.3(36-40) has several problems, which are discussed in several comments from Antoine Bertier and Tucker Taft. Various Alignment related problems were also discussed at the recent DR/XRG meeting in the UK. This LSN proposes a solution to the problems. We plan to replace 13.3(36-40) with the following: Language Design Principles: By default, the Alignment of a subtype should reflect the ``natural'' alignment for objects of the subtype on the machine. The Alignment, whether specified or default, should be known at compile time, even though Addresses are generally not known at compile time. (The generated code should never need to check at run time the number of zero bits at the end of an address to determine an alignment). If the implementation allocates an object, the implementation should ensure that the Address and Alignment are consistent with each other. If something outside the implementation allocates an object, the implementation should be allowed to assume that the Address and Alignment are consistent, but should not assume stricter alignments than that. For a subtype or object X: X'Alignment The Address of an object that is allocated under control of the implementation is an integral multiple of the Alignment of the object (that is, the Address modulo the Alignment is zero). The offset of a record component is a multiple of the Alignment of the component. For an object that is not allocated under control of the implementation (that is, one that is imported, that is allocated by a user-defined allocator, whose Address has been specified, or is designated by an access value returned by an instance of Unchecked_Conversion), the implementation may assume that the Address is an integral multiple of its Alignment; program execution is erroneous if this assumption is violated. The implementation shall not assume a stricter alignment. The value of this attribute is of type universal_integer. The Alignment of a subtype is positive. The Alignment of an object is non-negative; zero means that the object is not necessarily aligned on a storage element boundary. [We might want to make Alignment a type-related attribute (rather than a subtype-specific one) when applied to subtypes. This simplifies certain things. For example, type conversion is allowed between general access types if their designated subtypes statically match -- it would be bad if their Alignments did not match. We also need to cover Unchecked_Conversion between access types.] Alignment is specifiable for (first?) subtypes and stand-alone objects. For an Alignment clause, the expression shall be static, and its value positive. Program execution is erroneous if an Address clause is given that conflicts with the Alignment; the user has to either give an Alignment clause, or else know what Alignment the implementation will choose by default. A component_clause, Component_Size clause, or a pragma Pack can override a specified Alignment, unless the component is aliased, or is of a by-reference type. If an Alignment is specified for a composite subtype or object, this Alignment shall be equal to the least common multiple of any specified Alignments of the subcomponent subtypes, or an integer multiple thereof. The recommended level of support for the Alignment attribute for subtypes is: - An implementation should support specified Alignments that are factors and multiples of the number of storage elements per word, subject to the following: - An implementation need not support specified Alignments for combinations of Sizes and Alignments that cannot be easily loaded and stored by available machine instructions. - An implementation need not support specified Alignments that are greater than the maximum Alignment the implementation ever returns by default. The recommended level of support for the Alignment attribute for objects is: - Same as above, for subtypes, but in addition: - For stand-alone library-level objects of statically constrained subtypes, the implementation should support all alignments supported by the target linker. For example, page alignment is likely to be supported for such objects, but not for subtypes. NOTE The Alignment of a composite object is always equal to the least common multiple of the Alignments of its components, or a multiple thereof. Discussion: For default alignments, this follows from the semantics of Alignment. For specified alignments, it follows from a Legality Rule stated above. [End of proposed replacement for 13.3(36-40).] 13.3(37.b), which mentions interactions between Alignment and other representation items, might be more helpful as a NOTE. In fact, it might be better to have a NOTE summarizing all such interesting interactions. For an object X of subtype S, there are several possibilities for the relationship between X'Alignment and S'Alignment, and the relationship between two subtypes of the same type. - We could specify that X'Alignment = S'Alignment. - We could specify that X'Alignment = S'Alignment only if S'Alignment is specified by the user. This seems like a bad idea -- the semantics of S'Alignment being, say, 4 should be the same whether the 4 was chosen by the user or by the implementation. - If "subtype S2 is S1 ...;", we could specify that S2'Alignment = S1'Alignment if there is no constraint, but leave it implementation-defined if there is a constraint. - We could allow complete implementation freedom in cases where no Alignment clauses are given. This seems like a bad idea, because it detracts from the semantics of subtype Alignments -- if X'Alignment need not equal S'Alignment, then what does S'Alignment tell you? - Presumably, X'Alignment will be different from S'Alignment when X'Alignment is specified, or when X is a component, and its representation has been specified with a component_clause, Component_Size clause, or a pragma Pack. - It is not clear what X'Alignment should be when X'Address is meaningless. For example, suppose X is stored in a register. This is not a particularly important issue; we could safely leave it unspecified. - We could specify that X.all'Alignment is always equal to the designated subtype's Alignment. It might be a good idea to rearrange the order of the attributes in this section, so that Address and Alignment are together, since they are so closely related. Size and Alignment are the subtype-specific attributes, and so should also go together. Much of the following rationale and discussion material should be put in the AARM. Most objects are allocated by the implementation; for these, the implementation obeys the Alignment. The implementation is of course allowed to make an object *more* aligned than it's Alignment requires -- the object might just happen to land at an address that's a multiple of 4096. For formal parameters, the implementation might want to force an Alignment stricter than the parameter's subtype. For example, on some systems, it is a convention to always align parameters to 4 storage elements. Hence, one might initially assume that the implementation could evilly make all Alignments 1 by default, even though integers, say, are normally aligned on a 4-storage-element boundary. However, the implementation cannot get away with that -- if the Alignment is 1, the generated code cannot assume an Alignment of 4, at least not for objects allocated outside the control of the implementation. Of course implementations can assume anything they can prove, but typically an implementation will be unable to prove much about the alignment of, say, an imported object. Furthermore, the information about where an address "came from" can be lost to the compiler due to separate compilation. The Alignment of a subtype is never 0, because it doesn't make sense to say that the natural alignment of a subtype is 0. If the machine has no particular natural alignments, then all subtype Alignments will probably be 1 by default. For objects, it is illegal to specify an Alignment of 0; that wouldn't make sense, because it doesn't require the implementation to do anything. Furthermore, there is an implicit assumption in Ada that objects allocated outside the implementation are addressable. On the other hand, it is possible for an Alignment query to return 0 in some cases: for example, the Alignment of a component of a packed record might be 0. It is an error for an Address clause to disobey the object's Alignment. The error cannot be detected at compile time, in general, because the Address is not necessarily known at compile time (and is almost certainly not static). We do not require a run-time check, since efficiency seems paramount here, and Address clauses are treading on thin ice anyway. Hence, this misuse of Address clauses is just like any other misuse of Address clauses -- it's erroneous. A type extension can have a stricter Alignment than its parent. This can happen, for example, if the Alignment of the parent is 4, but the extension contains a component with Alignment 8. The Alignment of a class-wide type or object will have to be the maximum possible Alignment of any extension. The recommended level of support for the Alignment attribute is intended to reflect a minimum useful set of capabilities. An implementation can assume that all Alignments are multiples of each other -- 1, 2, 4, and 8 might be the only supported Alignments for subtypes. An Alignment of 3 or 6 is unlikely to be useful. For objects that can be allocated statically, the we recommend that the implementation support larger alignments, such as 4096. We do not recommend such large alignments for subtypes, because the maximum subtype alignment will also have to be used as the alignment of stack frames, heap objects, and class-wide objects. Similarly, we do not recommend such large alignments for stack-allocated objects. If the maximum default Alignment is 8 (say, Long_Float'Alignment = 8), then the implementation can refuse to accept stricter alignments for subtypes. This simplifies the generated code, since the compiler can align the stack and class-wide types to this maximum without a substantial waste of space. Note that the recommended level of support takes into account interactions between Size and Alignment. For example, on a 32-bit machine with 8-bit storage elements, where load and store instructions have to be aligned according to the size of the thing being loaded or stored, the implementation might accept an Alignment of 1 if the Size is 8, but might reject an Alignment of 1 if the Size is 32. One a machine where unaligned loads and stores are merely inefficient, we would expect an Alignment of 1 to be supported for any Size.