.. Copyright (C) 2020-2022 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:: cpp 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 *********************************************** .. class:: gccjit::extended_asm A `gccjit::extended_asm` represents an extended ``asm`` statement: a series of low-level instructions inside a function that convert inputs to outputs. :class:`gccjit::extended_asm` is a subclass of :class:`gccjit::object`. It is a thin wrapper around the C API's :c:type:`gcc_jit_extended_asm *`. 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:`gccjit::extended_asm`, followed by calls to add operands and set other properties of the statement. There are two API entrypoints for creating a :type:`gccjit::extended_asm`: * :func:`gccjit::block::add_extended_asm` for an ``asm`` statement with no control flow, and * :func:`gccjit::block::end_with_extended_asm_goto` for an ``asm goto``. For example, to create the equivalent of: .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc :start-after: // Quote from here in docs/cp/topics/asm.rst: example 1: C :end-before: // Quote up to here in docs/cp/topics/asm.rst: example 1: C :language: c the following API calls could be used: .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc :start-after: /* Quote from here in docs/cp/topics/asm.rst: example 1: jit. */ :end-before: /* Quote up to here in docs/cp/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:`gccjit::extended_asm::add_output_operand` and :func:`gccjit::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.cc :start-after: // Quote from here in docs/cp/topics/asm.rst: example 2: C :end-before: // Quote up to here in docs/cp/topics/asm.rst: example 2: C :language: c the following API calls could be used: .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc :start-after: /* Quote from here in docs/cp/topics/asm.rst: example 2: jit. */ :end-before: /* Quote up to here in docs/cp/topics/asm.rst: example 2: jit. */ :language: c .. function:: extended_asm \ gccjit::block::add_extended_asm (const std::string &asm_template,\ gccjit::location loc = location ()) Create a :type:`gccjit::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:: extended_asm\ gccjit::block::end_with_extended_asm_goto (const std::string &asm_template,\ std::vector goto_blocks,\ block *fallthrough_block,\ location loc = location ()) Create a :type:`gccjit::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.cc :start-after: // Quote from here in docs/cp/topics/asm.rst: example 3b: C :end-before: // Quote up to here in docs/cp/topics/asm.rst: example 3b: C :language: c the following API calls could be used: .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc :start-after: /* Quote from here in docs/cp/topics/asm.rst: example 3: jit. */ :end-before: /* Quote up to here in docs/cp/topics/asm.rst: example 3: jit. */ :language: c here referencing a :type:`gcc_jit_block` named "carry". ``num_goto_blocks`` 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:`gccjit::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:: gccjit::extended_asm &\ gccjit::extended_asm::set_volatile_flag (bool flag) Set whether the :type:`gccjit::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.cc :start-after: /* Quote from here in docs/cp/topics/asm.rst: example 4: jit. */ :end-before: /* Quote up to here in docs/cp/topics/asm.rst: example 4: jit. */ :language: c where the :type:`gccjit::extended_asm` is flagged as volatile. .. function:: gccjit::extended_asm &\ gccjit::extended_asm::set_inline_flag (bool flag) Set the equivalent of the `inline `_ qualifier in C's extended ``asm`` syntax. .. function:: gccjit::extended_asm&\ gccjit::extended_asm::add_output_operand (const std::string &asm_symbolic_name,\ const std::string &constraint,\ gccjit::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, and specifies the symbolic name for the operand. See the overload below for an alternative that does not supply a symbolic name. ``constraint`` corresponds to the ``constraint`` component of C's extended ``asm`` syntax. ``dest`` corresponds to the ``cvariablename`` component of C's extended ``asm`` syntax. .. code-block:: c++ // Example with a symbolic name ("aIndex"), the equivalent of: // : [aIndex] "=r" (index) ext_asm.add_output_operand ("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:: gccjit::extended_asm&\ gccjit::extended_asm::add_output_operand (const std::string &constraint,\ gccjit::lvalue dest) As above, but don't supply a symbolic name for the operand. .. code-block:: c++ // Example without a symbolic name, the equivalent of: // : "=r" (dst) ext_asm.add_output_operand ("=r", dst); .. function:: gccjit::extended_asm&\ gccjit::extended_asm::add_input_operand (const std::string &asm_symbolic_name, \ const std::string &constraint, \ gccjit::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. See the overload below for an alternative that does not supply a symbolic name. ``constraint`` corresponds to the ``constraint`` component of C's extended ``asm`` syntax. ``src`` corresponds to the ``cexpression`` component of C's extended ``asm`` syntax. .. code-block:: c++ // Example with a symbolic name ("aMask"), the equivalent of: // : [aMask] "r" (Mask) ext_asm.add_input_operand ("aMask", "r", mask); .. function:: gccjit::extended_asm&\ gccjit::extended_asm::add_input_operand (const std::string &constraint,\ gccjit::rvalue src) As above, but don't supply a symbolic name for the operand. .. code-block:: c++ // Example without a symbolic name, the equivalent of: // : "r" (src) ext_asm.add_input_operand ("r", src); .. function:: gccjit::extended_asm&\ gccjit::extended_asm::add_clobber (const std::string &victim) Add `victim` to the list of registers clobbered by the extended ``asm`` statement. 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++ ext_asm.add_clobber ("r0").add_clobber ("cc").add_clobber ("memory"); 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\ gccjit::context::add_top_level_asm (const char *asm_stmts,\ gccjit::location loc = location ()) 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.cc :start-after: // Quote from here in docs/cp/topics/asm.rst: example 5: C :end-before: // Quote up to here in docs/cp/topics/asm.rst: example 5: C :language: c the following API calls could be used: .. literalinclude:: ../../../../testsuite/jit.dg/test-asm.cc :start-after: /* Quote from here in docs/cp/topics/asm.rst: example 5: jit. */ :end-before: /* Quote up to here in docs/cp/topics/asm.rst: example 5: jit. */ :language: c