diff mbox series

[v2] gccjit: support dynamic alloca stub

Message ID 20241110181440.97725-2-i@zhuyi.fan
State New
Headers show
Series [v2] gccjit: support dynamic alloca stub | expand

Commit Message

Schrodinger ZHU Yifan Nov. 10, 2024, 6:17 p.m. UTC
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`.
gcc/jit/ChangeLog:

	* jit-builtins.cc (builtins_manager::make_builtin_function):
	(builtins_manager::make_type_for_stub):
	(builtins_manager::get_type_for_stub):
	(builtins_manager::get_attrs_tree):
	(builtins_manager::get_attrs_tree_for_stub):
	* jit-builtins.h:
	* jit-playback.cc (postprocess):

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                       |  69 
+++++++++-
 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(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-aligned-alloca.c
 create mode 100644 gcc/testsuite/jit.dg/test-stack-save-restore.c

+  CHECK_NON_NULL (test_stack_save_restore);
+  size_t value = test_stack_save_restore ();
+  CHECK_VALUE (value, 512 - 1024);
+}

Comments

Schrodinger ZHU Yifan Nov. 10, 2024, 6:21 p.m. UTC | #1
sorry, just noticed that the check_value was wrongly written on the last line of this patch. Other parts should be good. Should I correct it now in a new revision? Or is it okay to wait for further reviews for now?
On Sun, Nov 10, 2024 at 13:17, Schrodinger ZHU Yifan <i@zhuyi.fan> wrote:  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`.

gcc/jit/ChangeLog:



 * jit-builtins.cc (builtins_manager::make_builtin_function):

 (builtins_manager::make_type_for_stub):

 (builtins_manager::get_type_for_stub):

 (builtins_manager::get_attrs_tree):

 (builtins_manager::get_attrs_tree_for_stub):

 * jit-builtins.h:

 * jit-playback.cc (postprocess):



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 | 69 +++++++++-

 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(+), 3 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..06affd66634 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 (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 (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,15 +709,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/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: */

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..9d4174c3cd0

--- /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_call (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..e3119749c47

--- /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_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 (value, 512 - 1024);

+}
diff mbox series

Patch

diff --git a/gcc/jit/jit-builtins.cc b/gcc/jit/jit-builtins.cc
index 0c13c8db586..06affd66634 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 (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 (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,15 +709,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-b
uiltins.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 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: */
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..9d4174c3cd0
--- /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_call (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 --g
it 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..e3119749c47
--- /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);
+
+  /* Builti
n 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_ji
t_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_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, G
CC_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");