![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Ada 83 LRM Appendix F: Implementation-Dependent Characteristics This chapter provides information as required by the Ada 83 LRM Appendix F. The implementation-dependent characteristics of Rational Apex are described in the following sections:
- Pragmas
- Attributes
- Packages Standard and System
- Representation Clauses
- Implementation-Generated Names
- Address Clauses (LRM 13.5)
- Unchecked Programming
- Input/Output Packages
- Parameter Passing
- Other Implementation-Dependent Features
Pragmas
- General notes about pragma error handling
- A table of implementation dependencies in the predefined pragmas from Ada 83 LRM Annex B
- A table of implementation-defined pragmas
- Detailed descriptions of each of the implementation-defined pragmas
Error Handling for Pragmas
A pragma whose existence, placement, or arguments do not correspond to those allowed is ignored, by default, by the compiler and the runtime system. This means that a warning is generated if the compiler detects such an error, but the error does not prevent the compilation from completing successfully.
However, several Apex context switches allow you to specify whether to treat certain classes of invalid pragmas as errors that prevent successful compilation rather than as warnings. The following switches are discussed in greater detail in the Ada Runtime Guide:
- REJECT_BAD_LRM_PRAGMAS —— Affects the handling of illegal LRM-defined pragmas
- REJECT_BAD_RATIONAL_PRAGMAS —— Affects the handling of illegal Rational implementation-defined pragmas
- REJECT_UNDEFINED_PRAGMAS —— Affects the handling of pragmas defined in neither the LRM nor in Appendix F
If more than one of the same pragma is specified where it is not appropriate to do so (for example, two pragma Mains on the same unit), the first one is used and the others generate warnings at compile time.
References
Pragma warnings, LRM 2.8(9), 2.8(11).
Predefined Pragmas
For each pragma defined in Annex B of the Ada 83 LRM, Table 20 describes the extent to which Rational Ada supports it.
Implementation-Defined Pragmas
Table 21 summarizes all implementation-defined pragmas in Apex. Each pragma is described in more detail in the following subsections.
String-Valued Arguments to Pragmas
Many of the implementation-defined pragmas have arguments described as manifest string-valued expressions. These expressions are of type Standard.String and must be manifest to the compiler, that is, computable at compile time. For this purpose, a manifest expression is a semantically valid expression comprised only of string literals, character literals, predefined catenation operators, and references to constants of type Standard.String whose initial values are manifest.
Pragma Api
Designates a compilation unit as belonging to the user-visible portion of an API. The syntax is:
pragma API (api_name
);
Arguments
- Api_Name: An identifier obeying Ada syntax rules that names the API.
Usage
Pragma Api must appear at the end of a compilation unit.
Pragma Assert
Raises an exception if a specified Boolean expression evaluates to False at run time. The syntax is:
pragma ASSERT ([PREDICATE =>]boolean_expression
);
Arguments
- Predicate: The Boolean expression to be evaluated at run time.
Usage
When pragma Assert is encountered at run time, the Boolean expression is evaluated. If the result is False, the exception System.Assertion_Error is raised; if the result is True, no action is taken.
This pragma can appear anywhere that a declaration or statement is allowed.
Pragma Calling_Convention
Pragma Calling_Convention is always used in conjunction with either a pragma Import or a pragma Export. The functionality described in this section applies to imported C/C++ routines and exported Ada routines.
Pragmas Import and Export tell the compiler that a certain subprogram is imported from or exported to another language. Pragma Calling_Convention gives additional instructions to the compiler about specific calling conventions to be used. This affects the code generated by the compiler for the subprogram call (if imported) or for the subprogram prologue and epilog (when exported). The syntax is:
pragma Calling_Convention( [Entity =>]local_name
[,attribute1
=>value1
,] [,attribute2
=>value2
,] ...)
Note that the first argument of a pragma Calling_Convention (the "Entity" argument) always names a subprogram which is also referenced by a pragma Import or Export. The other arguments of pragma Calling_Convention (which must be named) depend on whether the pragma applies to an imported or an exported subprogram.
Arguments/Attributes
- Floating_Point_Status_Preserve => True | False: Tells the compiler whether to preserve (that is, save and restore) the floating point status register upon entry/exit of the subprogram body. Note that this is the only attribute that can be applied to both imported and exported routines.
True Save current the floating-point control state.
Establish floating-point control state for C
(from external __FP_CONTROL_FOR_C)
Make the CALL
Restore floating point state
False CALL [Default]
True Save the floating-point state in prologue
Re-establish floating-point control state for Ada
(from external __FP_CONTROL_FOR_ADA). Restore floating point in epilogue
False Nothing [Default]
The global variables __FP_CONTROL_FOR_ADA and __FP_CONTROL_FOR_C are initialized by the Ada runtime system to the value of the FLOATING_POINT_CONTROL and C_FLOATING_POINT_CONTROL fields of the user's configuration table, respectively.
The expected default IEEE floating-point behavior may differ between the Ada and C environments, so that the FP control bits in the status (or control) register need to be modified when making the transition for Ada to C, or vice versa, and then restored upon return.
For historical reasons, the attribute name is a slight misnomer. The first implementation was for a target where the floating-point control bits were in the floating-point STATUS register, and only specified that the status register should be PRESERVED (saved/restored) across the language boundary (another mechanism was used to establish the correct FP control bits in the foreign environment).
Note that Floating_Point_Status_Preserve only affects the floating point status (control) register, and not any other floating-point registers. Other FP registers should be saved/restored according to the normal calling conventions.
- Stack_Limit => None | Defeated | Call_Runtime: Tells the compiler how to initialize the stack limit upon entering the subprogram.
If Ada code is to be entered from a C environment, it is necessary that all the Ada code reachable from C have storage (stack limit) checks suppressed, or that a valid stack limit be establish upon entry to the Ada code. If Stack_Limit => None is used, it is assumed that storage checks have been suppressed on all Ada code reachable from this routine. Typically, this means the routine should be a leaf, or have a limited, well-defined, call graph. Stack_Limit => Defeated, sets the stack_limit to a maximal value. This effectively disables storage checks without actually suppresses. Stack_Limit => Call_Runtime is the default. Upon entry to the interfaced routine, the stack limit re-loaded with the correct value by means of a special call to the Ada runtime.
- Abort_Deferred => True | False: Tells the compiler whether to defer aborts when the subprogram is called.
True ts_abort_defer
CALL
ts_abort_restore
False call [Default]
The middle pass generates the calls to ts_defer_abort and ts_undefer_abort immediately before and after the call to the imported subprogram.
An exception handler needs to be wrapped around the call to make sure aborts get undeferred properly. Note that the C routine we are calling could call back into Ada which could then raise an exception.
Usage
Use pragma Calling_Convention to enable the running of several different IEEE floating point models within the same program. Using pragma Calling_Convention, C/C++ code using a floating point model that includes NaNs (Not-a-Number) and Infs (Infinity), can be used with Apex Ada.
To enable this facility, you must add pragma Calling_Convention after the pragma Import line where you declare the C++ procedure in Ada.
pragma Import (C, <subprogram>); pragma Calling_Convention (<subprogram>, Floating_Point_Status_Preserve => True);
This combination tells the compiler to load the floating point status register from the C_FLOATING_POINT_CONTROL field of the user configuration table before calling the C++ routine. After the C++ code returns, the value of the FLOATING_POINT_CONTROL field of the configuration table is restored to the floating point status register.
Additional information on this pragma can be found in pragma Calling_Convention.
Examples
The following code contains examples of pragma Calling_Convention for both imported and exported subprograms.
with System; package Ex is -- I. Example Imported subprograms: function Write (Fd : Integer; Buffer : System.Address; Size : Integer) return Integer; -- Nothing special do the default stuff. function Malloc (Size : Integer) return System.Address; pragma Import (C, Malloc); pragma Calling_Convention (Malloc, Abort_Deferred => True); -- If the application supports abort this call must be protected. procedure Graph; pragma Import (C, Graph); pragma Calling_Convention (Graph, Floating_Point_State_Preserve => True); -- This procedure uses floating-point. -- The Import pragma indicates that calling convention is C so the -- floating-point unit must be initialized correctly for a C function -- The C function may do other damage to the floating-point state so -- the floating-point state must be saved before making a call to -- graph and restored afterwards -- -- The program that uses graph will not be using aborts or ATC so -- the overhead required for abort deferral is not required
-- II. Example Exported subprograms: procedure Normal_Ada_Procedure; pragma Export (Normal_Ada_Procedure, C); pragma Calling_Convention (Normal_Ada_Procedure, Stack_Limit => Call_Runtime); -- Default case. This procedure is called from C but it is assumed that -- it is on the thread of an ada task. The runtime is called to -- initialize the stack limit.
procedure Normal_Ada_Float_Procedure; pragma Export (Normal_Ada_Float_Procedure, C); pragma Calling_Convention (Normal_Ada_Float_Procedure, Stack_Limit => Call_Runtime, Floating_Point_State_Preserve => True); -- Normal procedure that is going to do floating-point. -- Save the C floating-point state and initialize correctly for ada. -- Restore C floating-point state before returning.
procedure No_Tasking_Procedure; pragma Export (No_Tasking_Procedure, C); pragma Calling_Convention (No_Tasking_Procedure, Stack_Limit =>Defeated); -- This procedure is called from C but from a thread that does not -- contain an ada task. The stack limit will be loaded with 0 -- (stack_limit'max) so that stack limit checking code will not generate -- exceptions.
procedure Low_Level_Ada_Procedure; pragma Suppress (Storage_Check, On => Low_Level_Ada_Procedure); pragma Export (Low_Level_Ada_Procedure, C); pragma Calling_Convention (Low_Level_Ada_Procedure, Stack_Limit => None); -- This procedure should not initialize the stack limit register -- Stack limit checking has been disabled. -- The floating-point must not be touched. end Ex;Pragma Collection_Policy
Controls memory allocation for the collection designated by an access type. The syntax is:
pragma COLLECTION_POLICY (ACCESS_TYPE => access_type, INITIAL_SIZE => integer_expression [, EXTENSIBLE => boolean_expression] [, EXTENSION_SIZE => integer_expression]);
Arguments
- Access_Type: The access type on which to perform storage management.
- Initial_Size: The size in storage units of the initial collection created for an access type. A negative value is treated as zero. The default value is zero; this default can be changed using pragma Main.
- Extensible: Specifies whether the collection can be extended. If True, sets the extension size to the default or specified value of Extension_Size; otherwise, Extension_Size is ignored. The default value is True.
- Extension_Size: The minimum number of storage units by which the collection will be extended, when needed, if it is extensible. A negative value is treated as 0. The default value is 2,048 bytes. A default extension size for all collections can be set using pragma Main.
Usage
Pragma Collection_Policy must appear in the same declarative region as the access type to which it applies, after the access type's declaration and before any forcing occurrence of the access type. If the access type is a private type, the pragma must appear in the private part after the complete access-type declaration. If the pragma appears outside the specified areas, it is ignored.
For a description and example of the pragma's application, see "Managing Storage for Access Types" in the Ada Runtime Guide.
Notes
- The arguments must be specified using named association.
- Only one Collection_Policy pragma is allowed per access type. If more than one is specified, the first is applied and the rest are ignored.
- When an access type has an associated 'Storage_Size clause, any Collection_Policy pragma for that access type is ignored. This occurs because a declaration of the form:
for X'STORAGE_SIZE usesize
;
is functionally equivalent to:
pragma COLLECTION_POLICY (ACCESS_TYPE => X, INITIAL_SIZE =>size
, EXTENSIBLE => FALSE);
- If Initial_Size is nonpositive and Extensible is False, attempting to execute an allocator of the access type raises the Storage_Error exception.
References
- Access type, LRM 3.8
- Allocator, LRM 4.8
- Collection, LRM 3.8
- Forcing occurrence, LRM 13.1(6)
- Storage_Error, LRM 11.1
- Storage_Size, LRM 13.7.2
Pragma Export_Elaboration_Procedure
Defines a global symbolic name for the elaboration procedure of a given compilation unit. The syntax is:
pragma EXPORT_ELABORATION_PROCEDURE ([EXTERNAL =>] "external_name");
Parameters
- EXTERNAL: The global symbolic name associated with the elaboration procedure. EXTERNAL is a string literal.
Usage
Use this pragma to reference the elaboration procedure of an Ada module that is not otherwise elaborated. This exceptional case occurs when the module is not in the closure of the main program, or when the main program was not written in Ada.
Warning: Do not use this pragma unless you thoroughly understand the elaboration, runtime, and storage-model considerations.
Notes
- This pragma must appear immediately following the compilation unit to which it refers.
References
Pragmas Export_Function, Export_Object, and Export_Procedure
Indicates that an Ada function, procedure, constant, or variable will be called or referenced by code written in another language; also specifies the external name for the exported entity used at link time. The syntax is:
pragma EXPORT_FUNCTION ([INTERNAL =>] internal_name [, [EXTERNAL =>] external_name] [, [PARAMETER_TYPES =>] parameter_type_list] [, [RESULT_TYPE =>] type_mark] [, [LANGUAGE =>] language_name]);
pragma EXPORT_OBJECT ([INTERNAL =>] internal_name [, [EXTERNAL =>] external_name, [, [LANGUAGE =>] language_name]);
pragma EXPORT_PROCEDURE ([INTERNAL =>] internal_name [, [EXTERNAL =>] external_name] [, [PARAMETER_TYPES =>] parameter_type_list] [, [LANGUAGE =>] language_name]);
Arguments
- Internal: The Ada simple name of the Ada subprogram or object to be exported. For functions, this can also be an operator symbol.
- External: An optional manifest string-valued expression that specifies the global symbol name to be created by the Ada compiler. This name must obey the naming conventions for the host operating system's object-module format, and it might differ from the internal subprogram or object name. If an external name is not specified, the compiler chooses an external name based on the internal name, the language, and the host system. See Usage.
- Parameter_Types: A parenthesized, comma-separated list of type and/or subtype names that describes the parameter-type profile of an exported subprogram. If the subprogram has no parameters, the list can consist of the single word Null. This argument must be provided when the Internal_Name designates more than one overloaded subprogram in the current declarative part or package specification.
- Result_Type: The result-type profile of an exported function. This argument is allowed only for functions, and is required when Parameter_Types are specified for the function.
- Language: The name of the language in which the calling or referencing code is written. The language name must be one of ASM, C, Ada, Fortran, Pascal, or unchecked, Use C when exporting to C++.
Usage
Use these export pragmas when a subprogram or object defined in Ada is to be referenced by code written in a different language (or even by Ada code that is not in the Ada closure of the main program). The code generated for an exported subprogram will compensate for differences between the calling conventions of the foreign language and Ada (if any).
An exported entity can also be referenced directly by Ada code. The pragmas also affect the global name used at link time to designate the subprogram or object. If an External_Name is specified, that name is used; otherwise, the compiler selects a name based on the language and host system, as described in the table below for a subprogram whose internal name is "Sheba".
If the internal subprogram name is overloaded (and more than one of the overloaded subprograms appears in the same declarative part or package specification as the pragma), you must supply enough information for the compiler to determine unambiguously which subprogram to export. This is the purpose of the Parameter_Types argument (and for functions, the Result_Type argument).
Warning: Exporting a subprogram does not export the mechanism used by the compiler to perform elaboration checks. A call from another language to an exported subprogram with an unelaborated body can produce unpredictable results when the subprogram references an object that is itself unelaborated.
Warning: Accesses to Ada objects by non-Ada code are inherently unsafe; the compiler and runtime system cannot guarantee the integrity of such exported objects. It is the developer's responsibility to ensure that the code that accesses an exported object properly interprets and maintains the underlying structure of the object. When exporting constant objects, take special care that non-Ada code does not change the value of the constant.
Notes
- Pragma Export_Object can appear only at the place of a declarative item in a declarative part or package specification; the object to which it applies must have been declared by an earlier declarative item of the same declarative part or package specification. The same rule applies for Export_Function and Export_Procedure, except they might also appear at the end of a compilation unit that is a subprogram specification.
- If pragma External has previously been applied to the exported subprogram or object, pragma External prevails and the export pragma is ignored.
- An exported subprogram or object must be declared in a static scope; that is, it must not be inside any subprogram, task, generic unit, or block statement.
References for Subprograms
- Elaboration of a library unit, LRM 10.5
- Order of elaboration, LRM 3.9
- Overloading, LRM 8.3
- Parameter and result type profile, LRM 6.6
- Interfacing with Other Languages
References for Objects
Pragma External
Indicates that an Ada subprogram will be called by code written in another language. Together with pragma External_Name can be used as an alternative to pragma Export_Function or pragma Export_Procedure. The syntax is:
pragma EXTERNAL (language, internal_name);
Arguments
- Language: The name of the language in which the calling code is written.
- Internal_Name: The Ada simple name of the Ada subprogram to be exported. For functions, this can also be an operator symbol.
Usage
The context, allowed languages, and types of subprograms for pragmaExternal are the same as for pragma Interface, except that a body must be supplied for the subprogram. The code generated for the subprogram will compensate for differences between the calling conventions of the foreign language and Ada (if any).
To specify the global name to use for the subprogram at link time, use pragma External_Name. If no such name is specified, the compiler will select a name in the same way as for pragmas Export_Function and Export_Procedure.
Pragma External_Name
Specifies the external name used at link time for a subprogram or object so it can be referenced from other languages. The syntax is:
pragma EXTERNAL_NAME (internal_name, external_name);
Arguments
- Internal_Name: The Ada simple name of an object or a subprogram to which pragma External is applied.
- External_Name: A manifest string-valued expression that specifies the global symbol name to be created by the Ada compiler.This name must obey the naming conventions for the host operating system's object-module format, and it might differ from the internal subprogram or object name.
Usage
Use pragma External_Name in conjunction with pragma External on a subprogram or by itself on an object. If pragma Export_Object has previously been applied to an object, it prevails and pragma External_Name is ignored.The pragma can appear only at the place of a declarative item in a declarative part of package specification. The external entity to which it applies must have been declared by an earlier declarative item of the same declarative part or package specification.
Pragma Implicit_Code
Arguments
Usage
This pragma is used only for machine code procedures. Refer to Machine Code Insertions for more information.
Pragmas Import_Function, Import_Object, and Import_Procedure
Indicates that an Ada function, procedure, or variable is defined by code written in another language, and specifies the external name by which it is to be referenced at link time. Typically, the subprogram or object is defined using a language other than Ada, although Ada can be used. The syntax is:
pragma IMPORT_FUNCTION ([INTERNAL =>] internal_name [, [EXTERNAL =>] external_name] [, [PARAMETER_TYPES =>] parameter_type_list] [, [RESULT_TYPE =>] type_mark] [, [MECHANISM =>] mechanism_list]);
pragma IMPORT_OBJECT ([INTERNAL =>] internal_name [, [EXTERNAL =>] external_name,
[, [LANGUAGE =>] language_name]);
pragma IMPORT_PROCEDURE ([INTERNAL =>] internal_name [, [EXTERNAL =>] external_name] [, [PARAMETER_TYPES =>] parameter_type_list] [, [MECHANISM =>] mechanism_list]);
Arguments
- Internal: The Ada simple name of the non-Ada subprogram or object to be imported. For functions, this can also be an operator symbol.
- External: An optional manifest string-valued expression that specifies the global symbol name to be created by the Ada compiler. If an external name is not specified, the compiler chooses an external name based on the internal name, the language, and the host system. See Storage_Size, LRM 13.7.2.
- Parameter_Types:A parenthesized, comma-separated list of type and/or subtype names that describes the parameter-type profile of an imported subprogram. See Usage.
- Result_Type: The result-type profile of an imported function. This argument is allowed only for functions, and is required when Parameter_Types are specified for the function. See Notes.
- Mechanism: An optional, parenthesized, comma-separated list of parameter-passing mechanisms for the parameters passed by a subprogram. There must be a one-to-one correspondence between the passed parameters and the mechanisms. The supported mechanisms are:
- Value: The parameter cannot be of a record or array type.
- Reference: The corresponding parameter is passed by reference; that is, its address is passed
If you do not specify mechanisms, the compiler selects a mechanism that depends on the type of the parameter and the language of the subprogram being called. For ASM, UNCHECKED, C, and ADA, scalar and access parameters are passed by value, and other types by reference. For FORTRAN, all parameters are passed by reference. For PASCAL, scalar and access types are passed by value for IN parameters and reference for IN OUT and OUT parameters; other types are passed by reference.
Usage
Use the import pragmas to supply more information about a non-Ada subprogram specified with pragma Interface or a non-Ada object to be referenced by Ada code.
Every subprogram to which Import_Function or Import_Procedure is applied must also have an interface pragma applied, before the import pragma. The import pragma can be omitted if you want to use the compiler's defaults for the external name and parameter passing mechanisms.
If the internal Ada subprogram name is overloaded, you can supply enough information for the compiler to determine unambiguously which subprogram is being imported. Specify the Parameter_Types (and, for functions, the Result_Type) so that the compiler can construct the parameter- and/or result-type profile of the subprogram. If you omit these arguments, the import pragma (and pragma Interface) will apply to all of the overloaded subprograms of the same name in the same declarative part or package specification.
Warning: Accesses to non-Ada objects from Ada code are inherently unsafe; the compiler and runtime system cannot guarantee the integrity of such imported objects. It is the developer's responsibility to ensure that the code that accesses an imported object properly interprets and maintains the underlying structure of the object.
Notes
- Pragma Import_Object can appear only at the place of a declarative item in a declarative part or package specification. The same rule applies for Import_Function and Import_Procedure, except they may also appear at the end of a compilation unit that is a subprogram specification.
- If pragma Interface_Name has previously been applied to the subprogram(s) or object designated by the import pragma, the Interface_Name pragma prevails and the import pragma is ignored.
- An import pragma must not refer to a generic subprogram.
- An imported object must:
- Be a variable (not a constant).
- Be declared in a static scope; that is, it must not be inside any subprogram, task, generic unit, or block statement.
- To assign an imported object a default initial value, use pragma Initialize. See Pragma Initialize.
References for Subprograms
- Interface to other languages, LRM 13.9
- Pragma Interface, LRM 13.9
- Scalar types, LRM 3.3
- Interfacing with Other Languages
References for Objects
Pragma Initialize
Specifies that default initialization be carried out for an imported variable or a variable referenced by an address clause. The syntax is:
pragma INITIALIZE (simple_name);
Arguments
- simple_name: The variable to which default initialization is to be applied.
Usage
When a program imports a variable object or declares a variable with an address clause, the compiler assumes that this variable previously existed. The compiler makes no attempt to assign a default (initial) value to this variable, because the variable might already contain a valid value or might be given an initial value by some other program. By default, the compiler does not perform any implicit initialization on:
- Variables designated by address clauses.
- Imported variable objects; see Pragmas Import_Function, Import_Object, and Import_Procedure, and Pragma Interface_Name.
Pragma Initialize tells the compiler to assign an appropriate default value to the variable —— for example, setting pointers and pointer fields to null, record fields to the initial values present in the record type definition, and discriminants to their proper values. Hence, the variable must not have an explicit initial value.
No additional storage space is allocated because valid variables already exist.
- Have been declared earlier in the same declarative part
- Be an array or record
- Have an associated address clause, or it must have been imported using pragma Import_Object before the occurrence of pragma Initialize
- Not have an explicit initial value
Example
Pragma Initialize can be used to request that pointers be set to Null or that record fields be given some starting value.
References
Pragma Inline_Never
Completely prohibits inlining of a specified subprogram.The syntax is:
pragma Inline_Never (subprogram_name);
Usage
Use this pragma to specify that a subprogram should never be inlined at any optimization level.
Pragma Inline_Only
Specifies that a subprogram should always be inlined,. The syntax is:
pragma Inline_Only (subprogram_name);
Usage
Use this pragma to force the compiler to inline a specified subprogram, even at optimization level 0. Pragma Inline_Only (unlike pragma Inline) generates a hard error when the a call to the specified subprogram cannot be inlined. The current compiler cannot inline subprograms in the following scenarios:
- The subprogram contains nested subprograms.
- The caller and the callee are in sibling subunits.
- The caller is in an ancestor subunit of the callee.
- The caller and the callee are part of a set of mutually recursive routines.
- The callee is not called explicitly (for example, a finalization routine for a controlled type).
Pragma Interface_Name
Allows the specification of link names for subprograms and variables defined in other languages. The syntax is:
pragma INTERFACE_NAME (internal_name, external_name);
Arguments
- Internal_Name: The Ada simple name of an object or a subprogram to which pragma External is applied.
- External_Name: A manifest string-valued expression that specifies the global symbol name to be created by the Ada compiler. This name must obey the naming conventions for the host operating system's object-module format, and, therefore, it may differ from the internal subprogram or object name.
Usage
This pragma can be used as an alternative to pragmas Import_Function and Import_Procedure to specify the external name for an imported subprogram. If you wish to specify parameter mechanisms or distinguish between overloaded subprograms, you must use Import_Function or Import_Procedure instead. Any subprogram to which Interface_Name is applied must also have pragma Interface applied.
The places in which the pragma is legal and the restrictions that apply to it are the same as for the importing pragmas.
Pragma License
Used in an API specification, allows compilation of code referencing the API to proceed only after acquiring a license to do so.
pragma LICENSE ([FEATURE =>] manifest string-valued expression, [, [VERSION =>] unbased floating-point literal ]);
Arguments
- Feature: The name of the feature license required.
- Version: An unbased floating point literal giving the version number of the feature license.
Usage
Pragma License must appear at the end of a compilation unit that is a package declaration, a subprogram declaration, or a generic. Pragma Api must be applied to the same compilation unit and appear before pragma License.
Whenever the compiler encounters pragma License in the closure of a unit it is compiling, it attempts to acquire a license for the feature name and version given in the pragma. If it is unable to do so, the compilation will be aborted. At most one license for the name and version is required for any Apex session.
Example
pragma License ("Acme_Database", 3.0);
Pragma Link_With
Same functionality as pragma Linker_Options.
Pragma Linker_Options
Passes arguments to the target linker. The syntax is:
pragma Linker_Options (manifest_string_expression)
Usage
This pragma can appear in any package specification or declarative part. Its argument is passed as a command line argument to the target linker whenever the unit containing the pragma is in the closure of the main program being linked.
In constructing the target linker command line argument, the Linker_Options argument is first divided into tokens. Tokens are delimited by white-space.
Tokens are then passed to the linker command line. Tokens beginning with "+" and "-" tokens are interpreted as linker switches. Tokens beginning with "/" tokens are interpreted as rooted filenames. If a token begins with "-", "+", or "/", it is left untouched.
If a token begins with neither "-" nor "+" nor "/", then it is assumed to name a file and is prefixed with pathname of the directory containing the Ada unit in which the pragma appears. (This behavior is different from VADS, in which unqualified names are interpreted in the context of the main program being linked).
If a main program's closure contains more than one pragma Linker_Options, their contents will be separated by blanks on the linker command line. The order in which the arguments appear is not defined.
If pragma Linker_Options appears in the implementation of an API, that is, in a unit that also contains pragma Api, its contents are passed to the linker when the API is used in the closure of a main program, not when the API itself is linked.
Pragma Main
Designates an Ada main unit and determines some aspects of its runtime behavior. The syntax is:
pragma MAIN [ ([COLLECTION_INITIAL_SIZE => integer_expression,] [COLLECTION_EXTENSION_SIZE => integer_expression,] [DBG_SUSPEND_DISABLED_FLAG => boolean_expression,] [EXCEPTION_STACK_SIZE => integer_expression,] [FAST_RENDEZVOUS_ENABLED => boolean_expression,] [HEAP_EXTEND => integer_expression,] [HEAP_SIZE => integer_expression,] [IDLE_STACK_SIZE => integer_expression,] [NONBLOCKING_IO => boolean_expression,] [NUMERIC_SIGNAL_ENABLED => boolean_expression,] [POSIX_COMPLIANT => boolean_expression,] [SIGNAL_TASK_STACK_SIZE => integer_expression,] [STACK_SIZE => integer_expression,] [STORAGE_SIGNAL_ENABLED => boolean_expression,] [TASK_PRIORITY_DEFAULT => priority_expression,] [TASK_STACK_SIZE_DEFAULT => integer_expression,] [TASK_STORAGE_SIZE => integer_expression,] [TIME_SLICE => duration_expression,] [TIME_SLICE_PRIORITY => integer_expression,] [TIME_SLICING_ENABLED => boolean_expression,] [WAIT_STACK_SIZE => integer_expression,] [ZERO_STACKS_ENABLED => boolean_expression,] [TRACE_BUFFER_SIZE => integer_expression]);
All expressions must be static; all integer expressions must be nonnegative.
Arguments
- Collection_Extension_Size: An integer expression giving the minimum number of storage units by which an extensible collection will be extended when needed. This value can be overridden for individual access types using pragma Collection_Policy. The default value is zero.
- Collection_Initial_Size: An integer expression giving the default size in storage units of the initial collection that is created for an access type. This value may be overridden for individual access types using pragma Collection_Policy. The default value is zero.
- Dbg_Suspend_Disabled_Flag: Controls how the debugger behaves when a multitasking program takes a breakpoint. If True, only the task taking the breakpoint stops; if False, all tasks stop.
- Exception_Stack_Size: An integer expression giving the number of storage units set aside at the bottom of each tasks's stack for exception unwinding. The default value for this argument is set correctly and it will normally not require modification. Setting this value incorrectly could cause the program to be erroneous.
- Fast_Rendezvous_Enabled: A boolean expression indicating whether the fast rendezvous optimization is to be used. This optimization causes a rendezvous to be executed in the context of the calling task when the accepting task is already waiting. The default value is True; this value is typically set to False only when using Multiprocessor Ada.
- Heap_Extend: An integer expression that specifies the number of storage units by which the heap is to be extended when needed.
- Heap_Size: An integer expression that specifies how much space to allocate for the heap, in storage units, when the main unit begins execution. If this argument is specified, no additional space is allocated to the heap after initialization; requests for more heap space raise Storage_Error.
If not specified, heap space is allocated dynamically as needed until space is exhausted and Storage_Error is raised.
- Idle_Stack_Size: An integer expression giving the size of the stack for the idle task in storage units. The default value for this argument is set correctly and it will normally not require modification. Setting this value incorrectly could cause the program to be erroneous.
- Nonblocking_Io: Specifies whether I/O should block all tasks in the program. If True, only the task performing the I/O blocks; if False, the entire program blocks. For a description of limitations and operation, information about I/O in tasking programs, or for information about using blocking and nonblocking I/O" see "Files and I/O" in the Ada Runtime Guide. The default is False.
- Numeric_Signal_Enabled: Specifies whether the program uses the Unix signal SIGFPE to catch numeric errors. The default is True. If False is specified, the program will no longer conform to Ada semantics for floating point operations, but this can be useful when calling code written in other languages that use or ignore SIGFPE.
- Posix_Compliant: Specifies whether certain behavior described by the IEEE Portable Operating System Interface (POSIX) is required. If True, the following operational characteristics of programs compiled and linked under Apex are affected:
- The program can control only those UNIX signals explicitly allowed by POSIX.5 3.3.3.1 (those not "reserved for the Ada implementation").
- The program cannot install an interrupt-entry task to handle UNIX signals that the runtime system uses, nor can it install both an interrupt-entry task and an Ada procedural signal handler for the same signal (POSIX.5 3.3.2.1(963)).
- The default values for the Form-parameter fields in the Ada-predefined I/O packages are the POSIX.5 values rather than the Apex values. For information about field defaults, see the Files and I/O" chapter in the Ada Runtime Guide.
- Signal_Stack_Task_Size: An integer expression that specifies the size of the signal stack in storage units. The Rational Ada runtime system creates a signal stack for each task entry that is bound to an interrupt. The default value for this argument is set correctly and it will normally not require modification. Setting this value incorrectly could cause the program to be erroneous.
- Stack_Size: An integer expression that specifies the size of the main task stack in storage units. This quantity excludes the space at the bottom of the stack for exception handling, which can be expressed with the Exception_Stack_Size argument of this pragma.
- Storage_Signal_Enabled: Controls whether the runtime system catches segmentation violations (SIGSEGV) and turns them into Storage_Error. The default is False.
- Task_Priority_Default: An expression of type System.Priority that specifies the priority for any task without a pragma Priority. The default value is 0.
Note: This argument is only valid for Ada83. The default value of 0 is Ada83-specific. For a description of Task_Priority_Default for Ada95, see the Annex M section on Task_Priority_Default.
- Task_Stack_Size_Default: An integer expression that specifies the size, in storage units, of the stack for any task without a 'Storage_Size representation clause.
- Task_Storage_Size: Specifies the size in bytes of the area set aside in the task control block for user storage. The VADSexec services Allocate_Task_Storage and Get_Task_Storage manage this area in the task control block. The Ada95 task attributes as described in the system's programming annex and the rts_vads_exec subsystem manage this area of the task control block.
- Time_Slice: A nonnegative expression of type Standard_Duration that determines the quantity of time to allocate to an executing task. By default, or if the value is zero, no time slicing is used. This has an effect only in conjunction with preemptive scheduling; otherwise, it is ignored.
- Time_Slice_Priority: If time slicing is enabled, it applies only to tasks whose priority is less than or equal to this value.
- Time_Slicing_Enabled: Controls whether time slicing occurs. The default is True.
- Trace_Buffer_Size: The size in trace_buffer records (events) of the trace buffer used with the Apex Tasking Logic Analyzer. These records vary in size from 8 words to 14 words, depending on the Apex version and target. Package v_i_trace.1.ada contains the definition.
- Wait_Stack_Size: In a fast rendezvous, the accepting task saves its register context, switches to a wait stack, and waits. Eventually, the calling task restores and uses the accepting task's saved register context. Wait_Stack_Size is an integer expression that specifies how much stack is needed when the accepting task switches from its normal task stack to the special wait stack it uses to call a kernel service to block itself. This value is only used if Fast_Rendezvous_Enabled is True. Setting the Wait_Stack_Size to zero also disables the fast rendezvous optimization. The default value for this argument is set correctly and it will normally not require modification. Setting this value incorrectly could cause the program to be erroneous.
- Zero_Stacks_Enabled: At program startup, all the memory to be used for task stacks is initialized. The command name uses "zero", though memory is actually set to the fill value for the target. With the following exceptions, the value is 0. For LynxOS, the fill value is 16#FF#, and for VxWorks it is 16#EE#. If tasks are dynamically terminated and recreated, the stack area for recreated tasks is not initialized. This can lead to erroneous stack usage information displayed by the debugger's "lt use" command. Zero_Stacks_Enabled is set to True to guarantee that stacks of dynamically created tasks are initialized. Since it takes extra time to initialize the stack area, ZERO_STACKS_ENABLED is normally only set to True when used in conjunction with "lt use" for dynamically created tasks.
Usage
Use pragma Main after the end of the unit body of a parameterless library-unit subprogram to designate it as a main program. If the subprogram is a function, the type it returns must be Standard.Integer (the return value is passed to Unix as the exit status of the program). In Ada 95, the subprogram must not be a child unit or a rename.
Pragma Main can have two effects. It:
- Causes the unit to be linked automatically if it is in a directory or view for which you have requested linking. Main units without pragma Main are not linked unless explicitly requested.
- Permanently specifies the various properties and sizes given in its arguments.
Example
procedure Show_Main is begin Do_Something; end Show_Main; pragma Main (Stack_Size => 10*1024); --Change to 10 Kb
References
- Library unit, LRM 10.1
- Main program, LRM 10.1
- For information about heap and stack allocation, see the "Memory Management" chapter in the Ada Runtime Guide.
Pragma Must_Be_An_Entry
Specifies that the actual subprogram supplied in any instantiation for the given generic formal procedure must be a task entry. The syntax is:
pragma MUST_BE_AN_ENTRY (generic_formal_subprogram);
Arguments
- generic_formal_subprogram: The name of a formal procedure appearing in the same generic formal part as the pragma.
Usage
This pragma is used when a generic depends upon one or more of its formal subprograms being implemented as a task entry.
Pragma Must_Be_Constrained
Indicates whether formal private and limited private types within a generic formal part must be constrained or have default values. The syntax is:
pragma MUST_BE_CONSTRAINED (condition_list);
Arguments
- condition_list: A comma-separated list of conditions that specifies a set of types and whether each set must be constrained or have default discriminant values. Each element of the condition list has the format:
- condition: Can be either YES or NO. If omitted, the default is YES. Determines the setting for all types in the following type ID list.
- type_id_list: Is a comma-separated list of formal private or limited private types. These types must be defined in the same formal part as the pragma.
Usage
Use pragma Must_Be_Constrained to specify how you intend to use the formal parameters in a generic specification.
Each condition controls the types in the following type ID list, until the next occurrence of a condition. Consider this example:
pragma Must_Be_Constrained (Type_1, NO=>Type_2, Type_3, YES=>Type_4, Type_5);
At the beginning of the list, a condition is not specified, so YES is assumed; hence, Type_1 is constrained. NO controls the following type ID list, which includes Type_2 and Type_3; hence, they are unconstrained. YES controls the remaining type ID list, so Type_4 and Type_5 are constrained.
Notes
If the condition NO is specified, any use in the body that requires a constrained type will generate a semantic error. If YES is specified, any instantiations that contain actual parameters that require constrained types will generate semantic errors if the actual parameters are not constrained and have no default discriminant values.
References
- Constrained private type, LRM 7.4.2
- Generic formal type, LRM 12
- Matching rules for formal private types, LRM 12.3.2
- Limited private type, LRM 7.4.4
- Private type as generic formal type, LRM 12.1.2
Pragma Not_Elaborated
Suppresses the generation of elaboration code and issues warnings if elaboration code is required. Also causes elaboration checks to be suppressed for all subprograms declared in the package in which it appears. The syntax is:
pragma NOT_ELABORATED;
Arguments
Usage
Use this pragma when a package will not be elaborated because it is referenced from non-Ada code and it is not referenced from within the Ada closure of the main program. If the code generator produces a warning that elaboration code was generated and the unit is not in the Ada closure of the main program, the elaboration code won't be called and the package is unlikely to work properly.
This pragma must appear immediately within a nongeneric library package specification. The pragma is implicitly applied to the package body and its package subunits.
Pragma Restrictions
Arguments
Usage
Used only as a configuration pragme. Please refer to Configuration Pragmas for more information.
Pragma Signal_Handler
Installs an Ada procedure as a UNIX signal handler. The syntax is:
pragma SIGNAL_HANDLER (NAME => simple_name, SIGNAL => integer_expression);
Arguments
- Name: The simple Ada name of the signal-handling procedure.
- Signal: An integer expression (not necessarily static) specifying the UNIX signal number to be handled by the specified procedure.
Usage
Elaboration of the pragma has the effect of installing the specified procedure as a signal handler for the given signal. Subsequent occurrences of the specified signal will cause the specified procedure to be invoked.
The pragma and the procedure body must occur in the same declarative part, with the pragma following the procedure body. This prevents the installation of a procedure whose body has not yet been elaborated.
For information about Ada procedural signal handlers and details on the construction of the procedure, see the "Interrupt Handlers" chapter in the Ada Runtime Guide.
References
Pragma Suppress_All
Suppresses all permitted runtime checks. The syntax is:
pragma SUPPRESS_ALL;
Arguments
Usage
Use pragma Suppress_All to create the same effect as all of the following:
pragmaSuppress (Access_Check); pragma Suppress (Discriminant_Check); pragma Suppress (Division_Check); pragma Suppress (Elaboration_Check); pragma Suppress (Index_Check); pragma Suppress (Length_Check); pragma Suppress (Overflow_Check); pragma Suppress (Storage_Check); pragma Suppress (Range_Check);
Notes
- Pragma Suppress_All has no effect in a package specification.
- The pragma must appear immediately within a declarative part.
- Pragma Suppress_All (Ada83) is also equivalent to pragma Suppress (All_Checks); the latter is the preferred usage.
Note: In the future, Suppress (All_Checks) will be accepted in both Ada 95 and Ada83 package specifications, and this is the preferred form of the pragma
References
- Suppressing checks, LRM 11.7
Pragma Suppress_Elaboration_Checks
Suppresses all elaboration checks in a given compilation unit. The syntax is:
pragma Suppress_Elaboration_Checks;
Arguments
Usage
Use pragma Suppress_Elaboration_Checks at the end of any compilation unit to suppress elaboration checks for all subprograms in that unit. This is equivalent to placing a named pragma Suppress (Elaboration_Check) in each subprogram in the unit. For example;
package Watchdog is procedure Spot; procedure Bruno; end Watchdog; pragma Suppress_Elaboration_Checks;
package Watchdog is procedure Spot; procedrue Bruno; pragma Suppress (Elaboration_Check, On => Spot); pragma Suppress (Elaboration_Check, On => Bruno); end Watchdog;
References
- Suppressing checks, LRM 11.7
AttributesTable 22 summarizes all implementation-defined attributes in Rational Ada. Each attribute is described in more detail in the following subsections.
Compiler_Key
For a prefix N that denotes the name of an entity, N'Compiler_Key yields the full pathname of the compiler key, which indicates the compiler that was used to generate code for the unit containing the definition of N.
The entity named by N can be a program unit (package, subprogram, task, or generic), an object (variable, constant, named number, or parameter), a type or subtype (but not an incomplete type), or an exception.
The value returned by this attribute is of type String; for example, "/apex_home/keys/ada_rational_rs6k_aix".
This attribute can be used for runtime detection of incompatibilities in data representation. It typically is used when passing messages over a network to ensure that the reader and writer agree on how to interpret the message. See also Compiler_Version.
Compiler_Version
For a prefix N that denotes the name of an entity, N'Compiler_Version yields the version of the compiler that was used to generate code for the unit containing the definition of N.
The entity named by N can be a program unit (package, subprogram, task, or generic), an object (variable, constant, named number, or parameter), a type or subtype (but not an incomplete type), or an exception.
The value returned by this attribute is of type string; for example, "1.6.1A".
This attribute can be used for run-time detection of incompatibilities in data representation. It typically is used when passing messages over a network to ensure that the reader and writer agree on how to interpret the message. See also Compiler_Key.
Dope_Address
For an object or type A, A'Dope_Address yields the address of the dope vector that describes A. The value is of type System.Address. If the object or type denoted by A has no dope vector, this value is System.Null_Address. Non-array objects and types are allowed with this attribute so that they may be applied to formal types inside a generic, where the nature of the actual type is not known statically.
This attribute can be used in conjunction with 'Dope_Size for retrieving information about the object, as when reconstructing the array when passing messages over a network. For information about dope vectors, see the Ada Runtime Guide.
Dope_Size
For an object or type A, A'Dope_Size yields the size in bits of the dope vector. The value is of type Universal_Integer. A value of zero is returned if the type to which A belongs is not an array type.
A positive value is always returned, whether or not the object denoted by A has a dope vector. Use 'Dope_Address to determine whether the dope vector actually exists.
This attribute can be used for retrieving information about the object, as when reconstructing the array when passing messages over a network. For information about dope vectors, see the Ada Runtime Guide.
Entry_Number
For a prefix E that denotes a task entry or generic formal subprogram, E'Entry_Number yields a Universal_Integer value that uniquely identifies the entity denoted by E.
Homogeneous
For a prefix T that denotes an access type, T'Homogeneous yields a Boolean value. The value returned is True if all objects in the collection will always have the same constraints. The converse, however, is not true.
Applying this attribute to a type other than an access type is a semantic error. It is most useful when applied to a generic formal access type.
Note that the attribute is a property of the type, not of the subtype. Thus, for any access type T, T'Homogeneous yields the same value as T'Base'Homogeneous.
type T1 is access String (1..10);-- T1'Homogeneous=True type T2 is access String; -- T2'Homogeneous=False type T3 is new T2 (1 .. 10); -- T3'Homogeneous=False type T4 is new T1; -- T4'Homogeneous=True
At the implementation level, the attribute indicates whether constraint information is stored with allocated objects.
Type_Key
For a prefix T denoting a type declared in a library level package specification, T'Type_Key yields a string that uniquely identifies type T. This attribute typically is used when passing messages of a given type over a network to ensure that the reader and writer agree on the type to use when interpreting the message.
Attributes of Numeric Types
This section lists the values returned by attributes that apply to integer types, floating-point types, and the fixed-point type Duration.
Integer Types
The attributes that apply to integer types —— namely, 'First, 'Last, and 'Size —— yield the values shown in Table 23 for the predefined base types:
It is also possible to include a declaration of Tiny_Integer in package Standard. The inclusion of Tiny_Integer provides upward compatibility with the VADS compiler. This can be accomplished during the Apex installation process. If it has been included, the following line is included in the standard_1.ada file in Ada83 views of lrm.ss:
subtype Tiny_Integer is Short_Short_Integer;
The default is that this declaration is not included in package Standard.
If you want Tiny_Integer and it wasn't included during installation, then create a new view of lrm.ss. After deleting all Diana trees from the view (typically by cleaning down to archived), compile the view using the following command:
% rada -flag tiny_integer <your_new_view>.wrk
Floating-Point Types
The attributes that apply to floating-point types yield the following values for the predefined base type Float:
Type Duration
The attributes that apply to fixed-point types yield the following values for the predefined type Duration:
Packages Standard and SystemThis section contains the specifications for packages Standard and System.
Package System (LRM 13.7)
Full listings of package System and its language-defined children can be found in the following location.
$APEX_BASE/ada/lrm.ss/${APEX_ARCH_OS}.ada83.$APEX_PROD_VERSION.relThese meta names are set when Apex is invoked. Their values can be displayed using Tools > Session > Environment command.
Cross/Embedded Apex Releases:
The location of these packages for the Apex cross products is dependent on the target processor and runtime variant. Use Table 27 to locate the desired Apex cross location. APEX_BASE and APEX_PROD_VERSION are set when Apex is invoked. Their values can be displayed using Tools > Session > Environment command.
Package Standard (LRM Annex C)
A listing of package Standard is provided for each of the Apex platforms and can be found in the following location.
$APEX_BASE/ada/lrm.ss/${APEX_ARCH_OS}.ada83.$APEX_PROD_VERSION.relThese meta names are set when Apex is invoked. Their values can be displayed using Tools > Session > Environment command.
The location of this package for the Apex cross products is dependent on the target processor and runtime variant. Use Table 28 to locate the desired Apex cross location. APEX_BASE and APEX_PROD_VERSION are set when Apex is invoked. Their values can be displayed using Tools > Session > Environment command.
Table 29 shows the sizes of predefined integer and floating-point types:
Table 29 Sizes of Predefined Numeric Types
Ada type name Size
Short_Integer 16 bits
Integer 32 bits
Long_Integer 64 bits
Float 32 bits
Long_Float 64 bits
Fixed-point types are implemented using 32 bits.
Floating-point types are implemented according to the IEEE Standard for Binary Floating-Point Arithmetic (ANSI/IEEE Std. 754-1985).
Standard.Duration is a 32-bit fixed-point type with a delta of 2 -4.
Representation ClausesThis section discusses limitations on representation clauses in the following categories:
- Alignment of Types and Objects
- Representation-Clause Error Handling
- Length Clauses
- Enumeration Representation Clauses (LRM 13.3)
- Record Representation Clauses (LRM 13.4)
- Change of Representation (LRM 13.6)
Note that in general, a compiler must either accept a representation clause and comply with it, or reject it if it finds that it cannot implement it. When we say that a representation clause is "allowed" or "supported", we mean that it is accepted by the compiler, and therefore, that the generated code complies with that clause.
For related information, about sizes of objects, see the Ada Runtime Guide.
Alignment of Types and Objects
Note: In this discussion, the alignment is expressed in bytes.
In Ada 83, the only mechanism for controlling alignment is the alignment_clause of a record_representation_clause (RM83 13.4(2-4)). For instance:
type Rec is record C1 : Boolean; C2 : Integer; C3 : Character; end record; for Rec use record at mod 8; -- Alignment clause end record;
Note that while an alignment_clause is part of a record_representation_clause, which may include component_clauses, the presence of component_clauses is not mandatory. In the above example, the alignment for the type is specified to be 8, but the internal layout of the record is left unspecified (and will be chosen by the compiler).
The semantics of alignment_clauses are defined by RM83 13.4(4):
An alignment clause forces each record of the given type to be allocated at a starting address that is a multiple of the value of the given expression (that is, the address modulo of the expression must be zero.) An implementation may place restrictions on the allowable alignments.
Note the phrase "each record of the given type." This phrase implies that each and every object of the type has to comply with the given alignment. This includes objects allocated on the stack (for example, objects declared within subprograms) or allocated on the heap (for example, by means of an allocator).
Because of this rule, the allowable alignments are generally small,that is, limited to those that can be naturally supported by the machine instructions (for instance, 4- or 8-byte alignment on the stack). This means that in Ada 83, it is generally not possible to specify "large" alignments (for instance, page alignment). Some compilers (for example,VADS) have taken liberties with the language rules, and support larger alignments, but only enforce them on some objects (for example, statically allocated objects). While this approach was certainly pragmatic and useful given the limitations imposed by Ada 83, it made programs less portable. Moreover, the introduction of the Alignment attribute in Ada 95 provides much better support for controlling alignments. For this reason, Apex adheres to the strict rules of Ada 83, and only supports "small" alignments for types in Ada 83 (see below for the actual limits).
The actual limits for Apex are as follows:
Table 30 Type and Object Alignment Limits - Ada 83
4
8
8
8
8
8
4
8
Representation-Clause Error Handling
Normally, an invalid representation clause causes an error at compile time and prevents successful compilation.
Several Apex context switches, however, allow you to specify whether to treat certain classes of invalid representation clauses as nonfatal errors that allow successful compilation rather than as errors. The following switches are described in the online documentation:
- Ignore_Invalid_Rep_Specs. Affects the handling of both invalid and unsupported representation specifications.
- Ignore_Unsupported_Rep_Specs. Affects the handling of unsupported representation specifications only.
Length Clauses
Length clauses are supported by Rational Apex as follows:
- Length clauses are not supported for derived discriminated record types.
- The value of a 'Size attribute must be a positive static integer expression. It must be greater than or equal to the minimum size necessary to store the largest possible value of the type. 'Size attributes are supported for all scalar and composite types with the following restrictions:
- 'Storage_Size attributes are supported for access and task types. The value given by a 'Storage_Size attribute can be any integer expression, and it is not required to be static.
- 'Small attributes are supported for fixed-point types. The value given by a 'Small attribute must be a positive static real number that cannot be greater than the delta of the base type. It need not be a power of 2.
Enumeration Representation Clauses (LRM 13.3)
Enumeration representation clauses are supported with the following restriction:
- The allowable values for an enumeration clause range from Integer'First to Integer'Last.
Record Representation Clauses (LRM 13.4)
Both full and partial representation clauses are supported for both discriminated and undiscriminated records. Record component clauses are not allowed on:
- Array or record fields whose constraint involves a discriminant of the enclosing record
- Array or record fields whose constraint is not static
The static simple expression in the alignment clause part of a record representation clause —— see the Ada LRM 13.4 (4) —— must be a power of 2 with the following limits:
1 <= static_simple_expression <= 16
The size specified for a discrete field in a component clause must not exceed 32 bits.
Bit numbering in record representation clauses is machine dependent. On big-endian machines, bit 0 maps to the most significant bit. On little-endian machines, bit 0 maps to the least significant bit. Figures illustrating the bit numbering and addressing schemes for each of the Apex platforms are provided on the following pages. Select your platform from the following list:
- Digital UNIX and Intel Architecture Little Endian
- HP PA Addressing and Bit Numbering
- MIPS Little Endian
- MIPS Big Endian
- PowerPC Addressing and Bit Numbering
- RS/6000 Addressing and Bit Numbering
- SPARC Addressing and Bit Numbering
Representation clauses are not supported for derived discriminated record types.
Figure 4 Digital UNIX and Intel Architecture Little Endian
![]()
Figure 5 HP PA Addressing and Bit Numbering
![]()
Figure 6 MIPS Little Endian
![]()
Figure 7 MIPS Big Endian
![]()
Figure 8 PowerPC Addressing and Bit Numbering
![]()
Figure 9 RS/6000 Addressing and Bit Numbering
![]()
Figure 10 SPARC Addressing and Bit Numbering
![]()
Change of Representation (LRM 13.6)
Change of representation is supported wherever it is implied by support for representation specifications. In particular, type conversions between array types might cause packing or unpacking to occur. Conversions between related enumeration types with different representations can result in table-lookup operations.
Implementation-Generated NamesThe Ada LRM allows for the generation of names denoting implementation-dependent components in records. No such names are visible to the user for Apex.
Address Clauses (LRM 13.5)Address clauses cannot be applied to task types. No other restrictions are placed on address clauses.
An address clause can be attached to a task entry only when the task entry is used for signal (interrupt) catching; however, in this case, the task entry must be available at the time of the signal. For more information see Pragma Signal_Handler. For more information on interrupt-entry signal handling, see the Ada Runtime Guide.
Values of address clauses are not checked for validity. No check is made to determine whether an address clause causes the overlay of objects or of program units.
Unchecked ProgrammingUnchecked Storage Deallocation (LRM 13.10.1)
Unchecked storage deallocation is implemented by the Ada LRM-defined generic function Unchecked_Deallocation. This procedure can be instantiated with an object type and its access type, resulting in a procedure that deallocates the object's storage. Objects of any type can be deallocated.
The storage reserved for the entire collection associated with an access type is reclaimed when the program exits the scope in which the access type is declared. Placing an access-type declaration within a block can be a useful implementation strategy when conservation of memory is necessary within a collection. Space on the free list is coalesced when objects are deallocated.
Erroneous use of dangling references can be detected in certain cases. When detected, the Storage_Error exception is raised. Deallocation of objects that were not created through allocation (that is, through Unchecked_Conversion) can also be detected in certain cases, also raising Storage_Error.
Unchecked Type Conversion (LRM 13.10.2)
Unchecked type conversion is implemented by the generic function Unchecked_Conversion defined by the Ada LRM. This function can be instantiated with source and target types, resulting in a function that converts source data values into target data values.
Operation of Unchecked Type Conversion
In general, unchecked conversion produces reasonable results only if the source and the target type have the same size. The compiler generates a warning message if it detects that source and target types of an unchecked conversion have different sizes:
!!! ... is new Unchecked_Conversion (Source, Target) is unsafe;
Unchecked conversion to and from scalar types that include redundant high order bits is also considered unsafe. For example, the 28 most significant bits of new Integer range 0..15 are redundant because they are always equal to zero. If the compiler detects unchecked conversion to or from such types it generates the warning messages:
!!! Type is not a safe source type for unchecked conversion !!! Type is not a safe target type for unchecked conversion
The compiler generates similar warning messages for unchecked conversion to or from packed structured types, if the packed size is smaller than the default size of the type. Finally, if the source or the target type of an unchecked conversion has a dynamic size, the compiler generates the warning message:
!!! Type has a dynamic size, unchecked conversion may be unsafe
The user can ignore these messages, but the implementation as described here cannot guarantee that something sensible is returned in these cases. However, considerable effort is made to ensure that the result is well-defined.
Special care must be taken for unchecked conversion to record or array types. The layout of a record or array can contain unused bits that are normally initialized to zero by the compiler. If a value is assigned to such a record or array through Unchecked_Conversion, the unused bits can assume any value. This might result in the predefined equality operator returning False even if all visible fields of the two operands are equal.
Task types are treated as pointers (access values) to a task control block. Converting a task type thus converts is address into the target type, not the contents of the task control block.
Converting from Discrete, Fixed, Access, or Task Types to Discrete, Fixed, or Access Types
If Source'Size >= Target'Size, the least significant Target'Size, bits of the source operand are returned. If Source'Size < Target'Size, the source operand is extended to (at least) Target'Size bits —— sign-extended if Source is a signed type and zero-extended otherwise.
Converting from Discrete, Fixed, Access, or Task Types to Float Types
If the source type has fewer bits than the target type, the algorithm is intended to maximize the probability of producing a NaN (Not a Number).
If Source'Size >= Target'Size, the least significant Target'Size bits of the source operand are returned. If Source'Size < Target'Size, the source operand is extended with ones, which usually results in a NaN value.
Converting from Float Types to Discrete, Fixed, or Access Types
If Source'Size >= Target'Size, the low order bits of the source operand are returned. If Source'Size < Target'Size, the source operand is returned in the least significant bits of the result and zero-extended.
Converting from Float Types to Float Types
If Source'Size = Target'Size, the source operand is returned as a value of the target type. This is equivalent to a numerical conversion without range checks. If Source'Size /= Target'Size, the result of the operation is undefined.
Converting from Record or Array Types to Record or Array Types
If Source'Size >= Target'Size, the first Target'Size bits at the address of the source operand are returned. If Source'Size < Target'Size, the source operand is returned in the first.
Source'Size bits of the result, the remaining bits of the result being undefined. On current Apex (big-endian) architectures, the "first bits" means the bits #31, 30, 29, and so on.
Converting from Record or Array Types to Discrete, Fixed, or Access Types
If Source'Size >= Target'Size, the first Target'Size bits at the address of the source operand are returned. If Source'Size < Target'Size, the source operand is returned in the least significant bits of the result, which is otherwise filled with zeros.
Converting from Record or Array Types to Float Types
If Source'Size >= Target'Size, the first Target'Size bits at the address of the source operand are returned. If Source'Size < Target'Size, the source operand is returned in the least significant bits of the result, which is otherwise filled with ones (this should produce a NaN).
Converting from Scalar, Access, or Task Types to Record or Array Types
If Source'Size >= Target'Size, the least significant Target'Size bits of the source operand are returned. If Source'Size < Target'Size, the source operand is returned in the first Source'Size bits of the result, the remaining bits of the result being undefined.
Restrictions on Unchecked Type Conversion
The following restrictions apply to unchecked type conversion:
- The target type of an unchecked type conversion cannot be an unconstrained array type or an unconstrained discriminated type without default discriminants.
- Internal consistency among components of the target type is not guaranteed. Discriminant components can contain illegal values or be inconsistent with the use of those discriminants elsewhere in the type representation.
Input/Output PackagesThe Ada language defines specifications for four I/O packages: Sequential_Io, Direct_Io, Low_Level_Io, and Text_Io. The following subsections explain the implementation-dependent characteristics of those four packages provided with Apex.
Sequential_Io (LRM 14.2.2 and 14.2.3)
For the Read procedure of Sequential_Io, the Data_Error exception is raised only when the size of the data read from the file is greater than the size of the out parameter Item.
POSIX Compliance
The Form parameter on subprograms in Sequential_Io is compliant with the POSIX.5 standard. The Form parameter is discussed in detail in "Files and I/O" in the Ada Runtime Guide.
Direct_Io (LRM 14.2.4
)Package Direct_Io may not be instantiated with any type that is either an unconstrained array type or a discriminated record type without default discriminants. A semantic error is reported when an attempt is made to install any unit that contains an instantiation in which the actual type is such a forbidden type.
For the Read procedure of Direct_Io, no check is performed to ensure that the data read from the file can be interpreted as a value of the Element_Type.
Specification of Package Direct_Io (LRM 14.2.5)
The declaration of the type Count in package Direct_Io is:
type Count is new Integer range 0 .. Integer'Last / Element_Type'Size;
where Element_Type is the generic formal type parameter.
POSIX Compliance
The Form parameter on subprograms in Direct_Io is compliant with the POSIX.5 standard.The Form parameter is discussed in detail in "Files and I/O" in the Ada Runtime Guide.
Low_Level_Io (LRM 14.6)
Package Low_Level_Io is not provided with Apex.
Text_Io (LRM 14.3)
The Text_Io default input and output files are associated
with the UNIX standard input and standard output paths, respectively.Specification of Package Text_Io (LRM 14.3.10)
The declaration of the type Count in Text_Io is:
type Count is range 0 .. 1_000_000_000;
The declaration of the subtype Field in Text_Io is:
subtype Field is Integer range 0 .. Integer'Last;
Note that not all values of Text_Io.Field can be used in operations of package Text_io. The use of very large values for Field may cause problems on your system.
File-Management Operations
The operations of Get and Put are as described in the Ada LRM.
Data written using Put and Put_Line is not interpreted unless the data being written by Put is Ascii.Ff (a form feed). In this case, an Ascii.Lf (a line feed) is inserted. Data written using Put_Line is followed by the line terminator Ascii.Lf.
Data read using Get and Get_Line is not interpreted except that the line terminator, Ascii.Lf, and the page terminator, Ascii.Ff, are removed from the input stream.
POSIX Compliance
The Form parameter on subprograms in Text_Io is compliant with the POSIX.5 standard. The Form parameter is discussed in detail in "Files and I/O" in the Ada Runtime Guide.
Parameter PassingParameters are passed in registers or by pushing values (or addresses) on the stack, or by using a combination of registers and stack locations.
For calls to Ada procedures extra information (hidden parameters) may be passed for arrays (dope vector address), or for records ('CONSTRAINED), or for up-level references in nested procedures (static link). Dope vector addresses are passed immediately following the parameter with which they are associated. A static link, if required, is passed as the final parameter to a procedure.
In general, small results are returned in registers; large results with known targets are passed by reference. Large results of anonymous target and known size are passed by reference to a temporary created on the caller's stack. Large results of anonymous target and unknown size are returned by copying the value down from a temporary in the callee so the space used by the temporary can be reclaimed.
When only Ada programs and subprograms are being called, Apex may sometimes follow calling conventions different from those used by compilers for other languages. However, when interface calls are made using pragma Export or pragma import, Apex will generate code sequence that conforms to a standard.
Additional information on interface programming is available in Interfacing with Other Languages.
Machine Code Insertions may be used to explicitly build a call interface when compiler conventions are not compatible or when interfacing to assembly language.
The exact details of parameter passing are highly dependent on the target architecture. Additional information is available for each target processor. Select the desired section from the following list:
- Parameter Passing - Sun SPARC (32-bit)
- Parameter Passing - Sun SPARC V9 (64-bit)
- Parameter Passing - Alpha Architecture
- Parameter Passing - HP-PA
- Parameter Passing - IBM RS/6000
- Parameter Passing - M68k Family
- Parameter Passing - PowerPC Family
- Parameter Passing - MIPS Family
- Parameter Passing - RH-32
- Parameter Passing - Intel Architecture
Parameter Passing - Sun SPARC (32-bit)
For a detailed description on SPARC 32-bit calling conventions, please refer to the 32-bit Application Binary Interface (ABI) manual available for purchase or free download from Sparc International at http://www.sparc.org/.
What follows is a brief description on the roles of various registers in standard function calling sequence, based on the 32-bit ABI from Sparc International.
SPARC has 32 integer registers and 32 floating-point registers, that are accessible to any program, at any time. Of these, 8 integer registers and 32 floating-point registers are global to the program. All remaining 24 integer registers are windowed by way of save and restore instructions (in the prologue and epilogue, respectively, of the routine). Sets of 24 overlap each other by 8 registers each there by making caller's out registers coincide with callee's in registers.
The integer registers are named, global (%g0 to %g7), out (%o0 to %o7), local (%l0 to %l7), in (%i0 to %i7). The floating point registers are represented as %f0, %f1, ..., %f31. These are single precision floating-point registers. These registers are used in pairs for storing double precision values and are accessible as %d0, %d2, ..., %d30 (%d0 is %f0%f1, and so on).
Register Usage in Standard Calls
The following discussion assumes that register window is enabled by way of save and restore instructions. The compiler will not generate these instructions in a Machine_Code routine in the presence of "pragma Implicit_Code(Off);" statement, in which case, the current routine's register window is same as the caller's register window. In the presence of a register window, caller's %l0 through %l7 and %i0 through %i7 registers are not accessible from within the callee.
- Stack Pointer, %sp is %o6, and Frame Pointer, %fp is %i6 (which is in fact caller's %sp).
- While generating PIC (necessary for creating shared library), the local register %l7 is used to store the Global Offset Table Pointer (also known as the GP).
- The caller's return address is in %i7. The call instruction saves its address in %o7 (that's how the caller's return address ends up in %i7).
- Up to six parameters are passed to the callee via out registers (of the caller) %o0 through %o5 (this would appear in callee's %i0 through %i5). This is the case for integral types (including pointers) as well as float types. For one double float parameter, two integer registers are used. The rest of the parameters are passed on the stack.
- Integral and pointer return values are returned via %i0. Floating-point values are returned via %f0 (and %d0 if it is a double precision value).
- The local registers, %l0 through %l7 being local to the register window, are non-volatile across function calls.
- The in registers, %i0 through %i7, being local to the register window, are non-volatile across function calls (Yet, it has to be noted, %i0 through %i5, have the incoming parameters from its own caller).
- The out registers, %o0 through %o7, except %o6 (which is %sp), are volatile across function calls since they are used for parameter passing (%o0 through %o5) or to store the address of call instruction (%o7).
- Of the eight global registers, %g0 through %g7,
- %g0 is a read-only register with a value of zero,
- %g1 is volatile across function calls,
- %g2 through %g4 are reserved for application software (that is, non-volatile across calls to system libraries, but, application software is free to define special usages for them and preserve it across calls as necessary).
- Apex Ada compiler uses %g4 as the stack limit register.
- %g5 through %g7 are reserved for system software (that is, not available for use in application programs).
All the 32 floating-point registers are volatile across function calls.
Parameter Passing - Sun SPARC V9 (64-bit)
For a detailed description on SPARC V9 64-bit calling conventions, please refer to the 64-bit Application Binary Interface (ABI) manual available for purchase or free download from Sparc International at http://www.sparc.org/. What follows is a brief description on the roles of various registers in standard function calling sequence, based on the 64-bit ABI from Sparc International.
SPARC V9 has 32 integer registers, 32 single precision (32-bit) floating-point registers, and 16 double precision (64-bit) floating-point registers (these are present in SPARC V9 only), that are accessible to any program, at any time. Of these, 8 integer registers and all floating-point registers are global to the program. All remaining 24 integer registers are windowed by way of save and restore instructions (in the prologue and epilogue, respectively, of the routine). Sets of 24 overlap each other by 8 registers each there by making caller's out registers coincide with callee's in registers.
The integer registers are named, global (%g0 to %g7), out (%o0 to %o7), local (%l0 to %l7), in (%i0 to %i7). The single precision floating point registers are represented as %f0, %f1, ..., %f31. These registers are used in pairs for storing double precision values and they are accessible as %d0, %d2, ..., %d30 (%d0 is %f0%f1, and so on). The SPARC V9 specific double precision floating-point registers are accessible as %d32, %d34, ..., %d62 (%d32 is not equivalent to %f32%f33 register pair since, %d32 through %d62 are pure double precision float registers). SPARC V9 also supports quad precision (128-bit) floating-point registers and they overlap the 32-bit float registers and 64-bit float registers, and are accessible as %q0, %q4, ... %q28, %q32, ..., %q60, where %q0 is same as the quadruple %f0%f1%f2%f3 or pair %d0%d2, and so on till %q28. From %q32 onwards, there are no single precision float registers. So %q32 is equivalent to the register pair %d32%d33, so on. Apex Ada compiler does not support quad precision float types yet.
Register Usage in Standard Calls
The following discussion assumes that register window is enabled by way of save and restore instructions. The compiler will not generate these instructions in a Machine_Code routine in the presence of "pragma Implicit_Code(Off);" statement, in which case, the current routine's register window is same as the caller's register window. In the presence of a register window, caller's %l0 through %l7 and %i0 through %i7 registers are not accessible from within the callee.
- Stack Pointer, %sp is %o6, and Frame Pointer, %fp is %i6 (which is in fact caller's %sp).
- While generating PIC (necessary for creating shared library), the local register %l7 is used to store the Global Offset Table Pointer (also known as the GP).
- The caller's return address is in %i7. The call instruction saves its address in %o7 (that's how the caller's return address ends up in %i7).
- Up to six integral type (including pointers) parameters are passed to the callee via out registers (of the caller) %o0 through %o5 (this would appear in callee's %i0 through %i5). Upto 16 single and double precision float parameters are passed in float registers %f0, .. %f31. The rest of the parameters are passed on the stack.
- The 16 single precision float parameters are passed in odd numbered registers - %f1, %f3, %f5, ..., %f31. The 16 double precision float parameters are passed in %d0, %d2, ..., %d30. When passing mixed float and integer parameters, there could be unused integer and float parameter registers. For example, if the first and third parameters are of integral type, second (single) and fourth (double) are of float type, the first parameter would be in %o0, the second one will be in %f3, the third one will be in %o2, the fourth one will be in %d6 (same as %f6%f7).
- Integral and pointer return values are returned via %i0. Floating-point values are returned via %f0 (and %d0 if it is a double precision value).
- The local registers, %l0 through %l7 being local to the register window, are non-volatile across function calls.
- The in registers, %i0 through %i7, being local to the register window, are non-volatile across function calls (Yet, it has to be noted, %i0 through %i5, have the incoming parameters from its own caller).
- The out registers, %o0 through %o7, except %o6 (which is %sp), are volatile across function calls since they are used for parameter passing (%o0 through %o5) or to store the address of call instruction (%o7).
- Of the eight global registers, %g0 through %g7,
- %g0 is a read-only register with a value of zero,
- %g1 is volatile across function calls,
- %g2, %g3 are reserved for application software (that is, non-volatile across calls to system libraries, but, application software is free to define special usages for them and preserve it across calls as necessary),
- Apex Ada compiler uses %g2 as the stack limit register
- %g4 is volatile across function calls,
- %g5 is reserved by Apex Ada compiler for internal use (users must not use this register while writing machine_code routines),
- %g6, %g7 are reserved for system software (that is, not available for use in application programs).
- All the 16 SPARC V9 specific double precision floating-point registers are volatile across function calls. They do not take part in the standard calling sequence.
Parameter Passing - Alpha Architecture
For a detailed description of Alpha calling conventions, please refer to the following document:
Digital Unix - Calling standard for Alpha Systems
Part Number: AA-PYBAC-TEAvailable on-line in HTML or PDF format from Compaq Computer Corporation.
Additional Alpha documentation is available at http://tru64unix.compaq.com/faqs/publications/pub_page/doc_list.html
What follows here is a brief description of the register conventions use in a typical Ada calling sequence.
Typical Ada Calling Sequence
- 1 . The caller passes up to six arguments in registers. The first argument is passed in R16 (scalar) or F16 (float). The second argument is passed in R17 or F17, and so on, up to R21/F21. The remaining arguments are passed on the stack.
- 2 . Caller loads PV (R27) with the procedure value (address) of the routine to be called, and transfers control to called routine. The return address is in RA (R26).
- 3 . The called routine loads its GP value relative to the PV.
- 4 . The called routine checks if there is sufficient space available on the stack for its local storage. If not, a Storage_Error exception is raised.
- 5 . The called routine modifies the SP to allocate space for local storage.
- 6 . The called routine saves the return address (RA), and any registers in the set S0-S6 and F2-F9 that are modified by the routine.
- 7 . A trap barrier marks the end of the standard prologue. At this point none of the saved registers (S0-S6, F2-F9) have been modified, so the context of the calling routine is still intact.
- 8 . The called routine sets up a frame-pointer (S6 or FP) and an argument pointer (s4 or AP), if needed.
- 9 . The body of the called routine executes.
- 10 . The called routine puts the function result in V0 or F0.
- 11 . The return address (RA) and saved registers are restored.
- 12 . The stack pointer is restored, reclaiming local storage.
- 13 . The called routine returns to the caller.
- 14 . The caller re-loads its GP value relative to the return address.
- 15 . The caller assigns any result or out parameters to its local storage or static locations, if needed.
Parameter Passing - HP-PA
For a detailed description on PA-RISC calling conventions, please refer to the following documents:
32-Bit PA-RISC Run-Time Architecture (HP-UX 10.20)
32-Bit PA-RISC Run-Time Architecture (HP-UX 11.00)
64-Bit Run-Time Architecture for PA-RISC 2.0Additional PA-RISC documentation can be found at http://devresource.hp.com/STK/toc_ref.html#PA-RISC and http://docs.hp.com
What follows here is a brief description of the register conventions use in a typical Ada calling sequence.
Parameter Passing - IBM RS/6000
For a detailed description on IBM RS/6000 calling conventions, please refer to the following document:
SYSTEM V APPLICATION BINARY INTERFACE PowerPC Processor Supplement, Sun Microsystems and IBM, September 1995. Part Number: 802-3334-10.
Also available from ESOFTA at http://www.esofta.com/pdfs/SVR4abippc.pdf
What follows is a brief description of the register conventions followed in a typical Ada calling sequence.
Typical Ada Calling Sequence
- 1 . The caller passes scalar arguments in r3-r10; floating-point arguments in fr1-fr13; other arguments are passed on the stack. Mixing integer and floating-point parameters causes integer parameter registers to be skipped. For example, if (integer, float, integer) are passed then (r3, f1, r5) are used, not (r3, f1, r4). If the called routine is a foreign (non-Ada) routine (i.e. Pragma Import(C...)), then the caller saves the FPSCR prior to the call.
- 2 . Control is transferred to the called routine.
- 3 . The called routine allocates space for the frame and locals, and performs a stack overflow check (if not suppressed).
- 4 . Called routine saves floating-point registers in fr14-fr31, general registers in r13-r31, and condition register fields in cr2-cr4 that will be modified. (Sufficient space is allocated to save all these registers, but only the registers that are modified are saved and restored).
- 5 . Body of the called routine executes.
- 6 . Any function result is left in r3 or f1.
- 7 . Saved registers are restored.
- 8 . The space for the frame and locals is deallocated.
- 9 . The called routine returns to the caller.
- 10 . If the called routine was a foreign routine, the caller clears bits 0-3 of XER and restores the FPSCR.
- 11 . The caller assigns any result or out parameters to its local storage or static locations, if necessary.
Parameter Passing - M68k Family
When only Ada programs and subprograms are being called, Apex passes parameters using registers. The following conventions for passing parameters in registers is used:
- 1 . For scalar and access parameters (integers, enumerations, addresses and fixed point numbers), the first two parameters are passed (or returned) in D2 and D3. Subsequent parameters are passed on the stack.
- 2 . For floating point parameters (with hardware floating point), the first four parameters are passed (or returned) in fp0, fp1, fp2 and fp3. Subsequent parameters are passed on the stack.
- 3 . Registers d2 and d3 are scratch registers, i.e., they are no longer saved across calls. In this respect, they are like a0, a1, d0 and d1.
Note: Register parameters are incompatible with the standard MC68020 calling conventions. However, calls to subprograms with pragma Interface are called using the standard calling conventions.
Small results are returned in registers; large results with known targets are passed by reference. Large results of anonymous target and known size are passed by reference to a temporary created on the caller's stack. Large results of anonymous target and unknown size are returned by copying the value down from a temporary in the callee so the space used by the temporary can be reclaimed.
The compiler assumes the following calling conventions:
- 1 . caller copies register parameters into d2-d3 and fp0-fp3 as described above.
- 2 . caller pushes remaining arguments on stack in reverse order from their declaration.
- 3 . caller calls callee.
- 4 . callee builds display and allocates space for local variables with the LINK instruction.
- 5 . callee pushes any registers it uses in the sets d4-d7 and a2-a5 and fp4-fp7 if the M68881 is being used.
- 6 . callee executes.
- 7 . callee pops registers pushed in Step 5.
- 8 . callee leaves result in d0 or fp0 if callee is a function.
- 9 . callee deallocates local variables with the unlk instruction.
- 10 . callee returns to caller.
- 11 . caller copies back any out parameters or function values.
- 12 . caller deallocates the space used for arguments on the stack.
Note: Compilers for other languages follow calling conventions different from those used by Apex. When calling foreign language subprograms (with pragma Interface) or in routines callable from foreign languages (with pragma External), the caller allocates stack space for each parameter passed in a register plus an additional word in accordance with C compiler conventions. Also, floating point parameters are passed in the integer registers.
Machine code insertions can be used to explicitly build a call interface when compiler conventions are not compatible or when interfacing to assembly language.
For example, suppose an interface to a C function Pass_Int is desired, where the C compiler generated code such that the callee deallocates space for the parameters.
int pass_int(x) int x; {... }
The following Ada code provides a wrapper to call this function, while allowing the C function to handle the deallocation.
with MACHINE_CODE; function PASS_INT(X : INTEGER) return INTEGER is RETURN_VAL : INTEGER; procedure WRAPPER is use MACHINE_CODE; begin CODE_2'(MOVE_L, X'REF, decr(sp)); -- push x ontostack CODE_1'(JSR, EXT("_pass_int")); -- call pass_int via -- its link name CODE_2'(MOVE_L, D0, RETURN_VAL'REF); -- save result end WRAPPER; begin WRAPPER; return RETURN_VAL; end PASS_INT;
Parameter Passing - PowerPC Family
For a detailed description of PowerPC calling conventions, please refer to the following document:
PowerPC Embedded Application Binary Interface, Version 1.0,
IBM and Motorola, January 10, 1995.Available in PDF format from ESOFTA
What follows here is a brief description of the register conventions used in a typical Ada calling sequence.
Typical Ada Calling Sequence
- 1 . The caller passes scalar arguments in r3-r10; floating-point arguments in fr1-fr8; other arguments are passed on the stack. Mixing integer and floating-point parameters does not cause integer parameter registers to be skipped. For example, if (integer, float, integer) are passed then (r3, f1, r4) are used, not (r3, f1, r5). If the called routine is a foreign (non-Ada) routine (i.e. Pragma Import(C...)), then the caller saves the FPSCR prior to the call.
- 2 . Control is transferred to the called routine.
- 3 . The called routine assigns stack pointer r1 to frame pointer r31 (if necessary), allocates space for frame and locals and performs a stack overflow check (if not suppressed).
- 4 . The called routine saves floating-point registers in fr14-fr31, general registers in r13-r31, and condition register fields in cr2-cr4, that will be modified.
- 5 . If needed, the called routine sets up an argument pointer in r30.
- 6 . Body of the called routine executes.
- 7 . Any function result is left in r3 or f1.
- 8 . Saved registers are restored.
- 9 . The space for the frame and locals is deallocated.
- 10 . The called routine returns to the caller.
- 11 . If the called routine was a foreign routine, the caller clears bits 0-3 of XER and restores the FPSCR.
- 12 . The caller assigns any result or out parameters to its local storage or static locations, if necessary.
Parameter Passing - MIPS Family
For a detailed description of MIPS calling conventions, please refer to the following documents:
MIPSpro N32 ABI Handbook
IRIX 6.3 - Books (document number: 007-2816-004)MIPSpro 64-Bit Porting and Transition Guide
IRIX 6.3 - Books (document number: 007-2391-006)These documents can be located on-line from the SGI TechPubs Library.
What follows is a brief overview on the roles of various registers in a typical Ada calling sequence.
Typical Ada Calling Sequence
- 1 . The Caller passes scalar arguments in a0, a1, a2 and a3 and floating pointer arguments in f12 and f14. Other arguments are passed on the stack.
- 2 . Caller transfer control to the called routine.
- 3 . The called routine calculates space for local storage and performs a stack overflow check (unless suppressed). If there is sufficient space on the stack, SP is adjusted to create the space for local storage, otherwise a Storage_Error exception is raised.
- 4 . The called routine preserves registers in the set s0-s7, sp, s8 and ra if they are used. Registers f20 through f30 are also saved if used.
- 5 . The Called routine sets up a frame pointer (r30, aka fp) if the sp is modified in the body of the routine, otherwise a virtual frame pointer is used.
- 6 . The body of the called routine executes.
- 7 . If the called routine is a function, scalar results are returned in v0-v1 and floating-point results are returned in F0-F2.
- 8 . Saved registers are restored.
- 9 . The stack pointer is restored, reclaiming local storage.
- 10 . The called routine returns to the caller.
Parameter Passing - RH-32
When calling other languages, parameters are passed in registers and by pushing values (or addresses) on the stack. Extra information is passed for records ('CONSTRAINED) and for arrays (dope vector address).
Small results are returned in registers; large results with known targets are passed by reference. Large results of anonymous target and known size are passed by reference to a temporary created on the caller's stack. Large results of anonymous target and unknown size are returned by copying the value down from a temporary in the callee so the space used by the temporary can be reclaimed.
- 1 . caller passes scalar arguments in a0, a1, a2 and a3 and floating pointer arguments in f6 and f7. Other arguments are passed on the stack. Inter-language calls (for example, from a C routine to an Ada routine or from an Ada routine to a C routine) use the standard RH32 calling convention. To call a C procedure, declare the Ada interface using pragma Interface (language, subprogram). To declare an Ada procedure that is called from C or FORTRAN, use pragma External (language, subprogram).
- 2 . caller calls callee.
- 3 . callee allocates space for locals, if needed, by subtracting from the stack pointer. If the stack pointer is changed, a stack overflow check is executed.
- 4 . callee preserves registers in the set s0-s7, sp, s8 and ra if they are used. Also, registers f10 through f15 are saved if used.
- 5 . callee copies the display, if needed.
- 6 . callee sets up a frame pointer (r30, aka fp) if the sp is modified by code during the call. Otherwise, a virtual frame pointer is used.
- 7 . callee executes.
- 8 . callee puts return result in v0 or f0.
- 9 . saved registers are restored.
- 10 . the stack pointer is restored, reclaiming local storage.
- 11 . the callee returns to the caller.
Machine code insertions can be used to explicitly build a call interface when compiler conventions are not compatible or when interfacing to assembly language.
It is important to understand the referencing of parameters when using machine code insertions. Parameters cannot be treated like memory locations since in may cases, they are being held in registers. Attempting to treat a parameter held in a register like a memory location causes a compiler error.
Apex passes one or more parameters in registers. The Machine_Code package expects references to parameters (via the 'REF attribute) to be consistent with what Apex expects. For example, on RH32-based systems, the compiler passes the first 4 scalar parameters in registers a0-a3 and the first 2 floating parameters in f6 and f7. On the RH32, the ld_w instruction is used to move a value from a memory location into a register, while the Apex move mnemonic is the equivalent of moving a value from one register to another. Given the following example:
procedure test_machine_code (p1, p2, p3, p4, p5 : integer) is begin code_2'(ld, t0, p1'ref); -- (A) put p1 into register t0 code_2'(move, t1, p1'ref); -- (B) put p1 into register t1 code_2'(ld, t2, p5'ref); -- (C) put p5 into register t2 code_2'(move, t3, p5'ref); -- (D) put p5 into register t3 ...
Since the first 4 scalar parameters are passed in registers, p1 is in a register, while p5 is on the stack. Therefore (B) and (C) are legal, while (A) and (D) flag p1/p5 as being illegal operands.
Parameter Passing - Intel Architecture
Apex Ada uses the following calling conventions:
- 1 . The caller pushes arguments on stack in reverse order from their declaration
- 2 . The caller transfers control to the called routine
- 3 . The called routine pushes EBP on stack, and sets EBP to the new ESP (i.e. EBP points at the location of the old EBP).
- 4 . The called routine computes space for local variables and reforms a storage check (unless suppressed). If there is sufficient space on the stack, ESP is adjusted to create the space for local variables, otherwise a storage_error exception is raised. Except for the storage check, steps 3 and 4 are equivalent to the ENTER instruction.
- 5 . If the called routine has an external C interface (i.e. Pragma Export(C...)), then ESI, EDI, and EBX are saved on the stack.
- 6 . The body of the called routine executes.
- 7 . If the called routine is a function, scalar results are returned in EAX, and floating-point results are returned in ST(0).
- 8 . Registers saved in step 5 are restored.
- 9 . The called routine deallocates space for local variables, and restores EBP. This is done using the LEAVE instruction.
- 10 . The called routine returns to the caller.
- 11 . The caller copies back any out parameters or function value.
- 12 . The caller deallocates space used for arguments on the stack
Machine code insertions can be used to explicitly build a call interface when compiler conventions are not compatible or when interfacing to assembly language.
For example, suppose an interface to a C function Pass_Int is desired, where the C compiler generated code such that the callee deallocates space for the parameters:
int pass_int(x) int x; { ... }
The following Ada code provides a wrapper to call this function, while allowing the C function to handle the deallocation:
with Machine_Code; function Pass_Int (X : Integer) return Integer is Return_Val : Integer; procedure Wrapper is use Machine_Code; begin Code_1'(Push, X'Ref); -- push x onto the stack Code_1'(Call, Dword (Ext ("pass_int"))); -- call pass_int via link name Code_2'(Mov, Return_Val'Ref, Eax); -- save result end Wrapper; begin Wrapper; return Return_Val; end Pass_Int;
Other Implementation-Dependent FeaturesMachine Code (LRM 13.8)
Machine-code insertions are supported at this time for all platforms. Machine-code insertions are described in detail in Machine Code Insertions.
Rational Software Corporation http://www.rational.com support@rational.com techpubs@rational.com Copyright © 1993-2004, Rational Software Corporation. All rights reserved. |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |