compiler: compile runtime.getcaller{pc,sp} into builtin functions
authorIan Lance Taylor <iant@golang.org>
Thu, 22 Sep 2016 20:32:16 +0000 (20:32 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 22 Sep 2016 20:32:16 +0000 (20:32 +0000)
    The runtime functions runtime.getcallerpc and runtime.getcallersp are
    intended to be efficient ways to get the return and frame address of the
    caller (that is, the caller of runtime.getcallerpc).  In the C code that
    is implemented by simply using C macros:

    This patch essentially implements those macros in the Go code.

    It would be nice if we could just use //extern for this, but it doesn't
    work because the runtime code passes the right argument.  Of course we
    could change the runtime code, but these are common enough that I'd
    prefer to avoid the difference from the gc version of the runtime code.

    This patch corrects the existing declaration of __builtin_return_address
    to use uint32, rather than uint, for the parameter type.  The builtin
    functions take the C type "unsigned int", which for the targets we use
    corresponds to the Go type uint32.  Not that it should matter, really.

    Reviewed-on: https://go-review.googlesource.com/29653

From-SVN: r240382

gcc/go/ChangeLog
gcc/go/go-gcc.cc
gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h

index 9351ddafe16f35727a1940b0b6021bb6edf0fce9..16bc2b7466f8bef143459289c6a629228def51aa 100644 (file)
@@ -1,3 +1,8 @@
+2016-09-22  Ian Lance Taylor  <iant@golang.org>
+
+       * go-gcc.cc (Gcc_backend::Gcc_backend): Declare
+       __builtin_frame_address.
+
 2016-09-11  Ian Lance Taylor  <iant@golang.org>
 
        * go-gcc.cc (Gcc_backend::Gcc_backend): Add builtin versions of
index a332831b3107a83ab403f134bd6798c9f50442ca..f9ba9d59c1b317a902da7607e730b1f0a2beddca 100644 (file)
@@ -818,13 +818,14 @@ Gcc_backend::Gcc_backend()
                       math_function_type_long, true, false);
 
   // We use __builtin_return_address in the thunk we build for
-  // functions which call recover.
+  // functions which call recover, and for runtime.getcallerpc.
+  t = build_function_type_list(ptr_type_node, unsigned_type_node, NULL_TREE);
   this->define_builtin(BUILT_IN_RETURN_ADDRESS, "__builtin_return_address",
-                      NULL,
-                      build_function_type_list(ptr_type_node,
-                                               unsigned_type_node,
-                                               NULL_TREE),
-                      false, false);
+                      NULL, t, false, false);
+
+  // The runtime calls __builtin_frame_address for runtime.getcallersp.
+  this->define_builtin(BUILT_IN_FRAME_ADDRESS, "__builtin_frame_address",
+                      NULL, t, false, false);
 
   // The compiler uses __builtin_trap for some exception handling
   // cases.
index 0d5105d6afea1d3345b9c3bbef97117bdaaad14e..ece695428a6651b73f38635a6545ee492aab978a 100644 (file)
@@ -1,4 +1,4 @@
-34c4837efc21c35eb21f40efc9bb6b1d71dbda47
+4f84c5e0210e674163f3f6462da6f5be9e5b0a36
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index b893d2f92afe3e71007f68ec0cc017803d58e5ad..84c578dd7b1a07bf1b515d29bede33fa4424b6c8 100644 (file)
@@ -8897,6 +8897,45 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
                                                  bme->location());
     }
 
+  // Handle a couple of special runtime functions.  In the runtime
+  // package, getcallerpc returns the PC of the caller, and
+  // getcallersp returns the frame pointer of the caller.  Implement
+  // these by turning them into calls to GCC builtin functions.  We
+  // could implement them in normal code, but then we would have to
+  // explicitly unwind the stack.  These functions are intended to be
+  // efficient.  Note that this technique obviously only works for
+  // direct calls, but that is the only way they are used.  The actual
+  // argument to these functions is always the address of a parameter;
+  // we don't need that for the GCC builtin functions, so we just
+  // ignore it.
+  if (gogo->compiling_runtime()
+      && this->args_ != NULL
+      && this->args_->size() == 1
+      && gogo->package_name() == "runtime")
+    {
+      Func_expression* fe = this->fn_->func_expression();
+      if (fe != NULL
+         && fe->named_object()->is_function_declaration()
+         && fe->named_object()->package() == NULL)
+       {
+         std::string n = Gogo::unpack_hidden_name(fe->named_object()->name());
+         if (n == "getcallerpc")
+           {
+             static Named_object* builtin_return_address;
+             return this->lower_to_builtin(&builtin_return_address,
+                                           "__builtin_return_address",
+                                           0);
+           }
+         else if (n == "getcallersp")
+           {
+             static Named_object* builtin_frame_address;
+             return this->lower_to_builtin(&builtin_frame_address,
+                                           "__builtin_frame_address",
+                                           1);
+           }
+       }
+    }
+
   return this;
 }
 
@@ -8997,6 +9036,28 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
   this->varargs_are_lowered_ = true;
 }
 
+// Return a call to __builtin_return_address or __builtin_frame_address.
+
+Expression*
+Call_expression::lower_to_builtin(Named_object** pno, const char* name,
+                                 int arg)
+{
+  if (*pno == NULL)
+    *pno = Gogo::declare_builtin_rf_address(name);
+
+  Location loc = this->location();
+
+  Expression* fn = Expression::make_func_reference(*pno, NULL, loc);
+  Expression* a = Expression::make_integer_ul(arg, NULL, loc);
+  Expression_list *args = new Expression_list();
+  args->push_back(a);
+  Expression* call = Expression::make_call(fn, args, false, loc);
+
+  // The builtin functions return void*, but the Go functions return uintptr.
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+  return Expression::make_cast(uintptr_type, call, loc);
+}
+
 // Flatten a call with multiple results into a temporary.
 
 Expression*
index 8ecc11afd7ffd1f66d774d3c689786a6081eb545..357f7dbf9beb9a959b4c06ab082f5ff735abcee0 100644 (file)
@@ -2142,6 +2142,9 @@ class Call_expression : public Expression
   bool
   check_argument_type(int, const Type*, const Type*, Location, bool);
 
+  Expression*
+  lower_to_builtin(Named_object**, const char*, int);
+
   Expression*
   interface_method_function(Interface_field_reference_expression*,
                            Expression**);
index a3afdcb7b9ad3eaf184dd47441b00a6e4a3a1bc7..20c34208d5bf6fa04022537de3821311e5946096 100644 (file)
@@ -4146,25 +4146,8 @@ Build_recover_thunks::can_recover_arg(Location location)
 {
   static Named_object* builtin_return_address;
   if (builtin_return_address == NULL)
-    {
-      const Location bloc = Linemap::predeclared_location();
-
-      Typed_identifier_list* param_types = new Typed_identifier_list();
-      Type* uint_type = Type::lookup_integer_type("uint");
-      param_types->push_back(Typed_identifier("l", uint_type, bloc));
-
-      Typed_identifier_list* return_types = new Typed_identifier_list();
-      Type* voidptr_type = Type::make_pointer_type(Type::make_void_type());
-      return_types->push_back(Typed_identifier("", voidptr_type, bloc));
-
-      Function_type* fntype = Type::make_function_type(NULL, param_types,
-                                                      return_types, bloc);
-      builtin_return_address =
-       Named_object::make_function_declaration("__builtin_return_address",
-                                               NULL, fntype, bloc);
-      const char* n = "__builtin_return_address";
-      builtin_return_address->func_declaration_value()->set_asm_name(n);
-    }
+    builtin_return_address =
+      Gogo::declare_builtin_rf_address("__builtin_return_address");
 
   static Named_object* can_recover;
   if (can_recover == NULL)
@@ -4216,6 +4199,30 @@ Gogo::build_recover_thunks()
   this->traverse(&build_recover_thunks);
 }
 
+// Return a declaration for __builtin_return_address or
+// __builtin_frame_address.
+
+Named_object*
+Gogo::declare_builtin_rf_address(const char* name)
+{
+  const Location bloc = Linemap::predeclared_location();
+
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  Type* uint32_type = Type::lookup_integer_type("uint32");
+  param_types->push_back(Typed_identifier("l", uint32_type, bloc));
+
+  Typed_identifier_list* return_types = new Typed_identifier_list();
+  Type* voidptr_type = Type::make_pointer_type(Type::make_void_type());
+  return_types->push_back(Typed_identifier("", voidptr_type, bloc));
+
+  Function_type* fntype = Type::make_function_type(NULL, param_types,
+                                                  return_types, bloc);
+  Named_object* ret = Named_object::make_function_declaration(name, NULL,
+                                                             fntype, bloc);
+  ret->func_declaration_value()->set_asm_name(name);
+  return ret;
+}
+
 // Build a call to the runtime error function.
 
 Expression*
index fe9322c0be681a99bda057ab2d3e8b8d5ef0ba36..17d46d503fdbebe1cfaf0bfa301803da6275786e 100644 (file)
@@ -670,6 +670,11 @@ class Gogo
   void
   build_recover_thunks();
 
+  // Return a declaration for __builtin_return_address or
+  // __builtin_frame_address.
+  static Named_object*
+  declare_builtin_rf_address(const char* name);
+
   // Simplify statements which might use thunks: go and defer
   // statements.
   void