Commit 395389bf by Cherry Zhang Committed by Ian Lance Taylor

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
parent 6a362e12
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> 2019-05-08 Cherry Zhang <cherryyz@google.com>
* go-gcc.cc (Gcc_backend::Gcc_backend): Define memmove builtin. * go-gcc.cc (Gcc_backend::Gcc_backend): Define memmove builtin.
......
...@@ -776,6 +776,109 @@ Gcc_backend::Gcc_backend() ...@@ -776,6 +776,109 @@ Gcc_backend::Gcc_backend()
this->define_builtin(BUILT_IN_UNREACHABLE, "__builtin_unreachable", NULL, this->define_builtin(BUILT_IN_UNREACHABLE, "__builtin_unreachable", NULL,
build_function_type(void_type_node, void_list_node), build_function_type(void_type_node, void_list_node),
true, true); 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. // Get an unnamed integer type.
......
c0c8ad50627e3a59267e6e3de233a0b30cf64150 f8a3668cbcfa3f8cd6c26c62bce416714cd401fc
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -10460,9 +10460,16 @@ Call_expression::intrinsify(Gogo* gogo, ...@@ -10460,9 +10460,16 @@ Call_expression::intrinsify(Gogo* gogo,
Location loc = this->location(); Location loc = this->location();
Type* int_type = Type::lookup_integer_type("int"); 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* uint32_type = Type::lookup_integer_type("uint32");
Type* uint64_type = Type::lookup_integer_type("uint64"); Type* uint64_type = Type::lookup_integer_type("uint64");
Type* uintptr_type = Type::lookup_integer_type("uintptr"); 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") if (package == "runtime")
{ {
...@@ -10545,6 +10552,242 @@ Call_expression::intrinsify(Gogo* gogo, ...@@ -10545,6 +10552,242 @@ Call_expression::intrinsify(Gogo* gogo,
return Expression::make_conditional(cmp, c64, call, loc); 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; return NULL;
} }
......
...@@ -30,6 +30,8 @@ enum Runtime_function_type ...@@ -30,6 +30,8 @@ enum Runtime_function_type
RFT_BOOLPTR, RFT_BOOLPTR,
// Go type int, C type intgo. // Go type int, C type intgo.
RFT_INT, RFT_INT,
// Go type uint8, C type uint8_t.
RFT_UINT8,
// Go type int32, C type int32_t. // Go type int32, C type int32_t.
RFT_INT32, RFT_INT32,
// Go type uint32, C type uint32_t. // Go type uint32, C type uint32_t.
...@@ -109,6 +111,10 @@ runtime_function_type(Runtime_function_type bft) ...@@ -109,6 +111,10 @@ runtime_function_type(Runtime_function_type bft)
t = Type::lookup_integer_type("int"); t = Type::lookup_integer_type("int");
break; break;
case RFT_UINT8:
t = Type::lookup_integer_type("uint8");
break;
case RFT_INT32: case RFT_INT32:
t = Type::lookup_integer_type("int32"); t = Type::lookup_integer_type("int32");
break; break;
...@@ -250,6 +256,7 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e, ...@@ -250,6 +256,7 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
case RFT_BOOL: case RFT_BOOL:
case RFT_BOOLPTR: case RFT_BOOLPTR:
case RFT_INT: case RFT_INT:
case RFT_UINT8:
case RFT_INT32: case RFT_INT32:
case RFT_UINT32: case RFT_UINT32:
case RFT_INT64: case RFT_INT64:
......
...@@ -396,6 +396,38 @@ DEF_GO_RUNTIME(BUILTIN_BSWAP64, "__builtin_bswap64", P1(UINT64), ...@@ -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_CTZ, "__builtin_ctz", P1(UINT32), R1(INT32))
DEF_GO_RUNTIME(BUILTIN_CTZLL, "__builtin_ctzll", P1(UINT64), 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. // Remove helper macros.
#undef ABFT6 #undef ABFT6
#undef ABFT2 #undef ABFT2
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment