diff options
author | Richard Henderson <rth@redhat.com> | 2014-11-19 05:31:24 -0800 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2014-11-19 05:31:24 -0800 |
commit | 74893f25916c3cdcc7ad26af391c3f59a2a51a98 (patch) | |
tree | 6e11f41a5ade384361d3bf280fa4e43b0e99fa63 | |
parent | f2d3d07ee55fa52b41c1ec08e51269831961a772 (diff) | |
download | gcc-74893f25916c3cdcc7ad26af391c3f59a2a51a98.zip gcc-74893f25916c3cdcc7ad26af391c3f59a2a51a98.tar.gz gcc-74893f25916c3cdcc7ad26af391c3f59a2a51a98.tar.bz2 |
Allow the static chain to be set from C
We need to be able to set the static chain on a few calls within the
Go runtime, so expose this with __builtin_call_with_static_chain.
* c-family/c-common.c (c_common_reswords): Add
__builtin_call_with_static_chain.
* c-family/c-common.h (RID_BUILTIN_CALL_WITH_STATIC_CHAIN): New.
* c/c-parser.c (c_parser_postfix_expression): Handle it.
* doc/extend.texi (__builtin_call_with_static_chain): Document it.
From-SVN: r217771
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/c-family/c-common.c | 2 | ||||
-rw-r--r-- | gcc/c-family/c-common.h | 2 | ||||
-rw-r--r-- | gcc/c/c-parser.c | 40 | ||||
-rw-r--r-- | gcc/doc/extend.texi | 13 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cwsc0.c | 16 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/cwsc1.c | 46 |
8 files changed, 129 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8d47292..5a6a354 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2014-11-19 Richard Henderson <rth@redhat.com> + * c-family/c-common.c (c_common_reswords): Add + __builtin_call_with_static_chain. + * c-family/c-common.h (RID_BUILTIN_CALL_WITH_STATIC_CHAIN): New. + * c/c-parser.c (c_parser_postfix_expression): Handle it. + * doc/extend.texi (__builtin_call_with_static_chain): Document it. + * calls.c (prepare_call_address): Allow decl or type for first arg. (expand_call): Pass type to prepare_call_address if no decl. * gimple-fold.c (gimple_fold_call): Eliminate the static chain if diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 839111a..95b6b1b 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -453,6 +453,8 @@ const struct c_common_resword c_common_reswords[] = { "__attribute__", RID_ATTRIBUTE, 0 }, { "__auto_type", RID_AUTO_TYPE, D_CONLY }, { "__bases", RID_BASES, D_CXXONLY }, + { "__builtin_call_with_static_chain", + RID_BUILTIN_CALL_WITH_STATIC_CHAIN, D_CONLY }, { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY }, { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY }, { "__builtin_shuffle", RID_BUILTIN_SHUFFLE, 0 }, diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index ca6fc8b..7e53923 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -101,7 +101,7 @@ enum rid RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR, RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE, RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128, - RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, + RID_FRACT, RID_ACCUM, RID_AUTO_TYPE, RID_BUILTIN_CALL_WITH_STATIC_CHAIN, /* C11 */ RID_ALIGNAS, RID_GENERIC, diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index f90f6af..8a4fd39 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -7414,6 +7414,46 @@ c_parser_postfix_expression (c_parser *parser) = comptypes (e1, e2) ? integer_one_node : integer_zero_node; } break; + case RID_BUILTIN_CALL_WITH_STATIC_CHAIN: + { + vec<c_expr_t, va_gc> *cexpr_list; + c_expr_t *e2_p; + tree chain_value; + + c_parser_consume_token (parser); + if (!c_parser_get_builtin_args (parser, + "__builtin_call_with_static_chain", + &cexpr_list, false)) + { + expr.value = error_mark_node; + break; + } + if (vec_safe_length (cexpr_list) != 2) + { + error_at (loc, "wrong number of arguments to " + "%<__builtin_call_with_static_chain%>"); + expr.value = error_mark_node; + break; + } + + expr = (*cexpr_list)[0]; + e2_p = &(*cexpr_list)[1]; + *e2_p = convert_lvalue_to_rvalue (loc, *e2_p, true, true); + chain_value = e2_p->value; + mark_exp_read (chain_value); + + if (TREE_CODE (expr.value) != CALL_EXPR) + error_at (loc, "first argument to " + "%<__builtin_call_with_static_chain%> " + "must be a call expression"); + else if (TREE_CODE (TREE_TYPE (chain_value)) != POINTER_TYPE) + error_at (loc, "second argument to " + "%<__builtin_call_with_static_chain%> " + "must be a pointer type"); + else + CALL_EXPR_STATIC_CHAIN (expr.value) = chain_value; + break; + } case RID_BUILTIN_COMPLEX: { vec<c_expr_t, va_gc> *cexpr_list; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index d10a815..7178c9a 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -8913,6 +8913,7 @@ in the Cilk Plus language manual which can be found at @node Other Builtins @section Other Built-in Functions Provided by GCC @cindex built-in functions +@findex __builtin_call_with_static_chain @findex __builtin_fpclassify @findex __builtin_isfinite @findex __builtin_isnormal @@ -9501,6 +9502,18 @@ depending on the arguments' types. For example: @end deftypefn +@deftypefn {Built-in Function} @var{type} __builtin_call_with_static_chain (@var{call_exp}, @var{pointer_exp}) + +The @var{call_exp} expression must be a function call, and the +@var{pointer_exp} expression must be a pointer. The @var{pointer_exp} +is passed to the function call in the target's static chain location. +The result of builtin is the result of the function call. + +@emph{Note:} This builtin is only available for C@. +This builtin can be used to call Go closures from C. + +@end deftypefn + @deftypefn {Built-in Function} @var{type} __builtin_choose_expr (@var{const_exp}, @var{exp1}, @var{exp2}) You can use the built-in function @code{__builtin_choose_expr} to diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c3f1bf1..b4fcae8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-11-19 Richard Henderson <rth@redhat.com> + + * gcc.dg/cwsc0.c: New test. + * gcc.dg/cwsc1.c: New test. + 2014-11-19 Marek Polacek <polacek@redhat.com> PR sanitizer/63879 diff --git a/gcc/testsuite/gcc.dg/cwsc0.c b/gcc/testsuite/gcc.dg/cwsc0.c new file mode 100644 index 0000000..3d92222 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cwsc0.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ + +#include <stddef.h> + +void foo(void); +void test(int (*f)(void), char *p) +{ + __builtin_call_with_static_chain(f(), p); + __builtin_call_with_static_chain(p, f()); /* { dg-error "must be a call" } */ + __builtin_call_with_static_chain(f() + 1, p); /* { dg-error "must be a call" } */ + __builtin_call_with_static_chain(f(), 0); /* { dg-error "must be a pointer" } */ + __builtin_call_with_static_chain(f(), NULL); + __builtin_call_with_static_chain(foo, p); /* { dg-error "must be a call" } */ + __builtin_call_with_static_chain(foo(), p); + __builtin_call_with_static_chain(foo(), foo); +} diff --git a/gcc/testsuite/gcc.dg/cwsc1.c b/gcc/testsuite/gcc.dg/cwsc1.c new file mode 100644 index 0000000..e793e26 --- /dev/null +++ b/gcc/testsuite/gcc.dg/cwsc1.c @@ -0,0 +1,46 @@ +/* { dg-do run } */ +/* { dg-options "-O" } */ + +#if defined(__x86_64__) +# define CHAIN "%r10" +#elif defined(__i386__) +# define CHAIN "%ecx" +#elif defined(__aarch64__) +# define CHAIN "x18" +#elif defined(__alpha__) +# define CHAIN "$1" +#elif defined(__arm__) +# define CHAIN "ip" +#elif defined(__powerpc__) +# define CHAIN "11" +#elif defined(__s390__) +# define CHAIN "%r0" +#elif defined(__sparc__) +# ifdef __arch64__ +# define CHAIN "%g5" +# else +# define CHAIN "%g2" +# endif +#endif + +#ifdef CHAIN +void *__attribute__((noinline, noclone)) foo(void) +{ + register void *chain __asm__(CHAIN); + return chain; +} + +void * (*ptr)(void) = foo; +extern void abort(void); + +int main() +{ + char c; + void *x = __builtin_call_with_static_chain(ptr(), &c); + if (x != &c) + abort(); + return 0; +} +#else +int main() { return 0; } +#endif |