[PATCH v3] [GCCJIT] support dynamic alloca stub
Antoni Boucher
bouanto@zoho.com
Mon Nov 11 21:06:51 GMT 2024
Hi and thanks for the patch.
I would rather avoid having to hard-code the types of built-in
functions, especially since we can already access them via the function
gcc_jit_context_get_target_builtin_function that is available in this
patch: https://gcc.gnu.org/pipermail/jit/2023q4/001725.html
I'll soon address the review in this patch and we'll hopefully have it
merged soon.
Le 2024-11-10 à 16 h 40, Schrodinger ZHU Yifan a écrit :
> 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);
> +}
More information about the Jit
mailing list