* [committed] jit: add support for inline asm [PR87291]
@ 2020-11-12 22:35 David Malcolm
0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2020-11-12 22:35 UTC (permalink / raw)
To: gcc-patches, jit
This patch adds various entrypoints to libgccjit for directly embedding
asm statements into a compile, analogous to inline asm in the C frontend:
gcc_jit_block_add_extended_asm
gcc_jit_block_end_with_extended_asm_goto
gcc_jit_extended_asm_as_object
gcc_jit_extended_asm_set_volatile_flag
gcc_jit_extended_asm_set_inline_flag
gcc_jit_extended_asm_add_output_operand
gcc_jit_extended_asm_add_input_operand
gcc_jit_extended_asm_add_clobber
gcc_jit_context_add_top_level_asm
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to master as 421d0d0f54294a7bf2872b3b2ac521ce0fa9869e.
gcc/jit/ChangeLog:
PR jit/87291
* docs/cp/topics/asm.rst: New file.
* docs/cp/topics/index.rst (Topic Reference): Add it.
* docs/topics/asm.rst: New file.
* docs/topics/compatibility.rst (LIBGCCJIT_ABI_15): New.
* docs/topics/functions.rst (Statements): Add link to extended
asm.
* docs/topics/index.rst (Topic Reference): Add asm.rst.
* docs/topics/objects.rst: Add gcc_jit_extended_asm to ASCII art.
* jit-common.h (gcc::jit::recording::extended_asm): New forward
decl.
(gcc::jit::recording::top_level_asm): Likewise.
* jit-playback.c: Include "stmt.h".
(build_string): New.
(gcc::jit::playback::context::new_string_literal): Disambiguate
build_string call.
(gcc::jit::playback::context::add_top_level_asm): New.
(build_operand_chain): New.
(build_clobbers): New.
(build_goto_operands): New.
(gcc::jit::playback::block::add_extended_asm): New.
* jit-playback.h (gcc::jit::playback::context::add_top_level_asm):
New decl.
(struct gcc::jit::playback::asm_operand): New struct.
(gcc::jit::playback::block::add_extended_asm): New decl.
* jit-recording.c (gcc::jit::recording::context::dump_to_file):
Dump top-level asms.
(gcc::jit::recording::context::add_top_level_asm): New.
(gcc::jit::recording::block::add_extended_asm): New.
(gcc::jit::recording::block::end_with_extended_asm_goto): New.
(gcc::jit::recording::asm_operand::asm_operand): New.
(gcc::jit::recording::asm_operand::print): New.
(gcc::jit::recording::asm_operand::make_debug_string): New.
(gcc::jit::recording::output_asm_operand::write_reproducer): New.
(gcc::jit::recording::output_asm_operand::print): New.
(gcc::jit::recording::input_asm_operand::write_reproducer): New.
(gcc::jit::recording::input_asm_operand::print): New.
(gcc::jit::recording::extended_asm::add_output_operand): New.
(gcc::jit::recording::extended_asm::add_input_operand): New.
(gcc::jit::recording::extended_asm::add_clobber): New.
(gcc::jit::recording::extended_asm::replay_into): New.
(gcc::jit::recording::extended_asm::make_debug_string): New.
(gcc::jit::recording::extended_asm::write_flags): New.
(gcc::jit::recording::extended_asm::write_clobbers): New.
(gcc::jit::recording::extended_asm_simple::write_reproducer): New.
(gcc::jit::recording::extended_asm::maybe_populate_playback_blocks):
New.
(gcc::jit::recording::extended_asm_goto::extended_asm_goto): New.
(gcc::jit::recording::extended_asm_goto::replay_into): New.
(gcc::jit::recording::extended_asm_goto::write_reproducer): New.
(gcc::jit::recording::extended_asm_goto::get_successor_blocks):
New.
(gcc::jit::recording::extended_asm_goto::maybe_print_gotos): New.
(gcc::jit::recording::extended_asm_goto::maybe_populate_playback_blocks):
New.
(gcc::jit::recording::top_level_asm::top_level_asm): New.
(gcc::jit::recording::top_level_asm::replay_into): New.
(gcc::jit::recording::top_level_asm::make_debug_string): New.
(gcc::jit::recording::top_level_asm::write_to_dump): New.
(gcc::jit::recording::top_level_asm::write_reproducer): New.
* jit-recording.h
(gcc::jit::recording::context::add_top_level_asm): New decl.
(gcc::jit::recording::context::m_top_level_asms): New field.
(gcc::jit::recording::block::add_extended_asm): New decl.
(gcc::jit::recording::block::end_with_extended_asm_goto): New
decl.
(gcc::jit::recording::asm_operand): New class.
(gcc::jit::recording::output_asm_operand): New class.
(gcc::jit::recording::input_asm_operand): New class.
(gcc::jit::recording::extended_asm): New class.
(gcc::jit::recording::extended_asm_simple): New class.
(gcc::jit::recording::extended_asm_goto): New class.
(gcc::jit::recording::top_level_asm): New class.
* libgccjit++.h (gccjit::extended_asm): New forward decl.
(gccjit::context::add_top_level_asm): New.
(gccjit::block::add_extended_asm): New.
(gccjit::block::end_with_extended_asm_goto): New.
(gccjit::extended_asm): New class.
(gccjit::extended_asm::extended_asm): New ctors.
(gccjit::extended_asm::set_volatile_flag): New.
(gccjit::extended_asm::set_inline_flag): New.
(gccjit::extended_asm::add_output_operand): New.
(gccjit::extended_asm::add_input_operand): New.
(gccjit::extended_asm::add_clobber): New.
(gccjit::extended_asm::get_inner_extended_asm): New.
* libgccjit.c (struct gcc_jit_extended_asm): New.
(jit_error): Make "loc" param take a gcc::jit::recording::location *
rather than a gcc_jit_location *.
(gcc_jit_block_add_extended_asm): New entrypoint.
(gcc_jit_block_end_with_extended_asm_goto): New entrypoint.
(gcc_jit_extended_asm_as_object): New entrypoint.
(gcc_jit_extended_asm_set_volatile_flag): New entrypoint.
(gcc_jit_extended_asm_set_inline_flag): New entrypoint.
(gcc_jit_extended_asm_add_output_operand): New entrypoint.
(gcc_jit_extended_asm_add_clobber): New entrypoint.
(gcc_jit_context_add_top_level_asm): New entrypoint.
* libgccjit.h: Add gcc_jit_extended_asm to ASCII art.
(gcc_jit_extended_asm): New typedef.
(LIBGCCJIT_HAVE_ASM_STATEMENTS): New define.
(gcc_jit_block_add_extended_asm): New entrypoint.
(gcc_jit_block_end_with_extended_asm_goto): New entrypoint.
(gcc_jit_extended_asm_as_object): New entrypoint.
(gcc_jit_extended_asm_set_volatile_flag): New entrypoint.
(gcc_jit_extended_asm_set_inline_flag): New entrypoint.
(gcc_jit_extended_asm_add_output_operand): New entrypoint.
(gcc_jit_extended_asm_add_input_operand): New entrypoint.
(gcc_jit_extended_asm_add_clobber): New entrypoint.
(gcc_jit_context_add_top_level_asm): New entrypoint.
* libgccjit.map (LIBGCCJIT_ABI_15): New.
gcc/testsuite/ChangeLog:
PR jit/87291
* jit.dg/jit.exp: Load target-supports-dg.exp.
Set dg-do-what-default.
(jit-dg-test): Set dg-do-what and call dg-get-options, skipping
the test if it's not supported on the given target.
* jit.dg/test-asm.c: New test.
* jit.dg/test-asm.cc: New test.
---
gcc/jit/docs/cp/topics/asm.rst | 308 +++++++++++++++
gcc/jit/docs/cp/topics/index.rst | 1 +
gcc/jit/docs/topics/asm.rst | 311 ++++++++++++++++
gcc/jit/docs/topics/compatibility.rst | 17 +
gcc/jit/docs/topics/functions.rst | 3 +
gcc/jit/docs/topics/index.rst | 1 +
gcc/jit/docs/topics/objects.rst | 1 +
gcc/jit/jit-common.h | 2 +
gcc/jit/jit-playback.c | 125 ++++++-
gcc/jit/jit-playback.h | 27 ++
gcc/jit/jit-recording.c | 514 ++++++++++++++++++++++++++
gcc/jit/jit-recording.h | 215 +++++++++++
gcc/jit/libgccjit++.h | 170 +++++++++
gcc/jit/libgccjit.c | 188 +++++++++-
gcc/jit/libgccjit.h | 103 ++++++
gcc/jit/libgccjit.map | 13 +
gcc/testsuite/jit.dg/jit.exp | 31 ++
gcc/testsuite/jit.dg/test-asm.c | 492 ++++++++++++++++++++++++
gcc/testsuite/jit.dg/test-asm.cc | 453 +++++++++++++++++++++++
19 files changed, 2972 insertions(+), 3 deletions(-)
create mode 100644 gcc/jit/docs/cp/topics/asm.rst
create mode 100644 gcc/jit/docs/topics/asm.rst
create mode 100644 gcc/testsuite/jit.dg/test-asm.c
create mode 100644 gcc/testsuite/jit.dg/test-asm.cc
diff --git a/gcc/jit/docs/cp/topics/asm.rst b/gcc/jit/docs/cp/topics/asm.rst
new file mode 100644
index 00000000000..69e2d1e8da7
--- /dev/null
+++ b/gcc/jit/docs/cp/topics/asm.rst
@@ -0,0 +1,308 @@
+.. Copyright (C) 2020 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
+ <http://www.gnu.org/licenses/>.
+
+.. 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 <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
+***********************************************
+
+.. 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<block> 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 <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.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 <https://gcc.gnu.org/onlinedocs/gcc/Size-of-an-asm.html#Size-of-an-asm>`_
+ 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 <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, 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 <https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#GotoLabels>`_
+ 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 <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. 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 <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++
+
+ 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
diff --git a/gcc/jit/docs/cp/topics/index.rst b/gcc/jit/docs/cp/topics/index.rst
index 187a20d03b3..721e70cfa1b 100644
--- a/gcc/jit/docs/cp/topics/index.rst
+++ b/gcc/jit/docs/cp/topics/index.rst
@@ -28,3 +28,4 @@ Topic Reference
functions.rst
locations.rst
compilation.rst
+ asm.rst
diff --git a/gcc/jit/docs/topics/asm.rst b/gcc/jit/docs/topics/asm.rst
new file mode 100644
index 00000000000..b91514d4140
--- /dev/null
+++ b/gcc/jit/docs/topics/asm.rst
@@ -0,0 +1,311 @@
+.. Copyright (C) 2020 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
+ <http://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
diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index 6bfa101ed71..b953da590f1 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -226,3 +226,20 @@ entrypoints:
--------------------
``LIBGCCJIT_ABI_14`` covers the addition of
:func:`gcc_jit_global_set_initializer`
+
+.. _LIBGCCJIT_ABI_15:
+
+``LIBGCCJIT_ABI_15``
+-----------------------
+``LIBGCCJIT_ABI_15`` covers the addition of API entrypoints for directly
+embedding assembler instructions:
+
+ * :func:`gcc_jit_block_add_extended_asm`
+ * :func:`gcc_jit_block_end_with_extended_asm_goto`
+ * :func:`gcc_jit_extended_asm_as_object`
+ * :func:`gcc_jit_extended_asm_set_volatile_flag`
+ * :func:`gcc_jit_extended_asm_set_inline_flag`
+ * :func:`gcc_jit_extended_asm_add_output_operand`
+ * :func:`gcc_jit_extended_asm_add_input_operand`
+ * :func:`gcc_jit_extended_asm_add_clobber`
+ * :func:`gcc_jit_context_add_top_level_asm`
diff --git a/gcc/jit/docs/topics/functions.rst b/gcc/jit/docs/topics/functions.rst
index eb40d64010e..b869256a1cd 100644
--- a/gcc/jit/docs/topics/functions.rst
+++ b/gcc/jit/docs/topics/functions.rst
@@ -458,3 +458,6 @@ Statements
:start-after: /* Quote from here in docs/topics/functions.rst. */
:end-before: /* Quote up to here in docs/topics/functions.rst. */
:language: c
+
+See also :type:`gcc_jit_extended_asm` for entrypoints for adding inline
+assembler statements to a function.
diff --git a/gcc/jit/docs/topics/index.rst b/gcc/jit/docs/topics/index.rst
index 8352ca25818..d7cb86aa0d8 100644
--- a/gcc/jit/docs/topics/index.rst
+++ b/gcc/jit/docs/topics/index.rst
@@ -31,3 +31,4 @@ Topic Reference
compilation.rst
compatibility.rst
performance.rst
+ asm.rst
diff --git a/gcc/jit/docs/topics/objects.rst b/gcc/jit/docs/topics/objects.rst
index 12d3c9f7987..cdee2c0af6a 100644
--- a/gcc/jit/docs/topics/objects.rst
+++ b/gcc/jit/docs/topics/objects.rst
@@ -48,6 +48,7 @@ looks like this::
+- gcc_jit_lvalue
+- gcc_jit_param
+- gcc_jit_case
+ +- gcc_jit_extended_asm
There are casting methods for upcasting from subclasses to parent classes.
For example, :c:func:`gcc_jit_type_as_object`:
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index 4570bd2d717..b8c3685c073 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -131,7 +131,9 @@ namespace recording {
class base_call;
class function_pointer;
class statement;
+ class extended_asm;
class case_;
+ class top_level_asm;
/* End of recording types. */
}
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 4fac64dcab7..5bccf591a3f 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see
#include "opt-suggestions.h"
#include "gcc.h"
#include "diagnostic.h"
+#include "stmt.h"
#include <pthread.h>
@@ -86,6 +87,18 @@ namespace jit {
Playback.
**********************************************************************/
+/* Build a STRING_CST tree for STR, or return NULL if it is NULL.
+ The TREE_TYPE is not initialized. */
+
+static tree
+build_string (const char *str)
+{
+ if (str)
+ return ::build_string (strlen (str), str);
+ else
+ return NULL_TREE;
+}
+
/* The constructor for gcc::jit::playback::context. */
playback::context::context (recording::context *ctxt)
@@ -774,7 +787,7 @@ new_string_literal (const char *value)
tree a_type = build_array_type (char_type_node, i_type);
/* build_string len parameter must include NUL terminator when
building C strings. */
- tree t_str = build_string (len + 1, value);
+ tree t_str = ::build_string (len + 1, value);
TREE_TYPE (t_str) = a_type;
/* Convert to (const char*), loosely based on
@@ -821,6 +834,18 @@ as_truth_value (tree expr, location *loc)
return expr;
}
+/* Add a "top-level" basic asm statement (i.e. one outside of any functions)
+ containing ASM_STMTS.
+
+ Compare with c_parser_asm_definition. */
+
+void
+playback::context::add_top_level_asm (const char *asm_stmts)
+{
+ tree asm_str = build_string (asm_stmts);
+ symtab->finalize_toplevel_asm (asm_str);
+}
+
/* Construct a playback::rvalue instance (wrapping a tree) for a
unary op. */
@@ -1897,6 +1922,104 @@ add_switch (location *loc,
add_stmt (switch_stmt);
}
+/* Convert OPERANDS to a tree-based chain suitable for creating an
+ extended asm stmt.
+ Compare with c_parser_asm_operands. */
+
+static tree
+build_operand_chain (const auto_vec <playback::asm_operand> *operands)
+{
+ tree result = NULL_TREE;
+ unsigned i;
+ playback::asm_operand *asm_op;
+ FOR_EACH_VEC_ELT (*operands, i, asm_op)
+ {
+ tree name = build_string (asm_op->m_asm_symbolic_name);
+ tree str = build_string (asm_op->m_constraint);
+ tree value = asm_op->m_expr;
+ result = chainon (result,
+ build_tree_list (build_tree_list (name, str),
+ value));
+ }
+ return result;
+}
+
+/* Convert CLOBBERS to a tree-based list suitable for creating an
+ extended asm stmt.
+ Compare with c_parser_asm_clobbers. */
+
+static tree
+build_clobbers (const auto_vec <const char *> *clobbers)
+{
+ tree list = NULL_TREE;
+ unsigned i;
+ const char *clobber;
+ FOR_EACH_VEC_ELT (*clobbers, i, clobber)
+ {
+ tree str = build_string (clobber);
+ list = tree_cons (NULL_TREE, str, list);
+ }
+ return list;
+}
+
+/* Convert BLOCKS to a tree-based list suitable for creating an
+ extended asm stmt.
+ Compare with c_parser_asm_goto_operands. */
+
+static tree
+build_goto_operands (const auto_vec <playback::block *> *blocks)
+{
+ tree list = NULL_TREE;
+ unsigned i;
+ playback::block *b;
+ FOR_EACH_VEC_ELT (*blocks, i, b)
+ {
+ tree label = b->as_label_decl ();
+ tree name = build_string (IDENTIFIER_POINTER (DECL_NAME (label)));
+ TREE_USED (label) = 1;
+ list = tree_cons (name, label, list);
+ }
+ return nreverse (list);
+}
+
+/* Add an extended asm statement to this block.
+
+ Compare with c_parser_asm_statement (in c/c-parser.c)
+ and build_asm_expr (in c/c-typeck.c). */
+
+void
+playback::block::add_extended_asm (location *loc,
+ const char *asm_template,
+ bool is_volatile,
+ bool is_inline,
+ const auto_vec <asm_operand> *outputs,
+ const auto_vec <asm_operand> *inputs,
+ const auto_vec <const char *> *clobbers,
+ const auto_vec <block *> *goto_blocks)
+{
+ tree t_string = build_string (asm_template);
+ tree t_outputs = build_operand_chain (outputs);
+ tree t_inputs = build_operand_chain (inputs);
+ tree t_clobbers = build_clobbers (clobbers);
+ tree t_labels = build_goto_operands (goto_blocks);
+ t_string
+ = resolve_asm_operand_names (t_string, t_outputs, t_inputs, t_labels);
+ tree asm_stmt
+ = build5 (ASM_EXPR, void_type_node,
+ t_string, t_outputs, t_inputs, t_clobbers, t_labels);
+
+ /* asm statements without outputs, including simple ones, are treated
+ as volatile. */
+ ASM_VOLATILE_P (asm_stmt) = (outputs->length () == 0);
+ ASM_INPUT_P (asm_stmt) = 0; /* extended asm stmts are not "simple". */
+ ASM_INLINE_P (asm_stmt) = is_inline;
+ if (is_volatile)
+ ASM_VOLATILE_P (asm_stmt) = 1;
+ if (loc)
+ set_tree_location (asm_stmt, loc);
+ add_stmt (asm_stmt);
+}
+
/* Constructor for gcc::jit::playback::block. */
playback::block::
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 50b69753bb4..ff1f778d026 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -252,6 +252,8 @@ public:
timer *get_timer () const { return m_recording_ctxt->get_timer (); }
+ void add_top_level_asm (const char *asm_stmts);
+
private:
void dump_generated_code ();
@@ -514,6 +516,21 @@ struct case_
block *m_dest_block;
};
+struct asm_operand
+{
+ asm_operand (const char *asm_symbolic_name,
+ const char *constraint,
+ tree expr)
+ : m_asm_symbolic_name (asm_symbolic_name),
+ m_constraint (constraint),
+ m_expr (expr)
+ {}
+
+ const char *m_asm_symbolic_name;
+ const char *m_constraint;
+ tree m_expr;
+};
+
class block : public wrapper
{
public:
@@ -563,6 +580,16 @@ public:
block *default_block,
const auto_vec <case_> *cases);
+ void
+ add_extended_asm (location *loc,
+ const char *asm_template,
+ bool is_volatile,
+ bool is_inline,
+ const auto_vec <asm_operand> *outputs,
+ const auto_vec <asm_operand> *inputs,
+ const auto_vec <const char *> *clobbers,
+ const auto_vec <block *> *goto_blocks);
+
private:
void
set_tree_location (tree t, location *loc)
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 3a84c1fc5c0..1b0f8bc7db3 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -1578,6 +1578,10 @@ recording::context::dump_to_file (const char *path, bool update_locations)
{
fn->write_to_dump (d);
}
+
+ top_level_asm *tla;
+ FOR_EACH_VEC_ELT (m_top_level_asms, i, tla)
+ tla->write_to_dump (d);
}
static const char * const
@@ -1904,6 +1908,22 @@ recording::context::get_all_requested_dumps (vec <recording::requested_dump> *ou
out->splice (m_requested_dumps);
}
+/* Create a recording::top_level_asm instance and add it to this
+ context's list of mementos and to m_top_level_asms.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_add_top_level_asm. */
+
+void
+recording::context::add_top_level_asm (recording::location *loc,
+ const char *asm_stmts)
+{
+ recording::top_level_asm *asm_obj
+ = new recording::top_level_asm (this, loc, new_string (asm_stmts));
+ record (asm_obj);
+ m_top_level_asms.safe_push (asm_obj);
+}
+
/* This is a pre-compilation check for the context (and any parents).
Detect errors within the context, adding errors if any are found. */
@@ -4206,6 +4226,23 @@ recording::block::add_comment (recording::location *loc,
return result;
}
+/* Create a recording::extended_asm_simple instance and add it to
+ the block's context's list of mementos, and to the block's
+ list of statements.
+
+ Implements the heart of gcc_jit_block_add_extended_asm. */
+
+recording::extended_asm *
+recording::block::add_extended_asm (location *loc,
+ const char *asm_template)
+{
+ extended_asm *result
+ = new extended_asm_simple (this, loc, new_string (asm_template));
+ m_ctxt->record (result);
+ m_statements.safe_push (result);
+ return result;
+}
+
/* Create a recording::end_with_conditional instance and add it to
the block's context's list of mementos, and to the block's
list of statements.
@@ -4288,6 +4325,30 @@ recording::block::end_with_switch (recording::location *loc,
return result;
}
+/* Create a recording::extended_asm_goto instance and add it to
+ the block's context's list of mementos, and to the block's
+ list of statements.
+
+ Implements the heart of gcc_jit_block_end_with_extended_asm_goto. */
+
+
+recording::extended_asm *
+recording::block::end_with_extended_asm_goto (location *loc,
+ const char *asm_template,
+ int num_goto_blocks,
+ block **goto_blocks,
+ block *fallthrough_block)
+{
+ extended_asm *result
+ = new extended_asm_goto (this, loc, new_string (asm_template),
+ num_goto_blocks, goto_blocks,
+ fallthrough_block);
+ m_ctxt->record (result);
+ m_statements.safe_push (result);
+ m_has_been_terminated = true;
+ return result;
+}
+
/* Override the default implementation of
recording::memento::write_to_dump for blocks by writing
an unindented block name as a label, followed by the indented
@@ -6508,6 +6569,459 @@ recording::switch_::write_reproducer (reproducer &r)
cases_id);
}
+/* class asm_operand : public memento. */
+
+recording::asm_operand::asm_operand (extended_asm *ext_asm,
+ string *asm_symbolic_name,
+ string *constraint)
+: memento (ext_asm->get_context ()),
+ m_ext_asm (ext_asm),
+ m_asm_symbolic_name (asm_symbolic_name),
+ m_constraint (constraint)
+{
+}
+
+void
+recording::asm_operand::print (pretty_printer *pp) const
+{
+ if (m_asm_symbolic_name)
+ {
+ pp_character (pp, '[');
+ pp_string (pp, m_asm_symbolic_name->c_str ());
+ pp_character (pp, ']');
+ pp_space (pp);
+ }
+ pp_string (pp, m_constraint->get_debug_string ());
+ /* Subclass will add lvalue/rvalue. */
+}
+
+recording::string *
+recording::asm_operand::make_debug_string ()
+{
+ pretty_printer pp;
+ print (&pp);
+ return m_ctxt->new_string (pp_formatted_text (&pp), false);
+}
+
+/* class output_asm_operand : public asm_operand. */
+
+void
+recording::output_asm_operand::write_reproducer (reproducer &r)
+{
+ const char *fmt =
+ " gcc_jit_extended_asm_add_output_operand (%s, /* gcc_jit_extended_asm *ext_asm */\n"
+ " %s, /* const char *asm_symbolic_name */\n"
+ " %s, /* const char *constraint */\n"
+ " %s); /* gcc_jit_lvalue *dest */\n";
+ r.write (fmt,
+ r.get_identifier (m_ext_asm),
+ (m_asm_symbolic_name
+ ? m_asm_symbolic_name->get_debug_string () : "NULL"),
+ m_constraint->get_debug_string (),
+ r.get_identifier (m_dest));
+}
+
+void
+recording::output_asm_operand::print (pretty_printer *pp) const
+{
+ asm_operand::print (pp);
+ pp_string (pp, " (");
+ pp_string (pp, m_dest->get_debug_string ());
+ pp_string (pp, ")");
+}
+
+/* class input_asm_operand : public asm_operand. */
+
+void
+recording::input_asm_operand::write_reproducer (reproducer &r)
+{
+ const char *fmt =
+ " gcc_jit_extended_asm_add_input_operand (%s, /* gcc_jit_extended_asm *ext_asm */\n"
+ " %s, /* const char *asm_symbolic_name */\n"
+ " %s, /* const char *constraint */\n"
+ " %s); /* gcc_jit_rvalue *src */\n";
+ r.write (fmt,
+ r.get_identifier (m_ext_asm),
+ (m_asm_symbolic_name
+ ? m_asm_symbolic_name->get_debug_string () : "NULL"),
+ m_constraint->get_debug_string (),
+ r.get_identifier_as_rvalue (m_src));
+}
+
+void
+recording::input_asm_operand::print (pretty_printer *pp) const
+{
+ asm_operand::print (pp);
+ pp_string (pp, " (");
+ pp_string (pp, m_src->get_debug_string ());
+ pp_string (pp, ")");
+}
+
+/* The implementation of class gcc::jit::recording::extended_asm. */
+
+void
+recording::extended_asm::add_output_operand (const char *asm_symbolic_name,
+ const char *constraint,
+ lvalue *dest)
+{
+ output_asm_operand *op
+ = new output_asm_operand (this,
+ new_string (asm_symbolic_name),
+ new_string (constraint),
+ dest);
+ m_ctxt->record (op);
+ m_output_ops.safe_push (op);
+}
+
+void
+recording::extended_asm::add_input_operand (const char *asm_symbolic_name,
+ const char *constraint,
+ rvalue *src)
+{
+ input_asm_operand *op
+ = new input_asm_operand (this,
+ new_string (asm_symbolic_name),
+ new_string (constraint),
+ src);
+ m_ctxt->record (op);
+ m_input_ops.safe_push (op);
+}
+
+void
+recording::extended_asm::add_clobber (const char *victim)
+{
+ m_clobbers.safe_push (new_string (victim));
+}
+
+/* Implementation of recording::memento::replay_into
+ for recording::extended_asm. */
+
+void
+recording::extended_asm::replay_into (replayer *r)
+{
+ auto_vec<playback::asm_operand> playback_output_ops;
+ auto_vec<playback::asm_operand> playback_input_ops;
+ auto_vec<const char *> playback_clobbers;
+ auto_vec<playback::block *> playback_goto_blocks;
+
+ /* Populate outputs. */
+ {
+ output_asm_operand *rec_asm_op;
+ unsigned i;
+ FOR_EACH_VEC_ELT (m_output_ops, i, rec_asm_op)
+ {
+ playback::asm_operand playback_asm_op
+ (rec_asm_op->get_symbolic_name (),
+ rec_asm_op->get_constraint (),
+ rec_asm_op->get_lvalue ()->playback_lvalue ()->as_tree ());
+ playback_output_ops.safe_push (playback_asm_op);
+ }
+ }
+
+ /* Populate inputs. */
+ {
+ input_asm_operand *rec_asm_op;
+ unsigned i;
+ FOR_EACH_VEC_ELT (m_input_ops, i, rec_asm_op)
+ {
+ playback::asm_operand playback_asm_op
+ (rec_asm_op->get_symbolic_name (),
+ rec_asm_op->get_constraint (),
+ rec_asm_op->get_rvalue ()->playback_rvalue ()->as_tree ());
+ playback_input_ops.safe_push (playback_asm_op);
+ }
+ }
+
+ /* Populate clobbers. */
+ {
+ string *rec_clobber;
+ unsigned i;
+ FOR_EACH_VEC_ELT (m_clobbers, i, rec_clobber)
+ playback_clobbers.safe_push (rec_clobber->c_str ());
+ }
+
+ /* Populate playback blocks if an "asm goto". */
+ maybe_populate_playback_blocks (&playback_goto_blocks);
+
+ playback_block (get_block ())
+ ->add_extended_asm (playback_location (r),
+ m_asm_template->c_str (),
+ m_is_volatile, m_is_inline,
+ &playback_output_ops,
+ &playback_input_ops,
+ &playback_clobbers,
+ &playback_goto_blocks);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ an extended_asm "statement". */
+
+recording::string *
+recording::extended_asm::make_debug_string ()
+{
+ pretty_printer pp;
+ pp_string (&pp, "asm ");
+ if (m_is_volatile)
+ pp_string (&pp, "volatile ");
+ if (m_is_inline)
+ pp_string (&pp, "inline ");
+ if (is_goto ())
+ pp_string (&pp, "goto ");
+ pp_character (&pp, '(');
+ pp_string (&pp, m_asm_template->get_debug_string ());
+ pp_string (&pp, " : ");
+ unsigned i;
+ {
+ output_asm_operand *asm_op;
+ FOR_EACH_VEC_ELT (m_output_ops, i, asm_op)
+ {
+ if (i > 0)
+ pp_string (&pp, ", ");
+ asm_op->print (&pp);
+ }
+ }
+ pp_string (&pp, " : ");
+ {
+ input_asm_operand *asm_op;
+ FOR_EACH_VEC_ELT (m_input_ops, i, asm_op)
+ {
+ if (i > 0)
+ pp_string (&pp, ", ");
+ asm_op->print (&pp);
+ }
+ }
+ pp_string (&pp, " : ");
+ string *rec_clobber;
+ FOR_EACH_VEC_ELT (m_clobbers, i, rec_clobber)
+ {
+ if (i > 0)
+ pp_string (&pp, ", ");
+ pp_string (&pp, rec_clobber->get_debug_string ());
+ }
+ maybe_print_gotos (&pp);
+ pp_character (&pp, ')');
+ return new_string (pp_formatted_text (&pp));
+}
+
+void
+recording::extended_asm::write_flags (reproducer &r)
+{
+ if (m_is_volatile)
+ r.write (" gcc_jit_extended_asm_set_volatile_flag (%s, 1);\n",
+ r.get_identifier (this));
+ if (m_is_inline)
+ r.write (" gcc_jit_extended_asm_set_inline_flag (%s, 1);\n",
+ r.get_identifier (this));
+}
+
+void
+recording::extended_asm::write_clobbers (reproducer &r)
+{
+ string *clobber;
+ unsigned i;
+ FOR_EACH_VEC_ELT (m_clobbers, i, clobber)
+ r.write (" gcc_jit_extended_asm_add_clobber (%s, %s);\n",
+ r.get_identifier (this),
+ clobber->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ extended_asm_simple. */
+
+void
+recording::extended_asm_simple::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "extended_asm");
+ r.write (" gcc_jit_extended_asm *%s =\n"
+ " gcc_jit_block_add_extended_asm (%s, /*gcc_jit_block *block */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s); /* const char *asm_template */\n",
+ id,
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()),
+ m_asm_template->get_debug_string ());
+ write_flags (r);
+ write_clobbers (r);
+}
+
+void
+recording::extended_asm::
+maybe_populate_playback_blocks (auto_vec <playback::block *> *)
+{
+ /* Do nothing; not an "asm goto". */
+}
+
+/* The implementation of class gcc::jit::recording::extended_asm_goto. */
+
+/* recording::extended_asm_goto's ctor. */
+
+recording::extended_asm_goto::extended_asm_goto (block *b,
+ location *loc,
+ string *asm_template,
+ int num_goto_blocks,
+ block **goto_blocks,
+ block *fallthrough_block)
+: extended_asm (b, loc, asm_template),
+ m_goto_blocks (num_goto_blocks),
+ m_fallthrough_block (fallthrough_block)
+{
+ for (int i = 0; i < num_goto_blocks; i++)
+ m_goto_blocks.quick_push (goto_blocks[i]);
+}
+
+/* Implementation of recording::memento::replay_into
+ for recording::extended_asm_goto. */
+
+void
+recording::extended_asm_goto::replay_into (replayer *r)
+{
+ /* Chain up to base class impl. */
+ recording::extended_asm::replay_into (r);
+
+ /* ...and potentially add a goto for the fallthrough. */
+ if (m_fallthrough_block)
+ playback_block (get_block ())
+ ->add_jump (playback_location (r),
+ m_fallthrough_block->playback_block ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ extended_asm_goto. */
+
+void
+recording::extended_asm_goto::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "extended_asm");
+ const char *blocks_id = r.make_tmp_identifier ("blocks_for", this);
+ r.write (" gcc_jit_block *%s[%i] = {\n",
+ blocks_id,
+ m_goto_blocks.length ());
+ int i;
+ block *b;
+ FOR_EACH_VEC_ELT (m_goto_blocks, i, b)
+ r.write (" %s,\n", r.get_identifier (b));
+ r.write (" };\n");
+ r.write (" gcc_jit_extended_asm *%s =\n"
+ " gcc_jit_block_end_with_extended_asm_goto (%s, /*gcc_jit_block *block */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* const char *asm_template */\n"
+ " %i, /* int num_goto_blocks */\n"
+ " %s, /* gcc_jit_block **goto_blocks */\n"
+ " %s); /* gcc_jit_block *fallthrough_block */\n",
+ id,
+ r.get_identifier (get_block ()),
+ r.get_identifier (get_loc ()),
+ m_asm_template->get_debug_string (),
+ m_goto_blocks.length (),
+ blocks_id,
+ (m_fallthrough_block
+ ? r.get_identifier (m_fallthrough_block)
+ : "NULL"));
+ write_flags (r);
+ write_clobbers (r);
+}
+
+/* Override the poisoned default implementation of
+ gcc::jit::recording::statement::get_successor_blocks
+
+ An extended_asm_goto can jump to the m_goto_blocks, and to
+ the (optional) m_fallthrough_block. */
+
+vec <recording::block *>
+recording::extended_asm_goto::get_successor_blocks () const
+{
+ vec <block *> result;
+ result.create (m_goto_blocks.length () + 1);
+ if (m_fallthrough_block)
+ result.quick_push (m_fallthrough_block);
+ result.splice (m_goto_blocks);
+ return result;
+}
+
+/* Vfunc for use by recording::extended_asm::make_debug_string. */
+
+void
+recording::extended_asm_goto::maybe_print_gotos (pretty_printer *pp) const
+{
+ pp_string (pp, " : ");
+ unsigned i;
+ block *b;
+ FOR_EACH_VEC_ELT (m_goto_blocks, i, b)
+ {
+ if (i > 0)
+ pp_string (pp, ", ");
+ pp_string (pp, b->get_debug_string ());
+ }
+ /* Non-C syntax here. */
+ if (m_fallthrough_block)
+ pp_printf (pp, " [fallthrough: %s]",
+ m_fallthrough_block->get_debug_string ());
+}
+
+/* Vfunc for use by recording::extended_asm::replay_into. */
+
+void
+recording::extended_asm_goto::
+maybe_populate_playback_blocks (auto_vec <playback::block *> *out)
+{
+ unsigned i;
+ block *b;
+ FOR_EACH_VEC_ELT (m_goto_blocks, i, b)
+ out->safe_push (b->playback_block ());
+}
+
+/* class top_level_asm : public memento. */
+
+recording::top_level_asm::top_level_asm (context *ctxt,
+ location *loc,
+ string *asm_stmts)
+: memento (ctxt),
+ m_loc (loc),
+ m_asm_stmts (asm_stmts)
+{
+}
+
+/* Implementation of recording::memento::replay_into for top-level asm. */
+
+void
+recording::top_level_asm::replay_into (replayer *r)
+{
+ r->add_top_level_asm (m_asm_stmts->c_str ());
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ top-level asm. */
+
+recording::string *
+recording::top_level_asm::make_debug_string ()
+{
+ return string::from_printf (m_ctxt, "asm (%s)",
+ m_asm_stmts->get_debug_string ());
+}
+
+/* Override the default implementation of
+ recording::memento::write_to_dump.
+ Don't indent the string. */
+
+void
+recording::top_level_asm::write_to_dump (dump &d)
+{
+ d.write ("%s;\n", get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for top-level asm. */
+
+void
+recording::top_level_asm::write_reproducer (reproducer &r)
+{
+ r.write (" gcc_jit_context_add_top_level_asm (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s); /* const char *asm_stmts */\n",
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ m_asm_stmts->get_debug_string ());
+}
+
} // namespace gcc::jit
} // namespace gcc
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 9a43a7bf33a..e6948828d2a 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -301,6 +301,8 @@ public:
void set_timer (timer *t) { m_timer = t; }
timer *get_timer () const { return m_timer; }
+ void add_top_level_asm (location *loc, const char *asm_stmts);
+
private:
void log_all_options () const;
void log_str_option (enum gcc_jit_str_option opt) const;
@@ -344,6 +346,7 @@ private:
auto_vec<compound_type *> m_compound_types;
auto_vec<global *> m_globals;
auto_vec<function *> m_functions;
+ auto_vec<top_level_asm *> m_top_level_asms;
type *m_basic_types[NUM_GCC_JIT_TYPES];
type *m_FILE_type;
@@ -1275,6 +1278,10 @@ public:
add_comment (location *loc,
const char *text);
+ extended_asm *
+ add_extended_asm (location *loc,
+ const char *asm_template);
+
statement *
end_with_conditional (location *loc,
rvalue *boolval,
@@ -1296,6 +1303,13 @@ public:
int num_cases,
case_ **cases);
+ extended_asm *
+ end_with_extended_asm_goto (location *loc,
+ const char *asm_template,
+ int num_goto_blocks,
+ block **goto_blocks,
+ block *fallthrough_block);
+
playback::block *
playback_block () const
{
@@ -2112,6 +2126,207 @@ private:
auto_vec <case_ *> m_cases;
};
+class asm_operand : public memento
+{
+public:
+ asm_operand (extended_asm *ext_asm,
+ string *asm_symbolic_name,
+ string *constraint);
+
+ const char *get_symbolic_name () const
+ {
+ if (m_asm_symbolic_name)
+ return m_asm_symbolic_name->c_str ();
+ else
+ return NULL;
+ }
+
+ const char *get_constraint () const
+ {
+ return m_constraint->c_str ();
+ }
+
+ virtual void print (pretty_printer *pp) const;
+
+private:
+ string * make_debug_string () FINAL OVERRIDE;
+
+protected:
+ extended_asm *m_ext_asm;
+ string *m_asm_symbolic_name;
+ string *m_constraint;
+};
+
+class output_asm_operand : public asm_operand
+{
+public:
+ output_asm_operand (extended_asm *ext_asm,
+ string *asm_symbolic_name,
+ string *constraint,
+ lvalue *dest)
+ : asm_operand (ext_asm, asm_symbolic_name, constraint),
+ m_dest (dest)
+ {}
+
+ lvalue *get_lvalue () const { return m_dest; }
+
+ void replay_into (replayer *) FINAL OVERRIDE {}
+
+ void print (pretty_printer *pp) const FINAL OVERRIDE;
+
+private:
+ void write_reproducer (reproducer &r) FINAL OVERRIDE;
+
+private:
+ lvalue *m_dest;
+};
+
+class input_asm_operand : public asm_operand
+{
+public:
+ input_asm_operand (extended_asm *ext_asm,
+ string *asm_symbolic_name,
+ string *constraint,
+ rvalue *src)
+ : asm_operand (ext_asm, asm_symbolic_name, constraint),
+ m_src (src)
+ {}
+
+ rvalue *get_rvalue () const { return m_src; }
+
+ void replay_into (replayer *) FINAL OVERRIDE {}
+
+ void print (pretty_printer *pp) const FINAL OVERRIDE;
+
+private:
+ void write_reproducer (reproducer &r) FINAL OVERRIDE;
+
+private:
+ rvalue *m_src;
+};
+
+/* Abstract base class for extended_asm statements. */
+
+class extended_asm : public statement
+{
+public:
+ extended_asm (block *b,
+ location *loc,
+ string *asm_template)
+ : statement (b, loc),
+ m_asm_template (asm_template),
+ m_is_volatile (false),
+ m_is_inline (false)
+ {}
+
+ void set_volatile_flag (bool flag) { m_is_volatile = flag; }
+ void set_inline_flag (bool flag) { m_is_inline = flag; }
+
+ void add_output_operand (const char *asm_symbolic_name,
+ const char *constraint,
+ lvalue *dest);
+ void add_input_operand (const char *asm_symbolic_name,
+ const char *constraint,
+ rvalue *src);
+ void add_clobber (const char *victim);
+
+ void replay_into (replayer *r) OVERRIDE;
+
+ string *get_asm_template () const { return m_asm_template; }
+
+ virtual bool is_goto () const = 0;
+ virtual void maybe_print_gotos (pretty_printer *) const = 0;
+
+protected:
+ void write_flags (reproducer &r);
+ void write_clobbers (reproducer &r);
+
+private:
+ string * make_debug_string () FINAL OVERRIDE;
+ virtual void maybe_populate_playback_blocks
+ (auto_vec <playback::block *> *out) = 0;
+
+protected:
+ string *m_asm_template;
+ bool m_is_volatile;
+ bool m_is_inline;
+ auto_vec<output_asm_operand *> m_output_ops;
+ auto_vec<input_asm_operand *> m_input_ops;
+ auto_vec<string *> m_clobbers;
+};
+
+/* An extended_asm that's not a goto, as created by
+ gcc_jit_block_add_extended_asm. */
+
+class extended_asm_simple : public extended_asm
+{
+public:
+ extended_asm_simple (block *b,
+ location *loc,
+ string *asm_template)
+ : extended_asm (b, loc, asm_template)
+ {}
+
+ void write_reproducer (reproducer &r) OVERRIDE;
+ bool is_goto () const FINAL OVERRIDE { return false; }
+ void maybe_print_gotos (pretty_printer *) const FINAL OVERRIDE {}
+
+private:
+ void maybe_populate_playback_blocks
+ (auto_vec <playback::block *> *) FINAL OVERRIDE
+ {}
+};
+
+/* An extended_asm that's a asm goto, as created by
+ gcc_jit_block_end_with_extended_asm_goto. */
+
+class extended_asm_goto : public extended_asm
+{
+public:
+ extended_asm_goto (block *b,
+ location *loc,
+ string *asm_template,
+ int num_goto_blocks,
+ block **goto_blocks,
+ block *fallthrough_block);
+
+ void replay_into (replayer *r) FINAL OVERRIDE;
+ void write_reproducer (reproducer &r) OVERRIDE;
+
+ vec <block *> get_successor_blocks () const FINAL OVERRIDE;
+
+ bool is_goto () const FINAL OVERRIDE { return true; }
+ void maybe_print_gotos (pretty_printer *) const FINAL OVERRIDE;
+
+private:
+ void maybe_populate_playback_blocks
+ (auto_vec <playback::block *> *out) FINAL OVERRIDE;
+
+private:
+ auto_vec <block *> m_goto_blocks;
+ block *m_fallthrough_block;
+};
+
+/* A group of top-level asm statements, as created by
+ gcc_jit_context_add_top_level_asm. */
+
+class top_level_asm : public memento
+{
+public:
+ top_level_asm (context *ctxt, location *loc, string *asm_stmts);
+
+ void write_to_dump (dump &d) FINAL OVERRIDE;
+
+private:
+ void replay_into (replayer *r) FINAL OVERRIDE;
+ string * make_debug_string () FINAL OVERRIDE;
+ void write_reproducer (reproducer &r) FINAL OVERRIDE;
+
+private:
+ location *m_loc;
+ string *m_asm_stmts;
+};
+
} // namespace gcc::jit::recording
/* Create a recording::memento_of_new_rvalue_from_const instance and add
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index 1b9ef1a5db9..b4901ceb68a 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -46,6 +46,7 @@ namespace gccjit
class lvalue;
class param;
class case_;
+ class extended_asm;
class timer;
class auto_time;
@@ -316,6 +317,9 @@ namespace gccjit
rvalue max_value,
block dest_block);
+ void add_top_level_asm (const char *asm_stmts,
+ location loc = location ());
+
private:
gcc_jit_context *m_inner_ctxt;
};
@@ -449,6 +453,13 @@ namespace gccjit
block default_block,
std::vector <case_> cases,
location loc = location ());
+
+ extended_asm add_extended_asm (const std::string &asm_template,
+ location loc = location ());
+ extended_asm end_with_extended_asm_goto (const std::string &asm_template,
+ std::vector<block> goto_blocks,
+ block *fallthrough_block,
+ location loc = location ());
};
class rvalue : public object
@@ -509,6 +520,40 @@ namespace gccjit
gcc_jit_case *get_inner_case () const;
};
+ class extended_asm : public object
+ {
+ public:
+ extended_asm ();
+ extended_asm (gcc_jit_extended_asm *inner);
+
+ extended_asm &
+ set_volatile_flag (bool flag);
+
+ extended_asm &
+ set_inline_flag (bool flag);
+
+ extended_asm&
+ add_output_operand (const std::string &asm_symbolic_name,
+ const std::string &constraint,
+ gccjit::lvalue dest);
+ extended_asm&
+ add_output_operand (const std::string &constraint,
+ gccjit::lvalue dest);
+
+ extended_asm&
+ add_input_operand (const std::string &asm_symbolic_name,
+ const std::string &constraint,
+ gccjit::rvalue src);
+ extended_asm&
+ add_input_operand (const std::string &constraint,
+ gccjit::rvalue src);
+
+ extended_asm&
+ add_clobber (const std::string &victim);
+
+ gcc_jit_extended_asm *get_inner_extended_asm () const;
+ };
+
/* Overloaded operators, for those who want the most terse API
(at the possible risk of being a little too magical).
@@ -1259,6 +1304,14 @@ context::new_case (rvalue min_value,
dest_block.get_inner_block ()));
}
+inline void
+context::add_top_level_asm (const char *asm_stmts, location loc)
+{
+ gcc_jit_context_add_top_level_asm (m_inner_ctxt,
+ loc.get_inner_location (),
+ asm_stmts);
+}
+
// class object
inline context
object::get_context () const
@@ -1554,6 +1607,37 @@ block::end_with_switch (rvalue expr,
as_array_of_ptrs);
}
+inline extended_asm
+block::add_extended_asm (const std::string &asm_template,
+ location loc)
+{
+ return gcc_jit_block_add_extended_asm (get_inner_block (),
+ loc.get_inner_location (),
+ asm_template.c_str ());
+}
+
+inline extended_asm
+block::end_with_extended_asm_goto (const std::string &asm_template,
+ std::vector<block> goto_blocks,
+ block *fallthrough_block,
+ location loc)
+{
+ /* Treat std::vector as an array, relying on it not being resized: */
+ block *as_array_of_wrappers = &goto_blocks[0];
+
+ /* Treat the array as being of the underlying pointers, relying on
+ the wrapper type being such a pointer internally. */
+ gcc_jit_block **as_array_of_ptrs =
+ reinterpret_cast<gcc_jit_block **> (as_array_of_wrappers);
+ return gcc_jit_block_end_with_extended_asm_goto
+ (get_inner_block (),
+ loc.get_inner_location (),
+ asm_template.c_str (),
+ goto_blocks.size (),
+ as_array_of_ptrs,
+ fallthrough_block ? fallthrough_block->get_inner_block () : NULL);
+}
+
inline rvalue
block::add_call (function other,
location loc)
@@ -1767,6 +1851,92 @@ case_::get_inner_case () const
return reinterpret_cast<gcc_jit_case *> (get_inner_object ());
}
+// class extended_asm : public object
+inline extended_asm::extended_asm () : object () {}
+inline extended_asm::extended_asm (gcc_jit_extended_asm *inner)
+ : object (gcc_jit_extended_asm_as_object (inner))
+{
+}
+
+inline extended_asm&
+extended_asm::set_volatile_flag (bool flag)
+{
+ gcc_jit_extended_asm_set_volatile_flag (get_inner_extended_asm (), flag);
+ return *this;
+}
+
+inline extended_asm&
+extended_asm::set_inline_flag (bool flag)
+{
+ gcc_jit_extended_asm_set_inline_flag (get_inner_extended_asm (), flag);
+ return *this;
+}
+
+inline extended_asm&
+extended_asm::add_output_operand (const std::string &asm_symbolic_name,
+ const std::string &constraint,
+ gccjit::lvalue dest)
+{
+ gcc_jit_extended_asm_add_output_operand
+ (get_inner_extended_asm (),
+ asm_symbolic_name.c_str (),
+ constraint.c_str (),
+ dest.get_inner_lvalue ());
+ return *this;
+}
+
+inline extended_asm&
+extended_asm::add_output_operand (const std::string &constraint,
+ gccjit::lvalue dest)
+{
+ gcc_jit_extended_asm_add_output_operand
+ (get_inner_extended_asm (),
+ NULL, /* asm_symbolic_name */
+ constraint.c_str (),
+ dest.get_inner_lvalue ());
+ return *this;
+}
+
+inline extended_asm&
+extended_asm::add_input_operand (const std::string &asm_symbolic_name,
+ const std::string &constraint,
+ gccjit::rvalue src)
+{
+ gcc_jit_extended_asm_add_input_operand
+ (get_inner_extended_asm (),
+ asm_symbolic_name.c_str (),
+ constraint.c_str (),
+ src.get_inner_rvalue ());
+ return *this;
+}
+
+inline extended_asm&
+extended_asm::add_input_operand (const std::string &constraint,
+ gccjit::rvalue src)
+{
+ gcc_jit_extended_asm_add_input_operand
+ (get_inner_extended_asm (),
+ NULL, /* asm_symbolic_name */
+ constraint.c_str (),
+ src.get_inner_rvalue ());
+ return *this;
+}
+
+inline extended_asm&
+extended_asm::add_clobber (const std::string &victim)
+{
+ gcc_jit_extended_asm_add_clobber (get_inner_extended_asm (),
+ victim.c_str ());
+ return *this;
+}
+
+inline gcc_jit_extended_asm *
+extended_asm::get_inner_extended_asm () const
+{
+ /* Manual downcast: */
+ return reinterpret_cast<gcc_jit_extended_asm *> (get_inner_object ());
+}
+
/* Overloaded operators. */
// Unary operators
inline rvalue operator- (rvalue a)
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index a00aefc7108..f9c33c63c64 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -96,6 +96,11 @@ struct gcc_jit_timer : public timer
{
};
+struct gcc_jit_extended_asm : public gcc::jit::recording::extended_asm
+{
+};
+
+
/**********************************************************************
Error-handling.
@@ -300,13 +305,13 @@ struct gcc_jit_timer : public timer
static void
jit_error (gcc::jit::recording::context *ctxt,
- gcc_jit_location *loc,
+ gcc::jit::recording::location *loc,
const char *fmt, ...)
GNU_PRINTF(3, 4);
static void
jit_error (gcc::jit::recording::context *ctxt,
- gcc_jit_location *loc,
+ gcc::jit::recording::location *loc,
const char *fmt, ...)
{
va_list ap;
@@ -3290,3 +3295,182 @@ gcc_jit_version_patchlevel (void)
version_info vi;
return vi.patchlevel;
}
+
+/**********************************************************************
+ Asm support.
+ **********************************************************************/
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::block::add_extended_asm, in
+ jit-recording.c. */
+
+gcc_jit_extended_asm *
+gcc_jit_block_add_extended_asm (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ const char *asm_template)
+{
+ RETURN_NULL_IF_NOT_VALID_BLOCK (block, loc);
+ gcc::jit::recording::context *ctxt = block->get_context ();
+ JIT_LOG_FUNC (ctxt->get_logger ());
+ /* LOC can be NULL. */
+ RETURN_NULL_IF_FAIL (asm_template, ctxt, loc, "NULL asm_template");
+
+ return (gcc_jit_extended_asm *)block->add_extended_asm (loc, asm_template);
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::block::end_with_extended_asm_goto, in
+ jit-recording.c. */
+
+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)
+{
+ RETURN_NULL_IF_NOT_VALID_BLOCK (block, loc);
+ gcc::jit::recording::context *ctxt = block->get_context ();
+ JIT_LOG_FUNC (ctxt->get_logger ());
+ /* LOC can be NULL. */
+ RETURN_NULL_IF_FAIL (asm_template, ctxt, loc, "NULL asm_template");
+ RETURN_NULL_IF_FAIL (num_goto_blocks >= 0, ctxt, loc, "num_goto_blocks < 0");
+ for (int i = 0; i < num_goto_blocks; i++)
+ RETURN_NULL_IF_FAIL_PRINTF1 (goto_blocks[i],
+ ctxt, loc,
+ "NULL goto_blocks[%i]", i);
+ /* fallthrough_block can be NULL. */
+ return (gcc_jit_extended_asm *)block->end_with_extended_asm_goto
+ (loc, asm_template,
+ num_goto_blocks, (gcc::jit::recording::block **)goto_blocks,
+ fallthrough_block);
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, this calls the trivial
+ gcc::jit::recording::memento::as_object method (an extended_asm is a
+ memento), in jit-recording.h. */
+
+gcc_jit_object *
+gcc_jit_extended_asm_as_object (gcc_jit_extended_asm *ext_asm)
+{
+ RETURN_NULL_IF_FAIL (ext_asm, NULL, NULL, "NULL ext_asm");
+
+ return static_cast <gcc_jit_object *> (ext_asm->as_object ());
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::extended_asm::set_volatile_flag, in
+ jit-recording.c. */
+
+void
+gcc_jit_extended_asm_set_volatile_flag (gcc_jit_extended_asm *ext_asm,
+ int flag)
+{
+ RETURN_IF_FAIL (ext_asm, NULL, NULL, "NULL ext_asm");
+ ext_asm->set_volatile_flag (flag);
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::extended_asm::set_inline_flag, in
+ jit-recording.c. */
+
+void
+gcc_jit_extended_asm_set_inline_flag (gcc_jit_extended_asm *ext_asm,
+ int flag)
+{
+ RETURN_IF_FAIL (ext_asm, NULL, NULL, "NULL ext_asm");
+ ext_asm->set_inline_flag (flag);
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::extended_asm::add_output_operand, in
+ jit-recording.c. */
+
+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)
+{
+ RETURN_IF_FAIL (ext_asm, NULL, NULL, "NULL ext_asm");
+ gcc::jit::recording::context *ctxt = ext_asm->get_context ();
+ JIT_LOG_FUNC (ctxt->get_logger ());
+ gcc::jit::recording::location *loc = ext_asm->get_loc ();
+ /* asm_symbolic_name can be NULL. */
+ RETURN_IF_FAIL (constraint, ctxt, loc, "NULL constraint");
+ RETURN_IF_FAIL (dest, ctxt, loc, "NULL dest");
+ RETURN_IF_FAIL (!ext_asm->is_goto (), ctxt, loc,
+ "cannot add output operand to asm goto");
+ ext_asm->add_output_operand (asm_symbolic_name, constraint, dest);
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::extended_asm::add_input_operand, in
+ jit-recording.c. */
+
+extern 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)
+{
+ RETURN_IF_FAIL (ext_asm, NULL, NULL, "NULL ext_asm");
+ gcc::jit::recording::context *ctxt = ext_asm->get_context ();
+ JIT_LOG_FUNC (ctxt->get_logger ());
+ gcc::jit::recording::location *loc = ext_asm->get_loc ();
+ /* asm_symbolic_name can be NULL. */
+ RETURN_IF_FAIL (constraint, ctxt, loc, "NULL constraint");
+ RETURN_IF_FAIL (src, ctxt, loc, "NULL src");
+ ext_asm->add_input_operand (asm_symbolic_name, constraint, src);
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::extended_asm::add_clobber, in
+ jit-recording.c. */
+
+void
+gcc_jit_extended_asm_add_clobber (gcc_jit_extended_asm *ext_asm,
+ const char *victim)
+{
+ RETURN_IF_FAIL (ext_asm, NULL, NULL, "NULL ext_asm");
+ gcc::jit::recording::context *ctxt = ext_asm->get_context ();
+ JIT_LOG_FUNC (ctxt->get_logger ());
+ gcc::jit::recording::location *loc = ext_asm->get_loc ();
+ RETURN_IF_FAIL (victim, ctxt, loc, "NULL victim");
+ ext_asm->add_clobber (victim);
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::context::add_top_level_asm, in
+ jit-recording.c. */
+
+void
+gcc_jit_context_add_top_level_asm (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ const char *asm_stmts)
+{
+ RETURN_IF_FAIL (ctxt, NULL, NULL, "NULL ctxt");
+ JIT_LOG_FUNC (ctxt->get_logger ());
+ /* LOC can be NULL. */
+ RETURN_IF_FAIL (asm_stmts, ctxt, NULL, "NULL asm_stmts");
+ ctxt->add_top_level_asm (loc, asm_stmts);
+}
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index 7fbaa9f3162..c523f93a821 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -68,6 +68,7 @@ typedef struct gcc_jit_result gcc_jit_result;
+- gcc_jit_lvalue
+- gcc_jit_param
+- gcc_jit_case
+ +- gcc_jit_extended_asm
*/
typedef struct gcc_jit_object gcc_jit_object;
@@ -138,6 +139,12 @@ typedef struct gcc_jit_param gcc_jit_param;
destination block. */
typedef struct gcc_jit_case gcc_jit_case;
+/* A gcc_jit_extended_asm represents an assembly language statement,
+ analogous to an extended "asm" statement in GCC's C front-end: a series
+ of low-level instructions inside a function that convert inputs to
+ outputs. */
+typedef struct gcc_jit_extended_asm gcc_jit_extended_asm;
+
/* Acquire a JIT-compilation context. */
extern gcc_jit_context *
gcc_jit_context_acquire (void);
@@ -1518,6 +1525,102 @@ gcc_jit_version_minor (void);
extern int
gcc_jit_version_patchlevel (void);
+/**********************************************************************
+ Asm support.
+ **********************************************************************/
+
+/* Functions for adding inline assembler code, analogous to GCC's
+ "extended asm" syntax.
+
+ See https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html
+
+ These API entrypoints were added in LIBGCCJIT_ABI_15; you can test for their
+ presence using
+ #ifdef LIBGCCJIT_HAVE_ASM_STATEMENTS
+*/
+
+#define LIBGCCJIT_HAVE_ASM_STATEMENTS
+
+/* Create a gcc_jit_extended_asm for an extended asm statement
+ with no control flow (i.e. without the goto qualifier).
+
+ The asm_template parameter corresponds to the AssemblerTemplate
+ within C's extended asm syntax. It must be non-NULL. */
+
+extern gcc_jit_extended_asm *
+gcc_jit_block_add_extended_asm (gcc_jit_block *block,
+ gcc_jit_location *loc,
+ const char *asm_template);
+
+/* Create a 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. */
+
+extern 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);
+
+/* Upcasting from extended asm to object. */
+
+extern gcc_jit_object *
+gcc_jit_extended_asm_as_object (gcc_jit_extended_asm *ext_asm);
+
+/* Set whether the gcc_jit_extended_asm has side-effects, equivalent to
+ the "volatile" qualifier in C's extended asm syntax. */
+
+extern void
+gcc_jit_extended_asm_set_volatile_flag (gcc_jit_extended_asm *ext_asm,
+ int flag);
+
+/* Set the equivalent of the "inline" qualifier in C's extended asm
+ syntax. */
+
+extern void
+gcc_jit_extended_asm_set_inline_flag (gcc_jit_extended_asm *ext_asm,
+ int flag);
+
+/* Add an output operand to the extended asm statement.
+ "asm_symbolic_name" can be NULL.
+ "constraint" and "dest" must be non-NULL.
+ This function can't be called on an "asm goto" as such instructions
+ can't have outputs */
+
+extern 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 input operand to the extended asm statement.
+ "asm_symbolic_name" can be NULL.
+ "constraint" and "src" must be non-NULL. */
+
+extern 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 "victim" to the list of registers clobbered by the extended
+ asm statement. It must be non-NULL. */
+
+extern void
+gcc_jit_extended_asm_add_clobber (gcc_jit_extended_asm *ext_asm,
+ const char *victim);
+
+/* Add "asm_stmts", a set of top-level asm statements, analogous to
+ those created by GCC's "basic" asm syntax in C at file scope. */
+
+extern void
+gcc_jit_context_add_top_level_asm (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ const char *asm_stmts);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index a6e67e781a4..bcabe167c05 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -192,3 +192,16 @@ LIBGCCJIT_ABI_14 {
global:
gcc_jit_global_set_initializer;
} LIBGCCJIT_ABI_13;
+
+LIBGCCJIT_ABI_15 {
+ global:
+ gcc_jit_block_add_extended_asm;
+ gcc_jit_block_end_with_extended_asm_goto;
+ gcc_jit_extended_asm_as_object;
+ gcc_jit_extended_asm_set_volatile_flag;
+ gcc_jit_extended_asm_set_inline_flag;
+ gcc_jit_extended_asm_add_output_operand;
+ gcc_jit_extended_asm_add_input_operand;
+ gcc_jit_extended_asm_add_clobber;
+ gcc_jit_context_add_top_level_asm;
+} LIBGCCJIT_ABI_14;
diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp
index 2d8c884b6b8..9af87f9c6ad 100644
--- a/gcc/testsuite/jit.dg/jit.exp
+++ b/gcc/testsuite/jit.dg/jit.exp
@@ -37,12 +37,16 @@ load_lib target-libpath.exp
load_lib gcc.exp
load_lib g++.exp
load_lib dejagnu.exp
+load_lib target-supports-dg.exp
# Skip these tests for targets that don't support -lgccjit
if { ![check_effective_target_lgccjit] } {
return
}
+# The default do-what keyword.
+set dg-do-what-default compile
+
# Look for lines of the form:
# definitely lost: 11,316 bytes in 235 blocks
# indirectly lost: 352 bytes in 4 blocks
@@ -379,6 +383,33 @@ proc jit-dg-test { prog do_what extra_tool_flags } {
verbose " do_what: $do_what"
verbose " extra_tool_flags: $extra_tool_flags"
+ global dg-do-what-default
+ set dg-do-what [list ${dg-do-what-default} "" P]
+
+ set tmp [dg-get-options $prog]
+ foreach op $tmp {
+ verbose "Processing option: $op" 3
+ set status [catch "$op" errmsg]
+ if { $status != 0 } {
+ if { 0 && [info exists errorInfo] } {
+ # This also prints a backtrace which will just confuse
+ # testcase writers, so it's disabled.
+ perror "$name: $errorInfo\n"
+ } else {
+ perror "$name: $errmsg for \"$op\"\n"
+ }
+ perror "$name: $errmsg for \"$op\"" 0
+ return
+ }
+ }
+
+ # If we're not supposed to try this test on this target, we're done.
+ if { [lindex ${dg-do-what} 1] == "N" } {
+ unsupported "$name"
+ verbose "$name not supported on this target, skipping it" 3
+ return
+ }
+
# test-threads.c needs to be linked against pthreads
if {[string match "*test-threads.c" $prog]} {
append extra_tool_flags " -lpthread"
diff --git a/gcc/testsuite/jit.dg/test-asm.c b/gcc/testsuite/jit.dg/test-asm.c
new file mode 100644
index 00000000000..e7777eeb4fe
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-asm.c
@@ -0,0 +1,492 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+/**********************************************************************
+ Support fns for creating code.
+ **********************************************************************/
+
+/* Make a "void FUNC_NAME (void)" function with a single block, returning
+ that block. */
+
+static gcc_jit_block *
+make_single_block_func (gcc_jit_context *ctxt, const char *func_name)
+{
+ gcc_jit_type *void_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_function *func
+ = gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ func_name,
+ 0, NULL, 0);
+ return gcc_jit_function_new_block (func, "initial");
+}
+
+static const char *
+get_desc (gcc_jit_extended_asm *ext_asm)
+{
+ return gcc_jit_object_get_debug_string
+ (gcc_jit_extended_asm_as_object (ext_asm));
+}
+
+/**********************************************************************
+ Support fns for verifying code.
+ **********************************************************************/
+
+typedef void (*void_void_fn) (void);
+
+static void_void_fn
+get_test_fn (gcc_jit_result *result, const char *func_name)
+{
+ return (void_void_fn)gcc_jit_result_get_code (result, func_name);
+}
+
+/**********************************************************************
+ test_i386_basic_asm_1: simple example of asm
+ **********************************************************************/
+
+/* Create the equivalent of:
+
+ int src;
+ int dst;
+
+ void test_i386_basic_asm_1 (void)
+ {
+ // Quote from here in docs/topics/asm.rst: example 1: C
+ asm ("mov %1, %0\n\t"
+ "add $1, %0"
+ : "=r" (dst)
+ : "r" (src));
+ // Quote up to here in docs/topics/asm.rst: example 1: C
+ }
+
+ i.e. copy src to dst and add 1 to dst. */
+
+static void
+create_test_i386_basic_asm_1 (gcc_jit_context *ctxt)
+{
+ gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_lvalue *dst
+ = gcc_jit_context_new_global (ctxt, NULL,
+ GCC_JIT_GLOBAL_EXPORTED,
+ int_type, "dst");
+ gcc_jit_lvalue *src
+ = gcc_jit_context_new_global (ctxt, NULL,
+ GCC_JIT_GLOBAL_EXPORTED,
+ int_type, "src");
+
+ gcc_jit_block *block
+ = make_single_block_func (ctxt, "test_i386_basic_asm_1");
+
+ /* Quote from here in docs/topics/asm.rst: example 1: jit. */
+ gcc_jit_extended_asm *ext_asm
+ = gcc_jit_block_add_extended_asm (block, NULL,
+ "mov %1, %0\n\t"
+ "add $1, %0");
+ gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=r", dst);
+ gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r",
+ gcc_jit_lvalue_as_rvalue (src));
+ /* Quote up to here in docs/topics/asm.rst: example 1: jit. */
+
+ const char *desc = get_desc (ext_asm);
+ CHECK_STRING_VALUE
+ (desc,
+ "asm (\"mov %1, %0\\n\\tadd $1, %0\" : \"=r\" (dst) : \"r\" (src) : )");
+
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+static void
+verify_code_1 (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ void_void_fn test_i386_basic_asm_1
+ = get_test_fn (result, "test_i386_basic_asm_1");
+ CHECK_NON_NULL (test_i386_basic_asm_1);
+
+ int *dst_ptr = (int *)gcc_jit_result_get_global (result, "dst");
+ CHECK_NON_NULL (dst_ptr);
+ int *src_ptr = (int *)gcc_jit_result_get_global (result, "src");
+ CHECK_NON_NULL (src_ptr);
+
+ *src_ptr = 42;
+ *dst_ptr = 0;
+ test_i386_basic_asm_1 ();
+ CHECK_VALUE (*src_ptr, 42);
+ CHECK_VALUE (*dst_ptr, 43);
+}
+
+/**********************************************************************
+ test_i386_basic_asm_2: test of symbolic names and clobbers
+ **********************************************************************/
+
+/* Create the equivalent of:
+ uint32_t test_i386_basic_asm_2 (uint32_t Mask)
+ {
+ uint32_t Index;
+ // Quote from here in docs/topics/asm.rst: example 2: C
+ asm ("bsfl %[aMask], %[aIndex]"
+ : [aIndex] "=r" (Index)
+ : [aMask] "r" (Mask)
+ : "cc");
+ // Quote up to here in docs/topics/asm.rst: example 2: C
+ return Index;
+ }
+ i.e. return the first bit set in "Mask"
+
+ This exercises symbolic names and clobbers. */
+
+static void
+create_test_i386_basic_asm_2 (gcc_jit_context *ctxt)
+{
+ gcc_jit_type *uint32_type = gcc_jit_context_get_int_type (ctxt, 4, 0);
+ gcc_jit_param *mask
+ = gcc_jit_context_new_param (ctxt, NULL,
+ uint32_type, "Mask");
+ gcc_jit_function *func
+ = gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ uint32_type,
+ "test_i386_basic_asm_2",
+ 1, &mask, 0);
+ gcc_jit_lvalue *index
+ = gcc_jit_function_new_local (func, NULL,
+ uint32_type, "Index");
+ gcc_jit_block *block = gcc_jit_function_new_block (func, "initial");
+
+ /* Quote from here in docs/topics/asm.rst: example 2: jit. */
+ gcc_jit_extended_asm *ext_asm
+ = gcc_jit_block_add_extended_asm (block, NULL,
+ "bsfl %[aMask], %[aIndex]");
+ gcc_jit_extended_asm_add_output_operand (ext_asm, "aIndex", "=r", index);
+ gcc_jit_extended_asm_add_input_operand (ext_asm, "aMask", "r",
+ gcc_jit_param_as_rvalue (mask));
+ gcc_jit_extended_asm_add_clobber (ext_asm, "cc");
+ /* Quote up to here in docs/topics/asm.rst: example 2: jit. */
+
+ const char *desc = get_desc (ext_asm);
+ CHECK_STRING_VALUE
+ (desc,
+ "asm (\"bsfl %[aMask], %[aIndex]\""
+ " : [aIndex] \"=r\" (Index) : [aMask] \"r\" (Mask) : \"cc\")");
+
+ gcc_jit_block_end_with_return (block, NULL,
+ gcc_jit_lvalue_as_rvalue (index));
+}
+
+static void
+verify_code_2 (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef uint32_t (*fntype) (uint32_t);
+ fntype test_i386_basic_asm_2
+ = (fntype)gcc_jit_result_get_code (result, "test_i386_basic_asm_2");
+ CHECK_NON_NULL (test_i386_basic_asm_2);
+
+ CHECK_VALUE (test_i386_basic_asm_2 (1), 0);
+ CHECK_VALUE (test_i386_basic_asm_2 (2), 1);
+ CHECK_VALUE (test_i386_basic_asm_2 (4), 2);
+ CHECK_VALUE (test_i386_basic_asm_2 (8), 3);
+}
+
+/**********************************************************************
+ test_i386_basic_asm_3a/b: test of control flow: "asm goto"
+ **********************************************************************/
+
+/* Create the equivalent of:
+
+ int test_i386_basic_asm_3a (int p1, int p2)
+ {
+ asm goto ("btl %1, %0\n\t"
+ "jc %l2"
+ : // No outputs
+ : "r" (p1), "r" (p2)
+ : "cc"
+ : carry);
+
+ return 0;
+
+ carry:
+ return 1;
+ }
+
+ or (the "_3b" variant) using a name rather than a number for the goto
+ label:
+
+ // Quote from here in docs/topics/asm.rst: example 3b: C
+ asm goto ("btl %1, %0\n\t"
+ "jc %l[carry]"
+ : // No outputs
+ : "r" (p1), "r" (p2)
+ : "cc"
+ : carry);
+ // Quote up to here in docs/topics/asm.rst: example 3b: C
+
+ This exercises control flow with an asm. */
+
+static void
+create_test_i386_basic_asm_3 (gcc_jit_context *ctxt,
+ const char *funcname,
+ int use_name)
+{
+ gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_param *p1 = gcc_jit_context_new_param (ctxt, NULL, int_type, "p1");
+ gcc_jit_param *p2 = gcc_jit_context_new_param (ctxt, NULL, int_type, "p2");
+ gcc_jit_param *params[2] = {p1, p2};
+ gcc_jit_function *func
+ = gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ funcname,
+ 2, params, 0);
+ gcc_jit_block *b_start = gcc_jit_function_new_block (func, "start");
+ gcc_jit_block *b_fallthru = gcc_jit_function_new_block (func, "fallthru");
+ gcc_jit_block *b_carry = gcc_jit_function_new_block (func, "carry");
+
+ gcc_jit_rvalue *zero
+ = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0);
+ gcc_jit_rvalue *one
+ = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1);
+
+ /* Quote from here in docs/topics/asm.rst: example 3: jit. */
+ const char *asm_template =
+ (use_name
+ ? /* Label referred to by name: "%l[carry]". */
+ ("btl %1, %0\n\t"
+ "jc %l[carry]")
+ : /* Label referred to numerically: "%l2". */
+ ("btl %1, %0\n\t"
+ "jc %l2"));
+
+ gcc_jit_extended_asm *ext_asm
+ = gcc_jit_block_end_with_extended_asm_goto (b_start, NULL,
+ asm_template,
+ 1, &b_carry,
+ b_fallthru);
+ gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r",
+ gcc_jit_param_as_rvalue (p1));
+ gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r",
+ gcc_jit_param_as_rvalue (p2));
+ gcc_jit_extended_asm_add_clobber (ext_asm, "cc");
+ /* Quote up to here in docs/topics/asm.rst: example 3: jit. */
+
+ const char *desc = get_desc (ext_asm);
+ CHECK_STRING_VALUE
+ (desc,
+ (use_name
+ ? ("asm goto (\"btl %1, %0\\n\\tjc %l[carry]\" "
+ ": : \"r\" (p1), \"r\" (p2) : \"cc\" "
+ ": carry [fallthrough: fallthru])")
+ : ("asm goto (\"btl %1, %0\\n\\tjc %l2\" "
+ ": : \"r\" (p1), \"r\" (p2) : \"cc\" "
+ ": carry [fallthrough: fallthru])")));
+
+ gcc_jit_block_end_with_return (b_fallthru, NULL, zero);
+ gcc_jit_block_end_with_return (b_carry, NULL, one);
+}
+
+static void
+verify_code_3 (gcc_jit_context *ctxt, gcc_jit_result *result,
+ const char *funcname)
+{
+ typedef int (*test_i386_basic_asm_3_type) (int, int);
+
+ test_i386_basic_asm_3_type test_i386_basic_asm_3
+ = (test_i386_basic_asm_3_type) gcc_jit_result_get_code (result, funcname);
+ CHECK_NON_NULL (test_i386_basic_asm_3);
+
+ /* The fn should test bits, returning 0 or 1. */
+ /* Bit 0. */
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0000, 0), 0);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0001, 0), 1);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0002, 0), 0);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0003, 0), 1);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0004, 0), 0);
+ /* Bit 1. */
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0000, 1), 0);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0001, 1), 0);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0002, 1), 1);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0003, 1), 1);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0004, 1), 0);
+
+ for (int i = 0; i < 15; i++)
+ {
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0000, i), 0);
+ CHECK_VALUE (test_i386_basic_asm_3 (0xffff, i), 1);
+ }
+}
+
+/**********************************************************************
+ test_i386_basic_asm_4: test of "volatile"
+ **********************************************************************/
+
+/* Create the equivalent of:
+ uint64_t test_i386_basic_asm_4 (void)
+ {
+ uint64_t start_time, end_time;
+
+ // Get start time
+ 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" (start_time)
+ :
+ : "rdx");
+
+ // could do other work here
+
+ // Get end time
+ 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" (start_time)
+ :
+ : "rdx");
+
+ // Get elapsed time
+ return end_time - start_time;
+ }
+
+ This exercises "volatile"; without it, the optimizer can assume that
+ both asm generate the same value and thus the time difference is zero. */
+
+static void
+add_rdtsc (gcc_jit_block *block, gcc_jit_lvalue *msr)
+{
+ /* Quote from here in docs/topics/asm.rst: example 4: jit. */
+ gcc_jit_extended_asm *ext_asm
+ = gcc_jit_block_add_extended_asm
+ (block, NULL,
+ "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. */
+ gcc_jit_extended_asm_set_volatile_flag (ext_asm, 1);
+ gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=a", msr);
+ gcc_jit_extended_asm_add_clobber (ext_asm, "rdx");
+ /* Quote up to here in docs/topics/asm.rst: example 4: jit. */
+
+ const char *desc = get_desc (ext_asm);
+ CHECK_STRING_STARTS_WITH (desc, "asm volatile (");
+}
+
+static void
+create_test_i386_basic_asm_4 (gcc_jit_context *ctxt)
+{
+ gcc_jit_type *uint64_type = gcc_jit_context_get_int_type (ctxt, 8, 0);
+ gcc_jit_function *func
+ = gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ uint64_type,
+ "test_i386_basic_asm_4",
+ 0, NULL, 0);
+ gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
+
+ gcc_jit_lvalue *start_time
+ = gcc_jit_function_new_local (func, NULL, uint64_type, "start_time");
+ add_rdtsc (block, start_time);
+
+ gcc_jit_block_add_comment (block, NULL, "other work here");
+
+ gcc_jit_lvalue *end_time
+ = gcc_jit_function_new_local (func, NULL, uint64_type, "end_time");
+ add_rdtsc (block, end_time);
+
+ gcc_jit_rvalue *elapsed
+ = gcc_jit_context_new_binary_op (ctxt, NULL, GCC_JIT_BINARY_OP_MINUS,
+ uint64_type,
+ gcc_jit_lvalue_as_rvalue (end_time),
+ gcc_jit_lvalue_as_rvalue (start_time));
+ gcc_jit_block_end_with_return (block, NULL, elapsed);
+}
+
+static void
+verify_code_4 (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef uint64_t (*fntype) (void);
+ fntype test_i386_basic_asm_4
+ = (fntype)gcc_jit_result_get_code (result, "test_i386_basic_asm_4");
+
+ CHECK_NON_NULL (test_i386_basic_asm_4);
+
+ test_i386_basic_asm_4 ();
+}
+
+/**********************************************************************
+ test_i386_basic_asm_5: test of top-level asm
+ **********************************************************************/
+
+/* Create the equivalent of:
+
+ // Quote from here in docs/topics/asm.rst: example 5: C
+ asm ("\t.pushsection .text\n"
+ "\t.globl add_asm\n"
+ "\t.type add_asm, @function\n"
+ "add_asm:\n"
+ "\tmovq %rdi, %rax\n"
+ "\tadd %rsi, %rax\n"
+ "\tret\n"
+ "\t.popsection\n");
+ // Quote up to here in docs/topics/asm.rst: example 5: C
+
+ to add a simple function ("add_asm") directly in assembly language. */
+
+static void
+create_test_i386_basic_asm_5 (gcc_jit_context *ctxt)
+{
+ /* Quote from here in docs/topics/asm.rst: example 5: jit. */
+ gcc_jit_context_add_top_level_asm (ctxt, NULL,
+ "\t.pushsection .text\n"
+ "\t.globl add_asm\n"
+ "\t.type add_asm, @function\n"
+ "add_asm:\n"
+ "\tmovq %rdi, %rax\n"
+ "\tadd %rsi, %rax\n"
+ "\tret\n"
+ "\t# some asm here\n"
+ "\t.popsection\n");
+ /* Quote up to here in docs/topics/asm.rst: example 5: jit. */
+}
+
+static void
+verify_code_5 (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*test_i386_basic_asm_5_type) (int, int);
+ test_i386_basic_asm_5_type test_i386_basic_asm_5
+ = (test_i386_basic_asm_5_type) gcc_jit_result_get_code (result, "add_asm");
+ CHECK_NON_NULL (test_i386_basic_asm_5);
+
+ CHECK_VALUE (test_i386_basic_asm_5 (2, 2), 4);
+ CHECK_VALUE (test_i386_basic_asm_5 (20, 7), 27);
+}
+
+/**********************************************************************
+ Code for harness
+ **********************************************************************/
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ create_test_i386_basic_asm_1 (ctxt);
+ create_test_i386_basic_asm_2 (ctxt);
+ create_test_i386_basic_asm_3 (ctxt, "test_i386_basic_asm_3a", 0);
+ create_test_i386_basic_asm_3 (ctxt, "test_i386_basic_asm_3b", 1);
+ create_test_i386_basic_asm_4 (ctxt);
+ create_test_i386_basic_asm_5 (ctxt);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_NON_NULL (result);
+ verify_code_1 (ctxt, result);
+ verify_code_2 (ctxt, result);
+ verify_code_3 (ctxt, result, "test_i386_basic_asm_3a");
+ verify_code_3 (ctxt, result, "test_i386_basic_asm_3b");
+ verify_code_4 (ctxt, result);
+ verify_code_5 (ctxt, result);
+}
diff --git a/gcc/testsuite/jit.dg/test-asm.cc b/gcc/testsuite/jit.dg/test-asm.cc
new file mode 100644
index 00000000000..6f1828060ff
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-asm.cc
@@ -0,0 +1,453 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+
+#include "libgccjit++.h"
+
+#include "harness.h"
+
+/**********************************************************************
+ Support fns for creating code.
+ **********************************************************************/
+
+/* Make a "void FUNC_NAME (void)" function with a single block, returning
+ that block. */
+
+static gccjit::block
+make_single_block_func (gccjit::context ctxt, const char *func_name)
+{
+ gccjit::type void_type = ctxt.get_type (GCC_JIT_TYPE_VOID);
+ std::vector<gccjit::param> params;
+ gccjit::function func
+ = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ func_name, params, 0);
+ return func.new_block ("initial");
+}
+
+/**********************************************************************
+ Support fns for verifying code.
+ **********************************************************************/
+
+typedef void (*void_void_fn) (void);
+
+static void_void_fn
+get_test_fn (gcc_jit_result *result, const char *func_name)
+{
+ return (void_void_fn)gcc_jit_result_get_code (result, func_name);
+}
+
+/**********************************************************************
+ test_i386_basic_asm_1: simple example of asm
+ **********************************************************************/
+
+/* Create the equivalent of:
+
+ int src;
+ int dst;
+
+ void test_i386_basic_asm_1 (void)
+ {
+ // Quote from here in docs/cp/topics/asm.rst: example 1: C
+ asm ("mov %1, %0\n\t"
+ "add $1, %0"
+ : "=r" (dst)
+ : "r" (src));
+ // Quote up to here in docs/cp/topics/asm.rst: example 1: C
+ }
+
+ i.e. copy src to dst and add 1 to dst. */
+
+static void
+create_test_i386_basic_asm_1 (gcc_jit_context *c_ctxt)
+{
+ gccjit::context ctxt (c_ctxt);
+ gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
+ gccjit::lvalue dst
+ = ctxt.new_global (GCC_JIT_GLOBAL_EXPORTED, int_type, "dst");
+ gccjit::lvalue src
+ = ctxt.new_global (GCC_JIT_GLOBAL_EXPORTED, int_type, "src");
+
+ gccjit::block block
+ = make_single_block_func (ctxt, "test_i386_basic_asm_1");
+
+ gccjit::extended_asm ext_asm =
+ /* Quote from here in docs/cp/topics/asm.rst: example 1: jit. */
+ block.add_extended_asm ("mov %1, %0\n\t"
+ "add $1, %0")
+ .add_output_operand ("=r", dst)
+ .add_input_operand ("r", src);
+ /* Quote up to here in docs/cp/topics/asm.rst: example 1: jit. */
+
+ std::string desc = ext_asm.get_debug_string ();
+ CHECK_STRING_VALUE
+ (desc.c_str (),
+ "asm (\"mov %1, %0\\n\\tadd $1, %0\" : \"=r\" (dst) : \"r\" (src) : )");
+
+ block.end_with_return ();
+}
+
+static void
+verify_code_1 (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ void_void_fn test_i386_basic_asm_1
+ = get_test_fn (result, "test_i386_basic_asm_1");
+ CHECK_NON_NULL (test_i386_basic_asm_1);
+
+ int *dst_ptr = (int *)gcc_jit_result_get_global (result, "dst");
+ CHECK_NON_NULL (dst_ptr);
+ int *src_ptr = (int *)gcc_jit_result_get_global (result, "src");
+ CHECK_NON_NULL (src_ptr);
+
+ *src_ptr = 42;
+ *dst_ptr = 0;
+ test_i386_basic_asm_1 ();
+ CHECK_VALUE (*src_ptr, 42);
+ CHECK_VALUE (*dst_ptr, 43);
+}
+
+/**********************************************************************
+ test_i386_basic_asm_2: test of symbolic names and clobbers
+ **********************************************************************/
+
+/* Create the equivalent of:
+ uint32_t test_i386_basic_asm_2 (uint32_t Mask)
+ {
+ uint32_t Index;
+ // Quote from here in docs/cp/topics/asm.rst: example 2: C
+ asm ("bsfl %[aMask], %[aIndex]"
+ : [aIndex] "=r" (Index)
+ : [aMask] "r" (Mask)
+ : "cc");
+ // Quote up to here in docs/cp/topics/asm.rst: example 2: C
+ return Index;
+ }
+ i.e. return the first bit set in "Mask"
+
+ This exercises symbolic names and clobbers. */
+
+static void
+create_test_i386_basic_asm_2 (gcc_jit_context *c_ctxt)
+{
+ gccjit::context ctxt (c_ctxt);
+ gccjit::type uint32_type = ctxt.get_int_type (4, 0);
+ gccjit::param mask = ctxt.new_param (uint32_type, "Mask");
+ std::vector<gccjit::param> params {mask};
+ gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+ uint32_type,
+ "test_i386_basic_asm_2",
+ params, 0);
+ gccjit::lvalue index = func.new_local (uint32_type, "Index");
+ gccjit::block block = func.new_block ("initial");
+ gccjit::extended_asm ext_asm =
+ /* Quote from here in docs/cp/topics/asm.rst: example 2: jit. */
+ block.add_extended_asm ("bsfl %[aMask], %[aIndex]")
+ .add_output_operand ("aIndex", "=r", index)
+ .add_input_operand ("aMask", "r", mask)
+ .add_clobber ("cc");
+ /* Quote up to here in docs/cp/topics/asm.rst: example 2: jit. */
+
+ std::string desc = ext_asm.get_debug_string ();
+ CHECK_STRING_VALUE
+ (desc.c_str (),
+ "asm (\"bsfl %[aMask], %[aIndex]\""
+ " : [aIndex] \"=r\" (Index) : [aMask] \"r\" (Mask) : \"cc\")");
+
+ block.end_with_return (index);
+}
+
+static void
+verify_code_2 (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef uint32_t (*fntype) (uint32_t);
+ fntype test_i386_basic_asm_2
+ = (fntype)gcc_jit_result_get_code (result, "test_i386_basic_asm_2");
+ CHECK_NON_NULL (test_i386_basic_asm_2);
+
+ CHECK_VALUE (test_i386_basic_asm_2 (1), 0);
+ CHECK_VALUE (test_i386_basic_asm_2 (2), 1);
+ CHECK_VALUE (test_i386_basic_asm_2 (4), 2);
+ CHECK_VALUE (test_i386_basic_asm_2 (8), 3);
+}
+
+/**********************************************************************
+ test_i386_basic_asm_3a/b: test of control flow: "asm goto"
+ **********************************************************************/
+
+/* Create the equivalent of:
+
+ int test_i386_basic_asm_3a (int p1, int p2)
+ {
+ asm goto ("btl %1, %0\n\t"
+ "jc %l2"
+ : // No outputs
+ : "r" (p1), "r" (p2)
+ : "cc"
+ : carry);
+
+ return 0;
+
+ carry:
+ return 1;
+ }
+
+ or (the "_3b" variant) using a name rather than a number for the goto
+ label:
+
+ // Quote from here in docs/cp/topics/asm.rst: example 3b: C
+ asm goto ("btl %1, %0\n\t"
+ "jc %l[carry]"
+ : // No outputs
+ : "r" (p1), "r" (p2)
+ : "cc"
+ : carry);
+ // Quote up to here in docs/cp/topics/asm.rst: example 3b: C
+
+ This exercises control flow with an asm. */
+
+static void
+create_test_i386_basic_asm_3 (gcc_jit_context *c_ctxt,
+ const char *funcname,
+ int use_name)
+{
+ gccjit::context ctxt (c_ctxt);
+ gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
+ gccjit::param p1 = ctxt.new_param (int_type, "p1");
+ gccjit::param p2 = ctxt.new_param (int_type, "p2");
+ std::vector<gccjit::param> params ({p1, p2});
+ gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+ int_type,
+ funcname,
+ params, 0);
+ gccjit::block b_start = func.new_block ("start");
+ gccjit::block b_fallthru = func.new_block ("fallthru");
+ gccjit::block b_carry = func.new_block ("carry");
+
+ gccjit::rvalue zero = ctxt.new_rvalue (int_type, 0);
+ gccjit::rvalue one = ctxt.new_rvalue (int_type, 1);
+
+ /* Quote from here in docs/cp/topics/asm.rst: example 3: jit. */
+ const char *asm_template =
+ (use_name
+ ? /* Label referred to by name: "%l[carry]". */
+ ("btl %1, %0\n\t"
+ "jc %l[carry]")
+ : /* Label referred to numerically: "%l2". */
+ ("btl %1, %0\n\t"
+ "jc %l2"));
+
+ std::vector<gccjit::block> goto_blocks ({b_carry});
+ gccjit::extended_asm ext_asm
+ = (b_start.end_with_extended_asm_goto (asm_template,
+ goto_blocks,
+ &b_fallthru)
+ .add_input_operand ("r", p1)
+ .add_input_operand ("r", p2)
+ .add_clobber ("cc"));
+ /* Quote up to here in docs/cp/topics/asm.rst: example 3: jit. */
+
+ std::string desc = ext_asm.get_debug_string ();
+ CHECK_STRING_VALUE
+ (desc.c_str (),
+ (use_name
+ ? ("asm goto (\"btl %1, %0\\n\\tjc %l[carry]\" "
+ ": : \"r\" (p1), \"r\" (p2) : \"cc\" "
+ ": carry [fallthrough: fallthru])")
+ : ("asm goto (\"btl %1, %0\\n\\tjc %l2\" "
+ ": : \"r\" (p1), \"r\" (p2) : \"cc\" "
+ ": carry [fallthrough: fallthru])")));
+
+ b_fallthru.end_with_return (zero);
+ b_carry.end_with_return (one);
+}
+
+static void
+verify_code_3 (gcc_jit_context *ctxt, gcc_jit_result *result,
+ const char *funcname)
+{
+ typedef int (*test_i386_basic_asm_3_type) (int, int);
+
+ test_i386_basic_asm_3_type test_i386_basic_asm_3
+ = (test_i386_basic_asm_3_type) gcc_jit_result_get_code (result, funcname);
+ CHECK_NON_NULL (test_i386_basic_asm_3);
+
+ /* The fn should test bits, returning 0 or 1. */
+ /* Bit 0. */
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0000, 0), 0);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0001, 0), 1);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0002, 0), 0);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0003, 0), 1);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0004, 0), 0);
+ /* Bit 1. */
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0000, 1), 0);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0001, 1), 0);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0002, 1), 1);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0003, 1), 1);
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0004, 1), 0);
+
+ for (int i = 0; i < 15; i++)
+ {
+ CHECK_VALUE (test_i386_basic_asm_3 (0x0000, i), 0);
+ CHECK_VALUE (test_i386_basic_asm_3 (0xffff, i), 1);
+ }
+}
+
+/**********************************************************************
+ test_i386_basic_asm_4: test of "volatile"
+ **********************************************************************/
+
+/* Create the equivalent of:
+ uint64_t test_i386_basic_asm_4 (void)
+ {
+ uint64_t start_time, end_time;
+
+ // Get start time
+ 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" (start_time)
+ :
+ : "rdx");
+
+ // could do other work here
+
+ // Get end time
+ 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" (start_time)
+ :
+ : "rdx");
+
+ // Get elapsed time
+ return end_time - start_time;
+ }
+
+ This exercises "volatile"; without it, the optimizer can assume that
+ both asm generate the same value and thus the time difference is zero. */
+
+static void
+add_rdtsc (gccjit::block block, gccjit::lvalue msr)
+{
+ /* Quote from here in docs/cp/topics/asm.rst: example 4: jit. */
+ gccjit::extended_asm ext_asm
+ = block.add_extended_asm
+ ("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. */
+ .set_volatile_flag (true)
+ .add_output_operand ("=a", msr)
+ .add_clobber ("rdx");
+ /* Quote up to here in docs/cp/topics/asm.rst: example 4: jit. */
+
+ std::string desc = ext_asm.get_debug_string ();
+ CHECK_STRING_STARTS_WITH (desc.c_str (), "asm volatile (");
+}
+
+static void
+create_test_i386_basic_asm_4 (gcc_jit_context *c_ctxt)
+{
+ gccjit::context ctxt (c_ctxt);
+ gccjit::type uint64_type = ctxt.get_int_type (8, 0);
+ std::vector<gccjit::param> params;
+ gccjit::function func = ctxt.new_function (GCC_JIT_FUNCTION_EXPORTED,
+ uint64_type,
+ "test_i386_basic_asm_4",
+ params, 0);
+ gccjit::block block = func.new_block ();
+
+ gccjit::lvalue start_time = func.new_local (uint64_type, "start_time");
+ add_rdtsc (block, start_time);
+
+ block.add_comment ("other work here");
+
+ gccjit::lvalue end_time = func.new_local (uint64_type, "end_time");
+ add_rdtsc (block, end_time);
+
+ block.end_with_return (end_time - start_time);
+}
+
+static void
+verify_code_4 (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef uint64_t (*fntype) (void);
+ fntype test_i386_basic_asm_4
+ = (fntype)gcc_jit_result_get_code (result, "test_i386_basic_asm_4");
+
+ CHECK_NON_NULL (test_i386_basic_asm_4);
+
+ test_i386_basic_asm_4 ();
+}
+
+/**********************************************************************
+ test_i386_basic_asm_5: test of top-level asm
+ **********************************************************************/
+
+/* Create the equivalent of:
+
+ // Quote from here in docs/cp/topics/asm.rst: example 5: C
+ asm ("\t.pushsection .text\n"
+ "\t.globl add_asm\n"
+ "\t.type add_asm, @function\n"
+ "add_asm:\n"
+ "\tmovq %rdi, %rax\n"
+ "\tadd %rsi, %rax\n"
+ "\tret\n"
+ "\t.popsection\n");
+ // Quote up to here in docs/cp/topics/asm.rst: example 5: C
+
+ to add a simple function ("add_asm") directly in assembly language. */
+
+static void
+create_test_i386_basic_asm_5 (gcc_jit_context *c_ctxt)
+{
+ gccjit::context ctxt (c_ctxt);
+ /* Quote from here in docs/cp/topics/asm.rst: example 5: jit. */
+ ctxt.add_top_level_asm ("\t.pushsection .text\n"
+ "\t.globl add_asm\n"
+ "\t.type add_asm, @function\n"
+ "add_asm:\n"
+ "\tmovq %rdi, %rax\n"
+ "\tadd %rsi, %rax\n"
+ "\tret\n"
+ "\t# some asm here\n"
+ "\t.popsection\n");
+ /* Quote up to here in docs/cp/topics/asm.rst: example 5: jit. */
+}
+
+static void
+verify_code_5 (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef int (*test_i386_basic_asm_5_type) (int, int);
+ test_i386_basic_asm_5_type test_i386_basic_asm_5
+ = (test_i386_basic_asm_5_type) gcc_jit_result_get_code (result, "add_asm");
+ CHECK_NON_NULL (test_i386_basic_asm_5);
+
+ CHECK_VALUE (test_i386_basic_asm_5 (2, 2), 4);
+ CHECK_VALUE (test_i386_basic_asm_5 (20, 7), 27);
+}
+
+/**********************************************************************
+ Code for harness
+ **********************************************************************/
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ create_test_i386_basic_asm_1 (ctxt);
+ create_test_i386_basic_asm_2 (ctxt);
+ create_test_i386_basic_asm_3 (ctxt, "test_i386_basic_asm_3a", 0);
+ create_test_i386_basic_asm_3 (ctxt, "test_i386_basic_asm_3b", 1);
+ create_test_i386_basic_asm_4 (ctxt);
+ create_test_i386_basic_asm_5 (ctxt);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_NON_NULL (result);
+ verify_code_1 (ctxt, result);
+ verify_code_2 (ctxt, result);
+ verify_code_3 (ctxt, result, "test_i386_basic_asm_3a");
+ verify_code_3 (ctxt, result, "test_i386_basic_asm_3b");
+ verify_code_4 (ctxt, result);
+ verify_code_5 (ctxt, result);
+}
--
2.26.2
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2020-11-12 22:36 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-12 22:35 [committed] jit: add support for inline asm [PR87291] David Malcolm
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).