mirror of
https://git.planet-casio.com/Lephenixnoir/sh-elf-gcc.git
synced 2025-01-04 07:53:37 +01:00
3516 lines
105 KiB
Diff
3516 lines
105 KiB
Diff
|
# Contains the commits from https://github.com/antoyo/gcc/ needed for rustc_codegen_gcc to work
|
||
|
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
|
||
|
new file mode 100644
|
||
|
index 00000000000..5fab7cf772c
|
||
|
--- /dev/null
|
||
|
+++ b/.github/workflows/main.yml
|
||
|
@@ -0,0 +1,32 @@
|
||
|
+name: CI
|
||
|
+
|
||
|
+on:
|
||
|
+ - push
|
||
|
+ - pull_request
|
||
|
+
|
||
|
+jobs:
|
||
|
+ build:
|
||
|
+ runs-on: ubuntu-latest
|
||
|
+
|
||
|
+ strategy:
|
||
|
+ fail-fast: false
|
||
|
+
|
||
|
+ steps:
|
||
|
+ - uses: actions/checkout@v2
|
||
|
+
|
||
|
+ - name: Install mpfr
|
||
|
+ run: sudo apt-get install gcc-10 libmpfr-dev libmpc-dev
|
||
|
+
|
||
|
+ - name: Build libgccjit
|
||
|
+ run: |
|
||
|
+ cd ..
|
||
|
+ ls
|
||
|
+ mkdir build install
|
||
|
+ cd build
|
||
|
+ ../gcc/configure --enable-host-shared --enable-languages=jit,c++ --disable-bootstrap --disable-multilib --prefix=$(pwd)/../install
|
||
|
+ make -j4
|
||
|
+
|
||
|
+ - uses: actions/upload-artifact@v2
|
||
|
+ with:
|
||
|
+ name: libgccjit.so
|
||
|
+ path: /home/runner/work/gcc/build/gcc/libgccjit.so
|
||
|
diff --git a/gcc/config/i386/i386-builtins.cc b/gcc/config/i386/i386-builtins.cc
|
||
|
index 01192ef4259..37df854ba51 100644
|
||
|
--- a/gcc/config/i386/i386-builtins.cc
|
||
|
+++ b/gcc/config/i386/i386-builtins.cc
|
||
|
@@ -226,6 +226,22 @@ static GTY(()) tree ix86_builtins[(int) IX86_BUILTIN_MAX];
|
||
|
|
||
|
struct builtin_isa ix86_builtins_isa[(int) IX86_BUILTIN_MAX];
|
||
|
|
||
|
+static void
|
||
|
+clear_builtin_types (void)
|
||
|
+{
|
||
|
+ for (int i = 0 ; i < IX86_BT_LAST_CPTR + 1 ; i++)
|
||
|
+ ix86_builtin_type_tab[i] = NULL;
|
||
|
+
|
||
|
+ for (int i = 0 ; i < IX86_BUILTIN_MAX ; i++)
|
||
|
+ {
|
||
|
+ ix86_builtins[i] = NULL;
|
||
|
+ ix86_builtins_isa[i].set_and_not_built_p = true;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (int i = 0 ; i < IX86_BT_LAST_ALIAS + 1 ; i++)
|
||
|
+ ix86_builtin_func_type_tab[i] = NULL;
|
||
|
+}
|
||
|
+
|
||
|
tree get_ix86_builtin (enum ix86_builtins c)
|
||
|
{
|
||
|
return ix86_builtins[c];
|
||
|
@@ -1443,6 +1459,8 @@ ix86_init_builtins (void)
|
||
|
{
|
||
|
tree ftype, decl;
|
||
|
|
||
|
+ clear_builtin_types ();
|
||
|
+
|
||
|
ix86_init_builtin_types ();
|
||
|
|
||
|
/* Builtins to get CPU type and features. */
|
||
|
diff --git a/gcc/dwarf2asm.cc b/gcc/dwarf2asm.cc
|
||
|
index 65b95fee243..e66cd30c1fe 100644
|
||
|
--- a/gcc/dwarf2asm.cc
|
||
|
+++ b/gcc/dwarf2asm.cc
|
||
|
@@ -1159,4 +1159,14 @@ dw2_asm_output_encoded_addr_rtx (int encoding, rtx addr, bool is_public,
|
||
|
va_end (ap);
|
||
|
}
|
||
|
|
||
|
+void dwarf2asm_cc_finalize (void)
|
||
|
+{
|
||
|
+ if (indirect_pool)
|
||
|
+ {
|
||
|
+ indirect_pool->empty();
|
||
|
+ indirect_pool = NULL;
|
||
|
+ }
|
||
|
+ dw2_const_labelno = 0;
|
||
|
+}
|
||
|
+
|
||
|
#include "gt-dwarf2asm.h"
|
||
|
diff --git a/gcc/dwarf2asm.h b/gcc/dwarf2asm.h
|
||
|
index 37a0a05e5bb..80695b3c6c8 100644
|
||
|
--- a/gcc/dwarf2asm.h
|
||
|
+++ b/gcc/dwarf2asm.h
|
||
|
@@ -86,6 +86,8 @@ extern const char *eh_data_format_name (int);
|
||
|
extern rtx dw2_force_const_mem (rtx, bool);
|
||
|
extern void dw2_output_indirect_constants (void);
|
||
|
|
||
|
+void dwarf2asm_cc_finalize (void);
|
||
|
+
|
||
|
/* These are currently unused. */
|
||
|
|
||
|
#if 0
|
||
|
diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc
|
||
|
index 1f39df3b1e2..61b711d4a52 100644
|
||
|
--- a/gcc/dwarf2out.cc
|
||
|
+++ b/gcc/dwarf2out.cc
|
||
|
@@ -1003,6 +1003,9 @@ dwarf2out_do_cfi_startproc (bool second)
|
||
|
if (targetm.asm_out.make_eh_symbol_indirect != NULL)
|
||
|
ref = targetm.asm_out.make_eh_symbol_indirect (ref, true);
|
||
|
else
|
||
|
+ // TODO: HERE: should not insert multiple times the same personality function.
|
||
|
+ // If we don't, we segfault later, possibly because we don't generate the info for the duplicates.
|
||
|
+ // I'm not sure why it's attempting to insert multiple times the same personality function.
|
||
|
ref = dw2_force_const_mem (ref, true);
|
||
|
}
|
||
|
|
||
|
diff --git a/gcc/emit-rtl.cc b/gcc/emit-rtl.cc
|
||
|
index a11f72f606b..61603c37230 100644
|
||
|
--- a/gcc/emit-rtl.cc
|
||
|
+++ b/gcc/emit-rtl.cc
|
||
|
@@ -6191,8 +6191,13 @@ init_emit_once (void)
|
||
|
/* Don't use gen_rtx_CONST_INT here since gen_rtx_CONST_INT in this case
|
||
|
tries to use these variables. */
|
||
|
for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)
|
||
|
- const_int_rtx[i + MAX_SAVED_CONST_INT] =
|
||
|
- gen_rtx_raw_CONST_INT (VOIDmode, (HOST_WIDE_INT) i);
|
||
|
+ {
|
||
|
+ // Do not initialize twice the constants because there are used elsewhere
|
||
|
+ // and libgccjit execute this function twice.
|
||
|
+ if (const_int_rtx[i + MAX_SAVED_CONST_INT] == NULL)
|
||
|
+ const_int_rtx[i + MAX_SAVED_CONST_INT] =
|
||
|
+ gen_rtx_raw_CONST_INT (VOIDmode, (HOST_WIDE_INT) i);
|
||
|
+ }
|
||
|
|
||
|
if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT
|
||
|
&& STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT)
|
||
|
diff --git a/gcc/expr.cc b/gcc/expr.cc
|
||
|
index 15be1c8db99..7fa2c114cb2 100644
|
||
|
--- a/gcc/expr.cc
|
||
|
+++ b/gcc/expr.cc
|
||
|
@@ -13365,6 +13365,7 @@ const_vector_from_tree (tree exp)
|
||
|
tree
|
||
|
build_personality_function (const char *lang)
|
||
|
{
|
||
|
+ // TODO: rewrite by calling build_personality_function_with_name.
|
||
|
const char *unwind_and_version;
|
||
|
tree decl, type;
|
||
|
char *name;
|
||
|
@@ -13406,6 +13407,28 @@ build_personality_function (const char *lang)
|
||
|
return decl;
|
||
|
}
|
||
|
|
||
|
+tree
|
||
|
+build_personality_function_with_name (const char *name)
|
||
|
+{
|
||
|
+ tree decl, type;
|
||
|
+
|
||
|
+ type = build_function_type_list (unsigned_type_node,
|
||
|
+ integer_type_node, integer_type_node,
|
||
|
+ long_long_unsigned_type_node,
|
||
|
+ ptr_type_node, ptr_type_node, NULL_TREE);
|
||
|
+ decl = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
|
||
|
+ get_identifier (name), type);
|
||
|
+ DECL_ARTIFICIAL (decl) = 1;
|
||
|
+ DECL_EXTERNAL (decl) = 1;
|
||
|
+ TREE_PUBLIC (decl) = 1;
|
||
|
+
|
||
|
+ /* Zap the nonsensical SYMBOL_REF_DECL for this. What we're left with
|
||
|
+ are the flags assigned by targetm.encode_section_info. */
|
||
|
+ SET_SYMBOL_REF_DECL (XEXP (DECL_RTL (decl), 0), NULL);
|
||
|
+
|
||
|
+ return decl;
|
||
|
+}
|
||
|
+
|
||
|
/* Extracts the personality function of DECL and returns the corresponding
|
||
|
libfunc. */
|
||
|
|
||
|
diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc
|
||
|
index 0687567bc88..7ef09d71288 100644
|
||
|
--- a/gcc/jit/dummy-frontend.cc
|
||
|
+++ b/gcc/jit/dummy-frontend.cc
|
||
|
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
||
|
#include "config.h"
|
||
|
#include "system.h"
|
||
|
#include "coretypes.h"
|
||
|
+#include "target.h"
|
||
|
#include "jit-playback.h"
|
||
|
#include "stor-layout.h"
|
||
|
#include "debug.h"
|
||
|
@@ -29,8 +30,14 @@ along with GCC; see the file COPYING3. If not see
|
||
|
#include "options.h"
|
||
|
#include "stringpool.h"
|
||
|
#include "attribs.h"
|
||
|
+#include "jit-recording.h"
|
||
|
+#include "print-tree.h"
|
||
|
|
||
|
#include <mpfr.h>
|
||
|
+#include <unordered_map>
|
||
|
+#include <string>
|
||
|
+
|
||
|
+using namespace gcc::jit;
|
||
|
|
||
|
/* Attribute handling. */
|
||
|
|
||
|
@@ -86,6 +93,10 @@ static const struct attribute_spec::exclusions attr_const_pure_exclusions[] =
|
||
|
ATTR_EXCL (NULL, false, false, false)
|
||
|
};
|
||
|
|
||
|
+hash_map<nofree_string_hash, tree> target_builtins{};
|
||
|
+std::unordered_map<std::string, recording::function_type*> target_function_types{};
|
||
|
+recording::context target_builtins_ctxt{NULL};
|
||
|
+
|
||
|
/* Table of machine-independent attributes supported in libgccjit. */
|
||
|
const struct attribute_spec jit_attribute_table[] =
|
||
|
{
|
||
|
@@ -146,6 +157,20 @@ const struct attribute_spec jit_format_attribute_table[] =
|
||
|
{ NULL, 0, 0, false, false, false, false, NULL, NULL }
|
||
|
};
|
||
|
|
||
|
+char* jit_personality_func_name = NULL;
|
||
|
+static tree personality_decl;
|
||
|
+
|
||
|
+/* FIXME: This is a hack to preserve trees that we create from the
|
||
|
+ garbage collector. */
|
||
|
+
|
||
|
+static GTY (()) tree jit_gc_root;
|
||
|
+
|
||
|
+void
|
||
|
+jit_preserve_from_gc (tree t)
|
||
|
+{
|
||
|
+ jit_gc_root = tree_cons (NULL_TREE, t, jit_gc_root);
|
||
|
+}
|
||
|
+
|
||
|
/* Attribute handlers. */
|
||
|
|
||
|
/* Handle a "noreturn" attribute; arguments as in
|
||
|
@@ -507,12 +532,12 @@ struct GTY(()) lang_identifier
|
||
|
/* The resulting tree type. */
|
||
|
|
||
|
union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
|
||
|
- chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON) ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
|
||
|
-lang_tree_node
|
||
|
-{
|
||
|
- union tree_node GTY((tag ("0"),
|
||
|
- desc ("tree_node_structure (&%h)"))) generic;
|
||
|
- struct lang_identifier GTY((tag ("1"))) identifier;
|
||
|
+ chain_next ("(union lang_tree_node *) jit_tree_chain_next (&%h.generic)"))) lang_tree_node
|
||
|
+ {
|
||
|
+ union tree_node GTY ((tag ("0"),
|
||
|
+ desc ("tree_node_structure (&%h)")))
|
||
|
+ generic;
|
||
|
+ struct lang_identifier GTY ((tag ("1"))) identifier;
|
||
|
};
|
||
|
|
||
|
/* We don't use language_function. */
|
||
|
@@ -578,6 +603,8 @@ jit_end_diagnostic (diagnostic_context *context,
|
||
|
static bool
|
||
|
jit_langhook_init (void)
|
||
|
{
|
||
|
+ jit_gc_root = NULL_TREE;
|
||
|
+ personality_decl = NULL_TREE;
|
||
|
gcc_assert (gcc::jit::active_playback_ctxt);
|
||
|
JIT_LOG_SCOPE (gcc::jit::active_playback_ctxt->get_logger ());
|
||
|
|
||
|
@@ -592,15 +619,25 @@ jit_langhook_init (void)
|
||
|
global_dc->begin_diagnostic = jit_begin_diagnostic;
|
||
|
global_dc->end_diagnostic = jit_end_diagnostic;
|
||
|
|
||
|
- build_common_tree_nodes (false);
|
||
|
+ build_common_tree_nodes (flag_signed_char);
|
||
|
+
|
||
|
+ /* I don't know why this has to be done explicitly. */
|
||
|
+ void_list_node = build_tree_list (NULL_TREE, void_type_node);
|
||
|
|
||
|
+ target_builtins.empty ();
|
||
|
build_common_builtin_nodes ();
|
||
|
|
||
|
+ /* Initialize EH, if we've been told to do so. */
|
||
|
+ if (flag_exceptions)
|
||
|
+ using_eh_for_cleanups ();
|
||
|
+
|
||
|
/* The default precision for floating point numbers. This is used
|
||
|
for floating point constants with abstract type. This may
|
||
|
eventually be controllable by a command line option. */
|
||
|
mpfr_set_default_prec (256);
|
||
|
|
||
|
+ targetm.init_builtins ();
|
||
|
+
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
@@ -668,11 +705,216 @@ jit_langhook_type_for_mode (machine_mode mode, int unsignedp)
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
-/* Record a builtin function. We just ignore builtin functions. */
|
||
|
+recording::type* tree_type_to_jit_type (tree type)
|
||
|
+{
|
||
|
+ if (TREE_CODE (type) == VECTOR_TYPE)
|
||
|
+ {
|
||
|
+ tree inner_type = TREE_TYPE (type);
|
||
|
+ recording::type* element_type = tree_type_to_jit_type (inner_type);
|
||
|
+ poly_uint64 size = TYPE_VECTOR_SUBPARTS (type);
|
||
|
+ long constant_size = size.to_constant();
|
||
|
+ if (element_type != NULL)
|
||
|
+ return element_type->get_vector (constant_size);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ if (TREE_CODE (type) == REFERENCE_TYPE)
|
||
|
+ {
|
||
|
+ // For __builtin_ms_va_start.
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type.
|
||
|
+ }
|
||
|
+ if (TREE_CODE (type) == RECORD_TYPE)
|
||
|
+ {
|
||
|
+ // For __builtin_sysv_va_copy.
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type.
|
||
|
+ }
|
||
|
+ for (int i = 0; i < NUM_FLOATN_NX_TYPES; i++)
|
||
|
+ {
|
||
|
+ if (type == FLOATN_NX_TYPE_NODE (i))
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type.
|
||
|
+ }
|
||
|
+ }
|
||
|
+ if (type == void_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID);
|
||
|
+ }
|
||
|
+ else if (type == ptr_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID_PTR);
|
||
|
+ }
|
||
|
+ else if (type == const_ptr_type_node)
|
||
|
+ {
|
||
|
+ // Void const ptr.
|
||
|
+ recording::type* result = new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID_PTR);
|
||
|
+ return new recording::memento_of_get_const (result);
|
||
|
+ }
|
||
|
+ else if (type == unsigned_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UNSIGNED_INT);
|
||
|
+ }
|
||
|
+ else if (type == long_unsigned_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UNSIGNED_LONG);
|
||
|
+ }
|
||
|
+ else if (type == integer_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_INT);
|
||
|
+ }
|
||
|
+ else if (type == long_integer_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_LONG);
|
||
|
+ }
|
||
|
+ else if (type == long_long_integer_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_LONG_LONG);
|
||
|
+ }
|
||
|
+ else if (type == signed_char_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_SIGNED_CHAR);
|
||
|
+ }
|
||
|
+ else if (type == char_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_CHAR);
|
||
|
+ }
|
||
|
+ else if (type == unsigned_intQI_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UINT8_T);
|
||
|
+ }
|
||
|
+ else if (type == short_integer_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_SHORT);
|
||
|
+ }
|
||
|
+ else if (type == short_unsigned_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UNSIGNED_SHORT);
|
||
|
+ }
|
||
|
+ else if (type == complex_float_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_COMPLEX_FLOAT);
|
||
|
+ }
|
||
|
+ else if (type == complex_double_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_COMPLEX_DOUBLE);
|
||
|
+ }
|
||
|
+ else if (type == complex_long_double_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_COMPLEX_LONG_DOUBLE);
|
||
|
+ }
|
||
|
+ else if (type == float_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_FLOAT);
|
||
|
+ }
|
||
|
+ else if (type == double_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_DOUBLE);
|
||
|
+ }
|
||
|
+ else if (type == long_double_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_LONG_DOUBLE);
|
||
|
+ }
|
||
|
+ else if (type == bfloat16_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_BFLOAT16);
|
||
|
+ }
|
||
|
+ else if (type == dfloat128_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_VOID); // FIXME: wrong type.
|
||
|
+ }
|
||
|
+ else if (type == long_long_unsigned_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_UNSIGNED_LONG_LONG);
|
||
|
+ }
|
||
|
+ else if (type == boolean_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_BOOL);
|
||
|
+ }
|
||
|
+ else if (type == size_type_node)
|
||
|
+ {
|
||
|
+ return new recording::memento_of_get_type (&target_builtins_ctxt, GCC_JIT_TYPE_SIZE_T);
|
||
|
+ }
|
||
|
+ else if (TREE_CODE (type) == POINTER_TYPE)
|
||
|
+ {
|
||
|
+ tree inner_type = TREE_TYPE (type);
|
||
|
+ recording::type* element_type = tree_type_to_jit_type (inner_type);
|
||
|
+ return element_type->get_pointer();
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ // Attempt to find an unqualified type when the current type has qualifiers.
|
||
|
+ tree tp = TYPE_MAIN_VARIANT (type);
|
||
|
+ for ( ; tp != NULL ; tp = TYPE_NEXT_VARIANT (tp))
|
||
|
+ {
|
||
|
+ if (TYPE_QUALS (tp) == 0 && type != tp)
|
||
|
+ {
|
||
|
+ recording::type* result = tree_type_to_jit_type (tp);
|
||
|
+ if (result != NULL)
|
||
|
+ {
|
||
|
+ if (TYPE_READONLY (tp))
|
||
|
+ result = new recording::memento_of_get_const (result);
|
||
|
+ if (TYPE_VOLATILE (tp))
|
||
|
+ result = new recording::memento_of_get_volatile (result);
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ fprintf (stderr, "Unknown type:\n");
|
||
|
+ debug_tree (type);
|
||
|
+ abort ();
|
||
|
+ }
|
||
|
+
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+/* Record a builtin function. We save their types to be able to check types
|
||
|
+ in recording and for reflection. */
|
||
|
|
||
|
static tree
|
||
|
jit_langhook_builtin_function (tree decl)
|
||
|
{
|
||
|
+ if (TREE_CODE (decl) == FUNCTION_DECL)
|
||
|
+ {
|
||
|
+ const char* name = IDENTIFIER_POINTER (DECL_NAME (decl));
|
||
|
+ target_builtins.put (name, decl);
|
||
|
+
|
||
|
+ std::string string_name(name);
|
||
|
+ if (target_function_types.count (string_name) == 0)
|
||
|
+ {
|
||
|
+ tree function_type = TREE_TYPE (decl);
|
||
|
+ tree arg = TYPE_ARG_TYPES (function_type);
|
||
|
+ bool is_variadic = false;
|
||
|
+
|
||
|
+ auto_vec <recording::type *> param_types;
|
||
|
+
|
||
|
+ while (arg != void_list_node)
|
||
|
+ {
|
||
|
+ if (arg == NULL)
|
||
|
+ {
|
||
|
+ is_variadic = true;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (arg != void_list_node)
|
||
|
+ {
|
||
|
+ recording::type* arg_type = tree_type_to_jit_type(TREE_VALUE (arg));
|
||
|
+ if (arg_type == NULL)
|
||
|
+ return decl;
|
||
|
+ param_types.safe_push (arg_type);
|
||
|
+ }
|
||
|
+ arg = TREE_CHAIN (arg);
|
||
|
+ }
|
||
|
+
|
||
|
+ tree result_type = TREE_TYPE (function_type);
|
||
|
+ recording::type* return_type = tree_type_to_jit_type(result_type);
|
||
|
+
|
||
|
+ if (return_type == NULL)
|
||
|
+ return decl;
|
||
|
+
|
||
|
+ recording::function_type* func_type = new recording::function_type (&target_builtins_ctxt, return_type, param_types.length (),
|
||
|
+ param_types.address (), is_variadic, false);
|
||
|
+
|
||
|
+ target_function_types[string_name] = func_type;
|
||
|
+ }
|
||
|
+ }
|
||
|
return decl;
|
||
|
}
|
||
|
|
||
|
@@ -694,6 +936,25 @@ jit_langhook_getdecls (void)
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
+static tree
|
||
|
+jit_langhook_eh_personality (void)
|
||
|
+{
|
||
|
+ if (personality_decl == NULL_TREE)
|
||
|
+ {
|
||
|
+ if (jit_personality_func_name != NULL) {
|
||
|
+ personality_decl = build_personality_function_with_name (jit_personality_func_name);
|
||
|
+ jit_preserve_from_gc(personality_decl);
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ return lhd_gcc_personality();
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return personality_decl;
|
||
|
+}
|
||
|
+
|
||
|
+#undef LANG_HOOKS_EH_PERSONALITY
|
||
|
+#define LANG_HOOKS_EH_PERSONALITY jit_langhook_eh_personality
|
||
|
+
|
||
|
#undef LANG_HOOKS_NAME
|
||
|
#define LANG_HOOKS_NAME "libgccjit"
|
||
|
|
||
|
diff --git a/gcc/jit/jit-builtins.cc b/gcc/jit/jit-builtins.cc
|
||
|
index fb86c77d0fe..622a061ea89 100644
|
||
|
--- a/gcc/jit/jit-builtins.cc
|
||
|
+++ b/gcc/jit/jit-builtins.cc
|
||
|
@@ -215,7 +215,8 @@ builtins_manager::make_builtin_function (enum built_in_function builtin_id)
|
||
|
param_types.length (),
|
||
|
params,
|
||
|
func_type->is_variadic (),
|
||
|
- builtin_id);
|
||
|
+ builtin_id,
|
||
|
+ false);
|
||
|
delete[] params;
|
||
|
|
||
|
/* PR/64020 - If the client code is using builtin cos or sin,
|
||
|
@@ -582,7 +583,8 @@ builtins_manager::make_fn_type (enum jit_builtin_type,
|
||
|
result = m_ctxt->new_function_type (return_type,
|
||
|
num_args,
|
||
|
param_types,
|
||
|
- is_variadic);
|
||
|
+ is_variadic,
|
||
|
+ false);
|
||
|
|
||
|
error:
|
||
|
delete[] param_types;
|
||
|
@@ -609,6 +611,9 @@ builtins_manager::ensure_optimization_builtins_exist ()
|
||
|
We can't loop through all of the builtin_data array, we don't
|
||
|
support all types yet. */
|
||
|
(void)get_builtin_function_by_id (BUILT_IN_TRAP);
|
||
|
+ (void)get_builtin_function_by_id (BUILT_IN_POPCOUNT);
|
||
|
+ (void)get_builtin_function_by_id (BUILT_IN_POPCOUNTL);
|
||
|
+ (void)get_builtin_function_by_id (BUILT_IN_POPCOUNTLL);
|
||
|
}
|
||
|
|
||
|
/* Playback support. */
|
||
|
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
|
||
|
index 3ff7447fbf3..5c323411ea9 100644
|
||
|
--- a/gcc/jit/jit-common.h
|
||
|
+++ b/gcc/jit/jit-common.h
|
||
|
@@ -36,7 +36,7 @@ along with GCC; see the file COPYING3. If not see
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
-const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_INT128_T + 1;
|
||
|
+const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_BFLOAT16 + 1;
|
||
|
|
||
|
/* This comment is included by the docs.
|
||
|
|
||
|
@@ -93,6 +93,20 @@ const int NUM_GCC_JIT_TYPES = GCC_JIT_TYPE_INT128_T + 1;
|
||
|
|
||
|
End of comment for inclusion in the docs. */
|
||
|
|
||
|
+static inline tree
|
||
|
+jit_tree_chain_next (tree t)
|
||
|
+{
|
||
|
+ /* TREE_CHAIN of a type is TYPE_STUB_DECL, which is different
|
||
|
+ kind of object, never a long chain of nodes. Prefer
|
||
|
+ TYPE_NEXT_VARIANT for types. */
|
||
|
+ if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_TYPE_COMMON))
|
||
|
+ return TYPE_NEXT_VARIANT (t);
|
||
|
+ /* Otherwise, if there is TREE_CHAIN, return it. */
|
||
|
+ if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_COMMON))
|
||
|
+ return TREE_CHAIN (t);
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
namespace gcc {
|
||
|
|
||
|
namespace jit {
|
||
|
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
|
||
|
index 96e9227af40..0b107754ca8 100644
|
||
|
--- a/gcc/jit/jit-playback.cc
|
||
|
+++ b/gcc/jit/jit-playback.cc
|
||
|
@@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
|
||
|
|
||
|
#include "config.h"
|
||
|
#define INCLUDE_MUTEX
|
||
|
+#include "libgccjit.h"
|
||
|
#include "system.h"
|
||
|
#include "coretypes.h"
|
||
|
#include "target.h"
|
||
|
@@ -280,6 +281,8 @@ get_tree_node_for_type (enum gcc_jit_types type_)
|
||
|
|
||
|
case GCC_JIT_TYPE_FLOAT:
|
||
|
return float_type_node;
|
||
|
+ case GCC_JIT_TYPE_BFLOAT16:
|
||
|
+ return bfloat16_type_node;
|
||
|
case GCC_JIT_TYPE_DOUBLE:
|
||
|
return double_type_node;
|
||
|
case GCC_JIT_TYPE_LONG_DOUBLE:
|
||
|
@@ -326,7 +329,7 @@ playback::type *
|
||
|
playback::context::
|
||
|
new_array_type (playback::location *loc,
|
||
|
playback::type *element_type,
|
||
|
- int num_elements)
|
||
|
+ unsigned long num_elements)
|
||
|
{
|
||
|
gcc_assert (element_type);
|
||
|
|
||
|
@@ -407,7 +410,8 @@ playback::compound_type *
|
||
|
playback::context::
|
||
|
new_compound_type (location *loc,
|
||
|
const char *name,
|
||
|
- bool is_struct) /* else is union */
|
||
|
+ bool is_struct, /* else is union */
|
||
|
+ bool is_packed)
|
||
|
{
|
||
|
gcc_assert (name);
|
||
|
|
||
|
@@ -417,6 +421,9 @@ new_compound_type (location *loc,
|
||
|
TYPE_NAME (t) = get_identifier (name);
|
||
|
TYPE_SIZE (t) = 0;
|
||
|
|
||
|
+ if (is_packed)
|
||
|
+ TYPE_PACKED (t) = 1;
|
||
|
+
|
||
|
if (loc)
|
||
|
set_tree_location (t, loc);
|
||
|
|
||
|
@@ -424,7 +431,7 @@ new_compound_type (location *loc,
|
||
|
}
|
||
|
|
||
|
void
|
||
|
-playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
|
||
|
+playback::compound_type::set_fields (const auto_vec<playback::field *> *fields, bool is_packed)
|
||
|
{
|
||
|
/* Compare with c/c-decl.cc: finish_struct. */
|
||
|
tree t = as_tree ();
|
||
|
@@ -441,6 +448,10 @@ playback::compound_type::set_fields (const auto_vec<playback::field *> *fields)
|
||
|
DECL_SIZE (x) = bitsize_int (width);
|
||
|
DECL_BIT_FIELD (x) = 1;
|
||
|
}
|
||
|
+
|
||
|
+ if (is_packed && (DECL_BIT_FIELD (x)
|
||
|
+ || TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT))
|
||
|
+ DECL_PACKED (x) = 1;
|
||
|
fieldlist = chainon (x, fieldlist);
|
||
|
}
|
||
|
fieldlist = nreverse (fieldlist);
|
||
|
@@ -499,6 +510,36 @@ new_param (location *loc,
|
||
|
return new param (this, inner);
|
||
|
}
|
||
|
|
||
|
+const char* fn_attribute_to_string(gcc_jit_fn_attribute attr)
|
||
|
+{
|
||
|
+ switch (attr)
|
||
|
+ {
|
||
|
+ case GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE:
|
||
|
+ return "always_inline";
|
||
|
+ case GCC_JIT_FN_ATTRIBUTE_INLINE:
|
||
|
+ return NULL;
|
||
|
+ case GCC_JIT_FN_ATTRIBUTE_NOINLINE:
|
||
|
+ return "noinline";
|
||
|
+ case GCC_JIT_FN_ATTRIBUTE_TARGET:
|
||
|
+ return "target";
|
||
|
+ case GCC_JIT_FN_ATTRIBUTE_USED:
|
||
|
+ return "used";
|
||
|
+ case GCC_JIT_FN_ATTRIBUTE_VISIBILITY:
|
||
|
+ return "visibility";
|
||
|
+ }
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
+const char* variable_attribute_to_string(gcc_jit_variable_attribute attr)
|
||
|
+{
|
||
|
+ switch (attr)
|
||
|
+ {
|
||
|
+ case GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY:
|
||
|
+ return "visibility";
|
||
|
+ }
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+
|
||
|
/* Construct a playback::function instance. */
|
||
|
|
||
|
playback::function *
|
||
|
@@ -509,7 +550,10 @@ new_function (location *loc,
|
||
|
const char *name,
|
||
|
const auto_vec<param *> *params,
|
||
|
int is_variadic,
|
||
|
- enum built_in_function builtin_id)
|
||
|
+ enum built_in_function builtin_id,
|
||
|
+ const std::vector<gcc_jit_fn_attribute> &attributes,
|
||
|
+ const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes,
|
||
|
+ int is_target_builtin)
|
||
|
{
|
||
|
int i;
|
||
|
param *param;
|
||
|
@@ -532,6 +576,7 @@ new_function (location *loc,
|
||
|
|
||
|
/* FIXME: this uses input_location: */
|
||
|
tree fndecl = build_fn_decl (name, fn_type);
|
||
|
+ TREE_NOTHROW (fndecl) = 0;
|
||
|
|
||
|
if (loc)
|
||
|
set_tree_location (fndecl, loc);
|
||
|
@@ -543,6 +588,14 @@ new_function (location *loc,
|
||
|
DECL_RESULT (fndecl) = resdecl;
|
||
|
DECL_CONTEXT (resdecl) = fndecl;
|
||
|
|
||
|
+ if (is_target_builtin)
|
||
|
+ {
|
||
|
+ tree *decl = target_builtins.get(name);
|
||
|
+ if (decl != NULL)
|
||
|
+ fndecl = *decl;
|
||
|
+ else
|
||
|
+ add_error (loc, "cannot find target builtin %s", name);
|
||
|
+ }
|
||
|
if (builtin_id)
|
||
|
{
|
||
|
gcc_assert (loc == NULL);
|
||
|
@@ -594,6 +647,52 @@ new_function (location *loc,
|
||
|
DECL_ATTRIBUTES (fndecl));
|
||
|
}
|
||
|
|
||
|
+ for (auto attr: attributes)
|
||
|
+ {
|
||
|
+ if (attr == GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE)
|
||
|
+ {
|
||
|
+ DECL_DECLARED_INLINE_P (fndecl) = 1;
|
||
|
+ DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1;
|
||
|
+ }
|
||
|
+ else if (attr == GCC_JIT_FN_ATTRIBUTE_INLINE)
|
||
|
+ DECL_DECLARED_INLINE_P (fndecl) = 1;
|
||
|
+ else if (attr == GCC_JIT_FN_ATTRIBUTE_NOINLINE)
|
||
|
+ DECL_UNINLINABLE (fndecl) = 1;
|
||
|
+ /* See handle_used_attribute in gcc/c-family/c-attribs.cc. */
|
||
|
+ else if (attr == GCC_JIT_FN_ATTRIBUTE_USED)
|
||
|
+ {
|
||
|
+ TREE_USED (fndecl) = 1;
|
||
|
+ DECL_PRESERVE_P (fndecl) = 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ const char* attribute = fn_attribute_to_string (attr);
|
||
|
+ if (attribute)
|
||
|
+ {
|
||
|
+ tree ident = get_identifier (attribute);
|
||
|
+ DECL_ATTRIBUTES (fndecl) =
|
||
|
+ tree_cons (ident, NULL_TREE, DECL_ATTRIBUTES (fndecl));
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ for (auto attr: string_attributes)
|
||
|
+ {
|
||
|
+ gcc_jit_fn_attribute& name = std::get<0>(attr);
|
||
|
+ std::string& value = std::get<1>(attr);
|
||
|
+ tree attribute_value = build_tree_list (NULL_TREE, ::build_string (value.length () + 1, value.c_str ()));
|
||
|
+ const char* attribute = fn_attribute_to_string (name);
|
||
|
+ tree ident = attribute ? get_identifier (attribute) : NULL;
|
||
|
+
|
||
|
+ /* See handle_target_attribute in gcc/c-family/c-attribs.cc. */
|
||
|
+ if (name == GCC_JIT_FN_ATTRIBUTE_TARGET)
|
||
|
+ /* We need to call valid_attribute_p so that the hook set-up some internal options. */
|
||
|
+ if (!ident || !targetm.target_option.valid_attribute_p (fndecl, ident, attribute_value, 0))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (ident)
|
||
|
+ DECL_ATTRIBUTES (fndecl) =
|
||
|
+ tree_cons (ident, attribute_value, DECL_ATTRIBUTES (fndecl));
|
||
|
+ }
|
||
|
+
|
||
|
function *func = new function (this, fndecl, kind);
|
||
|
m_functions.safe_push (func);
|
||
|
return func;
|
||
|
@@ -607,7 +706,9 @@ global_new_decl (location *loc,
|
||
|
enum gcc_jit_global_kind kind,
|
||
|
type *type,
|
||
|
const char *name,
|
||
|
- enum global_var_flags flags)
|
||
|
+ enum global_var_flags flags,
|
||
|
+ bool readonly,
|
||
|
+ const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &attributes)
|
||
|
{
|
||
|
gcc_assert (type);
|
||
|
gcc_assert (name);
|
||
|
@@ -646,15 +747,33 @@ global_new_decl (location *loc,
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
- if (TYPE_READONLY (type_tree))
|
||
|
+ if (TYPE_READONLY (type_tree) || readonly)
|
||
|
TREE_READONLY (inner) = 1;
|
||
|
|
||
|
if (loc)
|
||
|
set_tree_location (inner, loc);
|
||
|
|
||
|
+ set_variable_attribute (attributes, inner);
|
||
|
+
|
||
|
return inner;
|
||
|
}
|
||
|
|
||
|
+void
|
||
|
+playback::
|
||
|
+set_variable_attribute(const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &attributes, tree decl)
|
||
|
+{
|
||
|
+ for (auto attr: attributes)
|
||
|
+ {
|
||
|
+ gcc_jit_variable_attribute& name = std::get<0>(attr);
|
||
|
+ std::string& value = std::get<1>(attr);
|
||
|
+ tree attribute_value = build_tree_list (NULL_TREE, ::build_string (value.length () + 1, value.c_str ()));
|
||
|
+ tree ident = get_identifier (variable_attribute_to_string (name));
|
||
|
+
|
||
|
+ DECL_ATTRIBUTES (decl) =
|
||
|
+ tree_cons (ident, attribute_value, DECL_ATTRIBUTES (decl));
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
/* In use by new_global and new_global_initialized. */
|
||
|
|
||
|
playback::lvalue *
|
||
|
@@ -674,10 +793,12 @@ new_global (location *loc,
|
||
|
enum gcc_jit_global_kind kind,
|
||
|
type *type,
|
||
|
const char *name,
|
||
|
- enum global_var_flags flags)
|
||
|
+ enum global_var_flags flags,
|
||
|
+ bool readonly,
|
||
|
+ const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &attributes)
|
||
|
{
|
||
|
tree inner =
|
||
|
- global_new_decl (loc, kind, type, name, flags);
|
||
|
+ global_new_decl (loc, kind, type, name, flags, readonly, attributes);
|
||
|
|
||
|
return global_finalize_lvalue (inner);
|
||
|
}
|
||
|
@@ -822,9 +943,11 @@ new_global_initialized (location *loc,
|
||
|
size_t initializer_num_elem,
|
||
|
const void *initializer,
|
||
|
const char *name,
|
||
|
- enum global_var_flags flags)
|
||
|
+ enum global_var_flags flags,
|
||
|
+ bool readonly,
|
||
|
+ const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &attributes)
|
||
|
{
|
||
|
- tree inner = global_new_decl (loc, kind, type, name, flags);
|
||
|
+ tree inner = global_new_decl (loc, kind, type, name, flags, readonly, attributes);
|
||
|
|
||
|
vec<constructor_elt, va_gc> *constructor_elements = NULL;
|
||
|
|
||
|
@@ -1007,10 +1130,30 @@ playback::context::new_rvalue_from_vector (location *,
|
||
|
vec_alloc (v, elements.length ());
|
||
|
for (unsigned i = 0; i < elements.length (); ++i)
|
||
|
CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
|
||
|
- tree t_ctor = build_constructor (type->as_tree (), v);
|
||
|
+ tree t_ctor;
|
||
|
+ t_ctor = build_constructor (type->as_tree (), v);
|
||
|
return new rvalue (this, t_ctor);
|
||
|
}
|
||
|
|
||
|
+/* Construct a playback::rvalue instance (wrapping a tree) for a
|
||
|
+ vector perm. */
|
||
|
+
|
||
|
+playback::rvalue *
|
||
|
+playback::context::new_rvalue_vector_perm (location *loc,
|
||
|
+ rvalue* elements1,
|
||
|
+ rvalue* elements2,
|
||
|
+ rvalue* mask)
|
||
|
+{
|
||
|
+ tree t_elements1 = elements1->as_tree ();
|
||
|
+ tree t_elements2 = elements2->as_tree ();
|
||
|
+ tree t_mask = mask->as_tree ();
|
||
|
+
|
||
|
+ tree t_vector_perm = build3 (VEC_PERM_EXPR, TREE_TYPE (t_elements1), t_elements1, t_elements2, t_mask);
|
||
|
+ if (loc)
|
||
|
+ set_tree_location (t_vector_perm, loc);
|
||
|
+ return new rvalue (this, t_vector_perm);
|
||
|
+}
|
||
|
+
|
||
|
/* Coerce a tree expression into a boolean tree expression. */
|
||
|
|
||
|
tree
|
||
|
@@ -1527,6 +1670,163 @@ new_array_access (location *loc,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+/* Construct a playback::rvalue instance (wrapping a tree) for a
|
||
|
+ vector conversion. */
|
||
|
+
|
||
|
+playback::rvalue *
|
||
|
+playback::context::
|
||
|
+convert_vector (location *loc,
|
||
|
+ rvalue *vector,
|
||
|
+ type *type)
|
||
|
+{
|
||
|
+ gcc_assert (vector);
|
||
|
+ gcc_assert (type);
|
||
|
+
|
||
|
+ /* For comparison, see:
|
||
|
+ c/c-common.cc: c_build_vec_convert
|
||
|
+ */
|
||
|
+
|
||
|
+ tree t_vector = vector->as_tree ();
|
||
|
+
|
||
|
+ /* It seems IFN_VEC_CONVERT only work on registers, not on memory. */
|
||
|
+ if (TREE_CODE (t_vector) == VAR_DECL)
|
||
|
+ DECL_REGISTER (t_vector) = 1;
|
||
|
+ tree t_result = build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_VEC_CONVERT, type->as_tree (), 1, t_vector);
|
||
|
+
|
||
|
+ if (loc)
|
||
|
+ set_tree_location (t_result, loc);
|
||
|
+
|
||
|
+ return new rvalue (this, t_result);
|
||
|
+}
|
||
|
+
|
||
|
+/* The following functions come from c-common.h. */
|
||
|
+/* Like c_mark_addressable but don't check register qualifier. */
|
||
|
+void
|
||
|
+common_mark_addressable_vec (tree t)
|
||
|
+{
|
||
|
+ while (handled_component_p (t) || TREE_CODE (t) == C_MAYBE_CONST_EXPR)
|
||
|
+ {
|
||
|
+ t = TREE_OPERAND (t, 0);
|
||
|
+ }
|
||
|
+ if (!VAR_P (t)
|
||
|
+ && TREE_CODE (t) != PARM_DECL
|
||
|
+ && TREE_CODE (t) != COMPOUND_LITERAL_EXPR
|
||
|
+ && TREE_CODE (t) != TARGET_EXPR)
|
||
|
+ return;
|
||
|
+ if (!VAR_P (t) || !DECL_HARD_REGISTER (t))
|
||
|
+ TREE_ADDRESSABLE (t) = 1;
|
||
|
+ if (TREE_CODE (t) == COMPOUND_LITERAL_EXPR)
|
||
|
+ TREE_ADDRESSABLE (COMPOUND_LITERAL_EXPR_DECL (t)) = 1;
|
||
|
+ else if (TREE_CODE (t) == TARGET_EXPR)
|
||
|
+ TREE_ADDRESSABLE (TARGET_EXPR_SLOT (t)) = 1;
|
||
|
+}
|
||
|
+
|
||
|
+/* Return true if TYPE is a vector type that should be subject to the GNU
|
||
|
+ vector extensions (as opposed to a vector type that is used only for
|
||
|
+ the purposes of defining target-specific built-in functions). */
|
||
|
+
|
||
|
+inline bool
|
||
|
+gnu_vector_type_p (const_tree type)
|
||
|
+{
|
||
|
+ return TREE_CODE (type) == VECTOR_TYPE && !TYPE_INDIVISIBLE_P (type);
|
||
|
+}
|
||
|
+
|
||
|
+/* Return nonzero if REF is an lvalue valid for this language.
|
||
|
+ Lvalues can be assigned, unless their type has TYPE_READONLY.
|
||
|
+ Lvalues can have their address taken, unless they have C_DECL_REGISTER. */
|
||
|
+
|
||
|
+bool
|
||
|
+lvalue_p (const_tree ref)
|
||
|
+{
|
||
|
+ const enum tree_code code = TREE_CODE (ref);
|
||
|
+
|
||
|
+ switch (code)
|
||
|
+ {
|
||
|
+ case REALPART_EXPR:
|
||
|
+ case IMAGPART_EXPR:
|
||
|
+ case COMPONENT_REF:
|
||
|
+ return lvalue_p (TREE_OPERAND (ref, 0));
|
||
|
+
|
||
|
+ case C_MAYBE_CONST_EXPR:
|
||
|
+ return lvalue_p (TREE_OPERAND (ref, 1));
|
||
|
+
|
||
|
+ case COMPOUND_LITERAL_EXPR:
|
||
|
+ case STRING_CST:
|
||
|
+ return true;
|
||
|
+
|
||
|
+ case MEM_REF:
|
||
|
+ case TARGET_MEM_REF:
|
||
|
+ /* MEM_REFs can appear from -fgimple parsing or folding, so allow them
|
||
|
+ here as well. */
|
||
|
+ case INDIRECT_REF:
|
||
|
+ case ARRAY_REF:
|
||
|
+ case VAR_DECL:
|
||
|
+ case PARM_DECL:
|
||
|
+ case RESULT_DECL:
|
||
|
+ case ERROR_MARK:
|
||
|
+ return (TREE_CODE (TREE_TYPE (ref)) != FUNCTION_TYPE
|
||
|
+ && TREE_CODE (TREE_TYPE (ref)) != METHOD_TYPE);
|
||
|
+
|
||
|
+ case BIND_EXPR:
|
||
|
+ return TREE_CODE (TREE_TYPE (ref)) == ARRAY_TYPE;
|
||
|
+
|
||
|
+ default:
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+bool
|
||
|
+convert_vector_to_array_for_subscript (tree *vecp)
|
||
|
+{
|
||
|
+ bool ret = false;
|
||
|
+ if (gnu_vector_type_p (TREE_TYPE (*vecp)))
|
||
|
+ {
|
||
|
+ tree type = TREE_TYPE (*vecp);
|
||
|
+
|
||
|
+ ret = !lvalue_p (*vecp);
|
||
|
+
|
||
|
+ /* We are building an ARRAY_REF so mark the vector as addressable
|
||
|
+ to not run into the gimplifiers premature setting of DECL_GIMPLE_REG_P
|
||
|
+ for function parameters. */
|
||
|
+ // NOTE: that was the missing piece for making vector access work with optimizations enabled.
|
||
|
+ common_mark_addressable_vec (*vecp);
|
||
|
+
|
||
|
+ *vecp = build1 (VIEW_CONVERT_EXPR,
|
||
|
+ build_array_type_nelts (TREE_TYPE (type),
|
||
|
+ TYPE_VECTOR_SUBPARTS (type)),
|
||
|
+ *vecp);
|
||
|
+ }
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+/* Construct a playback::lvalue instance (wrapping a tree) for a
|
||
|
+ vector access. */
|
||
|
+
|
||
|
+playback::lvalue *
|
||
|
+playback::context::
|
||
|
+new_vector_access (location *loc,
|
||
|
+ rvalue *vector,
|
||
|
+ rvalue *index)
|
||
|
+{
|
||
|
+ gcc_assert (vector);
|
||
|
+ gcc_assert (index);
|
||
|
+
|
||
|
+ /* For comparison, see:
|
||
|
+ c/c-typeck.cc: build_array_ref
|
||
|
+ */
|
||
|
+
|
||
|
+ tree t_vector = vector->as_tree ();
|
||
|
+ bool non_lvalue = convert_vector_to_array_for_subscript (&t_vector);
|
||
|
+ tree type = TREE_TYPE (TREE_TYPE (t_vector));
|
||
|
+ tree t_result = build4 (ARRAY_REF, type, t_vector, index->as_tree (), NULL_TREE, NULL_TREE);
|
||
|
+ if (non_lvalue)
|
||
|
+ t_result = non_lvalue (t_result);
|
||
|
+
|
||
|
+ if (loc)
|
||
|
+ set_tree_location (t_result, loc);
|
||
|
+ return new lvalue (this, t_result);
|
||
|
+}
|
||
|
+
|
||
|
/* Construct a tree for a field access. */
|
||
|
|
||
|
tree
|
||
|
@@ -1812,7 +2112,8 @@ playback::lvalue *
|
||
|
playback::function::
|
||
|
new_local (location *loc,
|
||
|
type *type,
|
||
|
- const char *name)
|
||
|
+ const char *name,
|
||
|
+ const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &attributes)
|
||
|
{
|
||
|
gcc_assert (type);
|
||
|
gcc_assert (name);
|
||
|
@@ -1825,6 +2126,8 @@ new_local (location *loc,
|
||
|
DECL_CHAIN (inner) = BIND_EXPR_VARS (m_inner_bind_expr);
|
||
|
BIND_EXPR_VARS (m_inner_bind_expr) = inner;
|
||
|
|
||
|
+ set_variable_attribute (attributes, inner);
|
||
|
+
|
||
|
if (loc)
|
||
|
set_tree_location (inner, loc);
|
||
|
return new lvalue (m_ctxt, inner);
|
||
|
@@ -1857,6 +2160,15 @@ playback::function::get_address (location *loc)
|
||
|
return new rvalue (m_ctxt, t_fnptr);
|
||
|
}
|
||
|
|
||
|
+/* Construct a new local within this playback::function. */
|
||
|
+
|
||
|
+void
|
||
|
+playback::function::
|
||
|
+set_personality_function (function *personality_function)
|
||
|
+{
|
||
|
+ DECL_FUNCTION_PERSONALITY (m_inner_fndecl) = personality_function->as_fndecl ();
|
||
|
+}
|
||
|
+
|
||
|
/* Build a statement list for the function as a whole out of the
|
||
|
lists of statements for the individual blocks, building labels
|
||
|
for each block. */
|
||
|
@@ -1875,6 +2187,11 @@ build_stmt_list ()
|
||
|
int j;
|
||
|
tree stmt;
|
||
|
|
||
|
+ // Do not add try/catch block to the function.
|
||
|
+ // TODO: explain why.
|
||
|
+ if (b->m_is_try_or_catch)
|
||
|
+ continue;
|
||
|
+
|
||
|
b->m_label_expr = build1 (LABEL_EXPR,
|
||
|
void_type_node,
|
||
|
b->as_label_decl ());
|
||
|
@@ -1973,6 +2290,70 @@ add_eval (location *loc,
|
||
|
add_stmt (rvalue->as_tree ());
|
||
|
}
|
||
|
|
||
|
+
|
||
|
+void
|
||
|
+playback::block::
|
||
|
+add_try_catch (location *loc,
|
||
|
+ block *try_block,
|
||
|
+ block *catch_block,
|
||
|
+ bool is_finally)
|
||
|
+{
|
||
|
+ gcc_assert (try_block);
|
||
|
+ gcc_assert (catch_block);
|
||
|
+
|
||
|
+ try_block->m_is_try_or_catch = true;
|
||
|
+ catch_block->m_is_try_or_catch = true;
|
||
|
+
|
||
|
+ if (loc)
|
||
|
+ {
|
||
|
+ set_tree_location (try_block->as_label_decl (), loc);
|
||
|
+ set_tree_location (catch_block->as_label_decl (), loc);
|
||
|
+ }
|
||
|
+
|
||
|
+ tree try_body = alloc_stmt_list ();
|
||
|
+ unsigned int i;
|
||
|
+ tree stmt;
|
||
|
+ FOR_EACH_VEC_ELT (try_block->m_stmts, i, stmt) {
|
||
|
+ append_to_statement_list (stmt, &try_body);
|
||
|
+ }
|
||
|
+
|
||
|
+ tree catch_body = alloc_stmt_list ();
|
||
|
+ unsigned int j;
|
||
|
+ tree catch_stmt;
|
||
|
+ FOR_EACH_VEC_ELT (catch_block->m_stmts, j, catch_stmt) {
|
||
|
+ append_to_statement_list (catch_stmt, &catch_body);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (is_finally)
|
||
|
+ {
|
||
|
+ tree success_body = alloc_stmt_list ();
|
||
|
+
|
||
|
+ // TODO: find a better way to keep the EH_ELSE_EXPR than creating an empty inline asm.
|
||
|
+ tree t_string = build_string ("");
|
||
|
+ tree asm_stmt
|
||
|
+ = build5 (ASM_EXPR, void_type_node, t_string, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE);
|
||
|
+
|
||
|
+ // asm statements without outputs, including simple ones, are treated
|
||
|
+ // as volatile.
|
||
|
+ ASM_VOLATILE_P (asm_stmt) = 1;
|
||
|
+ ASM_INPUT_P (asm_stmt) = 0;
|
||
|
+ append_to_statement_list (asm_stmt, &success_body);
|
||
|
+
|
||
|
+ // TODO: Don't automatically add the `EH_ELSE_EXPR`. Make an API to create such a node and let the user of libgccjit
|
||
|
+ // add it manually.
|
||
|
+ catch_body = build2 (EH_ELSE_EXPR, void_type_node, success_body, catch_body);
|
||
|
+ add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node,
|
||
|
+ try_body, catch_body));
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body);
|
||
|
+ tree try_catch = build2 (TRY_CATCH_EXPR, void_type_node,
|
||
|
+ try_body, catch_body);
|
||
|
+ add_stmt (try_catch);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
/* Add an assignment to the function's statement list. */
|
||
|
|
||
|
void
|
||
|
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
|
||
|
index 43e92d67d74..b767fec6da8 100644
|
||
|
--- a/gcc/jit/jit-playback.h
|
||
|
+++ b/gcc/jit/jit-playback.h
|
||
|
@@ -21,7 +21,9 @@ along with GCC; see the file COPYING3. If not see
|
||
|
#ifndef JIT_PLAYBACK_H
|
||
|
#define JIT_PLAYBACK_H
|
||
|
|
||
|
+#include <string>
|
||
|
#include <utility> // for std::pair
|
||
|
+#include <vector>
|
||
|
|
||
|
#include "timevar.h"
|
||
|
#include "varasm.h"
|
||
|
@@ -41,6 +43,9 @@ namespace jit {
|
||
|
|
||
|
namespace playback {
|
||
|
|
||
|
+void
|
||
|
+set_variable_attribute(const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &attributes, tree decl);
|
||
|
+
|
||
|
/* playback::context is an abstract base class.
|
||
|
|
||
|
The two concrete subclasses are:
|
||
|
@@ -69,7 +74,7 @@ public:
|
||
|
type *
|
||
|
new_array_type (location *loc,
|
||
|
type *element_type,
|
||
|
- int num_elements);
|
||
|
+ unsigned long num_elements);
|
||
|
|
||
|
field *
|
||
|
new_field (location *loc,
|
||
|
@@ -85,7 +90,8 @@ public:
|
||
|
compound_type *
|
||
|
new_compound_type (location *loc,
|
||
|
const char *name,
|
||
|
- bool is_struct); /* else is union */
|
||
|
+ bool is_struct, /* else is union */
|
||
|
+ bool is_packed);
|
||
|
|
||
|
type *
|
||
|
new_function_type (type *return_type,
|
||
|
@@ -104,14 +110,19 @@ public:
|
||
|
const char *name,
|
||
|
const auto_vec<param *> *params,
|
||
|
int is_variadic,
|
||
|
- enum built_in_function builtin_id);
|
||
|
+ enum built_in_function builtin_id,
|
||
|
+ const std::vector<gcc_jit_fn_attribute> &attributes,
|
||
|
+ const std::vector<std::pair<gcc_jit_fn_attribute, std::string>> &string_attributes,
|
||
|
+ int is_target_builtin);
|
||
|
|
||
|
lvalue *
|
||
|
new_global (location *loc,
|
||
|
enum gcc_jit_global_kind kind,
|
||
|
type *type,
|
||
|
const char *name,
|
||
|
- enum global_var_flags flags);
|
||
|
+ enum global_var_flags flags,
|
||
|
+ bool readonly,
|
||
|
+ const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &attributes);
|
||
|
|
||
|
lvalue *
|
||
|
new_global_initialized (location *loc,
|
||
|
@@ -121,7 +132,9 @@ public:
|
||
|
size_t initializer_num_elem,
|
||
|
const void *initializer,
|
||
|
const char *name,
|
||
|
- enum global_var_flags flags);
|
||
|
+ enum global_var_flags flags,
|
||
|
+ bool readonly,
|
||
|
+ const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &attributes);
|
||
|
|
||
|
rvalue *
|
||
|
new_ctor (location *log,
|
||
|
@@ -147,6 +160,12 @@ public:
|
||
|
type *type,
|
||
|
const auto_vec<rvalue *> &elements);
|
||
|
|
||
|
+ rvalue *
|
||
|
+ new_rvalue_vector_perm (location *loc,
|
||
|
+ rvalue* elements1,
|
||
|
+ rvalue* elements2,
|
||
|
+ rvalue* mask);
|
||
|
+
|
||
|
rvalue *
|
||
|
new_unary_op (location *loc,
|
||
|
enum gcc_jit_unary_op op,
|
||
|
@@ -191,6 +210,16 @@ public:
|
||
|
rvalue *ptr,
|
||
|
rvalue *index);
|
||
|
|
||
|
+ rvalue *
|
||
|
+ convert_vector (location *loc,
|
||
|
+ rvalue *vector,
|
||
|
+ type *type);
|
||
|
+
|
||
|
+ lvalue *
|
||
|
+ new_vector_access (location *loc,
|
||
|
+ rvalue *vector,
|
||
|
+ rvalue *index);
|
||
|
+
|
||
|
void
|
||
|
set_str_option (enum gcc_jit_str_option opt,
|
||
|
const char *value);
|
||
|
@@ -306,7 +335,9 @@ private:
|
||
|
enum gcc_jit_global_kind kind,
|
||
|
type *type,
|
||
|
const char *name,
|
||
|
- enum global_var_flags flags);
|
||
|
+ enum global_var_flags flags,
|
||
|
+ bool readonly,
|
||
|
+ const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &attributes);
|
||
|
lvalue *
|
||
|
global_finalize_lvalue (tree inner);
|
||
|
|
||
|
@@ -460,7 +491,7 @@ public:
|
||
|
: type (inner)
|
||
|
{}
|
||
|
|
||
|
- void set_fields (const auto_vec<field *> *fields);
|
||
|
+ void set_fields (const auto_vec<field *> *fields, bool is_packed);
|
||
|
};
|
||
|
|
||
|
class field : public wrapper
|
||
|
@@ -495,7 +526,8 @@ public:
|
||
|
lvalue *
|
||
|
new_local (location *loc,
|
||
|
type *type,
|
||
|
- const char *name);
|
||
|
+ const char *name,
|
||
|
+ const std::vector<std::pair<gcc_jit_variable_attribute, std::string>> &attributes);
|
||
|
|
||
|
block*
|
||
|
new_block (const char *name);
|
||
|
@@ -503,6 +535,9 @@ public:
|
||
|
rvalue *
|
||
|
get_address (location *loc);
|
||
|
|
||
|
+ void
|
||
|
+ set_personality_function (function *personality_function);
|
||
|
+
|
||
|
void
|
||
|
build_stmt_list ();
|
||
|
|
||
|
@@ -573,6 +608,12 @@ public:
|
||
|
add_eval (location *loc,
|
||
|
rvalue *rvalue);
|
||
|
|
||
|
+ void
|
||
|
+ add_try_catch (location *loc,
|
||
|
+ block *try_block,
|
||
|
+ block *catch_block,
|
||
|
+ bool is_finally);
|
||
|
+
|
||
|
void
|
||
|
add_assignment (location *loc,
|
||
|
lvalue *lvalue,
|
||
|
@@ -636,6 +677,7 @@ private:
|
||
|
|
||
|
public: // for now
|
||
|
tree m_label_expr;
|
||
|
+ bool m_is_try_or_catch = false;
|
||
|
|
||
|
friend class function;
|
||
|
};
|
||
|
@@ -813,4 +855,6 @@ extern playback::context *active_playback_ctxt;
|
||
|
|
||
|
} // namespace gcc
|
||
|
|
||
|
+extern hash_map<nofree_string_hash, tree> target_builtins;
|
||
|
+
|
||
|
#endif /* JIT_PLAYBACK_H */
|
||
|
diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc
|
||
|
index 2ce272267b8..603731b7fd4 100644
|
||
|
--- a/gcc/jit/jit-recording.cc
|
||
|
+++ b/gcc/jit/jit-recording.cc
|
||
|
@@ -840,9 +840,9 @@ recording::context::get_int_type (int num_bytes, int is_signed)
|
||
|
recording::type *
|
||
|
recording::context::new_array_type (recording::location *loc,
|
||
|
recording::type *element_type,
|
||
|
- int num_elements)
|
||
|
+ unsigned long num_elements)
|
||
|
{
|
||
|
- if (struct_ *s = element_type->dyn_cast_struct ())
|
||
|
+ /*if (struct_ *s = element_type->dyn_cast_struct ())
|
||
|
if (!s->get_fields ())
|
||
|
{
|
||
|
add_error (NULL,
|
||
|
@@ -850,7 +850,7 @@ recording::context::new_array_type (recording::location *loc,
|
||
|
" until the fields have been set",
|
||
|
s->get_name ()->c_str ());
|
||
|
return NULL;
|
||
|
- }
|
||
|
+ }*/
|
||
|
recording::type *result =
|
||
|
new recording::array_type (this, loc, element_type, num_elements);
|
||
|
record (result);
|
||
|
@@ -933,14 +933,16 @@ recording::function_type *
|
||
|
recording::context::new_function_type (recording::type *return_type,
|
||
|
int num_params,
|
||
|
recording::type **param_types,
|
||
|
- int is_variadic)
|
||
|
+ int is_variadic,
|
||
|
+ int is_target_builtin)
|
||
|
{
|
||
|
recording::function_type *fn_type
|
||
|
= new function_type (this,
|
||
|
return_type,
|
||
|
num_params,
|
||
|
param_types,
|
||
|
- is_variadic);
|
||
|
+ is_variadic,
|
||
|
+ is_target_builtin);
|
||
|
record (fn_type);
|
||
|
return fn_type;
|
||
|
}
|
||
|
@@ -962,7 +964,8 @@ recording::context::new_function_ptr_type (recording::location *, /* unused loc
|
||
|
= new_function_type (return_type,
|
||
|
num_params,
|
||
|
param_types,
|
||
|
- is_variadic);
|
||
|
+ is_variadic,
|
||
|
+ false);
|
||
|
|
||
|
/* Return a pointer-type to the function type. */
|
||
|
return fn_type->get_pointer ();
|
||
|
@@ -1005,7 +1008,7 @@ recording::context::new_function (recording::location *loc,
|
||
|
loc, kind, return_type,
|
||
|
new_string (name),
|
||
|
num_params, params, is_variadic,
|
||
|
- builtin_id);
|
||
|
+ builtin_id, false);
|
||
|
record (result);
|
||
|
m_functions.safe_push (result);
|
||
|
|
||
|
@@ -1044,6 +1047,52 @@ recording::context::get_builtin_function (const char *name)
|
||
|
return bm->get_builtin_function (name);
|
||
|
}
|
||
|
|
||
|
+/* Create a recording::function instance for a target-specific builtin.
|
||
|
+
|
||
|
+ Implements the post-error-checking part of
|
||
|
+ gcc_jit_context_get_target_builtin_function. */
|
||
|
+
|
||
|
+recording::function *
|
||
|
+recording::context::get_target_builtin_function (const char *name)
|
||
|
+{
|
||
|
+ const char *asm_name = name;
|
||
|
+ if (target_function_types.count (name) == 0)
|
||
|
+ {
|
||
|
+ fprintf (stderr, "Cannot find target builtin %s\n", name);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ recording::function_type* func_type = target_function_types[name]->copy (this)->dyn_cast_function_type ();
|
||
|
+ const vec<type *>& param_types = func_type->get_param_types ();
|
||
|
+ recording::param **params = new recording::param *[param_types.length ()];
|
||
|
+
|
||
|
+ int i;
|
||
|
+ recording::type *param_type;
|
||
|
+ FOR_EACH_VEC_ELT (param_types, i, param_type)
|
||
|
+ {
|
||
|
+ char buf[16];
|
||
|
+ snprintf (buf, 16, "arg%d", i);
|
||
|
+ params[i] = new_param (NULL,
|
||
|
+ param_type,
|
||
|
+ buf);
|
||
|
+ }
|
||
|
+
|
||
|
+ recording::function *result =
|
||
|
+ new recording::function (this,
|
||
|
+ NULL,
|
||
|
+ GCC_JIT_FUNCTION_IMPORTED, // FIXME
|
||
|
+ func_type->get_return_type (),
|
||
|
+ new_string (asm_name),
|
||
|
+ param_types.length (),
|
||
|
+ params,
|
||
|
+ func_type->is_variadic (),
|
||
|
+ BUILT_IN_NONE,
|
||
|
+ true);
|
||
|
+ record (result);
|
||
|
+
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
/* Create a recording::global instance and add it to this context's list
|
||
|
of mementos.
|
||
|
|
||
|
@@ -1108,6 +1157,18 @@ recording::context::new_rvalue_from_vector (location *loc,
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
+recording::rvalue *
|
||
|
+recording::context::new_rvalue_vector_perm (location *loc,
|
||
|
+ rvalue *elements1,
|
||
|
+ rvalue *elements2,
|
||
|
+ rvalue *mask)
|
||
|
+{
|
||
|
+ recording::rvalue *result
|
||
|
+ = new memento_of_new_rvalue_vector_perm (this, loc, elements1, elements2, mask);
|
||
|
+ record (result);
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
recording::rvalue *
|
||
|
recording::context::new_ctor (recording::location *loc,
|
||
|
recording::type *type,
|
||
|
@@ -1309,6 +1370,39 @@ recording::context::new_array_access (recording::location *loc,
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
+/* Create a recording::convert_vector instance and add it to this context's list
|
||
|
+ of mementos.
|
||
|
+
|
||
|
+ Implements the post-error-checking part of
|
||
|
+ gcc_jit_context_convert_vector. */
|
||
|
+
|
||
|
+recording::rvalue *
|
||
|
+recording::context::new_convert_vector (recording::location *loc,
|
||
|
+ recording::rvalue *vector,
|
||
|
+ recording::type *type)
|
||
|
+{
|
||
|
+ // TODO: instead have an "internal function" memento?
|
||
|
+ recording::rvalue *result = new convert_vector (this, loc, vector, type);
|
||
|
+ record (result);
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
+/* Create a recording::vector_access instance and add it to this context's list
|
||
|
+ of mementos.
|
||
|
+
|
||
|
+ Implements the post-error-checking part of
|
||
|
+ gcc_jit_context_new_vector_access. */
|
||
|
+
|
||
|
+recording::lvalue *
|
||
|
+recording::context::new_vector_access (recording::location *loc,
|
||
|
+ recording::rvalue *vector,
|
||
|
+ recording::rvalue *index)
|
||
|
+{
|
||
|
+ recording::lvalue *result = new vector_access (this, loc, vector, index);
|
||
|
+ record (result);
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
/* Create a recording::case_ instance and add it to this context's list
|
||
|
of mementos.
|
||
|
|
||
|
@@ -2294,6 +2388,12 @@ recording::type::get_aligned (size_t alignment_in_bytes)
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
+void
|
||
|
+recording::type::set_packed ()
|
||
|
+{
|
||
|
+ m_packed = true;
|
||
|
+}
|
||
|
+
|
||
|
/* Given a type, get a vector version of the type.
|
||
|
|
||
|
Implements the post-error-checking part of
|
||
|
@@ -2372,6 +2472,10 @@ recording::memento_of_get_type::get_size ()
|
||
|
case GCC_JIT_TYPE_FLOAT:
|
||
|
size = FLOAT_TYPE_SIZE;
|
||
|
break;
|
||
|
+ #ifdef HAVE_BFmode
|
||
|
+ case GCC_JIT_TYPE_BFLOAT16:
|
||
|
+ return GET_MODE_UNIT_SIZE (BFmode);
|
||
|
+ #endif
|
||
|
case GCC_JIT_TYPE_DOUBLE:
|
||
|
size = DOUBLE_TYPE_SIZE;
|
||
|
break;
|
||
|
@@ -2431,6 +2535,7 @@ recording::memento_of_get_type::dereference ()
|
||
|
case GCC_JIT_TYPE_INT64_T:
|
||
|
case GCC_JIT_TYPE_INT128_T:
|
||
|
case GCC_JIT_TYPE_FLOAT:
|
||
|
+ case GCC_JIT_TYPE_BFLOAT16:
|
||
|
case GCC_JIT_TYPE_DOUBLE:
|
||
|
case GCC_JIT_TYPE_LONG_DOUBLE:
|
||
|
case GCC_JIT_TYPE_COMPLEX_FLOAT:
|
||
|
@@ -2495,6 +2600,7 @@ recording::memento_of_get_type::is_int () const
|
||
|
return true;
|
||
|
|
||
|
case GCC_JIT_TYPE_FLOAT:
|
||
|
+ case GCC_JIT_TYPE_BFLOAT16:
|
||
|
case GCC_JIT_TYPE_DOUBLE:
|
||
|
case GCC_JIT_TYPE_LONG_DOUBLE:
|
||
|
return false;
|
||
|
@@ -2553,6 +2659,7 @@ recording::memento_of_get_type::is_signed () const
|
||
|
case GCC_JIT_TYPE_UINT128_T:
|
||
|
|
||
|
case GCC_JIT_TYPE_FLOAT:
|
||
|
+ case GCC_JIT_TYPE_BFLOAT16:
|
||
|
case GCC_JIT_TYPE_DOUBLE:
|
||
|
case GCC_JIT_TYPE_LONG_DOUBLE:
|
||
|
|
||
|
@@ -2612,6 +2719,7 @@ recording::memento_of_get_type::is_float () const
|
||
|
return false;
|
||
|
|
||
|
case GCC_JIT_TYPE_FLOAT:
|
||
|
+ case GCC_JIT_TYPE_BFLOAT16:
|
||
|
case GCC_JIT_TYPE_DOUBLE:
|
||
|
case GCC_JIT_TYPE_LONG_DOUBLE:
|
||
|
return true;
|
||
|
@@ -2675,6 +2783,7 @@ recording::memento_of_get_type::is_bool () const
|
||
|
return false;
|
||
|
|
||
|
case GCC_JIT_TYPE_FLOAT:
|
||
|
+ case GCC_JIT_TYPE_BFLOAT16:
|
||
|
case GCC_JIT_TYPE_DOUBLE:
|
||
|
case GCC_JIT_TYPE_LONG_DOUBLE:
|
||
|
return false;
|
||
|
@@ -2754,6 +2863,7 @@ static const char * const get_type_strings[] = {
|
||
|
"__int32_t", /* GCC_JIT_TYPE_INT32_T */
|
||
|
"__int64_t", /* GCC_JIT_TYPE_INT64_T */
|
||
|
"__int128_t", /* GCC_JIT_TYPE_INT128_T */
|
||
|
+ "bfloat16", /* GCC_JIT_TYPE_BFLOAT16 */
|
||
|
|
||
|
};
|
||
|
|
||
|
@@ -2800,6 +2910,7 @@ static const char * const get_type_enum_strings[] = {
|
||
|
"GCC_JIT_TYPE_INT32_T",
|
||
|
"GCC_JIT_TYPE_INT64_T",
|
||
|
"GCC_JIT_TYPE_INT128_T",
|
||
|
+ "GCC_JIT_TYPE_BFLOAT16",
|
||
|
};
|
||
|
|
||
|
void
|
||
|
@@ -3066,7 +3177,7 @@ recording::string *
|
||
|
recording::array_type::make_debug_string ()
|
||
|
{
|
||
|
return string::from_printf (m_ctxt,
|
||
|
- "%s[%d]",
|
||
|
+ "%s[%ld]",
|
||
|
m_element_type->get_debug_string (),
|
||
|
m_num_elements);
|
||
|
}
|
||
|
@@ -3082,7 +3193,7 @@ recording::array_type::write_reproducer (reproducer &r)
|
||
|
" gcc_jit_context_new_array_type (%s,\n"
|
||
|
" %s, /* gcc_jit_location *loc */\n"
|
||
|
" %s, /* gcc_jit_type *element_type */\n"
|
||
|
- " %i); /* int num_elements */\n",
|
||
|
+ " %li); /* int num_elements */\n",
|
||
|
id,
|
||
|
r.get_identifier (get_context ()),
|
||
|
r.get_identifier (m_loc),
|
||
|
@@ -3098,11 +3209,13 @@ recording::function_type::function_type (context *ctxt,
|
||
|
type *return_type,
|
||
|
int num_params,
|
||
|
type **param_types,
|
||
|
- int is_variadic)
|
||
|
+ int is_variadic,
|
||
|
+ int is_target_builtin)
|
||
|
: type (ctxt),
|
||
|
m_return_type (return_type),
|
||
|
m_param_types (),
|
||
|
- m_is_variadic (is_variadic)
|
||
|
+ m_is_variadic (is_variadic),
|
||
|
+ m_is_target_builtin (is_target_builtin)
|
||
|
{
|
||
|
for (int i = 0; i< num_params; i++)
|
||
|
m_param_types.safe_push (param_types[i]);
|
||
|
@@ -3484,7 +3597,8 @@ recording::struct_::replay_into (replayer *r)
|
||
|
set_playback_obj (
|
||
|
r->new_compound_type (playback_location (r, get_loc ()),
|
||
|
get_name ()->c_str (),
|
||
|
- true /* is_struct */));
|
||
|
+ true, /* is_struct */
|
||
|
+ m_packed));
|
||
|
}
|
||
|
|
||
|
const char *
|
||
|
@@ -3538,7 +3652,8 @@ recording::union_::replay_into (replayer *r)
|
||
|
set_playback_obj (
|
||
|
r->new_compound_type (playback_location (r, get_loc ()),
|
||
|
get_name ()->c_str (),
|
||
|
- false /* is_struct */));
|
||
|
+ false, /* is_struct */
|
||
|
+ m_packed));
|
||
|
}
|
||
|
|
||
|
/* Implementation of recording::memento::make_debug_string for
|
||
|
@@ -3609,7 +3724,7 @@ recording::fields::replay_into (replayer *)
|
||
|
playback_fields.create (m_fields.length ());
|
||
|
for (unsigned i = 0; i < m_fields.length (); i++)
|
||
|
playback_fields.safe_push (m_fields[i]->playback_field ());
|
||
|
- m_struct_or_union->playback_compound_type ()->set_fields (&playback_fields);
|
||
|
+ m_struct_or_union->playback_compound_type ()->set_fields (&playback_fields, m_struct_or_union->m_packed);
|
||
|
}
|
||
|
|
||
|
/* Override the default implementation of
|
||
|
@@ -3979,6 +4094,11 @@ void recording::lvalue::set_alignment (unsigned bytes)
|
||
|
m_alignment = bytes;
|
||
|
}
|
||
|
|
||
|
+void recording::lvalue::add_attribute (gcc_jit_variable_attribute attribute, const char* value)
|
||
|
+{
|
||
|
+ m_attributes.push_back (std::make_pair (attribute, std::string (value)));
|
||
|
+}
|
||
|
+
|
||
|
/* The implementation of class gcc::jit::recording::param. */
|
||
|
|
||
|
/* Implementation of pure virtual hook recording::memento::replay_into
|
||
|
@@ -4044,7 +4164,8 @@ recording::function::function (context *ctxt,
|
||
|
int num_params,
|
||
|
recording::param **params,
|
||
|
int is_variadic,
|
||
|
- enum built_in_function builtin_id)
|
||
|
+ enum built_in_function builtin_id,
|
||
|
+ int is_target_builtin)
|
||
|
: memento (ctxt),
|
||
|
m_loc (loc),
|
||
|
m_kind (kind),
|
||
|
@@ -4055,7 +4176,10 @@ recording::function::function (context *ctxt,
|
||
|
m_builtin_id (builtin_id),
|
||
|
m_locals (),
|
||
|
m_blocks (),
|
||
|
- m_fn_ptr_type (NULL)
|
||
|
+ m_fn_ptr_type (NULL),
|
||
|
+ m_attributes(),
|
||
|
+ m_string_attributes(),
|
||
|
+ m_is_target_builtin (is_target_builtin)
|
||
|
{
|
||
|
for (int i = 0; i< num_params; i++)
|
||
|
{
|
||
|
@@ -4114,7 +4238,40 @@ recording::function::replay_into (replayer *r)
|
||
|
m_name->c_str (),
|
||
|
¶ms,
|
||
|
m_is_variadic,
|
||
|
- m_builtin_id));
|
||
|
+ m_builtin_id,
|
||
|
+ m_attributes,
|
||
|
+ m_string_attributes,
|
||
|
+ m_is_target_builtin));
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of recording::memento::make_debug_string for
|
||
|
+ setting a personality function. */
|
||
|
+
|
||
|
+recording::string *
|
||
|
+recording::memento_of_set_personality_function::make_debug_string ()
|
||
|
+{
|
||
|
+ return string::from_printf (m_ctxt,
|
||
|
+ "%s",
|
||
|
+ m_personality_function->get_debug_string ());
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of recording::memento::write_reproducer for setting the personality function. */
|
||
|
+
|
||
|
+void
|
||
|
+recording::memento_of_set_personality_function::write_reproducer (reproducer &r)
|
||
|
+{
|
||
|
+ r.write (" gcc_jit_function_set_personality_function (%s,\n"
|
||
|
+ " %s);\n",
|
||
|
+ r.get_identifier (m_function),
|
||
|
+ r.get_identifier (m_personality_function));
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+recording::function::set_personality_function (function *function)
|
||
|
+{
|
||
|
+ recording::memento_of_set_personality_function *result =
|
||
|
+ new memento_of_set_personality_function (m_ctxt, this, function);
|
||
|
+ m_ctxt->record (result);
|
||
|
}
|
||
|
|
||
|
/* Create a recording::local instance and add it to
|
||
|
@@ -4259,6 +4416,13 @@ recording::function::validate ()
|
||
|
/* Iteratively walk the graph of blocks, marking their "m_is_reachable"
|
||
|
flag, starting at the initial block. */
|
||
|
auto_vec<block *> worklist (m_blocks.length ());
|
||
|
+ int j;
|
||
|
+ block *func_block;
|
||
|
+ /* Push the blocks used in try/catch because they're not successors of
|
||
|
+ other blocks. */
|
||
|
+ FOR_EACH_VEC_ELT (m_blocks, j, func_block)
|
||
|
+ if (func_block->m_is_reachable)
|
||
|
+ worklist.safe_push (func_block);
|
||
|
worklist.safe_push (m_blocks[0]);
|
||
|
while (worklist.length () > 0)
|
||
|
{
|
||
|
@@ -4347,7 +4511,8 @@ recording::function::get_address (recording::location *loc)
|
||
|
= m_ctxt->new_function_type (m_return_type,
|
||
|
m_params.length (),
|
||
|
param_types.address (),
|
||
|
- m_is_variadic);
|
||
|
+ m_is_variadic,
|
||
|
+ m_is_target_builtin);
|
||
|
m_fn_ptr_type = fn_type->get_pointer ();
|
||
|
}
|
||
|
gcc_assert (m_fn_ptr_type);
|
||
|
@@ -4357,6 +4522,18 @@ recording::function::get_address (recording::location *loc)
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
+void
|
||
|
+recording::function::add_attribute (gcc_jit_fn_attribute attribute)
|
||
|
+{
|
||
|
+ m_attributes.push_back (attribute);
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+recording::function::add_string_attribute (gcc_jit_fn_attribute attribute, const char* value)
|
||
|
+{
|
||
|
+ m_string_attributes.push_back (std::make_pair (attribute, std::string (value)));
|
||
|
+}
|
||
|
+
|
||
|
/* Implementation of recording::memento::make_debug_string for
|
||
|
functions. */
|
||
|
|
||
|
@@ -4441,6 +4618,31 @@ recording::block::add_eval (recording::location *loc,
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
+/* The implementation of class gcc::jit::recording::block. */
|
||
|
+
|
||
|
+/* Create a recording::try_catch 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_try_catch. */
|
||
|
+
|
||
|
+recording::statement *
|
||
|
+recording::block::add_try_catch (location *loc,
|
||
|
+ block *try_block,
|
||
|
+ block *catch_block,
|
||
|
+ bool is_finally)
|
||
|
+{
|
||
|
+ statement *result = new try_catch (this, loc, try_block, catch_block, is_finally);
|
||
|
+ // TODO: explain why we set the blocks reachable state.
|
||
|
+ try_block->m_is_reachable = true;
|
||
|
+ catch_block->m_is_reachable = true;
|
||
|
+ /* The finally block can fallthrough, so we don't require the user to terminate it. */
|
||
|
+ if (is_finally)
|
||
|
+ catch_block->m_has_been_terminated = true;
|
||
|
+ m_ctxt->record (result);
|
||
|
+ m_statements.safe_push (result);
|
||
|
+ return result;
|
||
|
+}
|
||
|
+
|
||
|
/* Create a recording::assignment instance and add it to
|
||
|
the block's context's list of mementos, and to the block's
|
||
|
list of statements.
|
||
|
@@ -4832,12 +5034,16 @@ recording::global::replay_into (replayer *r)
|
||
|
/ m_type->dereference ()->get_size (),
|
||
|
m_initializer,
|
||
|
playback_string (m_name),
|
||
|
- m_flags)
|
||
|
+ m_flags,
|
||
|
+ m_readonly,
|
||
|
+ m_attributes)
|
||
|
: r->new_global (playback_location (r, m_loc),
|
||
|
m_kind,
|
||
|
m_type->playback_type (),
|
||
|
playback_string (m_name),
|
||
|
- m_flags);
|
||
|
+ m_flags,
|
||
|
+ m_readonly,
|
||
|
+ m_attributes);
|
||
|
|
||
|
if (m_tls_model != GCC_JIT_TLS_MODEL_NONE)
|
||
|
global->set_tls_model (recording::tls_models[m_tls_model]);
|
||
|
@@ -5390,6 +5596,91 @@ recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r)
|
||
|
elements_id);
|
||
|
}
|
||
|
|
||
|
+/* The implementation of class
|
||
|
+ gcc::jit::recording::memento_of_new_rvalue_vector_perm. */
|
||
|
+
|
||
|
+/* The constructor for
|
||
|
+ gcc::jit::recording::memento_of_new_rvalue_vector_perm. */
|
||
|
+
|
||
|
+recording::memento_of_new_rvalue_vector_perm::
|
||
|
+memento_of_new_rvalue_vector_perm (context *ctxt,
|
||
|
+ location *loc,
|
||
|
+ rvalue *elements1,
|
||
|
+ rvalue *elements2,
|
||
|
+ rvalue *mask)
|
||
|
+: rvalue (ctxt, loc, elements1->get_type ()),
|
||
|
+ m_elements1 (elements1),
|
||
|
+ m_elements2 (elements2),
|
||
|
+ m_mask (mask)
|
||
|
+{
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of pure virtual hook recording::memento::replay_into
|
||
|
+ for recording::memento_of_new_rvalue_vector_perm. */
|
||
|
+
|
||
|
+void
|
||
|
+recording::memento_of_new_rvalue_vector_perm::replay_into (replayer *r)
|
||
|
+{
|
||
|
+ playback::rvalue *playback_elements1 = m_elements1->playback_rvalue ();
|
||
|
+ playback::rvalue *playback_elements2 = m_elements2->playback_rvalue ();
|
||
|
+ playback::rvalue *playback_mask = m_mask->playback_rvalue ();
|
||
|
+
|
||
|
+ set_playback_obj (r->new_rvalue_vector_perm (playback_location (r, m_loc),
|
||
|
+ playback_elements1,
|
||
|
+ playback_elements2,
|
||
|
+ playback_mask));
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of pure virtual hook recording::rvalue::visit_children
|
||
|
+ for recording::memento_of_new_rvalue_from_vector. */
|
||
|
+
|
||
|
+ void
|
||
|
+recording::memento_of_new_rvalue_vector_perm::visit_children (rvalue_visitor *v)
|
||
|
+{
|
||
|
+ v->visit (m_elements1);
|
||
|
+ v->visit (m_elements2);
|
||
|
+ v->visit (m_mask);
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of recording::memento::make_debug_string for
|
||
|
+ vectors. */
|
||
|
+
|
||
|
+ recording::string *
|
||
|
+recording::memento_of_new_rvalue_vector_perm::make_debug_string ()
|
||
|
+{
|
||
|
+ /* Now build a string. */
|
||
|
+ string *result = string::from_printf (m_ctxt,
|
||
|
+ "shufflevector(%s, %s, %s)",
|
||
|
+ m_elements1->get_debug_string (),
|
||
|
+ m_elements2->get_debug_string (),
|
||
|
+ m_mask->get_debug_string ());
|
||
|
+
|
||
|
+ return result;
|
||
|
+
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of recording::memento::write_reproducer for
|
||
|
+ vectors. */
|
||
|
+
|
||
|
+ void
|
||
|
+recording::memento_of_new_rvalue_vector_perm::write_reproducer (reproducer &r)
|
||
|
+{
|
||
|
+ const char *id = r.make_identifier (this, "vector");
|
||
|
+ r.write (" gcc_jit_rvalue *%s =\n"
|
||
|
+ " gcc_jit_context_new_rvalue_vector_perm (%s, /* gcc_jit_context *ctxt */\n"
|
||
|
+ " %s, /* gcc_jit_location *loc */\n"
|
||
|
+ " %s, /* gcc_jit_rvalue **elements1*/\n"
|
||
|
+ " %s, /* gcc_jit_rvalue **elements2*/\n"
|
||
|
+ " %s); /* gcc_jit_rvalue **mask*/\n",
|
||
|
+ id,
|
||
|
+ r.get_identifier (get_context ()),
|
||
|
+ r.get_identifier (m_loc),
|
||
|
+ r.get_identifier_as_rvalue (m_elements1),
|
||
|
+ r.get_identifier_as_rvalue (m_elements2),
|
||
|
+ r.get_identifier_as_rvalue (m_mask));
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
void
|
||
|
recording::ctor::visit_children (rvalue_visitor *v)
|
||
|
{
|
||
|
@@ -6260,6 +6551,114 @@ recording::array_access::write_reproducer (reproducer &r)
|
||
|
r.get_identifier_as_rvalue (m_index));
|
||
|
}
|
||
|
|
||
|
+/* The implementation of class gcc::jit::recording::convert_vector. */
|
||
|
+
|
||
|
+/* Implementation of pure virtual hook recording::memento::replay_into
|
||
|
+ for recording::convert_vector. */
|
||
|
+
|
||
|
+void
|
||
|
+recording::convert_vector::replay_into (replayer *r)
|
||
|
+{
|
||
|
+ set_playback_obj (
|
||
|
+ r->convert_vector (playback_location (r, m_loc),
|
||
|
+ m_vector->playback_rvalue (),
|
||
|
+ m_type->playback_type ()));
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of pure virtual hook recording::rvalue::visit_children
|
||
|
+ for recording::convert_vector. */
|
||
|
+
|
||
|
+void
|
||
|
+recording::convert_vector::visit_children (rvalue_visitor *v)
|
||
|
+{
|
||
|
+ v->visit (m_vector);
|
||
|
+}
|
||
|
+
|
||
|
+/* The implementation of class gcc::jit::recording::vector_access. */
|
||
|
+
|
||
|
+/* Implementation of pure virtual hook recording::memento::replay_into
|
||
|
+ for recording::vector_access. */
|
||
|
+
|
||
|
+void
|
||
|
+recording::vector_access::replay_into (replayer *r)
|
||
|
+{
|
||
|
+ set_playback_obj (
|
||
|
+ r->new_vector_access (playback_location (r, m_loc),
|
||
|
+ m_vector->playback_rvalue (),
|
||
|
+ m_index->playback_rvalue ()));
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of pure virtual hook recording::rvalue::visit_children
|
||
|
+ for recording::vector_access. */
|
||
|
+
|
||
|
+void
|
||
|
+recording::vector_access::visit_children (rvalue_visitor *v)
|
||
|
+{
|
||
|
+ v->visit (m_vector);
|
||
|
+ v->visit (m_index);
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of recording::memento::make_debug_string for
|
||
|
+ array accesses. */
|
||
|
+
|
||
|
+recording::string *
|
||
|
+recording::convert_vector::make_debug_string ()
|
||
|
+{
|
||
|
+ enum precedence prec = get_precedence ();
|
||
|
+ return string::from_printf (m_ctxt,
|
||
|
+ "(%s)%s",
|
||
|
+ m_type->get_debug_string (),
|
||
|
+ m_vector->get_debug_string_parens (prec));
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of recording::memento::write_reproducer for
|
||
|
+ convert_vector. */
|
||
|
+
|
||
|
+void
|
||
|
+recording::convert_vector::write_reproducer (reproducer &r)
|
||
|
+{
|
||
|
+ const char *id = r.make_identifier (this, "lvalue");
|
||
|
+ r.write (" gcc_jit_lvalue *%s = \n"
|
||
|
+ " gcc_jit_context_convert_vector (%s, /* gcc_jit_context *ctxt */\n"
|
||
|
+ " %s, /*gcc_jit_location *loc */\n"
|
||
|
+ " %s, /* gcc_jit_rvalue *vector */\n"
|
||
|
+ " %s); /* gcc_jit_type *type */\n",
|
||
|
+ id,
|
||
|
+ r.get_identifier (get_context ()),
|
||
|
+ r.get_identifier (m_loc),
|
||
|
+ r.get_identifier_as_rvalue (m_vector),
|
||
|
+ r.get_identifier_as_type (m_type));
|
||
|
+}
|
||
|
+
|
||
|
+recording::string *
|
||
|
+recording::vector_access::make_debug_string ()
|
||
|
+{
|
||
|
+ enum precedence prec = get_precedence ();
|
||
|
+ return string::from_printf (m_ctxt,
|
||
|
+ "%s[%s]",
|
||
|
+ m_vector->get_debug_string_parens (prec),
|
||
|
+ m_index->get_debug_string_parens (prec));
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of recording::memento::write_reproducer for
|
||
|
+ vector_access. */
|
||
|
+
|
||
|
+void
|
||
|
+recording::vector_access::write_reproducer (reproducer &r)
|
||
|
+{
|
||
|
+ const char *id = r.make_identifier (this, "lvalue");
|
||
|
+ r.write (" gcc_jit_lvalue *%s = \n"
|
||
|
+ " gcc_jit_context_new_vector_access (%s, /* gcc_jit_context *ctxt */\n"
|
||
|
+ " %s, /*gcc_jit_location *loc */\n"
|
||
|
+ " %s, /* gcc_jit_rvalue *vector */\n"
|
||
|
+ " %s); /* gcc_jit_rvalue *index */\n",
|
||
|
+ id,
|
||
|
+ r.get_identifier (get_context ()),
|
||
|
+ r.get_identifier (m_loc),
|
||
|
+ r.get_identifier_as_rvalue (m_vector),
|
||
|
+ r.get_identifier_as_rvalue (m_index));
|
||
|
+}
|
||
|
+
|
||
|
/* The implementation of class gcc::jit::recording::access_field_of_lvalue. */
|
||
|
|
||
|
/* Implementation of pure virtual hook recording::memento::replay_into
|
||
|
@@ -6575,7 +6974,8 @@ recording::local::replay_into (replayer *r)
|
||
|
playback::lvalue *obj = m_func->playback_function ()
|
||
|
->new_local (playback_location (r, m_loc),
|
||
|
m_type->playback_type (),
|
||
|
- playback_string (m_name));
|
||
|
+ playback_string (m_name),
|
||
|
+ m_attributes);
|
||
|
|
||
|
if (m_reg_name != NULL)
|
||
|
obj->set_register_name (m_reg_name->c_str ());
|
||
|
@@ -6649,6 +7049,17 @@ recording::statement::write_to_dump (dump &d)
|
||
|
m_loc = d.make_location ();
|
||
|
}
|
||
|
|
||
|
+/* The implementation of class gcc::jit::recording::memento_of_set_personality_function. */
|
||
|
+
|
||
|
+/* Implementation of pure virtual hook recording::memento::replay_into
|
||
|
+ for recording::memento_of_set_personality_function. */
|
||
|
+
|
||
|
+void
|
||
|
+recording::memento_of_set_personality_function::replay_into (replayer *r)
|
||
|
+{
|
||
|
+ m_function->playback_function ()->set_personality_function (m_personality_function->playback_function ());
|
||
|
+}
|
||
|
+
|
||
|
/* The implementation of class gcc::jit::recording::eval. */
|
||
|
|
||
|
/* Implementation of pure virtual hook recording::memento::replay_into
|
||
|
@@ -6687,6 +7098,59 @@ recording::eval::write_reproducer (reproducer &r)
|
||
|
r.get_identifier_as_rvalue (m_rvalue));
|
||
|
}
|
||
|
|
||
|
+/* The implementation of class gcc::jit::recording::try_catch. */
|
||
|
+
|
||
|
+/* Implementation of pure virtual hook recording::memento::replay_into
|
||
|
+ for recording::try_catch. */
|
||
|
+
|
||
|
+void
|
||
|
+recording::try_catch::replay_into (replayer *r)
|
||
|
+{
|
||
|
+ playback_block (get_block ())
|
||
|
+ ->add_try_catch (playback_location (r),
|
||
|
+ m_try_block->playback_block (),
|
||
|
+ m_catch_block->playback_block (),
|
||
|
+ m_is_finally);
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of recording::memento::make_debug_string for
|
||
|
+ an eval statement. */
|
||
|
+
|
||
|
+recording::string *
|
||
|
+recording::try_catch::make_debug_string ()
|
||
|
+{
|
||
|
+ if (m_is_finally)
|
||
|
+ return string::from_printf (m_ctxt,
|
||
|
+ "try { %s } finally { %s };",
|
||
|
+ m_try_block->get_debug_string (),
|
||
|
+ m_catch_block->get_debug_string ());
|
||
|
+ else
|
||
|
+ return string::from_printf (m_ctxt,
|
||
|
+ "try { %s } catch { %s };",
|
||
|
+ m_try_block->get_debug_string (),
|
||
|
+ m_catch_block->get_debug_string ());
|
||
|
+}
|
||
|
+
|
||
|
+/* Implementation of recording::memento::write_reproducer for
|
||
|
+ eval statements. */
|
||
|
+
|
||
|
+void
|
||
|
+recording::try_catch::write_reproducer (reproducer &r)
|
||
|
+{
|
||
|
+ const char *func_name = "gcc_jit_block_add_try_catch";
|
||
|
+ if (m_is_finally)
|
||
|
+ func_name = "gcc_jit_block_add_try_finally";
|
||
|
+ r.write (" %s (%s, /*gcc_jit_block *block */\n"
|
||
|
+ " %s, /* gcc_jit_location *loc */\n"
|
||
|
+ " %s, /* gcc_jit_block *try_block */\n"
|
||
|
+ " %s); /* gcc_jit_block *catch_block */\n",
|
||
|
+ func_name,
|
||
|
+ r.get_identifier (get_block ()),
|
||
|
+ r.get_identifier (get_loc ()),
|
||
|
+ r.get_identifier (m_try_block),
|
||
|
+ r.get_identifier (m_catch_block));
|
||
|
+}
|
||
|
+
|
||
|
/* The implementation of class gcc::jit::recording::assignment. */
|
||
|
|
||
|
/* Implementation of pure virtual hook recording::memento::replay_into
|
||
|
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
|
||
|
index e1236dec575..68a792a7cd5 100644
|
||
|
--- a/gcc/jit/jit-recording.h
|
||
|
+++ b/gcc/jit/jit-recording.h
|
||
|
@@ -23,13 +23,21 @@ along with GCC; see the file COPYING3. If not see
|
||
|
|
||
|
#include "jit-common.h"
|
||
|
#include "jit-logging.h"
|
||
|
+#include "libgccjit.h"
|
||
|
+
|
||
|
+#include <string>
|
||
|
+#include <vector>
|
||
|
+
|
||
|
+#include <string>
|
||
|
+#include <unordered_map>
|
||
|
|
||
|
class timer;
|
||
|
|
||
|
+extern std::unordered_map<std::string, gcc::jit::recording::function_type*> target_function_types;
|
||
|
+
|
||
|
namespace gcc {
|
||
|
|
||
|
namespace jit {
|
||
|
-
|
||
|
extern const char * const unary_op_reproducer_strings[];
|
||
|
extern const char * const binary_op_reproducer_strings[];
|
||
|
|
||
|
@@ -91,7 +99,7 @@ public:
|
||
|
type *
|
||
|
new_array_type (location *loc,
|
||
|
type *element_type,
|
||
|
- int num_elements);
|
||
|
+ unsigned long num_elements);
|
||
|
|
||
|
field *
|
||
|
new_field (location *loc,
|
||
|
@@ -116,7 +124,8 @@ public:
|
||
|
new_function_type (type *return_type,
|
||
|
int num_params,
|
||
|
type **param_types,
|
||
|
- int is_variadic);
|
||
|
+ int is_variadic,
|
||
|
+ int is_target_builtin);
|
||
|
|
||
|
type *
|
||
|
new_function_ptr_type (location *loc,
|
||
|
@@ -143,6 +152,9 @@ public:
|
||
|
function *
|
||
|
get_builtin_function (const char *name);
|
||
|
|
||
|
+ function *
|
||
|
+ get_target_builtin_function (const char *name);
|
||
|
+
|
||
|
lvalue *
|
||
|
new_global (location *loc,
|
||
|
enum gcc_jit_global_kind kind,
|
||
|
@@ -173,6 +185,12 @@ public:
|
||
|
vector_type *type,
|
||
|
rvalue **elements);
|
||
|
|
||
|
+ rvalue *
|
||
|
+ new_rvalue_vector_perm (location *loc,
|
||
|
+ rvalue *elements1,
|
||
|
+ rvalue *elements2,
|
||
|
+ rvalue *mask);
|
||
|
+
|
||
|
rvalue *
|
||
|
new_unary_op (location *loc,
|
||
|
enum gcc_jit_unary_op op,
|
||
|
@@ -215,6 +233,16 @@ public:
|
||
|
rvalue *ptr,
|
||
|
rvalue *index);
|
||
|
|
||
|
+ rvalue *
|
||
|
+ new_convert_vector (location *loc,
|
||
|
+ rvalue *vector,
|
||
|
+ type *type);
|
||
|
+
|
||
|
+ lvalue *
|
||
|
+ new_vector_access (location *loc,
|
||
|
+ rvalue *vector,
|
||
|
+ rvalue *index);
|
||
|
+
|
||
|
case_ *
|
||
|
new_case (rvalue *min_value,
|
||
|
rvalue *max_value,
|
||
|
@@ -527,6 +555,8 @@ public:
|
||
|
type *get_aligned (size_t alignment_in_bytes);
|
||
|
type *get_vector (size_t num_units);
|
||
|
|
||
|
+ void set_packed ();
|
||
|
+
|
||
|
/* Get the type obtained when dereferencing this type.
|
||
|
|
||
|
This will return NULL if it's not valid to dereference this type.
|
||
|
@@ -539,6 +569,8 @@ public:
|
||
|
these types. */
|
||
|
virtual size_t get_size () { gcc_unreachable (); }
|
||
|
|
||
|
+ virtual type* copy(context* ctxt) = 0;
|
||
|
+
|
||
|
/* Dynamic casts. */
|
||
|
virtual function_type *dyn_cast_function_type () { return NULL; }
|
||
|
virtual function_type *as_a_function_type() { gcc_unreachable (); return NULL; }
|
||
|
@@ -593,9 +625,13 @@ public:
|
||
|
protected:
|
||
|
type (context *ctxt)
|
||
|
: memento (ctxt),
|
||
|
+ m_packed (false),
|
||
|
m_pointer_to_this_type (NULL)
|
||
|
{}
|
||
|
|
||
|
+public:
|
||
|
+ bool m_packed;
|
||
|
+
|
||
|
private:
|
||
|
type *m_pointer_to_this_type;
|
||
|
};
|
||
|
@@ -613,6 +649,11 @@ public:
|
||
|
|
||
|
size_t get_size () final override;
|
||
|
|
||
|
+ type* copy(context* ctxt) final override
|
||
|
+ {
|
||
|
+ return ctxt->get_type (m_kind);
|
||
|
+ }
|
||
|
+
|
||
|
bool accepts_writes_from (type *rtype) final override
|
||
|
{
|
||
|
if (m_kind == GCC_JIT_TYPE_VOID_PTR)
|
||
|
@@ -664,6 +705,13 @@ public:
|
||
|
|
||
|
type *dereference () final override { return m_other_type; }
|
||
|
|
||
|
+ type* copy(context* ctxt) final override
|
||
|
+ {
|
||
|
+ type* result = new memento_of_get_pointer (m_other_type->copy (ctxt));
|
||
|
+ ctxt->record (result);
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
size_t get_size () final override;
|
||
|
|
||
|
bool accepts_writes_from (type *rtype) final override;
|
||
|
@@ -699,6 +747,7 @@ public:
|
||
|
|
||
|
size_t get_size () final override { return m_other_type->get_size (); };
|
||
|
|
||
|
+ // FIXME: this is wrong. A vector is not an int.
|
||
|
bool is_int () const final override { return m_other_type->is_int (); }
|
||
|
bool is_float () const final override { return m_other_type->is_float (); }
|
||
|
bool is_bool () const final override { return m_other_type->is_bool (); }
|
||
|
@@ -718,10 +767,11 @@ public:
|
||
|
memento_of_get_const (type *other_type)
|
||
|
: decorated_type (other_type) {}
|
||
|
|
||
|
- bool accepts_writes_from (type */*rtype*/) final override
|
||
|
+ type* copy(context* ctxt) final override
|
||
|
{
|
||
|
- /* Can't write to a "const". */
|
||
|
- return false;
|
||
|
+ type* result = new memento_of_get_const (m_other_type->copy (ctxt));
|
||
|
+ ctxt->record (result);
|
||
|
+ return result;
|
||
|
}
|
||
|
|
||
|
/* Strip off the "const", giving the underlying type. */
|
||
|
@@ -757,6 +807,13 @@ public:
|
||
|
return m_other_type->is_same_type_as (other->is_volatile ());
|
||
|
}
|
||
|
|
||
|
+ type* copy(context* ctxt) final override
|
||
|
+ {
|
||
|
+ type* result = new memento_of_get_volatile (m_other_type->copy (ctxt));
|
||
|
+ ctxt->record (result);
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
/* Strip off the "volatile", giving the underlying type. */
|
||
|
type *unqualified () final override { return m_other_type; }
|
||
|
|
||
|
@@ -777,11 +834,20 @@ public:
|
||
|
: decorated_type (other_type),
|
||
|
m_alignment_in_bytes (alignment_in_bytes) {}
|
||
|
|
||
|
+ type* copy(context* ctxt) final override
|
||
|
+ {
|
||
|
+ type* result = new memento_of_get_aligned (m_other_type->copy (ctxt), m_alignment_in_bytes);
|
||
|
+ ctxt->record (result);
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
/* Strip off the alignment, giving the underlying type. */
|
||
|
type *unqualified () final override { return m_other_type; }
|
||
|
|
||
|
void replay_into (replayer *) final override;
|
||
|
|
||
|
+ vector_type *dyn_cast_vector_type () final override { return m_other_type->dyn_cast_vector_type (); }
|
||
|
+
|
||
|
private:
|
||
|
string * make_debug_string () final override;
|
||
|
void write_reproducer (reproducer &r) final override;
|
||
|
@@ -798,6 +864,13 @@ public:
|
||
|
: decorated_type (other_type),
|
||
|
m_num_units (num_units) {}
|
||
|
|
||
|
+ type* copy(context* ctxt) final override
|
||
|
+ {
|
||
|
+ type* result = new vector_type(m_other_type->copy (ctxt), m_num_units);
|
||
|
+ ctxt->record (result);
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
size_t get_num_units () const { return m_num_units; }
|
||
|
|
||
|
vector_type *dyn_cast_vector_type () final override { return this; }
|
||
|
@@ -831,7 +904,7 @@ class array_type : public type
|
||
|
array_type (context *ctxt,
|
||
|
location *loc,
|
||
|
type *element_type,
|
||
|
- int num_elements)
|
||
|
+ unsigned long num_elements)
|
||
|
: type (ctxt),
|
||
|
m_loc (loc),
|
||
|
m_element_type (element_type),
|
||
|
@@ -840,12 +913,19 @@ class array_type : public type
|
||
|
|
||
|
type *dereference () final override;
|
||
|
|
||
|
+ type* copy(context* ctxt) final override
|
||
|
+ {
|
||
|
+ type* result = new array_type (ctxt, m_loc, m_element_type->copy (ctxt), m_num_elements);
|
||
|
+ ctxt->record (result);
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
bool is_int () const final override { return false; }
|
||
|
bool is_float () const final override { return false; }
|
||
|
bool is_bool () const final override { return false; }
|
||
|
type *is_pointer () final override { return NULL; }
|
||
|
type *is_array () final override { return m_element_type; }
|
||
|
- int num_elements () { return m_num_elements; }
|
||
|
+ unsigned long num_elements () { return m_num_elements; }
|
||
|
bool is_signed () const final override { return false; }
|
||
|
|
||
|
void replay_into (replayer *) final override;
|
||
|
@@ -857,7 +937,7 @@ class array_type : public type
|
||
|
private:
|
||
|
location *m_loc;
|
||
|
type *m_element_type;
|
||
|
- int m_num_elements;
|
||
|
+ unsigned long m_num_elements;
|
||
|
};
|
||
|
|
||
|
class function_type : public type
|
||
|
@@ -867,7 +947,8 @@ public:
|
||
|
type *return_type,
|
||
|
int num_params,
|
||
|
type **param_types,
|
||
|
- int is_variadic);
|
||
|
+ int is_variadic,
|
||
|
+ int is_target_builtin);
|
||
|
|
||
|
type *dereference () final override;
|
||
|
function_type *dyn_cast_function_type () final override { return this; }
|
||
|
@@ -875,6 +956,18 @@ public:
|
||
|
|
||
|
bool is_same_type_as (type *other) final override;
|
||
|
|
||
|
+ type* copy(context* ctxt) final override
|
||
|
+ {
|
||
|
+ auto_vec<type *> new_params{};
|
||
|
+ for (size_t i = 0; i < m_param_types.length (); i++)
|
||
|
+ new_params.safe_push (m_param_types[i]->copy (ctxt));
|
||
|
+
|
||
|
+ type* result = new function_type (ctxt, m_return_type->copy (ctxt), m_param_types.length (), new_params.address (),
|
||
|
+ m_is_variadic, m_is_target_builtin);
|
||
|
+ ctxt->record (result);
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
bool is_int () const final override { return false; }
|
||
|
bool is_float () const final override { return false; }
|
||
|
bool is_bool () const final override { return false; }
|
||
|
@@ -887,6 +980,7 @@ public:
|
||
|
type * get_return_type () const { return m_return_type; }
|
||
|
const vec<type *> &get_param_types () const { return m_param_types; }
|
||
|
int is_variadic () const { return m_is_variadic; }
|
||
|
+ int is_target_builtin () const { return m_is_target_builtin; }
|
||
|
|
||
|
string * make_debug_string_with_ptr ();
|
||
|
|
||
|
@@ -903,6 +997,7 @@ private:
|
||
|
type *m_return_type;
|
||
|
auto_vec<type *> m_param_types;
|
||
|
int m_is_variadic;
|
||
|
+ int m_is_target_builtin;
|
||
|
};
|
||
|
|
||
|
class field : public memento
|
||
|
@@ -1004,9 +1099,11 @@ public:
|
||
|
return static_cast <playback::compound_type *> (m_playback_obj);
|
||
|
}
|
||
|
|
||
|
-private:
|
||
|
+protected:
|
||
|
location *m_loc;
|
||
|
string *m_name;
|
||
|
+
|
||
|
+private:
|
||
|
fields *m_fields;
|
||
|
};
|
||
|
|
||
|
@@ -1019,6 +1116,13 @@ public:
|
||
|
|
||
|
struct_ *dyn_cast_struct () final override { return this; }
|
||
|
|
||
|
+ type* copy(context* ctxt) final override
|
||
|
+ {
|
||
|
+ type* result = new struct_ (ctxt, m_loc, m_name);
|
||
|
+ ctxt->record (result);
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
type *
|
||
|
as_type () { return this; }
|
||
|
|
||
|
@@ -1066,6 +1170,13 @@ public:
|
||
|
|
||
|
void replay_into (replayer *r) final override;
|
||
|
|
||
|
+ type* copy(context* ctxt) final override
|
||
|
+ {
|
||
|
+ type* result = new union_ (ctxt, m_loc, m_name);
|
||
|
+ ctxt->record (result);
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
bool is_union () const final override { return true; }
|
||
|
|
||
|
private:
|
||
|
@@ -1188,7 +1299,8 @@ public:
|
||
|
m_link_section (NULL),
|
||
|
m_reg_name (NULL),
|
||
|
m_tls_model (GCC_JIT_TLS_MODEL_NONE),
|
||
|
- m_alignment (0)
|
||
|
+ m_alignment (0),
|
||
|
+ m_attributes ()
|
||
|
{}
|
||
|
|
||
|
playback::lvalue *
|
||
|
@@ -1208,6 +1320,14 @@ public:
|
||
|
as_rvalue () { return this; }
|
||
|
|
||
|
const char *access_as_rvalue (reproducer &r) override;
|
||
|
+
|
||
|
+ void set_readonly ()
|
||
|
+ {
|
||
|
+ m_readonly = true;
|
||
|
+ }
|
||
|
+
|
||
|
+ void add_attribute (gcc_jit_variable_attribute attribute, const char* value);
|
||
|
+
|
||
|
virtual const char *access_as_lvalue (reproducer &r);
|
||
|
virtual bool is_global () const { return false; }
|
||
|
void set_tls_model (enum gcc_jit_tls_model model);
|
||
|
@@ -1221,6 +1341,8 @@ protected:
|
||
|
string *m_reg_name;
|
||
|
enum gcc_jit_tls_model m_tls_model;
|
||
|
unsigned m_alignment;
|
||
|
+ bool m_readonly = false;
|
||
|
+ std::vector<std::pair<gcc_jit_variable_attribute, std::string>> m_attributes;
|
||
|
};
|
||
|
|
||
|
class param : public lvalue
|
||
|
@@ -1274,7 +1396,8 @@ public:
|
||
|
int num_params,
|
||
|
param **params,
|
||
|
int is_variadic,
|
||
|
- enum built_in_function builtin_id);
|
||
|
+ enum built_in_function builtin_id,
|
||
|
+ int is_target_builtin);
|
||
|
|
||
|
void replay_into (replayer *r) final override;
|
||
|
|
||
|
@@ -1308,11 +1431,17 @@ public:
|
||
|
|
||
|
void write_to_dump (dump &d) final override;
|
||
|
|
||
|
+ bool is_target_builtin () const { return m_is_target_builtin; }
|
||
|
+
|
||
|
void validate ();
|
||
|
|
||
|
void dump_to_dot (const char *path);
|
||
|
|
||
|
rvalue *get_address (location *loc);
|
||
|
+ void set_personality_function (function *function);
|
||
|
+
|
||
|
+ void add_attribute (gcc_jit_fn_attribute attribute);
|
||
|
+ void add_string_attribute (gcc_jit_fn_attribute attribute, const char* value);
|
||
|
|
||
|
private:
|
||
|
string * make_debug_string () final override;
|
||
|
@@ -1329,6 +1458,9 @@ private:
|
||
|
auto_vec<local *> m_locals;
|
||
|
auto_vec<block *> m_blocks;
|
||
|
type *m_fn_ptr_type;
|
||
|
+ std::vector<gcc_jit_fn_attribute> m_attributes;
|
||
|
+ std::vector<std::pair<gcc_jit_fn_attribute, std::string>> m_string_attributes;
|
||
|
+ int m_is_target_builtin;
|
||
|
};
|
||
|
|
||
|
class block : public memento
|
||
|
@@ -1357,6 +1489,12 @@ public:
|
||
|
add_eval (location *loc,
|
||
|
rvalue *rvalue);
|
||
|
|
||
|
+ statement *
|
||
|
+ add_try_catch (location *loc,
|
||
|
+ block *try_block,
|
||
|
+ block *catch_block,
|
||
|
+ bool is_finally = false);
|
||
|
+
|
||
|
statement *
|
||
|
add_assignment (location *loc,
|
||
|
lvalue *lvalue,
|
||
|
@@ -1572,6 +1710,27 @@ private:
|
||
|
string *m_value;
|
||
|
};
|
||
|
|
||
|
+class memento_of_set_personality_function : public memento
|
||
|
+{
|
||
|
+public:
|
||
|
+ memento_of_set_personality_function (context *ctx,
|
||
|
+ function *func,
|
||
|
+ function *personality_function)
|
||
|
+ : memento(ctx),
|
||
|
+ m_function (func),
|
||
|
+ m_personality_function (personality_function) {}
|
||
|
+
|
||
|
+ void replay_into (replayer *r) final override;
|
||
|
+
|
||
|
+private:
|
||
|
+ string * make_debug_string () final override;
|
||
|
+ void write_reproducer (reproducer &r) final override;
|
||
|
+
|
||
|
+private:
|
||
|
+ function *m_function;
|
||
|
+ function *m_personality_function;
|
||
|
+};
|
||
|
+
|
||
|
class memento_of_new_rvalue_from_vector : public rvalue
|
||
|
{
|
||
|
public:
|
||
|
@@ -1597,6 +1756,33 @@ private:
|
||
|
auto_vec<rvalue *> m_elements;
|
||
|
};
|
||
|
|
||
|
+class memento_of_new_rvalue_vector_perm : public rvalue
|
||
|
+{
|
||
|
+public:
|
||
|
+ memento_of_new_rvalue_vector_perm (context *ctxt,
|
||
|
+ location *loc,
|
||
|
+ rvalue *elements1,
|
||
|
+ rvalue *elements2,
|
||
|
+ rvalue *mask);
|
||
|
+
|
||
|
+ void replay_into (replayer *r) final override;
|
||
|
+
|
||
|
+ void visit_children (rvalue_visitor *) final override;
|
||
|
+
|
||
|
+private:
|
||
|
+ string * make_debug_string () final override;
|
||
|
+ void write_reproducer (reproducer &r) final override;
|
||
|
+ enum precedence get_precedence () const final override
|
||
|
+ {
|
||
|
+ return PRECEDENCE_PRIMARY;
|
||
|
+ }
|
||
|
+
|
||
|
+private:
|
||
|
+ rvalue *m_elements1;
|
||
|
+ rvalue *m_elements2;
|
||
|
+ rvalue *m_mask;
|
||
|
+};
|
||
|
+
|
||
|
class ctor : public rvalue
|
||
|
{
|
||
|
public:
|
||
|
@@ -1879,6 +2065,64 @@ private:
|
||
|
rvalue *m_index;
|
||
|
};
|
||
|
|
||
|
+class convert_vector : public rvalue
|
||
|
+{
|
||
|
+public:
|
||
|
+ convert_vector (context *ctxt,
|
||
|
+ location *loc,
|
||
|
+ rvalue *vector,
|
||
|
+ type *type)
|
||
|
+ : rvalue (ctxt, loc, type),
|
||
|
+ m_vector (vector),
|
||
|
+ m_type (type)
|
||
|
+ {}
|
||
|
+
|
||
|
+ void replay_into (replayer *r) final override;
|
||
|
+
|
||
|
+ void visit_children (rvalue_visitor *v) final override;
|
||
|
+
|
||
|
+private:
|
||
|
+ string * make_debug_string () final override;
|
||
|
+ void write_reproducer (reproducer &r) final override;
|
||
|
+ enum precedence get_precedence () const final override
|
||
|
+ {
|
||
|
+ return PRECEDENCE_POSTFIX;
|
||
|
+ }
|
||
|
+
|
||
|
+private:
|
||
|
+ rvalue *m_vector;
|
||
|
+ type *m_type;
|
||
|
+};
|
||
|
+
|
||
|
+class vector_access : public lvalue
|
||
|
+{
|
||
|
+public:
|
||
|
+ vector_access (context *ctxt,
|
||
|
+ location *loc,
|
||
|
+ rvalue *vector,
|
||
|
+ rvalue *index)
|
||
|
+ : lvalue (ctxt, loc, vector->get_type ()->dyn_cast_vector_type ()->get_element_type ()),
|
||
|
+ m_vector (vector),
|
||
|
+ m_index (index)
|
||
|
+ {}
|
||
|
+
|
||
|
+ void replay_into (replayer *r) final override;
|
||
|
+
|
||
|
+ void visit_children (rvalue_visitor *v) final override;
|
||
|
+
|
||
|
+private:
|
||
|
+ string * make_debug_string () final override;
|
||
|
+ void write_reproducer (reproducer &r) final override;
|
||
|
+ enum precedence get_precedence () const final override
|
||
|
+ {
|
||
|
+ return PRECEDENCE_POSTFIX;
|
||
|
+ }
|
||
|
+
|
||
|
+private:
|
||
|
+ rvalue *m_vector;
|
||
|
+ rvalue *m_index;
|
||
|
+};
|
||
|
+
|
||
|
class access_field_of_lvalue : public lvalue
|
||
|
{
|
||
|
public:
|
||
|
@@ -2119,6 +2363,31 @@ private:
|
||
|
rvalue *m_rvalue;
|
||
|
};
|
||
|
|
||
|
+class try_catch : public statement
|
||
|
+{
|
||
|
+public:
|
||
|
+ try_catch (block *b,
|
||
|
+ location *loc,
|
||
|
+ block *try_block,
|
||
|
+ block *catch_block,
|
||
|
+ bool is_finally = false)
|
||
|
+ : statement (b, loc),
|
||
|
+ m_try_block (try_block),
|
||
|
+ m_catch_block (catch_block),
|
||
|
+ m_is_finally (is_finally) {}
|
||
|
+
|
||
|
+ void replay_into (replayer *r) final override;
|
||
|
+
|
||
|
+private:
|
||
|
+ string * make_debug_string () final override;
|
||
|
+ void write_reproducer (reproducer &r) final override;
|
||
|
+
|
||
|
+private:
|
||
|
+ block *m_try_block;
|
||
|
+ block *m_catch_block;
|
||
|
+ bool m_is_finally;
|
||
|
+};
|
||
|
+
|
||
|
class assignment : public statement
|
||
|
{
|
||
|
public:
|
||
|
diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc
|
||
|
index 8884128e8d8..bbf94231930 100644
|
||
|
--- a/gcc/jit/libgccjit.cc
|
||
|
+++ b/gcc/jit/libgccjit.cc
|
||
|
@@ -592,6 +592,20 @@ gcc_jit_type_is_pointer (gcc_jit_type *type)
|
||
|
return (gcc_jit_type *)type->is_pointer ();
|
||
|
}
|
||
|
|
||
|
+/* Public entrypoint. See description in libgccjit.h.
|
||
|
+
|
||
|
+ After error-checking, the real work is done by the
|
||
|
+ gcc::jit::recording::type::is_const method, in
|
||
|
+ jit-recording.cc. */
|
||
|
+
|
||
|
+gcc_jit_type *
|
||
|
+gcc_jit_type_is_const (gcc_jit_type *type)
|
||
|
+{
|
||
|
+ RETURN_NULL_IF_FAIL (type, NULL, NULL, "NULL type");
|
||
|
+
|
||
|
+ return (gcc_jit_type *)type->is_const ();
|
||
|
+}
|
||
|
+
|
||
|
/* Public entrypoint. See description in libgccjit.h.
|
||
|
|
||
|
After error-checking, the real work is done by the
|
||
|
@@ -751,7 +765,7 @@ gcc_jit_type *
|
||
|
gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
|
||
|
gcc_jit_location *loc,
|
||
|
gcc_jit_type *element_type,
|
||
|
- int num_elements)
|
||
|
+ unsigned long num_elements)
|
||
|
{
|
||
|
RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
|
||
|
JIT_LOG_FUNC (ctxt->get_logger ());
|
||
|
@@ -783,12 +797,13 @@ gcc_jit_context_new_field (gcc_jit_context *ctxt,
|
||
|
/* LOC can be NULL. */
|
||
|
RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
|
||
|
RETURN_NULL_IF_FAIL (name, ctxt, loc, "NULL name");
|
||
|
- RETURN_NULL_IF_FAIL_PRINTF2 (
|
||
|
+ // TODO: check at playback if the size is known.
|
||
|
+ /*RETURN_NULL_IF_FAIL_PRINTF2 (
|
||
|
type->has_known_size (),
|
||
|
ctxt, loc,
|
||
|
"unknown size for field \"%s\" (type: %s)",
|
||
|
name,
|
||
|
- type->get_debug_string ());
|
||
|
+ type->get_debug_string ());*/
|
||
|
RETURN_NULL_IF_FAIL_PRINTF1 (
|
||
|
!type->is_void (),
|
||
|
ctxt, loc,
|
||
|
@@ -995,6 +1010,7 @@ size_t
|
||
|
gcc_jit_struct_get_field_count (gcc_jit_struct *struct_type)
|
||
|
{
|
||
|
RETURN_VAL_IF_FAIL (struct_type, 0, NULL, NULL, "NULL struct type");
|
||
|
+ RETURN_VAL_IF_FAIL (struct_type->get_fields (), 0, NULL, NULL, "NULL fields");
|
||
|
return struct_type->get_fields ()->length ();
|
||
|
}
|
||
|
|
||
|
@@ -1745,6 +1761,23 @@ gcc_jit_context_new_array_constructor (gcc_jit_context *ctxt,
|
||
|
reinterpret_cast<gcc::jit::recording::rvalue**>(values));
|
||
|
}
|
||
|
|
||
|
+/* Public entrypoint. See description in libgccjit.h.
|
||
|
+
|
||
|
+ After error-checking, the real work is done by the
|
||
|
+ gcc::jit::recording::context::get_target_builtin_function method, in
|
||
|
+ jit-recording.c. */
|
||
|
+
|
||
|
+gcc_jit_function *
|
||
|
+gcc_jit_context_get_target_builtin_function (gcc_jit_context *ctxt,
|
||
|
+ const char *name)
|
||
|
+{
|
||
|
+ RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
|
||
|
+ JIT_LOG_FUNC (ctxt->get_logger ());
|
||
|
+ RETURN_NULL_IF_FAIL (name, ctxt, NULL, "NULL name");
|
||
|
+
|
||
|
+ return static_cast <gcc_jit_function *> (ctxt->get_target_builtin_function (name));
|
||
|
+}
|
||
|
+
|
||
|
/* Public entrypoint. See description in libgccjit.h. */
|
||
|
|
||
|
extern gcc_jit_lvalue *
|
||
|
@@ -1853,6 +1886,23 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global,
|
||
|
return global;
|
||
|
}
|
||
|
|
||
|
+/* Public entrypoint. See description in libgccjit.h.
|
||
|
+
|
||
|
+ After error-checking, the real work is done by the
|
||
|
+ gcc::jit::recording::global::set_readonly method, in
|
||
|
+ jit-recording.cc. */
|
||
|
+
|
||
|
+extern void
|
||
|
+gcc_jit_global_set_readonly (gcc_jit_lvalue *global)
|
||
|
+{
|
||
|
+ RETURN_IF_FAIL (global, NULL, NULL, "NULL global");
|
||
|
+ RETURN_IF_FAIL_PRINTF1 (global->is_global (), NULL, NULL,
|
||
|
+ "lvalue \"%s\" not a global",
|
||
|
+ global->get_debug_string ());
|
||
|
+
|
||
|
+ global->set_readonly ();
|
||
|
+}
|
||
|
+
|
||
|
/* Public entrypoint. See description in libgccjit.h.
|
||
|
|
||
|
After error-checking, this calls the trivial
|
||
|
@@ -2422,6 +2472,8 @@ gcc_jit_context_new_cast (gcc_jit_context *ctxt,
|
||
|
/* LOC can be NULL. */
|
||
|
RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
|
||
|
RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
|
||
|
+ gcc::jit::recording::vector_type *vector_type = type->dyn_cast_vector_type ();
|
||
|
+ RETURN_NULL_IF_FAIL (vector_type == NULL, ctxt, loc, "cannot cast vector types");
|
||
|
RETURN_NULL_IF_FAIL_PRINTF3 (
|
||
|
is_valid_cast (rvalue->get_type (), type),
|
||
|
ctxt, loc,
|
||
|
@@ -2488,6 +2540,60 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
|
||
|
return (gcc_jit_lvalue *)ctxt->new_array_access (loc, ptr, index);
|
||
|
}
|
||
|
|
||
|
+/* Public entrypoint. See description in libgccjit.h.
|
||
|
+
|
||
|
+ After error-checking, the real work is done by the
|
||
|
+ gcc::jit::recording::context::new_convert_vector method in
|
||
|
+ jit-recording.cc. */
|
||
|
+
|
||
|
+gcc_jit_rvalue *
|
||
|
+gcc_jit_context_convert_vector (gcc_jit_context *ctxt,
|
||
|
+ gcc_jit_location *loc,
|
||
|
+ gcc_jit_rvalue *vector,
|
||
|
+ gcc_jit_type *type)
|
||
|
+{
|
||
|
+ RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
|
||
|
+ JIT_LOG_FUNC (ctxt->get_logger ());
|
||
|
+ /* LOC can be NULL. */
|
||
|
+ RETURN_NULL_IF_FAIL (vector, ctxt, loc, "NULL vector");
|
||
|
+ RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
|
||
|
+
|
||
|
+ // TODO: check if the value is a vector.
|
||
|
+ // TODO: check if type is a vector type.
|
||
|
+ // TODO: check if the number of elements in vector and type matches.
|
||
|
+
|
||
|
+ return (gcc_jit_rvalue *)ctxt->new_convert_vector (loc, vector, type);
|
||
|
+}
|
||
|
+
|
||
|
+/* Public entrypoint. See description in libgccjit.h.
|
||
|
+
|
||
|
+ After error-checking, the real work is done by the
|
||
|
+ gcc::jit::recording::context::new_vector_access method in
|
||
|
+ jit-recording.cc. */
|
||
|
+
|
||
|
+extern gcc_jit_lvalue *
|
||
|
+gcc_jit_context_new_vector_access (gcc_jit_context *ctxt,
|
||
|
+ gcc_jit_location *loc,
|
||
|
+ gcc_jit_rvalue *vector,
|
||
|
+ gcc_jit_rvalue *index)
|
||
|
+{
|
||
|
+ RETURN_NULL_IF_FAIL (index, ctxt, loc, "NULL index");
|
||
|
+ RETURN_NULL_IF_FAIL_PRINTF2 (
|
||
|
+ vector->get_type ()->dyn_cast_vector_type (),
|
||
|
+ ctxt, loc,
|
||
|
+ "vector: %s (type: %s) is not a vector",
|
||
|
+ vector->get_debug_string (),
|
||
|
+ vector->get_type ()->get_debug_string ());
|
||
|
+ RETURN_NULL_IF_FAIL_PRINTF2 (
|
||
|
+ index->get_type ()->is_numeric (),
|
||
|
+ ctxt, loc,
|
||
|
+ "index: %s (type: %s) is not of numeric type",
|
||
|
+ index->get_debug_string (),
|
||
|
+ index->get_type ()->get_debug_string ());
|
||
|
+
|
||
|
+ return (gcc_jit_lvalue *)ctxt->new_vector_access (loc, vector, index);
|
||
|
+}
|
||
|
+
|
||
|
/* Public entrypoint. See description in libgccjit.h.
|
||
|
|
||
|
After error-checking, the real work is done by the
|
||
|
@@ -2801,6 +2907,64 @@ gcc_jit_block_add_eval (gcc_jit_block *block,
|
||
|
rvalue->verify_valid_within_stmt (__func__, stmt);
|
||
|
}
|
||
|
|
||
|
+/* Public entrypoint. See description in libgccjit.h.
|
||
|
+ After error-checking, the real work is done by the
|
||
|
+ gcc::jit::recording::block::add_try_catch method in jit-recording.c. */
|
||
|
+
|
||
|
+void
|
||
|
+gcc_jit_block_add_try_catch (gcc_jit_block *block,
|
||
|
+ gcc_jit_location *loc,
|
||
|
+ gcc_jit_block *try_block,
|
||
|
+ gcc_jit_block *catch_block)
|
||
|
+{
|
||
|
+ RETURN_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_IF_FAIL (try_block, ctxt, loc, "NULL rvalue");
|
||
|
+ RETURN_IF_FAIL (catch_block, ctxt, loc, "NULL rvalue");
|
||
|
+
|
||
|
+ gcc::jit::recording::statement *stmt = block->add_try_catch (loc, try_block, catch_block);
|
||
|
+
|
||
|
+ // TODO: remove this or use it.
|
||
|
+ /* "stmt" should be good enough to be usable in error-messages,
|
||
|
+ but might still not be compilable; perform some more
|
||
|
+ error-checking here. We do this here so that the error messages
|
||
|
+ can contain a stringified version of "stmt", whilst appearing
|
||
|
+ as close as possible to the point of failure. */
|
||
|
+ /*try_block->verify_valid_within_stmt (__func__, stmt);
|
||
|
+ catch_block->verify_valid_within_stmt (__func__, stmt);*/
|
||
|
+}
|
||
|
+
|
||
|
+/* Public entrypoint. See description in libgccjit.h.
|
||
|
+ After error-checking, the real work is done by the
|
||
|
+ gcc::jit::recording::block::add_try_catch method in jit-recording.c. */
|
||
|
+
|
||
|
+void
|
||
|
+gcc_jit_block_add_try_finally (gcc_jit_block *block,
|
||
|
+ gcc_jit_location *loc,
|
||
|
+ gcc_jit_block *try_block,
|
||
|
+ gcc_jit_block *finally_block)
|
||
|
+{
|
||
|
+ RETURN_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_IF_FAIL (try_block, ctxt, loc, "NULL rvalue");
|
||
|
+ RETURN_IF_FAIL (finally_block, ctxt, loc, "NULL rvalue");
|
||
|
+
|
||
|
+ gcc::jit::recording::statement *stmt = block->add_try_catch (loc, try_block, finally_block, true);
|
||
|
+
|
||
|
+ // TODO: remove this or use it.
|
||
|
+ /* "stmt" should be good enough to be usable in error-messages,
|
||
|
+ but might still not be compilable; perform some more
|
||
|
+ error-checking here. We do this here so that the error messages
|
||
|
+ can contain a stringified version of "stmt", whilst appearing
|
||
|
+ as close as possible to the point of failure. */
|
||
|
+ /*try_block->verify_valid_within_stmt (__func__, stmt);
|
||
|
+ catch_block->verify_valid_within_stmt (__func__, stmt);*/
|
||
|
+}
|
||
|
+
|
||
|
/* Public entrypoint. See description in libgccjit.h.
|
||
|
|
||
|
After error-checking, the real work is done by the
|
||
|
@@ -2821,7 +2985,7 @@ gcc_jit_block_add_assignment (gcc_jit_block *block,
|
||
|
RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
|
||
|
RETURN_IF_FAIL_PRINTF4 (
|
||
|
compatible_types (lvalue->get_type (),
|
||
|
- rvalue->get_type ()),
|
||
|
+ rvalue->get_type ()) || lvalue->get_type ()->is_const () != NULL,
|
||
|
ctxt, loc,
|
||
|
"mismatching types:"
|
||
|
" assignment to %s (type: %s) from %s (type: %s)",
|
||
|
@@ -2867,7 +3031,7 @@ gcc_jit_block_add_assignment_op (gcc_jit_block *block,
|
||
|
RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
|
||
|
RETURN_IF_FAIL_PRINTF4 (
|
||
|
compatible_types (lvalue->get_type (),
|
||
|
- rvalue->get_type ()),
|
||
|
+ rvalue->get_type ()) || lvalue->get_type ()->is_const () != NULL,
|
||
|
ctxt, loc,
|
||
|
"mismatching types:"
|
||
|
" assignment to %s (type: %s) involving %s (type: %s)",
|
||
|
@@ -3575,6 +3739,27 @@ gcc_jit_context_add_command_line_option (gcc_jit_context *ctxt,
|
||
|
ctxt->add_command_line_option (optname);
|
||
|
}
|
||
|
|
||
|
+/* Public entrypoint. See description in libgccjit.h.
|
||
|
+ After error-checking, the real work is done by the
|
||
|
+ gcc::jit::recording::function::set_personality_function method, in
|
||
|
+ jit-recording.c. */
|
||
|
+
|
||
|
+void
|
||
|
+gcc_jit_function_set_personality_function (gcc_jit_function *fn,
|
||
|
+ gcc_jit_function *personality_func)
|
||
|
+{
|
||
|
+ RETURN_IF_FAIL (fn, NULL, NULL, "NULL function");
|
||
|
+
|
||
|
+ fn->set_personality_function (personality_func);
|
||
|
+}
|
||
|
+
|
||
|
+extern char* jit_personality_func_name;
|
||
|
+
|
||
|
+void
|
||
|
+gcc_jit_set_global_personality_function_name (char* name) {
|
||
|
+ jit_personality_func_name = name;
|
||
|
+}
|
||
|
+
|
||
|
/* Public entrypoint. See description in libgccjit.h.
|
||
|
|
||
|
The real work is done by the
|
||
|
@@ -3950,6 +4135,38 @@ gcc_jit_type_get_aligned (gcc_jit_type *type,
|
||
|
return (gcc_jit_type *)type->get_aligned (alignment_in_bytes);
|
||
|
}
|
||
|
|
||
|
+void
|
||
|
+gcc_jit_type_set_packed (gcc_jit_type *type)
|
||
|
+{
|
||
|
+ RETURN_IF_FAIL (type, NULL, NULL, "NULL type");
|
||
|
+
|
||
|
+ type->set_packed ();
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+gcc_jit_function_add_attribute (gcc_jit_function *func, gcc_jit_fn_attribute attribute)
|
||
|
+{
|
||
|
+ RETURN_IF_FAIL (func, NULL, NULL, "NULL func");
|
||
|
+
|
||
|
+ func->add_attribute (attribute);
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+gcc_jit_function_add_string_attribute (gcc_jit_function *func, gcc_jit_fn_attribute attribute, const char* value)
|
||
|
+{
|
||
|
+ RETURN_IF_FAIL (func, NULL, NULL, "NULL func");
|
||
|
+
|
||
|
+ func->add_string_attribute (attribute, value);
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+gcc_jit_lvalue_add_attribute (gcc_jit_lvalue *variable, gcc_jit_variable_attribute attribute, const char* value)
|
||
|
+{
|
||
|
+ RETURN_IF_FAIL (variable, NULL, NULL, "NULL variable");
|
||
|
+
|
||
|
+ variable->add_attribute (attribute, value);
|
||
|
+}
|
||
|
+
|
||
|
/* Public entrypoint. See description in libgccjit.h.
|
||
|
|
||
|
After error-checking, the real work is done by the
|
||
|
@@ -4056,6 +4273,74 @@ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt,
|
||
|
(gcc::jit::recording::rvalue **)elements);
|
||
|
}
|
||
|
|
||
|
+/* Public entrypoint. See description in libgccjit.h.
|
||
|
+
|
||
|
+ After error-checking, the real work is done by the
|
||
|
+ gcc::jit::recording::context::new_rvalue_vector_perm method, in
|
||
|
+ jit-recording.cc. */
|
||
|
+
|
||
|
+gcc_jit_rvalue *
|
||
|
+gcc_jit_context_new_rvalue_vector_perm (gcc_jit_context *ctxt,
|
||
|
+ gcc_jit_location *loc,
|
||
|
+ gcc_jit_rvalue *elements1,
|
||
|
+ gcc_jit_rvalue *elements2,
|
||
|
+ gcc_jit_rvalue *mask)
|
||
|
+{
|
||
|
+ RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL ctxt");
|
||
|
+ JIT_LOG_FUNC (ctxt->get_logger ());
|
||
|
+
|
||
|
+ /* LOC can be NULL. */
|
||
|
+
|
||
|
+ gcc::jit::recording::type *elements1_type = elements1->get_type ();
|
||
|
+ gcc::jit::recording::type *elements2_type = elements2->get_type ();
|
||
|
+ RETURN_NULL_IF_FAIL_PRINTF4 (
|
||
|
+ compatible_types (elements1->get_type ()->unqualified (),
|
||
|
+ elements2->get_type ()->unqualified ()),
|
||
|
+ ctxt, loc,
|
||
|
+ "mismatching types for vector perm:"
|
||
|
+ " elements1: %s (type: %s) elements2: %s (type: %s)",
|
||
|
+ elements1->get_debug_string (),
|
||
|
+ elements1_type->get_debug_string (),
|
||
|
+ elements2->get_debug_string (),
|
||
|
+ elements2_type->get_debug_string ());
|
||
|
+
|
||
|
+ gcc::jit::recording::type *mask_type = mask->get_type ();
|
||
|
+ gcc::jit::recording::vector_type *mask_vector_type = mask_type->dyn_cast_vector_type ();
|
||
|
+ gcc::jit::recording::vector_type *elements1_vector_type = elements1_type->dyn_cast_vector_type ();
|
||
|
+
|
||
|
+ size_t mask_len = mask_vector_type->get_num_units ();
|
||
|
+ size_t elements1_len = elements1_vector_type->get_num_units ();
|
||
|
+
|
||
|
+ RETURN_NULL_IF_FAIL_PRINTF2 (
|
||
|
+ mask_len == elements1_len,
|
||
|
+ ctxt, loc,
|
||
|
+ "mismatching length for mask:"
|
||
|
+ " elements1 length: %ld mask length: %ld",
|
||
|
+ mask_len,
|
||
|
+ elements1_len);
|
||
|
+
|
||
|
+ gcc::jit::recording::type *mask_element_type = mask_vector_type->get_element_type ();
|
||
|
+
|
||
|
+ RETURN_NULL_IF_FAIL (
|
||
|
+ mask_element_type->is_int (),
|
||
|
+ ctxt, loc,
|
||
|
+ "elements of mask must be of an integer type");
|
||
|
+
|
||
|
+ gcc::jit::recording::type *elements1_element_type = elements1_vector_type->get_element_type ();
|
||
|
+ size_t mask_element_size = mask_element_type->get_size ();
|
||
|
+ size_t elements1_element_size = elements1_element_type->get_size ();
|
||
|
+
|
||
|
+ RETURN_NULL_IF_FAIL_PRINTF2 (
|
||
|
+ mask_element_size == elements1_element_size,
|
||
|
+ ctxt, loc,
|
||
|
+ "mismatching size for mask element type:"
|
||
|
+ " elements1 element type: %ld mask element type: %ld",
|
||
|
+ mask_element_size,
|
||
|
+ elements1_element_size);
|
||
|
+
|
||
|
+ return (gcc_jit_rvalue *)ctxt->new_rvalue_vector_perm(loc, elements1, elements2, mask);
|
||
|
+}
|
||
|
+
|
||
|
/* A mutex around the cached state in parse_basever.
|
||
|
Ideally this would be within parse_basever, but the mutex is only needed
|
||
|
by libgccjit. */
|
||
|
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
|
||
|
index b3c389e93f6..f5537adbc91 100644
|
||
|
--- a/gcc/jit/libgccjit.h
|
||
|
+++ b/gcc/jit/libgccjit.h
|
||
|
@@ -604,7 +604,9 @@ enum gcc_jit_types
|
||
|
GCC_JIT_TYPE_INT16_T,
|
||
|
GCC_JIT_TYPE_INT32_T,
|
||
|
GCC_JIT_TYPE_INT64_T,
|
||
|
- GCC_JIT_TYPE_INT128_T
|
||
|
+ GCC_JIT_TYPE_INT128_T,
|
||
|
+
|
||
|
+ GCC_JIT_TYPE_BFLOAT16,
|
||
|
};
|
||
|
|
||
|
extern gcc_jit_type *
|
||
|
@@ -652,7 +654,7 @@ extern gcc_jit_type *
|
||
|
gcc_jit_context_new_array_type (gcc_jit_context *ctxt,
|
||
|
gcc_jit_location *loc,
|
||
|
gcc_jit_type *element_type,
|
||
|
- int num_elements);
|
||
|
+ unsigned long num_elements);
|
||
|
|
||
|
/* Struct-handling. */
|
||
|
|
||
|
@@ -1021,6 +1023,12 @@ extern gcc_jit_lvalue *
|
||
|
gcc_jit_global_set_initializer_rvalue (gcc_jit_lvalue *global,
|
||
|
gcc_jit_rvalue *init_value);
|
||
|
|
||
|
+/* Create a reference to a machine-specific builtin function (sometimes called
|
||
|
+ intrinsic functions). */
|
||
|
+extern gcc_jit_function *
|
||
|
+gcc_jit_context_get_target_builtin_function (gcc_jit_context *ctxt,
|
||
|
+ const char *name);
|
||
|
+
|
||
|
#define LIBGCCJIT_HAVE_gcc_jit_global_set_initializer
|
||
|
|
||
|
/* Set an initial value for a global, which must be an array of
|
||
|
@@ -1036,6 +1044,9 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global,
|
||
|
const void *blob,
|
||
|
size_t num_bytes);
|
||
|
|
||
|
+extern void
|
||
|
+gcc_jit_global_set_readonly (gcc_jit_lvalue *global);
|
||
|
+
|
||
|
/* Upcasting. */
|
||
|
extern gcc_jit_object *
|
||
|
gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue);
|
||
|
@@ -1292,6 +1303,18 @@ gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
|
||
|
gcc_jit_rvalue *ptr,
|
||
|
gcc_jit_rvalue *index);
|
||
|
|
||
|
+extern gcc_jit_rvalue *
|
||
|
+gcc_jit_context_convert_vector (gcc_jit_context *ctxt,
|
||
|
+ gcc_jit_location *loc,
|
||
|
+ gcc_jit_rvalue *vector,
|
||
|
+ gcc_jit_type *type);
|
||
|
+
|
||
|
+extern gcc_jit_lvalue *
|
||
|
+gcc_jit_context_new_vector_access (gcc_jit_context *ctxt,
|
||
|
+ gcc_jit_location *loc,
|
||
|
+ gcc_jit_rvalue *vector,
|
||
|
+ gcc_jit_rvalue *index);
|
||
|
+
|
||
|
/* Field access is provided separately for both lvalues and rvalues. */
|
||
|
|
||
|
/* Accessing a field of an lvalue of struct type, analogous to:
|
||
|
@@ -1391,6 +1414,38 @@ gcc_jit_block_add_eval (gcc_jit_block *block,
|
||
|
gcc_jit_location *loc,
|
||
|
gcc_jit_rvalue *rvalue);
|
||
|
|
||
|
+/* Add a try/catch statement.
|
||
|
+ This is equivalent to this C++ code:
|
||
|
+ try {
|
||
|
+ try_block
|
||
|
+ }
|
||
|
+ catch (...) {
|
||
|
+ catch_block
|
||
|
+ }
|
||
|
+*/
|
||
|
+
|
||
|
+void
|
||
|
+gcc_jit_block_add_try_catch (gcc_jit_block *block,
|
||
|
+ gcc_jit_location *loc,
|
||
|
+ gcc_jit_block *try_block,
|
||
|
+ gcc_jit_block *catch_block);
|
||
|
+
|
||
|
+/* Add a try/finally statement.
|
||
|
+ This is equivalent to this C++-like code:
|
||
|
+ try {
|
||
|
+ try_block
|
||
|
+ }
|
||
|
+ finally {
|
||
|
+ finally_block
|
||
|
+ }
|
||
|
+*/
|
||
|
+
|
||
|
+void
|
||
|
+gcc_jit_block_add_try_finally (gcc_jit_block *block,
|
||
|
+ gcc_jit_location *loc,
|
||
|
+ gcc_jit_block *try_block,
|
||
|
+ gcc_jit_block *finally_block);
|
||
|
+
|
||
|
/* Add evaluation of an rvalue, assigning the result to the given
|
||
|
lvalue.
|
||
|
|
||
|
@@ -1788,6 +1843,12 @@ extern gcc_jit_rvalue *
|
||
|
gcc_jit_function_get_address (gcc_jit_function *fn,
|
||
|
gcc_jit_location *loc);
|
||
|
|
||
|
+void
|
||
|
+gcc_jit_function_set_personality_function (gcc_jit_function *fn,
|
||
|
+ gcc_jit_function *personality_func);
|
||
|
+
|
||
|
+extern void
|
||
|
+gcc_jit_set_global_personality_function_name (char* name);
|
||
|
|
||
|
#define LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector
|
||
|
|
||
|
@@ -1806,6 +1867,21 @@ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt,
|
||
|
size_t num_elements,
|
||
|
gcc_jit_rvalue **elements);
|
||
|
|
||
|
+/* Build a permutation vector rvalue from an 3 arrays of elements.
|
||
|
+
|
||
|
+ "vec_type" should be a vector type, created using gcc_jit_type_get_vector.
|
||
|
+
|
||
|
+ This API entrypoint was added in LIBGCCJIT_ABI_25; you can test for its
|
||
|
+ presence using
|
||
|
+ #ifdef LIBGCCJIT_HAVE_TARGET_BUILTIN
|
||
|
+*/
|
||
|
+extern gcc_jit_rvalue *
|
||
|
+gcc_jit_context_new_rvalue_vector_perm (gcc_jit_context *ctxt,
|
||
|
+ gcc_jit_location *loc,
|
||
|
+ gcc_jit_rvalue *elements1,
|
||
|
+ gcc_jit_rvalue *elements2,
|
||
|
+ gcc_jit_rvalue *mask);
|
||
|
+
|
||
|
#define LIBGCCJIT_HAVE_gcc_jit_version
|
||
|
|
||
|
/* Functions to retrieve libgccjit version.
|
||
|
@@ -1969,6 +2045,11 @@ gcc_jit_type_is_integral (gcc_jit_type *type);
|
||
|
extern gcc_jit_type *
|
||
|
gcc_jit_type_is_pointer (gcc_jit_type *type);
|
||
|
|
||
|
+/* Return the type behind const type or NULL if it's not a
|
||
|
+ * const type. */
|
||
|
+extern gcc_jit_type *
|
||
|
+gcc_jit_type_is_const (gcc_jit_type *type);
|
||
|
+
|
||
|
/* Given a type, return a dynamic cast to a vector type or NULL. */
|
||
|
extern gcc_jit_vector_type *
|
||
|
gcc_jit_type_dyncast_vector (gcc_jit_type *type);
|
||
|
@@ -1990,6 +2071,40 @@ gcc_jit_vector_type_get_element_type (gcc_jit_vector_type *vector_type);
|
||
|
extern gcc_jit_type *
|
||
|
gcc_jit_type_unqualified (gcc_jit_type *type);
|
||
|
|
||
|
+/* Given type "T", get type "T __attribute__ ((packed))". */
|
||
|
+extern void
|
||
|
+gcc_jit_type_set_packed (gcc_jit_type *type);
|
||
|
+
|
||
|
+/* Function attributes. */
|
||
|
+enum gcc_jit_fn_attribute
|
||
|
+{
|
||
|
+ GCC_JIT_FN_ATTRIBUTE_ALWAYS_INLINE,
|
||
|
+ GCC_JIT_FN_ATTRIBUTE_INLINE,
|
||
|
+ GCC_JIT_FN_ATTRIBUTE_NOINLINE,
|
||
|
+ GCC_JIT_FN_ATTRIBUTE_TARGET,
|
||
|
+ GCC_JIT_FN_ATTRIBUTE_USED,
|
||
|
+ GCC_JIT_FN_ATTRIBUTE_VISIBILITY,
|
||
|
+};
|
||
|
+
|
||
|
+/* Add an attribute to a function. */
|
||
|
+// TODO: also support integer values.
|
||
|
+extern void
|
||
|
+gcc_jit_function_add_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute);
|
||
|
+
|
||
|
+extern void
|
||
|
+gcc_jit_function_add_string_attribute (gcc_jit_function *func, enum gcc_jit_fn_attribute attribute, const char* value);
|
||
|
+
|
||
|
+/* Variable attributes. */
|
||
|
+enum gcc_jit_variable_attribute
|
||
|
+{
|
||
|
+ GCC_JIT_VARIABLE_ATTRIBUTE_VISIBILITY,
|
||
|
+};
|
||
|
+
|
||
|
+/* Add an attribute to a variable. */
|
||
|
+// TODO: also support integer values.
|
||
|
+extern void
|
||
|
+gcc_jit_lvalue_add_attribute (gcc_jit_lvalue *variable, enum gcc_jit_variable_attribute attribute, const char* value);
|
||
|
+
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif /* __cplusplus */
|
||
|
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
|
||
|
index cc22b2b414e..a10a85ceace 100644
|
||
|
--- a/gcc/jit/libgccjit.map
|
||
|
+++ b/gcc/jit/libgccjit.map
|
||
|
@@ -271,3 +271,49 @@ LIBGCCJIT_ABI_24 {
|
||
|
gcc_jit_lvalue_set_alignment;
|
||
|
gcc_jit_lvalue_get_alignment;
|
||
|
} LIBGCCJIT_ABI_23;
|
||
|
+
|
||
|
+LIBGCCJIT_ABI_25 {
|
||
|
+ global:
|
||
|
+ gcc_jit_type_set_packed;
|
||
|
+} LIBGCCJIT_ABI_24;
|
||
|
+
|
||
|
+LIBGCCJIT_ABI_26 {
|
||
|
+ global:
|
||
|
+ gcc_jit_type_is_const;
|
||
|
+} LIBGCCJIT_ABI_25;
|
||
|
+
|
||
|
+LIBGCCJIT_ABI_27 {
|
||
|
+ global:
|
||
|
+ gcc_jit_context_convert_vector;
|
||
|
+} LIBGCCJIT_ABI_26;
|
||
|
+
|
||
|
+LIBGCCJIT_ABI_28 {
|
||
|
+ global:
|
||
|
+ gcc_jit_global_set_readonly;
|
||
|
+} LIBGCCJIT_ABI_27;
|
||
|
+
|
||
|
+LIBGCCJIT_ABI_29 {
|
||
|
+ global:
|
||
|
+ gcc_jit_function_add_attribute;
|
||
|
+ gcc_jit_function_add_string_attribute;
|
||
|
+} LIBGCCJIT_ABI_28;
|
||
|
+
|
||
|
+LIBGCCJIT_ABI_30 {
|
||
|
+ global:
|
||
|
+ gcc_jit_lvalue_add_attribute;
|
||
|
+} LIBGCCJIT_ABI_29;
|
||
|
+
|
||
|
+LIBGCCJIT_ABI_31 {
|
||
|
+ global:
|
||
|
+ gcc_jit_block_add_try_catch;
|
||
|
+ gcc_jit_block_add_try_finally;
|
||
|
+ gcc_jit_function_set_personality_function;
|
||
|
+} LIBGCCJIT_ABI_30;
|
||
|
+
|
||
|
+LIBGCCJIT_ABI_32 {
|
||
|
+ global:
|
||
|
+ gcc_jit_context_get_target_builtin_function;
|
||
|
+ gcc_jit_context_new_rvalue_vector_perm;
|
||
|
+ gcc_jit_context_new_vector_access;
|
||
|
+ gcc_jit_set_global_personality_function_name;
|
||
|
+} LIBGCCJIT_ABI_31;
|
||
|
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
|
||
|
index 80606076e78..988e14ae9bc 100644
|
||
|
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
|
||
|
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
|
||
|
@@ -319,6 +319,9 @@
|
||
|
/* test-setting-alignment.c: This can't be in the testcases array as it
|
||
|
is target-specific. */
|
||
|
|
||
|
+/* test-target-builtins.c: This can't be in the testcases array as it
|
||
|
+ is target-specific. */
|
||
|
+
|
||
|
/* test-string-literal.c */
|
||
|
#define create_code create_code_string_literal
|
||
|
#define verify_code verify_code_string_literal
|
||
|
diff --git a/gcc/testsuite/jit.dg/test-target-builtins.c b/gcc/testsuite/jit.dg/test-target-builtins.c
|
||
|
new file mode 100644
|
||
|
index 00000000000..0ffb48e97f6
|
||
|
--- /dev/null
|
||
|
+++ b/gcc/testsuite/jit.dg/test-target-builtins.c
|
||
|
@@ -0,0 +1,77 @@
|
||
|
+/* { dg-do compile { target x86_64-*-* } } */
|
||
|
+
|
||
|
+#include <stdlib.h>
|
||
|
+#include <stdio.h>
|
||
|
+
|
||
|
+#include "libgccjit.h"
|
||
|
+
|
||
|
+#define TEST_PROVIDES_MAIN
|
||
|
+#include "harness.h"
|
||
|
+
|
||
|
+void
|
||
|
+create_code (gcc_jit_context *ctxt, void *user_data)
|
||
|
+{
|
||
|
+ CHECK_NON_NULL (gcc_jit_context_get_target_builtin_function (ctxt, "__builtin_ia32_xgetbv"));
|
||
|
+ gcc_jit_function *builtin_eh_pointer = gcc_jit_context_get_target_builtin_function (ctxt, "__builtin_eh_pointer");
|
||
|
+ CHECK_NON_NULL (builtin_eh_pointer);
|
||
|
+
|
||
|
+ gcc_jit_type *int_type =
|
||
|
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
|
||
|
+ gcc_jit_type *void_ptr =
|
||
|
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
|
||
|
+ gcc_jit_function *func_main =
|
||
|
+ gcc_jit_context_new_function (ctxt, NULL,
|
||
|
+ GCC_JIT_FUNCTION_EXPORTED,
|
||
|
+ int_type,
|
||
|
+ "main",
|
||
|
+ 0, NULL,
|
||
|
+ 0);
|
||
|
+ gcc_jit_rvalue *zero = gcc_jit_context_zero (ctxt, int_type);
|
||
|
+ gcc_jit_block *block = gcc_jit_function_new_block (func_main, NULL);
|
||
|
+ gcc_jit_lvalue *variable = gcc_jit_function_new_local(func_main, NULL, void_ptr, "variable");
|
||
|
+ gcc_jit_block_add_assignment (block, NULL, variable,
|
||
|
+ gcc_jit_context_new_call (ctxt, NULL, builtin_eh_pointer, 1, &zero));
|
||
|
+ gcc_jit_block_end_with_return (block, NULL, zero);
|
||
|
+}
|
||
|
+
|
||
|
+void
|
||
|
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
|
||
|
+{
|
||
|
+ CHECK_NON_NULL (result);
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+main (int argc, char **argv)
|
||
|
+{
|
||
|
+ /* This is the same as the main provided by harness.h, but it first create a dummy context and compile
|
||
|
+ in order to add the target builtins to libgccjit's internal state. */
|
||
|
+ gcc_jit_context *ctxt;
|
||
|
+ ctxt = gcc_jit_context_acquire ();
|
||
|
+ if (!ctxt)
|
||
|
+ {
|
||
|
+ fail ("gcc_jit_context_acquire failed");
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ gcc_jit_result *result;
|
||
|
+ result = gcc_jit_context_compile (ctxt);
|
||
|
+ gcc_jit_result_release (result);
|
||
|
+ gcc_jit_context_release (ctxt);
|
||
|
+
|
||
|
+ int i;
|
||
|
+
|
||
|
+ for (i = 1; i <= 5; i++)
|
||
|
+ {
|
||
|
+ snprintf (test, sizeof (test),
|
||
|
+ "%s iteration %d of %d",
|
||
|
+ extract_progname (argv[0]),
|
||
|
+ i, 5);
|
||
|
+
|
||
|
+ //printf ("ITERATION %d\n", i);
|
||
|
+ test_jit (argv[0], NULL);
|
||
|
+ //printf ("\n");
|
||
|
+ }
|
||
|
+
|
||
|
+ totals ();
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
|
||
|
index 42937f0ba00..4469e0f069d 100644
|
||
|
--- a/gcc/toplev.cc
|
||
|
+++ b/gcc/toplev.cc
|
||
|
@@ -2332,6 +2332,7 @@ toplev::finalize (void)
|
||
|
cgraphunit_cc_finalize ();
|
||
|
symtab_thunks_cc_finalize ();
|
||
|
dwarf2out_cc_finalize ();
|
||
|
+ dwarf2asm_cc_finalize ();
|
||
|
gcse_cc_finalize ();
|
||
|
ipa_cp_cc_finalize ();
|
||
|
ira_costs_cc_finalize ();
|
||
|
diff --git a/gcc/tree.cc b/gcc/tree.cc
|
||
|
index 78b64ee98b3..ea95e67bb79 100644
|
||
|
--- a/gcc/tree.cc
|
||
|
+++ b/gcc/tree.cc
|
||
|
@@ -15006,6 +15006,7 @@ void
|
||
|
tree_cc_finalize (void)
|
||
|
{
|
||
|
clear_nonstandard_integer_type_cache ();
|
||
|
+ gcc_eh_personality_decl = NULL;
|
||
|
}
|
||
|
|
||
|
#if CHECKING_P
|
||
|
diff --git a/gcc/tree.h b/gcc/tree.h
|
||
|
index e730a2a3e56..99695c647fe 100644
|
||
|
--- a/gcc/tree.h
|
||
|
+++ b/gcc/tree.h
|
||
|
@@ -6479,6 +6479,7 @@ extern tree get_inner_reference (tree, poly_int64_pod *, poly_int64_pod *,
|
||
|
tree *, machine_mode *, int *, int *, int *);
|
||
|
|
||
|
extern tree build_personality_function (const char *);
|
||
|
+extern tree build_personality_function_with_name (const char *);
|
||
|
|
||
|
struct GTY(()) int_n_trees_t {
|
||
|
/* These parts are initialized at runtime */
|