Package Machine_Code
provides machine code support as described
in the Ada 95 Reference Manual in two separate forms:
The two features are similar, and both closely related to the mechanism
provided by the asm instruction in the GNU C compiler. Full understanding
and use of the facilities in this package requires understanding the asm
instruction as described in
Using and Porting the GNU Compiler Collection (GCC) by Richard
Stallman. Calls to the function Asm
and the procedure Asm
have identical semantic restrictions and effects as described below.
Both are provided so that the procedure call can be used as a statement,
and the function call can be used to form a code_statement.
The first example given in the GCC documentation is the C asm
instruction:
asm ("fsinx %1 %0" : "=f" (result) : "f" (angle));
The equivalent can be written for GNAT as:
Asm ("fsinx %1 %0", My_Float'Asm_Output ("=f", result), My_Float'Asm_Input ("f", angle));
The first argument to Asm
is the assembler template, and is
identical to what is used in GNU C. This string must be a static
expression. The second argument is the output operand list. It is
either a single Asm_Output
attribute reference, or a list of such
references enclosed in parentheses (technically an array aggregate of
such references).
The Asm_Output
attribute denotes a function that takes two
parameters. The first is a string, the second is the name of a variable
of the type designated by the attribute prefix. The first (string)
argument is required to be a static expression and designates the
constraint for the parameter (e.g. what kind of register is
required). The second argument is the variable to be updated with the
result. The possible values for constraint are the same as those used in
the RTL, and are dependent on the configuration file used to build the
GCC back end. If there are no output operands, then this argument may
either be omitted, or explicitly given as No_Output_Operands
.
The second argument of my_float'Asm_Output
functions as
though it were an out
parameter, which is a little curious, but
all names have the form of expressions, so there is no syntactic
irregularity, even though normally functions would not be permitted
out
parameters. The third argument is the list of input
operands. It is either a single Asm_Input
attribute reference, or
a list of such references enclosed in parentheses (technically an array
aggregate of such references).
The Asm_Input
attribute denotes a function that takes two
parameters. The first is a string, the second is an expression of the
type designated by the prefix. The first (string) argument is required
to be a static expression, and is the constraint for the parameter,
(e.g. what kind of register is required). The second argument is the
value to be used as the input argument. The possible values for the
constant are the same as those used in the RTL, and are dependent on
the configuration file used to built the GCC back end.
If there are no input operands, this argument may either be omitted, or
explicitly given as No_Input_Operands
. The fourth argument, not
present in the above example, is a list of register names, called the
clobber argument. This argument, if given, must be a static string
expression, and is a space or comma separated list of names of registers
that must be considered destroyed as a result of the Asm
call. If
this argument is the null string (the default value), then the code
generator assumes that no additional registers are destroyed.
The fifth argument, not present in the above example, called the
volatile argument, is by default False
. It can be set to
the literal value True
to indicate to the code generator that all
optimizations with respect to the instruction specified should be
suppressed, and that in particular, for an instruction that has outputs,
the instruction will still be generated, even if none of the outputs are
used. See the full description in the GCC manual for further details.
The Asm
subprograms may be used in two ways. First the procedure
forms can be used anywhere a procedure call would be valid, and
correspond to what the RM calls “intrinsic” routines. Such calls can
be used to intersperse machine instructions with other Ada statements.
Second, the function forms, which return a dummy value of the limited
private type Asm_Insn
, can be used in code statements, and indeed
this is the only context where such calls are allowed. Code statements
appear as aggregates of the form:
Asm_Insn'(Asm (...)); Asm_Insn'(Asm_Volatile (...));
In accordance with RM rules, such code statements are allowed only within subprograms whose entire body consists of such statements. It is not permissible to intermix such statements with other Ada statements.
Typically the form using intrinsic procedure calls is more convenient
and more flexible. The code statement form is provided to meet the RM
suggestion that such a facility should be made available. The following
is the exact syntax of the call to Asm
. As usual, if named notation
is used, the arguments may be given in arbitrary order, following the
normal rules for use of positional and named arguments)
ASM_CALL ::= Asm ( [Template =>] static_string_EXPRESSION [,[Outputs =>] OUTPUT_OPERAND_LIST ] [,[Inputs =>] INPUT_OPERAND_LIST ] [,[Clobber =>] static_string_EXPRESSION ] [,[Volatile =>] static_boolean_EXPRESSION] ) OUTPUT_OPERAND_LIST ::= [PREFIX.]No_Output_Operands | OUTPUT_OPERAND_ATTRIBUTE | (OUTPUT_OPERAND_ATTRIBUTE {,OUTPUT_OPERAND_ATTRIBUTE}) OUTPUT_OPERAND_ATTRIBUTE ::= SUBTYPE_MARK'Asm_Output (static_string_EXPRESSION, NAME) INPUT_OPERAND_LIST ::= [PREFIX.]No_Input_Operands | INPUT_OPERAND_ATTRIBUTE | (INPUT_OPERAND_ATTRIBUTE {,INPUT_OPERAND_ATTRIBUTE}) INPUT_OPERAND_ATTRIBUTE ::= SUBTYPE_MARK'Asm_Input (static_string_EXPRESSION, EXPRESSION)
The identifiers No_Input_Operands
and No_Output_Operands
are declared in the package Machine_Code
and must be referenced
according to normal visibility rules. In particular if there is no
use
clause for this package, then appropriate package name
qualification is required.