===================================================================
@@ -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.
===================================================================
@@ -10252,42 +10252,6 @@ 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.
- 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* gog
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,
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
===================================================================
@@ -2427,7 +2427,7 @@ class Call_expression : public Expressio
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*,
===================================================================
@@ -4566,11 +4566,6 @@ Build_recover_thunks::function(Named_obj
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(Lo
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*
===================================================================
@@ -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
===================================================================
@@ -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_t
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
case RFT_BOOLPTR:
case RFT_INT:
case RFT_INT32:
+ case RFT_UINT32:
case RFT_INT64:
case RFT_UINT64:
case RFT_UINTPTR:
===================================================================
@@ -376,6 +376,26 @@ DEF_GO_RUNTIME(UNREACHABLE, "__builtin_u
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