Message ID | 20241110181440.97725-2-i@zhuyi.fan |
---|---|
State | New |
Headers | show |
Series | [v2] gccjit: support dynamic alloca stub | expand |
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 --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");