public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Ian Lance Taylor <iant@golang.org>
To: gcc-patches <gcc-patches@gcc.gnu.org>,
		gofrontend-dev <gofrontend-dev@googlegroups.com>
Subject: Go patch committed: Intrinsify runtime/internal/atomic functions
Date: Fri, 17 May 2019 00:21:00 -0000	[thread overview]
Message-ID: <CAOyqgcUfhNqUfBtRroHB5SyKeRn0=faPVO7KhJsF8QLa1rKH+w@mail.gmail.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 498 bytes --]

This patch to the Go frontend by Cherry Zhang intrinsifies the
runtime/internal/atomic functions.  Currently the
runtime/internal/atomic functions are implemented in C using C
compiler intrinsics.  This patch lets the Go frontend recognize these
functions and turn them into intrinsics directly.  Bootstrapped and
ran Go testsuite on x86_64-pc-linux-gnu.  Committed to mainline.

Ian

2019-05-16  Cherry Zhang  <cherryyz@google.com>

* go-gcc.cc (Gcc_backend::Gcc_backend): Define atomic builtins.

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 18734 bytes --]

Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 271182)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -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.
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 271303)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -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.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 271303)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -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;
 }
Index: gcc/go/gofrontend/runtime.cc
===================================================================
--- gcc/go/gofrontend/runtime.cc	(revision 271303)
+++ gcc/go/gofrontend/runtime.cc	(working copy)
@@ -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_t
 	  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
     case RFT_BOOL:
     case RFT_BOOLPTR:
     case RFT_INT:
+    case RFT_UINT8:
     case RFT_INT32:
     case RFT_UINT32:
     case RFT_INT64:
Index: gcc/go/gofrontend/runtime.def
===================================================================
--- gcc/go/gofrontend/runtime.def	(revision 271303)
+++ gcc/go/gofrontend/runtime.def	(working copy)
@@ -396,6 +396,38 @@ DEF_GO_RUNTIME(BUILTIN_BSWAP64, "__built
 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

             reply	other threads:[~2019-05-17  0:21 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-05-17  0:21 Ian Lance Taylor [this message]
2019-05-19 12:22 ` Andreas Schwab
2019-05-22  1:17   ` Jim Wilson
2019-05-23  1:37     ` [gofrontend-dev] " Cherry Zhang via gcc-patches
2019-05-23  1:41       ` Ian Lance Taylor
2019-05-30 20:50         ` Jim Wilson
2019-05-30 20:51       ` Jim Wilson
2019-05-30 18:37     ` Andreas Schwab
2019-05-30 20:56       ` Jim Wilson
2019-06-03 14:12         ` Maciej Rozycki
2019-06-03 17:03           ` Ian Lance Taylor
2019-06-03 20:11             ` Maciej Rozycki
2019-06-03 17:21           ` Andreas Schwab

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAOyqgcUfhNqUfBtRroHB5SyKeRn0=faPVO7KhJsF8QLa1rKH+w@mail.gmail.com' \
    --to=iant@golang.org \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=gofrontend-dev@googlegroups.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).