This patch adds dynamic alloca stubs support to GCCJIT.
DEF_BUILTIN_STUB only defines the enum for builtins instead of
providing the type. Therefore, builtins with stub will lead to
ICE before this patch. This applies to `alloca_with_align`,
`stack_save` and `stack_restore`.
This patch adds special handling for builtins defined by
DEF_BUILTIN_STUB.
Additionally, it fixes that supercontext is not
set for blocks emitted by gccjit. This triggers a SEGV error inside
`fold_builtin_with_align`.
This is the third roll of the patch:
- Fix wrong test cases mistakenly introduced in V2.
- Undo the removal of `gcc_assert` inside get_attrs_tree for non-stub builtin
functions.
gcc/jit/ChangeLog:
* jit-builtins.cc (builtins_manager::make_builtin_function): Add stub
type handling.
(builtins_manager::make_type_for_stub): Add stub type handling.
(builtins_manager::get_type_for_stub): Add stub type handling.
(builtins_manager::get_attrs_tree): Add stub attribute hand
ling.
(builtins_manager::get_attrs_tree_for_stub): Add stub attribute
handling.
* jit-builtins.h: Add new functions for stubs.
* jit-playback.cc (postprocess): Always set supercontext.
gcc/testsuite/ChangeLog:
* jit.dg/test-aligned-alloca.c: New test.
* jit.dg/test-stack-save-restore.c: New test.
---
gcc/jit/jit-builtins.cc | 68 +++++++++-
gcc/jit/jit-builtins.h | 7 +
gcc/jit/jit-playback.cc | 1 +
gcc/testsuite/jit.dg/test-aligned-alloca.c | 121 ++++++++++++++++++
.../jit.dg/test-stack-save-restore.c | 114 +++++++++++++++++
5 files changed, 309 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/jit.dg/test-aligned-alloca.c
create mode 100644 gcc/testsuite/jit.dg/test-stack-save-restore.c
diff --git a/gcc/jit/jit-builtins.cc b/gcc/jit/jit-builtins.cc
index 0c13c8db586..5f61775beb7 100644
--- a/gcc/jit/jit-builtins.cc
+++ b/gcc/jit/jit-builtins.cc
@@ -23,
6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "target.h"
#include "jit-playback.h"
#include "stringpool.h"
+#include "tree-core.h"
#include "jit-builtins.h"
@@ -185,7 +186,8 @@ builtins_manager::make_builtin_function (enum built_in_function builtin_id)
{
const struct builtin_data& bd = builtin_data[builtin_id];
enum jit_builtin_type type_id = bd.type;
- recording::type *t = get_type (type_id);
+ recording::type *t = type_id == BT_LAST ? get_type_for_stub (builtin_id)
+ : get_type (type_id);
if (!t)
return NULL;
recording::function_type *func_type = t->as_a_function_type ();
@@ -333,6 +335,52 @@ builtins_manager::get_type (enum jit_builtin_type type_id)
return m_types[type_id];
}
+/* Create the recording::type for special builtins whose types are not defined
+ in builtin-types.def. */
+
+recording::type *
+builtins_manager::make_type_for_stub (enum built_in_function builtin_id)
+{
+ switch (bui
ltin_id)
+ {
+ default:
+ return reinterpret_cast<recording::type *> (-1);
+ case BUILT_IN_ALLOCA_WITH_ALIGN:
+ {
+ recording::type *p = m_ctxt->get_type (GCC_JIT_TYPE_SIZE_T);
+ recording::type *r = m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR);
+ recording::type *params[2] = { p, p };
+ return m_ctxt->new_function_type (r, 2, params, false);
+ }
+ case BUILT_IN_STACK_SAVE:
+ {
+ recording::type *r = m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR);
+ return m_ctxt->new_function_type (r, 0, nullptr, false);
+ }
+ case BUILT_IN_STACK_RESTORE:
+ {
+ recording::type *p = m_ctxt->get_type (GCC_JIT_TYPE_VOID_PTR);
+ recording::type *r = m_ctxt->get_type (GCC_JIT_TYPE_VOID);
+ recording::type *params[1] = { p };
+ return m_ctxt->new_function_type (r, 1, params, false);
+ }
+ }
+}
+
+/* Get the recording::type for a given type of builtin function,
+ by ID, creating it if it doesn't already exist. */
+
+recording::type *
+builtins_manager::get_type_for_stub (enum built_in_function type_id)
+{
+ if (m_types[type_id] == nullptr)
+ m_types[type_id] = make_type_for_stub (type_id);
+ recording::type *t = m_types[type_id];
+ if (reinterpret_cast<intptr_t> (t) == -1)
+ return nullptr;
+ return t;
+}
+
/* Create the recording::type for a given type of builtin function. */
recording::type *
@@ -661,10 +709,26 @@ tree
builtins_manager::get_attrs_tree (enum built_in_function builtin_id)
{
enum built_in_attribute attr = builtin_data[builtin_id].attr;
+ if (attr == ATTR_LAST)
+ return get_attrs_tree_for_stub (builtin_id);
return get_attrs_tree (attr);
}
-/* As above, but for an enum built_in_attribute. */
+/* Get attributes for builtin stubs. */
+
+tree
+builtins_manager::get_attrs_tree_for_stub (enum built_in_function builtin_id)
+{
+ switch (builtin_id)
+ {
+ default:
+ return NULL_TREE;
+ case BUILT_IN_ALLOCA_WITH_ALIGN:
+ retu
rn get_attrs_tree (BUILT_IN_ALLOCA);
+ }
+}
+
+/* As get_attrs_tree, but for an enum built_in_attribute. */
tree
builtins_manager::get_attrs_tree (enum built_in_attribute attr)
diff --git a/gcc/jit/jit-builtins.h b/gcc/jit/jit-builtins.h
index 17e118481d6..f4de3707201 100644
--- a/gcc/jit/jit-builtins.h
+++ b/gcc/jit/jit-builtins.h
@@ -124,6 +124,9 @@ public:
tree
get_attrs_tree (enum built_in_function builtin_id);
+ tree
+ get_attrs_tree_for_stub (enum built_in_function builtin_id);
+
tree
get_attrs_tree (enum built_in_attribute attr);
@@ -146,6 +149,10 @@ private:
recording::type *
make_type (enum jit_builtin_type type_id);
+ recording::type *get_type_for_stub (enum built_in_function type_id);
+
+ recording::type *make_type_for_stub (enum built_in_function type_id);
+
recording::type*
make_primitive_type (enum jit_builtin_type type_id);
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
index e3
2e837f2fe..acdb25c7d09 100644
--- a/gcc/jit/jit-playback.cc
+++ b/gcc/jit/jit-playback.cc
@@ -2118,6 +2118,7 @@ postprocess ()
/* Seem to need this in gimple-low.cc: */
gcc_assert (m_inner_block);
DECL_INITIAL (m_inner_fndecl) = m_inner_block;
+ BLOCK_SUPERCONTEXT (m_inner_block) = m_inner_fndecl;
/* how to add to function? the following appears to be how to
set the body of a m_inner_fndecl: */
diff --git a/gcc/testsuite/jit.dg/test-aligned-alloca.c
b/gcc/testsuite/jit.dg/test-aligned-alloca.c
new file mode 100644
index 00000000000..358adba708a
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-aligned-alloca.c
@@ -0,0 +1,121 @@
+#define __need_size_t
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+fill (void *ptr)
+{
+ for (int i = 0; i < 100; i++)
+ ((int *)ptr)[i] = i;
+}
+
+void
+sum (void *ptr, int *sum)
+{
+ *sum = 0;
+ for (int i =
0; i < 100; i++)
+ *sum += ((int *)ptr)[i];
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /*
+ size_t test_aligned_alloca (typeof(fill) *fill, typeof(sum) *sum, int* sum_p)
+ {
+ void *p;
+ p = __builtin_alloca_with_align (sizeof (int) * 100, 128);
+ fill (p);
+ sum (p, sum_p);
+ return (size_t)p;
+ }
+ */
+
+ /* Types */
+ gcc_jit_type *size_t_type
+ = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T);
+ gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *int_ptr_type = gcc_jit_type_get_pointer (int_type);
+ gcc_jit_type *void_ptr_type
+ = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+ gcc_jit_type *void_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *fill_ptr_type = gcc_jit_context_new_function_ptr_type (
+ ctxt, NULL, void_type, 1, &void_ptr_type, 0);
+ gcc_jit_type *sum_params[] = { void_ptr_type
, int_ptr_type };
+ gcc_jit_type *sum_ptr_type = gcc_jit_context_new_function_ptr_type (
+ ctxt, NULL, void_type, 2, sum_params, 0);
+
+ /* Function */
+ gcc_jit_param *fill_param
+ = gcc_jit_context_new_param (ctxt, NULL, fill_ptr_type, "fill");
+ gcc_jit_rvalue *rv_fill = gcc_jit_param_as_rvalue (fill_param);
+ gcc_jit_param *sum_param
+ = gcc_jit_context_new_param (ctxt, NULL, sum_ptr_type, "sum");
+ gcc_jit_rvalue *rv_sum = gcc_jit_param_as_rvalue (sum_param);
+ gcc_jit_param *sum_p_param
+ = gcc_jit_context_new_param (ctxt, NULL, int_ptr_type, "sum_p");
+ gcc_jit_rvalue *rv_sum_p = gcc_jit_param_as_rvalue (sum_p_param);
+ gcc_jit_param *params[] = { fill_param, sum_param, sum_p_param };
+ gcc_jit_function *test_aligned_alloca = gcc_jit_context_new_function (
+ ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, size_t_type,
+ "test_aligned_alloca", 3, params, 0);
+
+ /* Variables */
+ gcc_jit_lvalue *p = gcc_jit_function_new_local (
test_aligned_alloca, NULL,
+ void_ptr_type, "p");
+ gcc_jit_rvalue *rv_p = gcc_jit_lvalue_as_rvalue (p);
+
+ /* Blocks */
+ gcc_jit_block *block
+ = gcc_jit_function_new_block (test_aligned_alloca, NULL);
+
+ /* p = __builtin_alloca_with_align (sizeof (int) * 100, 128); */
+ gcc_jit_rvalue *sizeof_int = gcc_jit_context_new_sizeof (ctxt, int_type);
+ gcc_jit_rvalue *c100
+ = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 100);
+ gcc_jit_rvalue *size = gcc_jit_context_new_binary_op (
+ ctxt, NULL, GCC_JIT_BINARY_OP_MULT, size_t_type, sizeof_int, c100);
+ gcc_jit_rvalue *c128x8
+ = gcc_jit_context_new_rvalue_from_long (ctxt, size_t_type, 128 * 8);
+ gcc_jit_function *alloca_with_align = gcc_jit_context_get_builtin_function (
+ ctxt, "__builtin_alloca_with_align");
+ gcc_jit_rvalue *args[] = { size, c128x8 };
+ gcc_jit_rvalue *alloca_with_align_call
+ = gcc_jit_context_new_ca
ll (ctxt, NULL, alloca_with_align, 2, args);
+ gcc_jit_block_add_assignment (block, NULL, p, alloca_with_align_call);
+
+ /* fill (p); */
+ gcc_jit_rvalue *call_fill
+ = gcc_jit_context_new_call_through_ptr (ctxt, NULL, rv_fill, 1, &rv_p);
+ gcc_jit_block_add_eval (block, NULL, call_fill);
+
+ /* sum (p, sum_p); */
+ gcc_jit_rvalue *sum_args[] = { rv_p, rv_sum_p };
+ gcc_jit_rvalue *call_sum
+ = gcc_jit_context_new_call_through_ptr (ctxt, NULL, rv_sum, 2, sum_args);
+ gcc_jit_block_add_eval (block, NULL, call_sum);
+
+ /* return (size_t)p; */
+ gcc_jit_rvalue *cast_p
+ = gcc_jit_context_new_bitcast (ctxt, NULL, rv_p, size_t_type);
+ gcc_jit_block_end_with_return (block, NULL, cast_p);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef size_t (*fn_type) (typeof (fill) *, typeof (sum) *, int *);
+ CHECK_NON_NULL (result);
+ fn_type test_aligned_alloca
+ = (fn_type)gcc_jit_result_get_code (result
, "test_aligned_alloca");
+ CHECK_NON_NULL (test_aligned_alloca);
+ int value;
+ size_t addr = test_aligned_alloca (fill, sum, &value);
+ CHECK_VALUE (addr % 128, 0);
+ CHECK_VALUE (value, 4950);
+}
diff --git a/gcc/testsuite/jit.dg/test-stack-save-restore.c
b/gcc/testsuite/jit.dg/test-stack-save-restore.c
new file mode 100644
index 00000000000..4e6ca5391ae
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-stack-save-restore.c
@@ -0,0 +1,114 @@
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /*
+ size_t test_stack_save_restore() {
+ void *p;
+ size_t a, b;
+ p = __builtin_stack_save();
+ a = (size_t)__builtin_alloca(1024);
+ __builtin_stack_restore(p);
+
+ p = __builtin_stack_save();
+ b = (size_t)__builtin_alloca(512);
+ __builtin_stack_restore(p);
+
+ return b - a;
+
}
+ */
+
+ /* Types */
+ gcc_jit_type *size_t_type
+ = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T);
+ gcc_jit_type *void_ptr_type
+ = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID_PTR);
+
+ /* Function */
+ gcc_jit_function *test_stack_save_restore = gcc_jit_context_new_function (
+ ctxt, NULL, GCC_JIT_FUNCTION_EXPORTED, size_t_type,
+ "test_stack_save_restore", 0, NULL, 0);
+
+ /* Variables */
+ gcc_jit_lvalue *p = gcc_jit_function_new_local (test_stack_save_restore,
+ NULL, void_ptr_type, "p");
+ gcc_jit_lvalue *a = gcc_jit_function_new_local (test_stack_save_restore,
+ NULL, size_t_type, "a");
+ gcc_jit_lvalue *b = gcc_jit_function_new_local (test_stack_save_restore,
+ NULL, size_t_type, "b");
+ gcc_jit_rvalue *rv_p = gcc_jit_lvalue_as_rvalue (p);
+ gcc_jit_rvalue *rv_a =
gcc_jit_lvalue_as_rvalue (a);
+ gcc_jit_rvalue *rv_b = gcc_jit_lvalue_as_rvalue (b);
+
+ /* Blocks */
+ gcc_jit_block *block
+ = gcc_jit_function_new_block (test_stack_save_restore, NULL);
+
+ /* Builtin functions */
+ gcc_jit_function *stack_save
+ = gcc_jit_context_get_builtin_function (ctxt, "__builtin_stack_save");
+ gcc_jit_function *stack_restore
+ = gcc_jit_context_get_builtin_function (ctxt, "__builtin_stack_restore");
+ gcc_jit_function *alloca
+ = gcc_jit_context_get_builtin_function (ctxt, "__builtin_alloca");
+
+ /* Common code */
+ gcc_jit_rvalue *call_stack_save
+ = gcc_jit_context_new_call (ctxt, NULL, stack_save, 0, NULL);
+ gcc_jit_rvalue *call_stack_restore
+ = gcc_jit_context_new_call (ctxt, NULL, stack_restore, 1, &rv_p);
+
+ /* p = __builtin_stack_save(); */
+ gcc_jit_block_add_assignment (block, NULL, p, call_stack_save);
+
+ /* a = (size_t)__builtin_alloca(1024); */
+ gcc_jit_rvalue *c1024
+
= gcc_jit_context_new_rvalue_from_int (ctxt, size_t_type, 1024);
+ gcc_jit_rvalue *call_alloca_1024
+ = gcc_jit_context_new_call (ctxt, NULL, alloca, 1, &c1024);
+ gcc_jit_rvalue *cast_alloca_1024 = gcc_jit_context_new_bitcast (
+ ctxt, NULL, call_alloca_1024, size_t_type);
+ gcc_jit_block_add_assignment (block, NULL, a, cast_alloca_1024);
+
+ /* __builtin_stack_restore(p); */
+ gcc_jit_block_add_eval (block, NULL, call_stack_restore);
+
+ /* p = __builtin_stack_save(); */
+ gcc_jit_block_add_assignment (block, NULL, p, call_stack_save);
+
+ /* b = (size_t)__builtin_alloca(512); */
+ gcc_jit_rvalue *c512
+ = gcc_jit_context_new_rvalue_from_int (ctxt, size_t_type, 512);
+ gcc_jit_rvalue *call_alloca_512
+ = gcc_jit_context_new_call (ctxt, NULL, alloca, 1, &c512);
+ gcc_jit_rvalue *cast_alloca_512
+ = gcc_jit_context_new_bitcast (ctxt, NULL, call_alloca_512, size_t_type);
+ gcc_jit_block_add_assignment (block, NULL, b, cast_all
oca_512);
+
+ /* __builtin_stack_restore(p); */
+ gcc_jit_block_add_eval (block, NULL, call_stack_restore);
+
+ /* return b - a; */
+ gcc_jit_rvalue *sub = gcc_jit_context_new_binary_op (
+ ctxt, NULL, GCC_JIT_BINARY_OP_MINUS, size_t_type, rv_b, rv_a);
+ gcc_jit_block_end_with_return (block, NULL, sub);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef size_t (*fn_type) (void);
+ CHECK_NON_NULL (result);
+ fn_type test_stack_save_restore
+ = (fn_type)gcc_jit_result_get_code (result, "test_stack_save_restore");
+ CHECK_NON_NULL (test_stack_save_restore);
+ size_t value = test_stack_save_restore ();
+ CHECK_VALUE (value, 512);
+}