From 3b1e46937d11b043d0986a3dfefaee27454c3da0 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 6 Feb 2022 18:25:25 -0800 Subject: [PATCH] compiler: recognize Go 1.18 runtime/internal/atomic methods The Go 1.18 library introduces specific types in runtime/internal/atomic. Recognize and optimize the methods on those types, as we do with the functions in runtime/internal/atomic. While we're here avoid getting confused by methods in any other package that we recognize specially. Change-Id: I75c31f75dcf65ce13f3c69022e8ec36e05eab994 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/383654 Trust: Ian Lance Taylor Reviewed-by: Than McIntosh Reviewed-by: Cherry Mui --- go/expressions.cc | 156 +++++++++++++++++++++++++++++++++++++++++++++- go/runtime.def | 4 ++ 2 files changed, 159 insertions(+), 1 deletion(-) diff --git a/go/expressions.cc b/go/expressions.cc index 1e6890a3..d7b64767 100644 --- a/go/expressions.cc +++ b/go/expressions.cc @@ -11613,12 +11613,16 @@ Call_expression::intrinsify(Gogo* gogo, std::string package = (no->package() != NULL ? no->package()->pkgpath() : gogo->pkgpath()); + bool is_method = ((no->is_function() && no->func_value()->is_method()) + || (no->is_function_declaration() + && no->func_declaration_value()->is_method())); Location loc = this->location(); Type* int_type = Type::lookup_integer_type("int"); Type* int32_type = Type::lookup_integer_type("int32"); Type* int64_type = Type::lookup_integer_type("int64"); Type* uint_type = Type::lookup_integer_type("uint"); + Type* uint8_type = Type::lookup_integer_type("uint8"); Type* uint32_type = Type::lookup_integer_type("uint32"); Type* uint64_type = Type::lookup_integer_type("uint64"); Type* uintptr_type = Type::lookup_integer_type("uintptr"); @@ -11629,6 +11633,9 @@ Call_expression::intrinsify(Gogo* gogo, if (package == "sync/atomic") { + if (is_method) + return NULL; + // sync/atomic functions and runtime/internal/atomic functions // are very similar. In order not to duplicate code, we just // redirect to the latter and let the code below to handle them. @@ -11694,6 +11701,9 @@ Call_expression::intrinsify(Gogo* gogo, if (package == "runtime/internal/sys") { + if (is_method) + return NULL; + // runtime/internal/sys functions and math/bits functions // are very similar. In order not to duplicate code, we just // redirect to the latter and let the code below to handle them. @@ -11713,6 +11723,9 @@ Call_expression::intrinsify(Gogo* gogo, if (package == "runtime") { + if (is_method) + return NULL; + // 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 @@ -11743,6 +11756,9 @@ Call_expression::intrinsify(Gogo* gogo, } else if (package == "math/bits") { + if (is_method) + return NULL; + if ((name == "ReverseBytes16" || name == "ReverseBytes32" || name == "ReverseBytes64" || name == "ReverseBytes") && this->args_ != NULL && this->args_->size() == 1) @@ -11913,9 +11929,137 @@ Call_expression::intrinsify(Gogo* gogo, { int memorder = __ATOMIC_SEQ_CST; + if (is_method) + { + Function_type* ftype = (no->is_function() + ? no->func_value()->type() + : no->func_declaration_value()->type()); + Type* rtype = ftype->receiver()->type()->deref(); + go_assert(rtype->named_type() != NULL); + const std::string& rname(rtype->named_type()->name()); + if (rname == "Int32") + { + if (name == "Load") + name = "LoadInt32"; + else if (name == "Store") + name = "Storeint32"; + else if (name == "CompareAndSwap") + name = "Casint32"; + else if (name == "Swap") + name = "Xchgint32"; + else if (name == "Add") + name = "Xaddint32"; + else + go_unreachable(); + } + else if (rname == "Int64") + { + if (name == "Load") + name = "LoadInt64"; + else if (name == "Store") + name = "Storeint64"; + else if (name == "CompareAndSwap") + name = "Casint64"; + else if (name == "Swap") + name = "Xchgint64"; + else if (name == "Add") + name = "Xaddint64"; + else + go_unreachable(); + } + else if (rname == "Uint8") + { + if (name == "Load") + name = "Load8"; + else if (name == "Store") + name = "Store8"; + else if (name == "And") + name = "And8"; + else if (name == "Or") + name = "Or8"; + else + go_unreachable(); + } + else if (rname == "Uint32") + { + if (name == "Load") + name = "Load"; + else if (name == "LoadAcquire") + name = "LoadAcq"; + else if (name == "Store") + name = "Store"; + else if (name == "CompareAndSwap") + name = "Cas"; + else if (name == "CompareAndSwapRelease") + name = "CasRel"; + else if (name == "Swap") + name = "Xchg"; + else if (name == "And") + name = "And"; + else if (name == "Or") + name = "Or"; + else if (name == "Add") + name = "Xadd"; + else + go_unreachable(); + } + else if (rname == "Uint64") + { + if (name == "Load") + name = "Load64"; + else if (name == "Store") + name = "Store64"; + else if (name == "CompareAndSwap") + name = "Cas64"; + else if (name == "Swap") + name = "Xchgt64"; + else if (name == "Add") + name = "Xadd64"; + else + go_unreachable(); + } + else if (rname == "Uintptr") + { + if (name == "Load") + name = "Loaduintptr"; + else if (name == "LoadAcquire") + name = "Loadacquintptr"; + else if (name == "Store") + name = "Storeuintptr"; + else if (name == "StoreRelease") + name = "StoreReluintptr"; + else if (name == "CompareAndSwap") + name = "Casuintptr"; + else if (name == "Swap") + name = "Xchguintptr"; + else if (name == "Add") + name = "Xadduintptr"; + else + go_unreachable(); + } + else if (rname == "Float64") + { + // Needs unsafe type conversion. Don't intrinsify for now. + return NULL; + } + else if (rname == "UnsafePointer") + { + if (name == "Load") + name = "Loadp"; + else if (name == "StoreNoWB") + name = "StorepoWB"; + else if (name == "CompareAndSwapNoWB") + name = "Casp1"; + else + go_unreachable(); + } + else + go_unreachable(); + } + if ((name == "Load" || name == "Load64" || name == "Loadint64" || name == "Loadp" || name == "Loaduint" || name == "Loaduintptr" || name == "LoadAcq" - || name == "Loadint32") + || name == "Loadint32" || name == "Load8") && this->args_ != NULL && this->args_->size() == 1) { if (int_size < 8 && (name == "Load64" || name == "Loadint64")) @@ -11972,6 +12116,11 @@ Call_expression::intrinsify(Gogo* gogo, res_type = uint32_type; memorder = __ATOMIC_ACQUIRE; } + else if (name == "Load8") + { + code = Runtime::ATOMIC_LOAD_1; + res_type = uint8_type; + } else go_unreachable(); Expression* a1 = this->args_->front(); @@ -12012,6 +12161,8 @@ Call_expression::intrinsify(Gogo* gogo, code = Runtime::ATOMIC_STORE_4; memorder = __ATOMIC_RELEASE; } + else if (name == "Store8") + code = Runtime::ATOMIC_STORE_1; else go_unreachable(); Expression* a3 = Expression::make_integer_ul(memorder, int32_type, loc); @@ -12179,6 +12330,9 @@ Call_expression::intrinsify(Gogo* gogo, } else if (package == "internal/abi") { + if (is_method) + return NULL; + if ((name == "FuncPCABI0" || name == "FuncPCABIInternal") && this->args_ != NULL && this->args_->size() == 1) diff --git a/go/runtime.def b/go/runtime.def index 87a27085..b7dd4456 100644 --- a/go/runtime.def +++ b/go/runtime.def @@ -478,6 +478,10 @@ DEF_GO_RUNTIME(ATOMIC_ADD_FETCH_4, "__atomic_add_fetch_4", DEF_GO_RUNTIME(ATOMIC_ADD_FETCH_8, "__atomic_add_fetch_8", P3(POINTER, UINT64, INT32), R1(UINT64)) +DEF_GO_RUNTIME(ATOMIC_LOAD_1, "__atomic_load_1", P2(POINTER, INT32), + R1(UINT8)) +DEF_GO_RUNTIME(ATOMIC_STORE_1, "__atomic_store_1", P3(POINTER, UINT8, INT32), + R0()) DEF_GO_RUNTIME(ATOMIC_AND_FETCH_1, "__atomic_and_fetch_1", P3(POINTER, UINT8, INT32), R1(UINT8))