mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-22 15:00:55 +08:00
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
This commit is contained in:
parent
f2d3d07ee5
commit
74893f2591
@ -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
|
||||
|
@ -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 },
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
16
gcc/testsuite/gcc.dg/cwsc0.c
Normal file
16
gcc/testsuite/gcc.dg/cwsc0.c
Normal file
@ -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);
|
||||
}
|
46
gcc/testsuite/gcc.dg/cwsc1.c
Normal file
46
gcc/testsuite/gcc.dg/cwsc1.c
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user