aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCherry Zhang <cherryyz@google.com>2019-05-17 00:21:22 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-05-17 00:21:22 +0000
commit395389bf9492a69db79747943d32abd0b7ac36c3 (patch)
treec47f111e7291a1fc34360a96cd67dbdfe84dc56a
parent6a362e1237fa3d7f2330181566eff02d83794475 (diff)
downloadgcc-395389bf9492a69db79747943d32abd0b7ac36c3.zip
gcc-395389bf9492a69db79747943d32abd0b7ac36c3.tar.gz
gcc-395389bf9492a69db79747943d32abd0b7ac36c3.tar.bz2
compiler: intrinsify runtime/internal/atomic functions
Currently runtime/internal/atomic functions are implemented in C using C compiler intrinsics. This CL lets the Go frontend recognize these functions and turn them into intrinsics directly. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/176918 * go-gcc.cc (Gcc_backend::Gcc_backend): Define atomic builtins. From-SVN: r271308
-rw-r--r--gcc/go/ChangeLog4
-rw-r--r--gcc/go/go-gcc.cc103
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc243
-rw-r--r--gcc/go/gofrontend/runtime.cc7
-rw-r--r--gcc/go/gofrontend/runtime.def32
6 files changed, 390 insertions, 1 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index 10c2b69..255d3b5 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,7 @@
+2019-05-16 Cherry Zhang <cherryyz@google.com>
+
+ * go-gcc.cc (Gcc_backend::Gcc_backend): Define atomic builtins.
+
2019-05-08 Cherry Zhang <cherryyz@google.com>
* go-gcc.cc (Gcc_backend::Gcc_backend): Define memmove builtin.
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index e0e4333..1b26f2b 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -776,6 +776,109 @@ Gcc_backend::Gcc_backend()
this->define_builtin(BUILT_IN_UNREACHABLE, "__builtin_unreachable", NULL,
build_function_type(void_type_node, void_list_node),
true, true);
+
+ // We provide some atomic functions.
+ t = build_function_type_list(uint32_type_node,
+ ptr_type_node,
+ integer_type_node,
+ NULL_TREE);
+ this->define_builtin(BUILT_IN_ATOMIC_LOAD_4, "__atomic_load_4", NULL,
+ t, false, false);
+
+ t = build_function_type_list(uint64_type_node,
+ ptr_type_node,
+ integer_type_node,
+ NULL_TREE);
+ this->define_builtin(BUILT_IN_ATOMIC_LOAD_8, "__atomic_load_8", NULL,
+ t, false, false);
+
+ t = build_function_type_list(void_type_node,
+ ptr_type_node,
+ uint32_type_node,
+ integer_type_node,
+ NULL_TREE);
+ this->define_builtin(BUILT_IN_ATOMIC_STORE_4, "__atomic_store_4", NULL,
+ t, false, false);
+
+ t = build_function_type_list(void_type_node,
+ ptr_type_node,
+ uint64_type_node,
+ integer_type_node,
+ NULL_TREE);
+ this->define_builtin(BUILT_IN_ATOMIC_STORE_8, "__atomic_store_8", NULL,
+ t, false, false);
+
+ t = build_function_type_list(uint32_type_node,
+ ptr_type_node,
+ uint32_type_node,
+ integer_type_node,
+ NULL_TREE);
+ this->define_builtin(BUILT_IN_ATOMIC_EXCHANGE_4, "__atomic_exchange_4", NULL,
+ t, false, false);
+
+ t = build_function_type_list(uint64_type_node,
+ ptr_type_node,
+ uint64_type_node,
+ integer_type_node,
+ NULL_TREE);
+ this->define_builtin(BUILT_IN_ATOMIC_EXCHANGE_8, "__atomic_exchange_8", NULL,
+ t, false, false);
+
+ t = build_function_type_list(boolean_type_node,
+ ptr_type_node,
+ ptr_type_node,
+ uint32_type_node,
+ boolean_type_node,
+ integer_type_node,
+ integer_type_node,
+ NULL_TREE);
+ this->define_builtin(BUILT_IN_ATOMIC_COMPARE_EXCHANGE_4,
+ "__atomic_compare_exchange_4", NULL,
+ t, false, false);
+
+ t = build_function_type_list(boolean_type_node,
+ ptr_type_node,
+ ptr_type_node,
+ uint64_type_node,
+ boolean_type_node,
+ integer_type_node,
+ integer_type_node,
+ NULL_TREE);
+ this->define_builtin(BUILT_IN_ATOMIC_COMPARE_EXCHANGE_8,
+ "__atomic_compare_exchange_8", NULL,
+ t, false, false);
+
+ t = build_function_type_list(uint32_type_node,
+ ptr_type_node,
+ uint32_type_node,
+ integer_type_node,
+ NULL_TREE);
+ this->define_builtin(BUILT_IN_ATOMIC_ADD_FETCH_4, "__atomic_add_fetch_4", NULL,
+ t, false, false);
+
+ t = build_function_type_list(uint64_type_node,
+ ptr_type_node,
+ uint64_type_node,
+ integer_type_node,
+ NULL_TREE);
+ this->define_builtin(BUILT_IN_ATOMIC_ADD_FETCH_8, "__atomic_add_fetch_8", NULL,
+ t, false, false);
+
+ t = build_function_type_list(unsigned_char_type_node,
+ ptr_type_node,
+ unsigned_char_type_node,
+ integer_type_node,
+ NULL_TREE);
+ this->define_builtin(BUILT_IN_ATOMIC_AND_FETCH_1, "__atomic_and_fetch_1", NULL,
+ t, false, false);
+
+ t = build_function_type_list(unsigned_char_type_node,
+ ptr_type_node,
+ unsigned_char_type_node,
+ integer_type_node,
+ NULL_TREE);
+ this->define_builtin(BUILT_IN_ATOMIC_OR_FETCH_1, "__atomic_or_fetch_1", NULL,
+ t, false, false);
}
// Get an unnamed integer type.
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index c3da5bf..578bef7 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-c0c8ad50627e3a59267e6e3de233a0b30cf64150
+f8a3668cbcfa3f8cd6c26c62bce416714cd401fc
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 d162b05..dd559b4 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -10460,9 +10460,16 @@ Call_expression::intrinsify(Gogo* gogo,
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* uint32_type = Type::lookup_integer_type("uint32");
Type* uint64_type = Type::lookup_integer_type("uint64");
Type* uintptr_type = Type::lookup_integer_type("uintptr");
+ Type* pointer_type = Type::make_pointer_type(Type::make_void_type());
+
+ 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 == "runtime")
{
@@ -10545,6 +10552,242 @@ Call_expression::intrinsify(Gogo* gogo,
return Expression::make_conditional(cmp, c64, call, loc);
}
}
+ else if (package == "runtime/internal/atomic")
+ {
+ int memorder = __ATOMIC_SEQ_CST;
+
+ if ((name == "Load" || name == "Load64" || name == "Loadint64" || name == "Loadp"
+ || name == "Loaduint" || name == "Loaduintptr" || name == "LoadAcq")
+ && this->args_ != NULL && this->args_->size() == 1)
+ {
+ if (int_size < 8 && (name == "Load64" || name == "Loadint64"))
+ // On 32-bit architectures we need to check alignment.
+ // Not intrinsify for now.
+ return NULL;
+
+ Runtime::Function code;
+ Type* res_type;
+ if (name == "Load")
+ {
+ code = Runtime::ATOMIC_LOAD_4;
+ res_type = uint32_type;
+ }
+ else if (name == "Load64")
+ {
+ code = Runtime::ATOMIC_LOAD_8;
+ res_type = uint64_type;
+ }
+ else if (name == "Loadint64")
+ {
+ code = Runtime::ATOMIC_LOAD_8;
+ res_type = int64_type;
+ }
+ else if (name == "Loaduint")
+ {
+ code = (int_size == 8
+ ? Runtime::ATOMIC_LOAD_8
+ : Runtime::ATOMIC_LOAD_4);
+ res_type = uint_type;
+ }
+ else if (name == "Loaduintptr")
+ {
+ code = (ptr_size == 8
+ ? Runtime::ATOMIC_LOAD_8
+ : Runtime::ATOMIC_LOAD_4);
+ res_type = uintptr_type;
+ }
+ else if (name == "Loadp")
+ {
+ code = (ptr_size == 8
+ ? Runtime::ATOMIC_LOAD_8
+ : Runtime::ATOMIC_LOAD_4);
+ res_type = pointer_type;
+ }
+ else if (name == "LoadAcq")
+ {
+ code = Runtime::ATOMIC_LOAD_4;
+ res_type = uint32_type;
+ memorder = __ATOMIC_ACQUIRE;
+ }
+ else
+ go_unreachable();
+ Expression* a1 = this->args_->front();
+ Expression* a2 = Expression::make_integer_ul(memorder, int32_type, loc);
+ Expression* call = Runtime::make_call(code, loc, 2, a1, a2);
+ return Expression::make_unsafe_cast(res_type, call, loc);
+ }
+
+ if ((name == "Store" || name == "Store64" || name == "StorepNoWB"
+ || name == "Storeuintptr" || name == "StoreRel")
+ && this->args_ != NULL && this->args_->size() == 2)
+ {
+ if (int_size < 8 && name == "Store64")
+ return NULL;
+
+ Runtime::Function code;
+ Expression* a1 = this->args_->at(0);
+ Expression* a2 = this->args_->at(1);
+ if (name == "Store")
+ code = Runtime::ATOMIC_STORE_4;
+ else if (name == "Store64")
+ 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")
+ {
+ code = (ptr_size == 8 ? Runtime::ATOMIC_STORE_8 : Runtime::ATOMIC_STORE_4);
+ a2 = Expression::make_unsafe_cast(uintptr_type, a2, loc);
+ a2 = Expression::make_cast(uint64_type, a2, loc);
+ }
+ else if (name == "StoreRel")
+ {
+ code = Runtime::ATOMIC_STORE_4;
+ memorder = __ATOMIC_RELEASE;
+ }
+ else
+ go_unreachable();
+ Expression* a3 = Expression::make_integer_ul(memorder, int32_type, loc);
+ return Runtime::make_call(code, loc, 3, a1, a2, a3);
+ }
+
+ if ((name == "Xchg" || name == "Xchg64" || name == "Xchguintptr")
+ && this->args_ != NULL && this->args_->size() == 2)
+ {
+ if (int_size < 8 && name == "Xchg64")
+ return NULL;
+
+ Runtime::Function code;
+ Type* res_type;
+ if (name == "Xchg")
+ {
+ code = Runtime::ATOMIC_EXCHANGE_4;
+ res_type = uint32_type;
+ }
+ else if (name == "Xchg64")
+ {
+ code = Runtime::ATOMIC_EXCHANGE_8;
+ res_type = uint64_type;
+ }
+ else if (name == "Xchguintptr")
+ {
+ code = (ptr_size == 8
+ ? Runtime::ATOMIC_EXCHANGE_8
+ : Runtime::ATOMIC_EXCHANGE_4);
+ res_type = uintptr_type;
+ }
+ else
+ go_unreachable();
+ Expression* a1 = this->args_->at(0);
+ Expression* a2 = this->args_->at(1);
+ Expression* a3 = Expression::make_integer_ul(memorder, int32_type, loc);
+ Expression* call = Runtime::make_call(code, loc, 3, a1, a2, a3);
+ return Expression::make_cast(res_type, call, loc);
+ }
+
+ if ((name == "Cas" || name == "Cas64" || name == "Casuintptr"
+ || name == "Casp1" || name == "CasRel")
+ && this->args_ != NULL && this->args_->size() == 3)
+ {
+ if (int_size < 8 && name == "Cas64")
+ return NULL;
+
+ Runtime::Function code;
+ Expression* a1 = this->args_->at(0);
+
+ // Builtin cas takes a pointer to the old value.
+ // Store it in a temporary and take the address.
+ Expression* a2 = this->args_->at(1);
+ Temporary_statement* ts = Statement::make_temporary(NULL, a2, loc);
+ inserter->insert(ts);
+ a2 = Expression::make_temporary_reference(ts, loc);
+ a2 = Expression::make_unary(OPERATOR_AND, a2, loc);
+
+ Expression* a3 = this->args_->at(2);
+ if (name == "Cas")
+ code = Runtime::ATOMIC_COMPARE_EXCHANGE_4;
+ else if (name == "Cas64")
+ code = Runtime::ATOMIC_COMPARE_EXCHANGE_8;
+ else if (name == "Casuintptr")
+ code = (ptr_size == 8
+ ? Runtime::ATOMIC_COMPARE_EXCHANGE_8
+ : Runtime::ATOMIC_COMPARE_EXCHANGE_4);
+ else if (name == "Casp1")
+ {
+ code = (ptr_size == 8
+ ? Runtime::ATOMIC_COMPARE_EXCHANGE_8
+ : Runtime::ATOMIC_COMPARE_EXCHANGE_4);
+ a3 = Expression::make_unsafe_cast(uintptr_type, a3, loc);
+ a3 = Expression::make_cast(uint64_type, a3, loc);
+ }
+ else if (name == "CasRel")
+ {
+ code = Runtime::ATOMIC_COMPARE_EXCHANGE_4;
+ memorder = __ATOMIC_RELEASE;
+ }
+ else
+ go_unreachable();
+ Expression* a4 = Expression::make_boolean(false, loc);
+ Expression* a5 = Expression::make_integer_ul(memorder, int32_type, loc);
+ Expression* a6 = Expression::make_integer_ul(__ATOMIC_RELAXED, int32_type, loc);
+ return Runtime::make_call(code, loc, 6, a1, a2, a3, a4, a5, a6);
+ }
+
+ if ((name == "Xadd" || name == "Xadd64" || name == "Xaddint64"
+ || name == "Xadduintptr")
+ && this->args_ != NULL && this->args_->size() == 2)
+ {
+ if (int_size < 8 && (name == "Xadd64" || name == "Xaddint64"))
+ return NULL;
+
+ Runtime::Function code;
+ Type* res_type;
+ if (name == "Xadd")
+ {
+ code = Runtime::ATOMIC_ADD_FETCH_4;
+ res_type = uint32_type;
+ }
+ else if (name == "Xadd64")
+ {
+ code = Runtime::ATOMIC_ADD_FETCH_8;
+ res_type = uint64_type;
+ }
+ else if (name == "Xaddint64")
+ {
+ code = Runtime::ATOMIC_ADD_FETCH_8;
+ res_type = int64_type;
+ }
+ else if (name == "Xadduintptr")
+ {
+ code = (ptr_size == 8
+ ? Runtime::ATOMIC_ADD_FETCH_8
+ : Runtime::ATOMIC_ADD_FETCH_4);
+ res_type = uintptr_type;
+ }
+ else
+ go_unreachable();
+ Expression* a1 = this->args_->at(0);
+ Expression* a2 = this->args_->at(1);
+ Expression* a3 = Expression::make_integer_ul(memorder, int32_type, loc);
+ Expression* call = Runtime::make_call(code, loc, 3, a1, a2, a3);
+ return Expression::make_cast(res_type, call, loc);
+ }
+
+ if ((name == "And8" || name == "Or8")
+ && this->args_ != NULL && this->args_->size() == 2)
+ {
+ Runtime::Function code;
+ if (name == "And8")
+ code = Runtime::ATOMIC_AND_FETCH_1;
+ else if (name == "Or8")
+ code = Runtime::ATOMIC_OR_FETCH_1;
+ else
+ go_unreachable();
+ Expression* a1 = this->args_->at(0);
+ Expression* a2 = this->args_->at(1);
+ Expression* a3 = Expression::make_integer_ul(memorder, int32_type, loc);
+ return Runtime::make_call(code, loc, 3, a1, a2, a3);
+ }
+ }
return NULL;
}
diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc
index 289d6bf..28aca44 100644
--- a/gcc/go/gofrontend/runtime.cc
+++ b/gcc/go/gofrontend/runtime.cc
@@ -30,6 +30,8 @@ enum Runtime_function_type
RFT_BOOLPTR,
// Go type int, C type intgo.
RFT_INT,
+ // Go type uint8, C type uint8_t.
+ RFT_UINT8,
// Go type int32, C type int32_t.
RFT_INT32,
// Go type uint32, C type uint32_t.
@@ -109,6 +111,10 @@ runtime_function_type(Runtime_function_type bft)
t = Type::lookup_integer_type("int");
break;
+ case RFT_UINT8:
+ t = Type::lookup_integer_type("uint8");
+ break;
+
case RFT_INT32:
t = Type::lookup_integer_type("int32");
break;
@@ -250,6 +256,7 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
case RFT_BOOL:
case RFT_BOOLPTR:
case RFT_INT:
+ case RFT_UINT8:
case RFT_INT32:
case RFT_UINT32:
case RFT_INT64:
diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def
index a5264ee..226eeac 100644
--- a/gcc/go/gofrontend/runtime.def
+++ b/gcc/go/gofrontend/runtime.def
@@ -396,6 +396,38 @@ DEF_GO_RUNTIME(BUILTIN_BSWAP64, "__builtin_bswap64", P1(UINT64),
DEF_GO_RUNTIME(BUILTIN_CTZ, "__builtin_ctz", P1(UINT32), R1(INT32))
DEF_GO_RUNTIME(BUILTIN_CTZLL, "__builtin_ctzll", P1(UINT64), R1(INT32))
+// Atomics.
+DEF_GO_RUNTIME(ATOMIC_LOAD_4, "__atomic_load_4", P2(POINTER, INT32),
+ R1(UINT32))
+DEF_GO_RUNTIME(ATOMIC_LOAD_8, "__atomic_load_8", P2(POINTER, INT32),
+ R1(UINT64))
+DEF_GO_RUNTIME(ATOMIC_STORE_4, "__atomic_store_4", P3(POINTER, UINT32, INT32),
+ R0())
+DEF_GO_RUNTIME(ATOMIC_STORE_8, "__atomic_store_8", P3(POINTER, UINT64, INT32),
+ R0())
+DEF_GO_RUNTIME(ATOMIC_EXCHANGE_4, "__atomic_exchange_4", P3(POINTER, UINT32, INT32),
+ R1(UINT32))
+DEF_GO_RUNTIME(ATOMIC_EXCHANGE_8, "__atomic_exchange_8", P3(POINTER, UINT64, INT32),
+ R1(UINT64))
+DEF_GO_RUNTIME(ATOMIC_COMPARE_EXCHANGE_4, "__atomic_compare_exchange_4",
+ P6(POINTER, POINTER, UINT32, BOOL, INT32, INT32),
+ R1(BOOL))
+DEF_GO_RUNTIME(ATOMIC_COMPARE_EXCHANGE_8, "__atomic_compare_exchange_8",
+ P6(POINTER, POINTER, UINT64, BOOL, INT32, INT32),
+ R1(BOOL))
+DEF_GO_RUNTIME(ATOMIC_ADD_FETCH_4, "__atomic_add_fetch_4",
+ P3(POINTER, UINT32, INT32),
+ R1(UINT32))
+DEF_GO_RUNTIME(ATOMIC_ADD_FETCH_8, "__atomic_add_fetch_8",
+ P3(POINTER, UINT64, INT32),
+ R1(UINT64))
+DEF_GO_RUNTIME(ATOMIC_AND_FETCH_1, "__atomic_and_fetch_1",
+ P3(POINTER, UINT8, INT32),
+ R1(UINT8))
+DEF_GO_RUNTIME(ATOMIC_OR_FETCH_1, "__atomic_or_fetch_1",
+ P3(POINTER, UINT8, INT32),
+ R1(UINT8))
+
// Remove helper macros.
#undef ABFT6
#undef ABFT2