aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2014-11-19 05:31:24 -0800
committerRichard Henderson <rth@gcc.gnu.org>2014-11-19 05:31:24 -0800
commit74893f25916c3cdcc7ad26af391c3f59a2a51a98 (patch)
tree6e11f41a5ade384361d3bf280fa4e43b0e99fa63 /gcc
parentf2d3d07ee55fa52b41c1ec08e51269831961a772 (diff)
downloadgcc-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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/c-family/c-common.c2
-rw-r--r--gcc/c-family/c-common.h2
-rw-r--r--gcc/c/c-parser.c40
-rw-r--r--gcc/doc/extend.texi13
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/cwsc0.c16
-rw-r--r--gcc/testsuite/gcc.dg/cwsc1.c46
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