Machine Code Insertions (GNAT Reference Manual)

### 16.1 Machine Code Insertions ¶

Package `Machine_Code` provides machine code support as described in the Ada Reference Manual in two separate forms:

- Machine code statements, consisting of qualified expressions that fit the requirements of RM section 13.8.
- An intrinsic callable procedure, providing an alternative mechanism of including machine instructions in a subprogram.

The two features are similar, and both are 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, see the section on Extended Asm in Using_the_GNU_Compiler_Collection_(GCC).

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.

Consider this 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 (see the section on Constraints in Using_the_GNU_Compiler_Collection_(GCC)) for the parameter; e.g., what kind of register is required. The second argument is the variable to be written or 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`. No support is provided for GNU C’s symbolic names for output parameters.

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 constraint are the same as those used in the RTL, and are dependent on the configuration file used to built the GCC back end. No support is provided for GNU C’s symbolic names for input parameters.

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. In addition to registers, the special clobbers `memory` and `cc` as described in the GNU C docs are both supported.

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 in particular an instruction that has outputs will still be generated, even if none of the outputs are used. See Using_the_GNU_Compiler_Collection_(GCC) for the full description. Generally it is strongly advisable to use Volatile for any ASM statement that is missing either input or output operands or to avoid unwanted optimizations. A warning is generated if this advice is not followed.

No support is provided for GNU C’s `asm goto` feature.

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.