blob: 6c1397f894818f915117662d3cb1362564aa572c [file] [log] [blame]
.. Copyright (C) 2020-2022 Free Software Foundation, Inc.
Originally contributed by David Malcolm <dmalcolm@redhat.com>
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
<https://www.gnu.org/licenses/>.
.. 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 <https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html>`_
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 <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#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 <https://gcc.gnu.org/onlinedocs/gcc/Size-of-an-asm.html#Size-of-an-asm>`_
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 <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#OutputOperands>`_
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 <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#GotoLabels>`_
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 <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#InputOperands>`_
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 <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#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