Allow the static chain to be set from C
authorRichard Henderson <rth@redhat.com>
Wed, 19 Nov 2014 13:31:24 +0000 (05:31 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Wed, 19 Nov 2014 13:31:24 +0000 (05:31 -0800)
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

gcc/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c/c-parser.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/cwsc0.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/cwsc1.c [new file with mode: 0644]

index 8d47292c654d4b93eb44f0c6074748b4acaf221d..5a6a3544c33d7714915b78584e16a0f056c9b225 100644 (file)
@@ -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
index 839111a2122790e650e23bc75abfcfd823b242d0..95b6b1b93e05a6461036cf845ea280176a172cab 100644 (file)
@@ -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 },
index ca6fc8beaf88323e335a3bae7fecd81b664ad2bb..7e53923a551e5df0f8df024cd16ecd72cb2eb9cd 100644 (file)
@@ -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,
index f90f6af776e9cc26224c24ba2877b2662b0b0edd..8a4fd39fe803080afd3e91b84d43dc86fbe6257a 100644 (file)
@@ -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;
index d10a815a977ffee504241ea0e47c4137c7daf357..7178c9a7e8e271a7e76033cd4e49de4b1bd2d9d8 100644 (file)
@@ -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
index c3f1bf1e36ffd294e9aaacbb4051c41b27bb741b..b4fcae8c06199165d8e383e87f58fe17454363c0 100644 (file)
@@ -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 (file)
index 0000000..3d92222
--- /dev/null
@@ -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 (file)
index 0000000..e793e26
--- /dev/null
@@ -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