diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 9351ddafe16..16bc2b7466f 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,8 @@ +2016-09-22 Ian Lance Taylor + + * go-gcc.cc (Gcc_backend::Gcc_backend): Declare + __builtin_frame_address. + 2016-09-11 Ian Lance Taylor * go-gcc.cc (Gcc_backend::Gcc_backend): Add builtin versions of diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index a332831b310..f9ba9d59c1b 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -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. diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 0d5105d6afe..ece695428a6 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index b893d2f92af..84c578dd7b1 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -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* diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 8ecc11afd7f..357f7dbf9be 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -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**); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index a3afdcb7b9a..20c34208d5b 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -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* diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index fe9322c0be6..17d46d503fd 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -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