compiler: compile runtime.getcaller{pc,sp} into builtin functions
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
This commit is contained in:
parent
1c681c7bf7
commit
0cb904afbe
7 changed files with 108 additions and 26 deletions
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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*
|
||||
|
|
|
@ -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**);
|
||||
|
|
|
@ -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*
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue