From c9c41a6b1bf681e319b3b3df035eeb9ad754ea0d Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 30 May 2019 17:26:46 +0000 Subject: [PATCH] compiler: intrinsify sync/atomic functions Let the Go frontend recognize sync/atomic functions and turn them into intrinsics. Also make sure not to intrinsify calls in go or defer statements. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/178937 From-SVN: r271784 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 118 ++++++++++++++++++++++++++++--- gcc/go/gofrontend/statements.cc | 4 +- 3 files changed, 112 insertions(+), 12 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 6a291b5402a..b7b0f5027b8 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -84b8000c32f671c6cc89df1290ed6e0170308644 +4dc60d989293d070702024e7dea52b9849f74775 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 ad898b7f38c..e3a662736a0 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -10432,7 +10432,8 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*, // Lower to compiler intrinsic if possible. Func_expression* fe = this->fn_->func_expression(); - if (fe != NULL + if (!this->is_concurrent_ && !this->is_deferred_ + && fe != NULL && (fe->named_object()->is_function_declaration() || fe->named_object()->is_function())) { @@ -10471,6 +10472,73 @@ Call_expression::intrinsify(Gogo* gogo, int int_size = int_type->named_type()->real_type()->integer_type()->bits() / 8; int ptr_size = uintptr_type->named_type()->real_type()->integer_type()->bits() / 8; + if (package == "sync/atomic") + { + // 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. + // In case there is no equivalent functions (slight variance + // in types), we just make an artificial name (begin with '$'). + // Note: no StorePointer, SwapPointer, and CompareAndSwapPointer, + // as they need write barriers. + if (name == "LoadInt32") + name = "$Loadint32"; + else if (name == "LoadInt64") + name = "Loadint64"; + else if (name == "LoadUint32") + name = "Load"; + else if (name == "LoadUint64") + name = "Load64"; + else if (name == "LoadUintptr") + name = "Loaduintptr"; + else if (name == "LoadPointer") + name = "Loadp"; + else if (name == "StoreInt32") + name = "$Storeint32"; + else if (name == "StoreInt64") + name = "$Storeint64"; + else if (name == "StoreUint32") + name = "Store"; + else if (name == "StoreUint64") + name = "Store64"; + else if (name == "StoreUintptr") + name = "Storeuintptr"; + else if (name == "AddInt32") + name = "$Xaddint32"; + else if (name == "AddInt64") + name = "Xaddint64"; + else if (name == "AddUint32") + name = "Xadd"; + else if (name == "AddUint64") + name = "Xadd64"; + else if (name == "AddUintptr") + name = "Xadduintptr"; + else if (name == "SwapInt32") + name = "$Xchgint32"; + else if (name == "SwapInt64") + name = "$Xchgint64"; + else if (name == "SwapUint32") + name = "Xchg"; + else if (name == "SwapUint64") + name = "Xchg64"; + else if (name == "SwapUintptr") + name = "Xchguintptr"; + else if (name == "CompareAndSwapInt32") + name = "$Casint32"; + else if (name == "CompareAndSwapInt64") + name = "$Casint64"; + else if (name == "CompareAndSwapUint32") + name = "Cas"; + else if (name == "CompareAndSwapUint64") + name = "Cas64"; + else if (name == "CompareAndSwapUintptr") + name = "Casuintptr"; + else + return NULL; + + package = "runtime/internal/atomic"; + } + if (package == "runtime") { // Handle a couple of special runtime functions. In the runtime @@ -10557,7 +10625,8 @@ Call_expression::intrinsify(Gogo* gogo, int memorder = __ATOMIC_SEQ_CST; if ((name == "Load" || name == "Load64" || name == "Loadint64" || name == "Loadp" - || name == "Loaduint" || name == "Loaduintptr" || name == "LoadAcq") + || name == "Loaduint" || name == "Loaduintptr" || name == "LoadAcq" + || name == "$Loadint32") && this->args_ != NULL && this->args_->size() == 1) { if (int_size < 8 && (name == "Load64" || name == "Loadint64")) @@ -10577,6 +10646,11 @@ Call_expression::intrinsify(Gogo* gogo, code = Runtime::ATOMIC_LOAD_8; res_type = uint64_type; } + else if (name == "$Loadint32") + { + code = Runtime::ATOMIC_LOAD_4; + res_type = int32_type; + } else if (name == "Loadint64") { code = Runtime::ATOMIC_LOAD_8; @@ -10618,10 +10692,11 @@ Call_expression::intrinsify(Gogo* gogo, } if ((name == "Store" || name == "Store64" || name == "StorepNoWB" - || name == "Storeuintptr" || name == "StoreRel") + || name == "Storeuintptr" || name == "StoreRel" + || name == "$Storeint32" || name == "$Storeint64") && this->args_ != NULL && this->args_->size() == 2) { - if (int_size < 8 && name == "Store64") + if (int_size < 8 && (name == "Store64" || name == "$Storeint64")) return NULL; Runtime::Function code; @@ -10631,6 +10706,10 @@ Call_expression::intrinsify(Gogo* gogo, code = Runtime::ATOMIC_STORE_4; else if (name == "Store64") code = Runtime::ATOMIC_STORE_8; + else if (name == "$Storeint32") + code = Runtime::ATOMIC_STORE_4; + else if (name == "$Storeint64") + code = Runtime::ATOMIC_STORE_8; else if (name == "Storeuintptr") code = (ptr_size == 8 ? Runtime::ATOMIC_STORE_8 : Runtime::ATOMIC_STORE_4); else if (name == "StorepNoWB") @@ -10650,10 +10729,11 @@ Call_expression::intrinsify(Gogo* gogo, return Runtime::make_call(code, loc, 3, a1, a2, a3); } - if ((name == "Xchg" || name == "Xchg64" || name == "Xchguintptr") + if ((name == "Xchg" || name == "Xchg64" || name == "Xchguintptr" + || name == "$Xchgint32" || name == "$Xchgint64") && this->args_ != NULL && this->args_->size() == 2) { - if (int_size < 8 && name == "Xchg64") + if (int_size < 8 && (name == "Xchg64" || name == "Xchgint64")) return NULL; Runtime::Function code; @@ -10668,6 +10748,16 @@ Call_expression::intrinsify(Gogo* gogo, code = Runtime::ATOMIC_EXCHANGE_8; res_type = uint64_type; } + else if (name == "$Xchgint32") + { + code = Runtime::ATOMIC_EXCHANGE_4; + res_type = int32_type; + } + else if (name == "$Xchgint64") + { + code = Runtime::ATOMIC_EXCHANGE_8; + res_type = int64_type; + } else if (name == "Xchguintptr") { code = (ptr_size == 8 @@ -10685,10 +10775,11 @@ Call_expression::intrinsify(Gogo* gogo, } if ((name == "Cas" || name == "Cas64" || name == "Casuintptr" - || name == "Casp1" || name == "CasRel") + || name == "Casp1" || name == "CasRel" + || name == "$Casint32" || name == "$Casint64") && this->args_ != NULL && this->args_->size() == 3) { - if (int_size < 8 && name == "Cas64") + if (int_size < 8 && (name == "Cas64" || name == "$Casint64")) return NULL; Runtime::Function code; @@ -10707,6 +10798,10 @@ Call_expression::intrinsify(Gogo* gogo, code = Runtime::ATOMIC_COMPARE_EXCHANGE_4; else if (name == "Cas64") code = Runtime::ATOMIC_COMPARE_EXCHANGE_8; + else if (name == "$Casint32") + code = Runtime::ATOMIC_COMPARE_EXCHANGE_4; + else if (name == "$Casint64") + code = Runtime::ATOMIC_COMPARE_EXCHANGE_8; else if (name == "Casuintptr") code = (ptr_size == 8 ? Runtime::ATOMIC_COMPARE_EXCHANGE_8 @@ -10733,7 +10828,7 @@ Call_expression::intrinsify(Gogo* gogo, } if ((name == "Xadd" || name == "Xadd64" || name == "Xaddint64" - || name == "Xadduintptr") + || name == "Xadduintptr" || name == "$Xaddint32") && this->args_ != NULL && this->args_->size() == 2) { if (int_size < 8 && (name == "Xadd64" || name == "Xaddint64")) @@ -10751,6 +10846,11 @@ Call_expression::intrinsify(Gogo* gogo, code = Runtime::ATOMIC_ADD_FETCH_8; res_type = uint64_type; } + else if (name == "$Xaddint32") + { + code = Runtime::ATOMIC_ADD_FETCH_4; + res_type = int32_type; + } else if (name == "Xaddint64") { code = Runtime::ATOMIC_ADD_FETCH_8; diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index c850b49bebd..e3354892b40 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -2682,8 +2682,6 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name) gogo->add_conversions_in_block(b); - gogo->flatten_block(function, b); - if (may_call_recover || recover_arg != NULL || this->classification() == STATEMENT_GO) @@ -2707,6 +2705,8 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name) } } + gogo->flatten_block(function, b); + // That is all the thunk has to do. gogo->finish_function(location); } -- 2.30.2