This patch to the Go frontend compilers the runtime functions
getcallerpc and getcallersp into calls to __builtin_return_address and
__builtin_frame_address.  This is how we currently handle those
functions in the C code, using #define's in runtime.h.  This handles
the functions the same way in the Go code.  This is done by specially
recognizing the functions in the compiler, so that they will work
efficiently without doing a real stack unwind.

This fixes a breakage in libgo when libgo is compiled without
optimization, as currently all calls to these functions are compiled
out when optimizing but not when not optimizing.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian

2016-09-22  Ian Lance Taylor  <i...@golang.org>

* go-gcc.cc (Gcc_backend::Gcc_backend): Declare
__builtin_frame_address.
Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc    (revision 240083)
+++ gcc/go/go-gcc.cc    (working copy)
@@ -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: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE     (revision 240378)
+++ gcc/go/gofrontend/MERGE     (working copy)
@@ -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: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc    (revision 240378)
+++ gcc/go/gofrontend/expressions.cc    (working copy)
@@ -8897,6 +8897,45 @@ Call_expression::do_lower(Gogo* gogo, Na
                                                  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* gog
   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: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h     (revision 240334)
+++ gcc/go/gofrontend/expressions.h     (working copy)
@@ -2143,6 +2143,9 @@ class Call_expression : public Expressio
   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: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc   (revision 240334)
+++ gcc/go/gofrontend/gogo.cc   (working copy)
@@ -4146,25 +4146,8 @@ Build_recover_thunks::can_recover_arg(Lo
 {
   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: gcc/go/gofrontend/gogo.h
===================================================================
--- gcc/go/gofrontend/gogo.h    (revision 240053)
+++ gcc/go/gofrontend/gogo.h    (working copy)
@@ -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

Reply via email to