PowerAda Representation Clauses
Representation clauses are supported, although you should only use them when there is a specific need. The support applies to enumeration representation clauses, record representation clauses, address clauses, interrupt entries, and length clauses.
The alignment restrictions on the components of an object within a record that has a record representation clause applied to its type: FLOAT and LONG_FLOAT components must be aligned on a byte boundary, and nested record components must be aligned on a byte boundary. The compiler rejects any representation clause that violates these restrictions. Floating-point types cannot have sizes other than their natural sizes (32 or 64 bits) and are rejected at compile time otherwise. The elements of a packed boolean array occupy a single bit each.
Enumeration Representation Clauses
The compiler supports representation clauses for enumeration types, as described in RM95 section 13.4. The values specified in an enumeration representation clause must be within the bounds of type INTEGER. The specification of a representation clause for an enumeration type causes the generation of a position table that maps each enumeration value to its position (0, 1, ...). The position is used for arrays indexed with the enumeration type and to implement attributes 'POS, 'IMAGE, and 'VALUE, 'WIDTH. See Chapter 9, "Pragma IMAGES" for more information.
- Address clauses with the name of an object are supported (
- Address clauses with the name of a subprogram, package, or task unit (
See RM95 section 13.3(10))are not supported.
If an address clause is used on the name of a subprogram, the compiler detects it and displays a message.
Record Representation Clauses
Pragma PACK allocates components of records and arrays to minimize storage requirements. PowerAda implements packing of records and arrays, provided that they have no components whose size cannot be determined at compile time. For example, pragma
PACK has no effect upon a record that has a component whose size depends upon a discriminant.
If the array elements can fit into 8 bits (that is, if each array element is within the range -128 through 127 or 0 through 255), the compiler will use 8 bits for each packed element. Note that the code required to fetch and sign extend a byte is longer than that to fetch an unsigned byte, so array operations may be more efficient when the array elements are constrained to a range with positive bounds, for example 1 through 10 instead of -4 through 5; thus if you require a large array of bytes, use elements constrained to a range of 0 through 255.
You should only pack records when the record layout is unimportant and the space allocated for the record type must be minimized.
The size specification for a type must allow for enough storage space to accommodate every allowable value in the type. Incorrect size specifications are detected at compile time. If you specify the SIZE attribute for a composite type, all constraints on an object of the type and on its subcomponents must be static. For an unconstrained array type, the index subtypes must also be static.
No sign bit is included in the size calculation for non-negative ranges. Biased representations are not supported; for instance, a range of 100 through 101 requires 7 bits, not 1. Note that if you use a size clause for a discrete type, inefficient code may be generated.
For example, given:
type Nibble is range 0 .. 15; for Nibble'Size use 4;
Each object of type NIBBLE will occupy only 4 bits, and relatively expensive bit-field instructions will be used for operations on each NIBBLE. A single declared object of type NIBBLE will be aligned on a storage-unit boundary, in this case an 8-bit boundary.
For floating-point and access types, a size clause has no effect on the representation. Task types are implemented as access types and are also unaffected by size clauses.
For composite types such as arrays or records, a size clause acts like an implicit pragma
PACK, followed by a check that the resulting size is no greater than the requested size. Note that the composite type will be packed whether or not it is necessary to meet the requested size.
STORAGE_SIZE Attribute for Tasks
A length clause that uses the STORAGE_SIZE attribute for a task type specifies the number of bytes to be reserved for an activation of a task of the type. The compiler creates a stack of at least 32K bytes for each task that has no length clause specified.
SMALL Attribute for Fixed-Point Types
The SMALL attribute is a positive real number that specifies the precision of a fixed-point type. You can specify this attribute by applying a length clause to the first named subtype of a fixed point type. 'SMALL can have any value. Elaboration of a real type defines a set of model numbers. All other real values are defined in terms of model numbers using explicit error bounds. For example, in the following type declaration,
type Fixed is delta 0.25 range -10.0..10.0;
FIXED'SMALL is 0.25. The expression 3.0 = 12 * 0.25 is a model number because it is a multiple of the value for 'SMALL.
The value of the expression of the length clause must not be greater than the delta attribute of the first named subtype. The effect of the length clause is to use this value of 'SMALL for the representation of values of the fixed point-base type. The length clause also affects the amount of storage for objects that have this type.
If a length clause is not used, for model numbers defined by a fixed point constraint, the value of SMALL is defined as the largest power of two that is not greater than the delta of the fixed accuracy definition.
If a length clause is used, the model numbers are multiples of the specified value for SMALL. Using values that are not powers of 2 for 'SMALL results in slower code for multiplication and division operations, because of the extra rounding that the program must do.