On Sat, Nov 9, 2024 at 8:30 PM Schrodinger ZHU Yifan <i...@zhuyi.fan> 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 <quic_apin...@quicinc.com>


Thanks,
Andrew Pinski


>      threshold /= 10;
>    if (size > threshold)
>      return NULL_TREE;
> --
> 2.43.0
>

Reply via email to