diff mbox series

[GCCJIT] support dynamic alloca stub

Message ID 20241110042152.772-2-i@zhuyi.fan
State New
Headers show
Series [GCCJIT] support dynamic alloca stub | expand

Commit Message

Schrodinger ZHU Yifan Nov. 10, 2024, 4:29 a.m. UTC
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

Comments

Andrew Pinski Nov. 10, 2024, 4:47 a.m. UTC | #1
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_apinski@quicinc.com>


Thanks,
Andrew Pinski


>      threshold /= 10;
>    if (size > threshold)
>      return NULL_TREE;
> --
> 2.43.0
>
Schrodinger ZHU Yifan Nov. 10, 2024, 4:58 a.m. UTC | #2
Thank you for the quick review. Indeed, I reverted the changes to tree-ssa-ccp.cc and applied your changes. All tests still pass.



Schrodinger ZHU Yifan, Ph.D. Student
Computer Science Department, University of Rochester

Personal Email: i@zhuyi.fan
Work Email: yifanzhu@rochester.edu
Website: https://www.cs.rochester.edu/~yzhu104/Main.html
Github: SchrodingerZhu
GPG Fingerprint: BA02CBEB8CB5D8181E9368304D2CC545A78DBCC3


On Saturday, November 9th, 2024 at 11:47 PM, Andrew Pinski <pinskia@gmail.com> wrote:

> 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_apinski@quicinc.com
> 

> 

> 

> Thanks,
> Andrew Pinski
> 

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

Patch

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))
     threshold /= 10;
   if (size > threshold)
     return NULL_TREE;