.. Copyright (C) 2020-2024 Free Software Foundation, Inc. Originally contributed by David Malcolm This is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . .. default-domain:: c Using Assembly Language with libgccjit ====================================== libgccjit has some support for directly embedding assembler instructions. This is based on GCC's support for inline ``asm`` in C code, and the following assumes a familiarity with that functionality. See `How to Use Inline Assembly Language in C Code `_ in GCC's documentation, the "Extended Asm" section in particular. These entrypoints were added in :ref:`LIBGCCJIT_ABI_15`; you can test for their presence using .. code-block:: c #ifdef LIBGCCJIT_HAVE_ASM_STATEMENTS Adding assembler instructions within a function *********************************************** .. type:: gcc_jit_extended_asm A `gcc_jit_extended_asm` represents an extended ``asm`` statement: a series of low-level instructions inside a function that convert inputs to outputs. To avoid having an API entrypoint with a very large number of parameters, an extended ``asm`` statement is made in stages: an initial call to create the :type:`gcc_jit_extended_asm`, followed by calls to add operands and set other properties of the statement. There are two API entrypoints for creating a :type:`gcc_jit_extended_asm`: * :func:`gcc_jit_block_add_extended_asm` for an ``asm`` statement with no control flow, and * :func:`gcc_jit_block_end_with_extended_asm_goto` for an ``asm goto``. For example, to create the equivalent of: .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c :start-after: // Quote from here in docs/topics/asm.rst: example 1: C :end-before: // Quote up to here in docs/topics/asm.rst: example 1: C :language: c the following API calls could be used: .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c :start-after: /* Quote from here in docs/topics/asm.rst: example 1: jit. */ :end-before: /* Quote up to here in docs/topics/asm.rst: example 1: jit. */ :language: c .. warning:: When considering the numbering of operands within an extended ``asm`` statement (e.g. the ``%0`` and ``%1`` above), the equivalent to the C syntax is followed i.e. all output operands, then all input operands, regardless of what order the calls to :func:`gcc_jit_extended_asm_add_output_operand` and :func:`gcc_jit_extended_asm_add_input_operand` were made in. As in the C syntax, operands can be given symbolic names to avoid having to number them. For example, to create the equivalent of: .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c :start-after: // Quote from here in docs/topics/asm.rst: example 2: C :end-before: // Quote up to here in docs/topics/asm.rst: example 2: C :language: c the following API calls could be used: .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c :start-after: /* Quote from here in docs/topics/asm.rst: example 2: jit. */ :end-before: /* Quote up to here in docs/topics/asm.rst: example 2: jit. */ :language: c .. function:: gcc_jit_extended_asm *\ gcc_jit_block_add_extended_asm (gcc_jit_block *block,\ gcc_jit_location *loc,\ const char *asm_template) Create a :type:`gcc_jit_extended_asm` for an extended ``asm`` statement with no control flow (i.e. without the ``goto`` qualifier). The parameter ``asm_template`` corresponds to the `AssemblerTemplate` within C's extended ``asm`` syntax. It must be non-NULL. The call takes a copy of the underlying string, so it is valid to pass in a pointer to an on-stack buffer. .. function:: gcc_jit_extended_asm *\ gcc_jit_block_end_with_extended_asm_goto (gcc_jit_block *block,\ gcc_jit_location *loc,\ const char *asm_template,\ int num_goto_blocks,\ gcc_jit_block **goto_blocks,\ gcc_jit_block *fallthrough_block) Create a :type:`gcc_jit_extended_asm` for an extended ``asm`` statement that may perform jumps, and use it to terminate the given block. This is equivalent to the ``goto`` qualifier in C's extended ``asm`` syntax. For example, to create the equivalent of: .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c :start-after: // Quote from here in docs/topics/asm.rst: example 3b: C :end-before: // Quote up to here in docs/topics/asm.rst: example 3b: C :language: c the following API calls could be used: .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c :start-after: /* Quote from here in docs/topics/asm.rst: example 3: jit. */ :end-before: /* Quote up to here in docs/topics/asm.rst: example 3: jit. */ :language: c here referencing a :type:`gcc_jit_block` named "carry". ``num_goto_blocks`` must be >= 0. ``goto_blocks`` must be non-NULL. This corresponds to the ``GotoLabels`` parameter within C's extended ``asm`` syntax. The block names can be referenced within the assembler template. ``fallthrough_block`` can be NULL. If non-NULL, it specifies the block to fall through to after the statement. .. note:: This is needed since each :type:`gcc_jit_block` must have a single exit point, as a basic block: you can't jump from the middle of a block. A "goto" is implicitly added after the asm to handle the fallthrough case, which is equivalent to what would have happened in the C case. .. function:: void\ gcc_jit_extended_asm_set_volatile_flag (gcc_jit_extended_asm *ext_asm,\ int flag) Set whether the :type:`gcc_jit_extended_asm` has side-effects, equivalent to the `volatile `_ qualifier in C's extended asm syntax. For example, to create the equivalent of: .. code-block:: c asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX. "shl $32, %%rdx\n\t" // Shift the upper bits left. "or %%rdx, %0" // 'Or' in the lower bits. : "=a" (msr) : : "rdx"); the following API calls could be used: .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c :start-after: /* Quote from here in docs/topics/asm.rst: example 4: jit. */ :end-before: /* Quote up to here in docs/topics/asm.rst: example 4: jit. */ :language: c where the :type:`gcc_jit_extended_asm` is flagged as volatile. .. function:: void\ gcc_jit_extended_asm_set_inline_flag (gcc_jit_extended_asm *ext_asm,\ int flag) Set the equivalent of the `inline `_ qualifier in C's extended ``asm`` syntax. .. function:: void\ gcc_jit_extended_asm_add_output_operand (gcc_jit_extended_asm *ext_asm,\ const char *asm_symbolic_name,\ const char *constraint,\ gcc_jit_lvalue *dest) Add an output operand to the extended ``asm`` statement. See the `Output Operands `_ section of the documentation of the C syntax. ``asm_symbolic_name`` corresponds to the ``asmSymbolicName`` component of C's extended ``asm`` syntax. It can be NULL. If non-NULL it specifies the symbolic name for the operand. ``constraint`` corresponds to the ``constraint`` component of C's extended ``asm`` syntax. It must be non-NULL. ``dest`` corresponds to the ``cvariablename`` component of C's extended ``asm`` syntax. It must be non-NULL. .. code-block:: c // Example with a NULL symbolic name, the equivalent of: // : "=r" (dst) gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=r", dst); // Example with a symbolic name ("aIndex"), the equivalent of: // : [aIndex] "=r" (index) gcc_jit_extended_asm_add_output_operand (ext_asm, "aIndex", "=r", index); This function can't be called on an ``asm goto`` as such instructions can't have outputs; see the `Goto Labels `_ section of GCC's "Extended Asm" documentation. .. function:: void\ gcc_jit_extended_asm_add_input_operand (gcc_jit_extended_asm *ext_asm,\ const char *asm_symbolic_name,\ const char *constraint,\ gcc_jit_rvalue *src) Add an input operand to the extended ``asm`` statement. See the `Input Operands `_ section of the documentation of the C syntax. ``asm_symbolic_name`` corresponds to the ``asmSymbolicName`` component of C's extended ``asm`` syntax. It can be NULL. If non-NULL it specifies the symbolic name for the operand. ``constraint`` corresponds to the ``constraint`` component of C's extended ``asm`` syntax. It must be non-NULL. ``src`` corresponds to the ``cexpression`` component of C's extended ``asm`` syntax. It must be non-NULL. .. code-block:: c // Example with a NULL symbolic name, the equivalent of: // : "r" (src) gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", gcc_jit_lvalue_as_rvalue (src)); // Example with a symbolic name ("aMask"), the equivalent of: // : [aMask] "r" (Mask) gcc_jit_extended_asm_add_input_operand (ext_asm, "aMask", "r", gcc_jit_lvalue_as_rvalue (mask)); .. function:: void\ gcc_jit_extended_asm_add_clobber (gcc_jit_extended_asm *ext_asm,\ const char *victim) Add `victim` to the list of registers clobbered by the extended ``asm`` statement. It must be non-NULL. See the `Clobbers and Scratch Registers `_ section of the documentation of the C syntax. Statements with multiple clobbers will require multiple calls, one per clobber. For example: .. code-block:: c gcc_jit_extended_asm_add_clobber (ext_asm, "r0"); gcc_jit_extended_asm_add_clobber (ext_asm, "cc"); gcc_jit_extended_asm_add_clobber (ext_asm, "memory"); A :type:`gcc_jit_extended_asm` is a :type:`gcc_jit_object` "owned" by the block's context. The following upcast is available: .. function:: gcc_jit_object *\ gcc_jit_extended_asm_as_object (gcc_jit_extended_asm *ext_asm) Upcast from extended ``asm`` to object. Adding top-level assembler statements ************************************* In addition to creating extended ``asm`` instructions within a function, there is support for creating "top-level" assembler statements, outside of any function. .. function:: void \ gcc_jit_context_add_top_level_asm (gcc_jit_context *ctxt,\ gcc_jit_location *loc,\ const char *asm_stmts) Create a set of top-level asm statements, analogous to those created by GCC's "basic" ``asm`` syntax in C at file scope. For example, to create the equivalent of: .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c :start-after: // Quote from here in docs/topics/asm.rst: example 5: C :end-before: // Quote up to here in docs/topics/asm.rst: example 5: C :language: c the following API calls could be used: .. literalinclude:: ../../../testsuite/jit.dg/test-asm.c :start-after: /* Quote from here in docs/topics/asm.rst: example 5: jit. */ :end-before: /* Quote up to here in docs/topics/asm.rst: example 5: jit. */ :language: c