On Sat, Nov 9, 2024 at 8:30 PM Schrodinger ZHU Yifan <[email protected]> wrote:
>
> This patch adds dynamic alloca stubs support to GCCJIT.
>
> DEF_BUILTIN_STUB only define 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 add special handling for builtins defined by
> DEF_BUILTIN_STUB. Additionally, it fixes `fold_builtin_with_align`
> by adding an addtional check on the presence of supercontext. For
> blocks created by GCCJIT, such field does not exist while the folder
> implementation assumes the existence on default.
>
> This is my first patch to GCC and GCCJIT. I mainly work on LLVM and other
> github-based projects before. So it is a bit hard for me to get familiar with
> the workflow. I managed to pass the GNU Style check locally but I don't think
> I am
> doing the correct formatting. Also, I tried the changelog script but
> I don't think the patch contains the changelog list. Is it because I did not
> invoke it as a g
> it-hook?
>
> Please refer me to more detailed guideline to correct the format or changelog
> if needed. I am *really really* for the inconvenience.
>
> ---
> gcc/jit/jit-builtins.cc | 66 +++++++-
> gcc/jit/jit-builtins.h | 7 +
> gcc/testsuite/jit.dg/test-aligned-alloca.c | 141 ++++++++++++++++++
> .../jit.dg/test-stack-save-restore.c | 116 ++++++++++++++
> gcc/tree-ssa-ccp.cc | 3 +-
> 5 files changed, 329 insertions(+), 4 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..bf4251701d3 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,49 @@ 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 (builtin_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 (typ
> e_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,15 +706,30 @@ 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:
> + return 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)
> {
> - gcc_assert (attr < ATTR_LAST);
> if (!m_attributes [attr])
> m_attributes [attr] = make_attrs_tree (attr);
> return m_attributes [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/testsuite/jit.dg/test-aligned-alloca.c
> b/gcc/testsuite/jit.dg/t
> est-aligned-alloca.c
> new file mode 100644
> index 00000000000..e107746b82f
> --- /dev/null
> +++ b/gcc/testsuite/jit.dg/test-aligned-alloca.c
> @@ -0,0 +1,141 @@
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <stddef.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)
> +{
> + /*
> + bool test_aligned_alloca (typeof(fill) *fill, typeof(sum) *sum, int*
> sum_p) {
> + size_t addr;
> + void *p;
> +
> + p = __builtin_alloca_with_align (sizeof (int) * 100, 128);
> + addr = (size_t)p;
> + fill (p);
> + sum (p, sum_p);
> + return (addr & 127) == 0;
> + }
> + */
> +
> + /* Types */
> + gcc_jit_type *size_t_type
> + = gcc_jit_context_g
> et_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 *bool_type
> + = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_BOOL);
> + 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_pa
> ram_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, bool_type, "test_aligned_alloca", 3, params, 0);
> +
> +
> + /* Variables */
> + gcc_jit_lvalue *addr
> + = gcc_jit_function_new_local (test_aligned_alloca, NULL,
> size_t_type, "addr");
> + gcc_jit_lvalue *p
> + = gcc_jit_function_new_local (test_aligned_alloca, NULL,
> void_ptr_type, "p");
> + gcc_jit_rvalue *rv_addr = gcc_jit_lvalue_as_rvalue (addr);
> + gcc_jit_rvalue *rv_p = gcc_jit_lvalue_as_rv
> alue (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 *c128
> + = gcc_jit_context_new_rvalue_from_int(ctxt, size_t_type, 128);
> + gcc_jit_function *alloca_with_align
> + = gcc_jit_context_get_builtin_function (ctxt,
> "__builtin_alloca_with_align");
> + gcc_jit_rvalue *args[] = {size, c128};
> + gcc_jit_rvalue *alloca_with_align_call
> + = gcc_jit_context_new_call (ctxt, NULL, alloca_with_align, 2, args);
> + gcc_jit_block_add_assignment (block, NULL, p, alloca_with_align_
> call);
> +
> + /* addr = (size_t)p; */
> + gcc_jit_rvalue *cast_p
> + = gcc_jit_context_new_bitcast (ctxt, NULL, rv_p, size_t_type);
> + gcc_jit_block_add_assignment (block, NULL, addr, cast_p);
> +
> + /* 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 (addr & 127) == 0; */
> + gcc_jit_rvalue *c127
> + = gcc_jit_context_new_rvalue_from_int(ctxt, size_t_type, 127);
> + gcc_jit_rvalue *and_op
> + = gcc_jit_context_new_binary_op(ctxt, NULL,
> GCC_JIT_BINARY_OP_BITWISE_AND, size_t_type, rv_addr, c127);
> + gcc_jit_rvalue *c0
> + = gcc_jit_context_new_rva
> lue_from_int(ctxt, size_t_type, 0);
> + gcc_jit_rvalue *eq_op
> + = gcc_jit_context_new_comparison(ctxt, NULL, GCC_JIT_COMPARISON_EQ,
> and_op, c0);
> + gcc_jit_block_end_with_return (block, NULL, eq_op);
> +}
> +
> +void
> +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
> +{
> + typedef void (*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;
> + test_aligned_alloca (fill, sum, &value);
> + CHECK (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..0bee247be9f
> --- /dev/null
> +++ b/gcc/testsuite/jit.dg/test-stack-save-restore.c
> @@ -0,0 +1,116 @@
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <stddef.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_lv
> alue *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_rv
> alue *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_alloca_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 == 512);
> +}
> diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tre
> e-ssa-ccp.cc
> index fcb91c58335..d721c471f74 100644
> --- a/gcc/tree-ssa-ccp.cc
> +++ b/gcc/tree-ssa-ccp.cc
> @@ -2671,7 +2671,8 @@ fold_builtin_alloca_with_align (gimple *stmt)
> block = gimple_block (stmt);
> if (!(cfun->after_inlining
> && block
> - && TREE_CODE (BLOCK_SUPERCONTEXT (block)) == FUNCTION_DECL))
> + && BLOCK_SUPERCONTEXT (block)
> + && TREE_CODE (BLOCK_SUPERCONTEXT (block)) == FUNCTION_DECL))
This change seems incorrect. Every block should have a super context.
Including the last block which should point to a function decl. Maybe
gccjit is not setting up the blocks correctly where the supper most
one is not setting its context to being the function decl.
I think the following patch will fix that bug:
```
diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc
index e32e837f2fe..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: */
```
Signed-off-by: Andrew Pinski <[email protected]>
Thanks,
Andrew Pinski
> threshold /= 10;
> if (size > threshold)
> return NULL_TREE;
> --
> 2.43.0
>