From f6d67708ca8d0efbeeb5742ef177db2e1a096278 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 16 May 2019 23:23:58 +0000 Subject: [PATCH] compiler: add intrinsics for runtime/internal/sys functions runtime/internal/sys.Ctz32/64 and Bswap32/64 are currently implemented with compiler builtin functions. But if they are called from another package, the compiler does not know and therefore cannot turn them into compiler intrinsics. This CL makes the compiler recognize these functions and turn them into intrinsics directly, as the gc compiler does. This CL sets up a way for adding intrinsics in the compiler. More intrinsics will be added in later CLs. Also move the handling of runtime.getcallerpc/sp to the new way of generating intrinsics. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/176917 From-SVN: r271303 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 177 ++++++++++++++++++++----------- gcc/go/gofrontend/expressions.h | 2 +- gcc/go/gofrontend/gogo.cc | 45 +------- gcc/go/gofrontend/gogo.h | 5 - gcc/go/gofrontend/runtime.cc | 7 ++ gcc/go/gofrontend/runtime.def | 20 ++++ 7 files changed, 149 insertions(+), 109 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index fba3721f23d..c3da5bfce87 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -2df0879e7880057293c0a59be6868a3e6ea5105b +c0c8ad50627e3a59267e6e3de233a0b30cf64150 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 8af0dd43a88..d162b056211 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -10252,42 +10252,6 @@ 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. - if (gogo->compiling_runtime() && 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 ((this->args_ == NULL || this->args_->size() == 0) - && n == "getcallerpc") - { - static Named_object* builtin_return_address; - int arg = 0; - return this->lower_to_builtin(&builtin_return_address, - "__builtin_return_address", - &arg); - } - else if ((this->args_ == NULL || this->args_->size() == 0) - && n == "getcallersp") - { - static Named_object* builtin_dwarf_cfa; - return this->lower_to_builtin(&builtin_dwarf_cfa, - "__builtin_dwarf_cfa", - NULL); - } - } - } - // If this is a call to an imported function for which we have an // inlinable function body, add it to the list of functions to give // to the backend as inlining opportunities. @@ -10401,31 +10365,6 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function, this->varargs_are_lowered_ = true; } -// Return a call to __builtin_return_address or __builtin_dwarf_cfa. - -Expression* -Call_expression::lower_to_builtin(Named_object** pno, const char* name, - int* arg) -{ - if (*pno == NULL) - *pno = Gogo::declare_builtin_rf_address(name, arg != NULL); - - Location loc = this->location(); - - Expression* fn = Expression::make_func_reference(*pno, NULL, loc); - Expression_list *args = new Expression_list(); - if (arg != NULL) - { - Expression* a = Expression::make_integer_ul(*arg, NULL, loc); - 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* @@ -10491,9 +10430,125 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*, this->args_ = args; } + // Lower to compiler intrinsic if possible. + Func_expression* fe = this->fn_->func_expression(); + if (fe != NULL + && (fe->named_object()->is_function_declaration() + || fe->named_object()->is_function())) + { + Expression* ret = this->intrinsify(gogo, inserter); + if (ret != NULL) + return ret; + } + return this; } +// Lower a call to a compiler intrinsic if possible. +// Returns NULL if it is not an intrinsic. + +Expression* +Call_expression::intrinsify(Gogo* gogo, + Statement_inserter* inserter) +{ + Func_expression* fe = this->fn_->func_expression(); + Named_object* no = fe->named_object(); + std::string name = Gogo::unpack_hidden_name(no->name()); + std::string package = (no->package() != NULL + ? no->package()->pkgpath() + : gogo->pkgpath()); + Location loc = this->location(); + + Type* int_type = Type::lookup_integer_type("int"); + Type* uint32_type = Type::lookup_integer_type("uint32"); + Type* uint64_type = Type::lookup_integer_type("uint64"); + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + + if (package == "runtime") + { + // 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. + if (name == "getcallerpc" + && (this->args_ == NULL || this->args_->size() == 0)) + { + Expression* arg = Expression::make_integer_ul(0, uint32_type, loc); + Expression* call = + Runtime::make_call(Runtime::BUILTIN_RETURN_ADDRESS, loc, + 1, arg); + // The builtin functions return void*, but the Go functions return uintptr. + return Expression::make_cast(uintptr_type, call, loc); + } + else if (name == "getcallersp" + && (this->args_ == NULL || this->args_->size() == 0)) + + { + Expression* call = + Runtime::make_call(Runtime::BUILTIN_DWARF_CFA, loc, 0); + // The builtin functions return void*, but the Go functions return uintptr. + return Expression::make_cast(uintptr_type, call, loc); + } + } + else if (package == "runtime/internal/sys") + { + if (name == "Bswap32" + && this->args_ != NULL && this->args_->size() == 1) + { + Expression* arg = this->args_->front(); + return Runtime::make_call(Runtime::BUILTIN_BSWAP32, loc, 1, arg); + } + else if (name == "Bswap64" + && this->args_ != NULL && this->args_->size() == 1) + { + Expression* arg = this->args_->front(); + return Runtime::make_call(Runtime::BUILTIN_BSWAP64, loc, 1, arg); + } + else if (name == "Ctz32" + && this->args_ != NULL && this->args_->size() == 1) + { + Expression* arg = this->args_->front(); + if (!arg->is_variable()) + { + Temporary_statement* ts = Statement::make_temporary(uint32_type, arg, loc); + inserter->insert(ts); + arg = Expression::make_temporary_reference(ts, loc); + } + // arg == 0 ? 32 : __builtin_ctz(arg) + Expression* zero = Expression::make_integer_ul(0, uint32_type, loc); + Expression* cmp = Expression::make_binary(OPERATOR_EQEQ, arg, zero, loc); + Expression* c32 = Expression::make_integer_ul(32, int_type, loc); + Expression* call = Runtime::make_call(Runtime::BUILTIN_CTZ, loc, 1, arg->copy()); + call = Expression::make_cast(int_type, call, loc); + return Expression::make_conditional(cmp, c32, call, loc); + } + else if (name == "Ctz64" + && this->args_ != NULL && this->args_->size() == 1) + { + Expression* arg = this->args_->front(); + if (!arg->is_variable()) + { + Temporary_statement* ts = Statement::make_temporary(uint64_type, arg, loc); + inserter->insert(ts); + arg = Expression::make_temporary_reference(ts, loc); + } + // arg == 0 ? 64 : __builtin_ctzll(arg) + Expression* zero = Expression::make_integer_ul(0, uint64_type, loc); + Expression* cmp = Expression::make_binary(OPERATOR_EQEQ, arg, zero, loc); + Expression* c64 = Expression::make_integer_ul(64, int_type, loc); + Expression* call = Runtime::make_call(Runtime::BUILTIN_CTZLL, loc, 1, arg->copy()); + call = Expression::make_cast(int_type, call, loc); + return Expression::make_conditional(cmp, c64, call, loc); + } + } + + return NULL; +} + // Make implicit type conversions explicit. void diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index b1811ea2f1f..21a214db632 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -2427,7 +2427,7 @@ class Call_expression : public Expression check_argument_type(int, const Type*, const Type*, Location, bool); Expression* - lower_to_builtin(Named_object**, const char*, int*); + intrinsify(Gogo*, Statement_inserter*); Expression* interface_method_function(Interface_field_reference_expression*, diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 06657cb2be4..02120f2e1fd 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -4566,11 +4566,6 @@ Build_recover_thunks::function(Named_object* orig_no) Expression* Build_recover_thunks::can_recover_arg(Location location) { - static Named_object* builtin_return_address; - if (builtin_return_address == NULL) - builtin_return_address = - Gogo::declare_builtin_rf_address("__builtin_return_address", true); - Type* uintptr_type = Type::lookup_integer_type("uintptr"); static Named_object* can_recover; if (can_recover == NULL) @@ -4589,20 +4584,15 @@ Build_recover_thunks::can_recover_arg(Location location) can_recover->func_declaration_value()->set_asm_name("runtime.canrecover"); } - Expression* fn = Expression::make_func_reference(builtin_return_address, - NULL, location); - Expression* zexpr = Expression::make_integer_ul(0, NULL, location); - Expression_list *args = new Expression_list(); - args->push_back(zexpr); - - Expression* call = Expression::make_call(fn, args, false, location); + Expression* call = Runtime::make_call(Runtime::BUILTIN_RETURN_ADDRESS, + location, 1, zexpr); call = Expression::make_unsafe_cast(uintptr_type, call, location); - args = new Expression_list(); + Expression_list* args = new Expression_list(); args->push_back(call); - fn = Expression::make_func_reference(can_recover, NULL, location); + Expression* fn = Expression::make_func_reference(can_recover, NULL, location); return Expression::make_call(fn, args, false, location); } @@ -4622,33 +4612,6 @@ Gogo::build_recover_thunks() this->traverse(&build_recover_thunks); } -// Return a declaration for __builtin_return_address or -// __builtin_dwarf_cfa. - -Named_object* -Gogo::declare_builtin_rf_address(const char* name, bool hasarg) -{ - const Location bloc = Linemap::predeclared_location(); - - Typed_identifier_list* param_types = new Typed_identifier_list(); - if (hasarg) - { - 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 448da047316..e67a8a5db6c 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -764,11 +764,6 @@ class Gogo void build_recover_thunks(); - // Return a declaration for __builtin_return_address or - // __builtin_dwarf_cfa. - static Named_object* - declare_builtin_rf_address(const char* name, bool hasarg); - // Simplify statements which might use thunks: go and defer // statements. void diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc index 7ecbf689409..289d6bf8297 100644 --- a/gcc/go/gofrontend/runtime.cc +++ b/gcc/go/gofrontend/runtime.cc @@ -32,6 +32,8 @@ enum Runtime_function_type RFT_INT, // Go type int32, C type int32_t. RFT_INT32, + // Go type uint32, C type uint32_t. + RFT_UINT32, // Go type int64, C type int64_t. RFT_INT64, // Go type uint64, C type uint64_t. @@ -111,6 +113,10 @@ runtime_function_type(Runtime_function_type bft) t = Type::lookup_integer_type("int32"); break; + case RFT_UINT32: + t = Type::lookup_integer_type("uint32"); + break; + case RFT_INT64: t = Type::lookup_integer_type("int64"); break; @@ -245,6 +251,7 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e, case RFT_BOOLPTR: case RFT_INT: case RFT_INT32: + case RFT_UINT32: case RFT_INT64: case RFT_UINT64: case RFT_UINTPTR: diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index c17b4816d87..a5264eebada 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -376,6 +376,26 @@ DEF_GO_RUNTIME(UNREACHABLE, "__builtin_unreachable", P0(), R0()) DEF_GO_RUNTIME(BUILTIN_MEMMOVE, "__builtin_memmove", P3(POINTER, POINTER, UINTPTR), R0()) +// Various intrinsics. + +// Get the caller's PC, used for runtime.getcallerpc. +DEF_GO_RUNTIME(BUILTIN_RETURN_ADDRESS, "__builtin_return_address", + P1(UINT32), R1(POINTER)) + +// Get the caller's SP, used for runtime.getcallersp. +DEF_GO_RUNTIME(BUILTIN_DWARF_CFA, "__builtin_dwarf_cfa", P0(), + R1(POINTER)) + +// Swap bytes. +DEF_GO_RUNTIME(BUILTIN_BSWAP32, "__builtin_bswap32", P1(UINT32), + R1(UINT32)) +DEF_GO_RUNTIME(BUILTIN_BSWAP64, "__builtin_bswap64", P1(UINT64), + R1(UINT64)) + +// Count trailing zeros. +DEF_GO_RUNTIME(BUILTIN_CTZ, "__builtin_ctz", P1(UINT32), R1(INT32)) +DEF_GO_RUNTIME(BUILTIN_CTZLL, "__builtin_ctzll", P1(UINT64), R1(INT32)) + // Remove helper macros. #undef ABFT6 #undef ABFT2 -- 2.30.2