libgccjit: Add support for register variables [PR104072]

gcc/jit/
	PR jit/104072
	* docs/_build/texinfo/libgccjit.texi: Regenerate.
	* docs/topics/compatibility.rst (LIBGCCJIT_ABI_22): New ABI tag.
	* docs/topics/expressions.rst: Add documentation for the
	function gcc_jit_lvalue_set_register_name.
	* jit-playback.h: New function (set_register_name).
	* jit-recording.cc: New function (set_register_name) and add
	support for register variables.
	* jit-recording.h: New field (m_reg_name) and new function
	(set_register_name).
	* libgccjit.cc: New function (gcc_jit_lvalue_set_register_name).
	* libgccjit.h: New function (gcc_jit_lvalue_set_register_name).
	* libgccjit.map (LIBGCCJIT_ABI_22): New ABI tag.

gcc/
	PR jit/104072
	* reginfo.cc: New functions (clear_global_regs_cache,
	reginfo_cc_finalize) to avoid an issue where compiling the same
	code multiple times gives an error about assigning the same
	register to 2 global variables.
	* rtl.h: New function (reginfo_cc_finalize).
	* toplev.cc: Call it.

gcc/testsuite/
	PR jit/104072
	* jit.dg/all-non-failing-tests.h: Add new
	test-register-variable.
	* jit.dg/harness.h: Add -fdiagnostics-color=never to context's
	command-line options.
	* jit.dg/test-error-register-variable-bad-name.c: New test.
	* jit.dg/test-error-register-variable-size-mismatch.c: New test.
	* jit.dg/test-register-variable.c: New test.
This commit is contained in:
Antoni Boucher 2022-04-12 17:20:30 -04:00 committed by David Malcolm
parent 30f7c83e9c
commit 5780ff348a
17 changed files with 895 additions and 615 deletions

File diff suppressed because it is too large Load Diff

View File

@ -343,3 +343,12 @@ of a global with an rvalue and to use constructors:
value from one type to another: value from one type to another:
* :func:`gcc_jit_context_new_bitcast` * :func:`gcc_jit_context_new_bitcast`
.. _LIBGCCJIT_ABI_22:
``LIBGCCJIT_ABI_22``
--------------------
``LIBGCCJIT_ABI_22`` covers the addition of an API entrypoint to set the
register name of a variable:
* :func:`gcc_jit_lvalue_set_register_name`

View File

@ -761,6 +761,26 @@ where the rvalue is computed by reading from the storage area.
#ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_link_section #ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_link_section
.. function:: void\
gcc_jit_lvalue_set_register_name (gcc_jit_lvalue *lvalue,\
const char *reg_name);
Set the register name of a variable.
The parameter ``reg_name`` must be non-NULL. Analogous to:
.. code-block:: c
register int variable asm ("r12");
in C.
This entrypoint was added in :ref:`LIBGCCJIT_ABI_22`; you can test for
its presence using
.. code-block:: c
#ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_register_name
Global variables Global variables
**************** ****************

View File

@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include <utility> // for std::pair #include <utility> // for std::pair
#include "timevar.h" #include "timevar.h"
#include "varasm.h"
#include "jit-recording.h" #include "jit-recording.h"
@ -706,6 +707,14 @@ public:
set_decl_section_name (as_tree (), name); set_decl_section_name (as_tree (), name);
} }
void
set_register_name (const char* reg_name)
{
set_user_assembler_name (as_tree (), reg_name);
DECL_REGISTER (as_tree ()) = 1;
DECL_HARD_REGISTER (as_tree ()) = 1;
}
private: private:
bool mark_addressable (location *loc); bool mark_addressable (location *loc);
}; };

View File

@ -3965,6 +3965,11 @@ void recording::lvalue::set_link_section (const char *name)
m_link_section = new_string (name); m_link_section = new_string (name);
} }
void recording::lvalue::set_register_name (const char *reg_name)
{
m_reg_name = new_string (reg_name);
}
/* The implementation of class gcc::jit::recording::param. */ /* The implementation of class gcc::jit::recording::param. */
/* Implementation of pure virtual hook recording::memento::replay_into /* Implementation of pure virtual hook recording::memento::replay_into
@ -4831,6 +4836,9 @@ recording::global::replay_into (replayer *r)
if (m_link_section != NULL) if (m_link_section != NULL)
global->set_link_section (m_link_section->c_str ()); global->set_link_section (m_link_section->c_str ());
if (m_reg_name != NULL)
global->set_register_name (m_reg_name->c_str ());
set_playback_obj (global); set_playback_obj (global);
} }
@ -6551,11 +6559,15 @@ recording::function_pointer::write_reproducer (reproducer &r)
void void
recording::local::replay_into (replayer *r) recording::local::replay_into (replayer *r)
{ {
set_playback_obj ( playback::lvalue *obj = m_func->playback_function ()
m_func->playback_function ()
->new_local (playback_location (r, m_loc), ->new_local (playback_location (r, m_loc),
m_type->playback_type (), m_type->playback_type (),
playback_string (m_name))); playback_string (m_name));
if (m_reg_name != NULL)
obj->set_register_name (m_reg_name->c_str ());
set_playback_obj (obj);
} }
/* Override the default implementation of /* Override the default implementation of

View File

@ -1170,8 +1170,9 @@ public:
location *loc, location *loc,
type *type_) type *type_)
: rvalue (ctxt, loc, type_), : rvalue (ctxt, loc, type_),
m_tls_model (GCC_JIT_TLS_MODEL_NONE), m_link_section (NULL),
m_link_section (NULL) m_reg_name (NULL),
m_tls_model (GCC_JIT_TLS_MODEL_NONE)
{} {}
playback::lvalue * playback::lvalue *
@ -1195,10 +1196,12 @@ public:
virtual bool is_global () const { return false; } virtual bool is_global () const { return false; }
void set_tls_model (enum gcc_jit_tls_model model); void set_tls_model (enum gcc_jit_tls_model model);
void set_link_section (const char *name); void set_link_section (const char *name);
void set_register_name (const char *reg_name);
protected: protected:
enum gcc_jit_tls_model m_tls_model;
string *m_link_section; string *m_link_section;
string *m_reg_name;
enum gcc_jit_tls_model m_tls_model;
}; };
class param : public lvalue class param : public lvalue

View File

@ -2699,6 +2699,20 @@ gcc_jit_lvalue_set_link_section (gcc_jit_lvalue *lvalue,
lvalue->set_link_section (section_name); lvalue->set_link_section (section_name);
} }
/* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the
gcc::jit::recording::lvalue::set_register_name method in jit-recording.cc. */
void
gcc_jit_lvalue_set_register_name (gcc_jit_lvalue *lvalue,
const char *reg_name)
{
RETURN_IF_FAIL (lvalue, NULL, NULL, "NULL lvalue");
RETURN_IF_FAIL (reg_name, NULL, NULL, "NULL reg_name");
lvalue->set_register_name (reg_name);
}
/* Public entrypoint. See description in libgccjit.h. /* Public entrypoint. See description in libgccjit.h.
After error-checking, the real work is done by the After error-checking, the real work is done by the

View File

@ -1320,6 +1320,18 @@ extern void
gcc_jit_lvalue_set_link_section (gcc_jit_lvalue *lvalue, gcc_jit_lvalue_set_link_section (gcc_jit_lvalue *lvalue,
const char *section_name); const char *section_name);
#define LIBGCCJIT_HAVE_gcc_jit_lvalue_set_register_name
/* Make this variable a register variable and set its register name.
This API entrypoint was added in LIBGCCJIT_ABI_22; you can test for its
presence using
#ifdef LIBGCCJIT_HAVE_gcc_jit_lvalue_set_register_name
*/
void
gcc_jit_lvalue_set_register_name (gcc_jit_lvalue *lvalue,
const char *reg_name);
extern gcc_jit_lvalue * extern gcc_jit_lvalue *
gcc_jit_function_new_local (gcc_jit_function *func, gcc_jit_function_new_local (gcc_jit_function *func,
gcc_jit_location *loc, gcc_jit_location *loc,

View File

@ -255,3 +255,8 @@ LIBGCCJIT_ABI_21 {
global: global:
gcc_jit_context_new_bitcast; gcc_jit_context_new_bitcast;
} LIBGCCJIT_ABI_20; } LIBGCCJIT_ABI_20;
LIBGCCJIT_ABI_22 {
global:
gcc_jit_lvalue_set_register_name;
} LIBGCCJIT_ABI_21;

View File

@ -122,6 +122,24 @@ const char * reg_class_names[] = REG_CLASS_NAMES;
reginfo has been initialized. */ reginfo has been initialized. */
static int no_global_reg_vars = 0; static int no_global_reg_vars = 0;
static void
clear_global_regs_cache (void)
{
for (size_t i = 0 ; i < FIRST_PSEUDO_REGISTER ; i++)
{
global_regs[i] = 0;
global_regs_decl[i] = NULL;
}
}
void
reginfo_cc_finalize (void)
{
clear_global_regs_cache ();
no_global_reg_vars = 0;
CLEAR_HARD_REG_SET (global_reg_set);
}
/* Given a register bitmap, turn on the bits in a HARD_REG_SET that /* Given a register bitmap, turn on the bits in a HARD_REG_SET that
correspond to the hard registers, if any, set in that map. This correspond to the hard registers, if any, set in that map. This
could be done far more efficiently by having all sorts of special-cases could be done far more efficiently by having all sorts of special-cases

View File

@ -3774,6 +3774,7 @@ extern bool resize_reg_info (void);
extern void free_reg_info (void); extern void free_reg_info (void);
extern void init_subregs_of_mode (void); extern void init_subregs_of_mode (void);
extern void finish_subregs_of_mode (void); extern void finish_subregs_of_mode (void);
extern void reginfo_cc_finalize (void);
/* recog.cc */ /* recog.cc */
extern rtx extract_asm_operands (rtx); extern rtx extract_asm_operands (rtx);

View File

@ -313,6 +313,9 @@
#undef create_code #undef create_code
#undef verify_code #undef verify_code
/* test-register-variable.c: This can't be in the testcases array as it
is target-specific. */
/* test-string-literal.c */ /* test-string-literal.c */
#define create_code create_code_string_literal #define create_code create_code_string_literal
#define verify_code verify_code_string_literal #define verify_code verify_code_string_literal

View File

@ -262,6 +262,10 @@ static void set_options (gcc_jit_context *ctxt, const char *argv0)
ctxt, ctxt,
GCC_JIT_BOOL_OPTION_DUMP_SUMMARY, GCC_JIT_BOOL_OPTION_DUMP_SUMMARY,
0); 0);
/* Make it easier to compare error messages by disabling colorization,
rather then have them be affected by whether stderr is going to a tty. */
gcc_jit_context_add_command_line_option
(ctxt, "-fdiagnostics-color=never");
} }
#endif /* #ifndef TEST_ESCHEWS_SET_OPTIONS */ #endif /* #ifndef TEST_ESCHEWS_SET_OPTIONS */

View File

@ -0,0 +1,35 @@
/*
Test that the proper error is triggered when we build a register variable
with a register name that doesn't exist.
*/
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_lvalue *global_variable =
gcc_jit_context_new_global (
ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED, int_type, "global_variable");
gcc_jit_lvalue_set_register_name(global_variable, "this_is_not_a_register");
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
/* Ensure that the bad API usage prevents the API giving a bogus
result back. */
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE (gcc_jit_context_get_last_error (ctxt),
"invalid register name for 'global_variable'");
}

View File

@ -0,0 +1,38 @@
/*
Test that the proper error is triggered when we build a register variable
with a register name that doesn't exist.
*/
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_type *array_type =
gcc_jit_context_new_array_type (ctxt, NULL, int_type, 4096);
gcc_jit_lvalue *global_variable =
gcc_jit_context_new_global (
ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED, array_type, "global_variable");
gcc_jit_lvalue_set_register_name(global_variable, "r12");
}
void
verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
{
/* Ensure that the bad API usage prevents the API giving a bogus
result back. */
CHECK_VALUE (result, NULL);
/* Verify that the correct error message was emitted. */
CHECK_STRING_VALUE
(gcc_jit_context_get_last_error (ctxt),
"data type of 'global_variable' isn't suitable for a register");
}

View File

@ -0,0 +1,56 @@
/* { dg-do compile { target x86_64-*-* } } */
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
/* We don't want set_options() in harness.h to set -O3 so our little local
is optimized away. */
#define TEST_ESCHEWS_SET_OPTIONS
static void set_options (gcc_jit_context *ctxt, const char *argv0)
{
}
#define TEST_COMPILING_TO_FILE
#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER
#define OUTPUT_FILENAME "output-of-test-link-section-assembler.c.s"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Let's try to inject the equivalent of:
register int global_variable asm ("r13");
int main() {
register int variable asm ("r12");
return 0;
}
*/
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_lvalue *global_variable =
gcc_jit_context_new_global (
ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED, int_type, "global_variable");
gcc_jit_lvalue_set_register_name(global_variable, "r13");
gcc_jit_function *func_main =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
int_type,
"main",
0, NULL,
0);
gcc_jit_lvalue *variable = gcc_jit_function_new_local(func_main, NULL, int_type, "variable");
gcc_jit_lvalue_set_register_name(variable, "r12");
gcc_jit_rvalue *two = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 2);
gcc_jit_rvalue *one = gcc_jit_context_one (ctxt, int_type);
gcc_jit_block *block = gcc_jit_function_new_block (func_main, NULL);
gcc_jit_block_add_assignment(block, NULL, variable, one);
gcc_jit_block_add_assignment(block, NULL, global_variable, two);
gcc_jit_block_end_with_return (block, NULL, gcc_jit_lvalue_as_rvalue(variable));
}
/* { dg-final { jit-verify-output-file-was-created "" } } */
/* { dg-final { jit-verify-assembler-output "movl \\\$1, %r12d" } } */
/* { dg-final { jit-verify-assembler-output "movl \\\$2, %r13d" } } */

View File

@ -2379,6 +2379,7 @@ toplev::finalize (void)
ipa_cp_cc_finalize (); ipa_cp_cc_finalize ();
ira_costs_cc_finalize (); ira_costs_cc_finalize ();
tree_cc_finalize (); tree_cc_finalize ();
reginfo_cc_finalize ();
/* save_decoded_options uses opts_obstack, so these must /* save_decoded_options uses opts_obstack, so these must
be cleaned up together. */ be cleaned up together. */