compiler: add intrinsics for runtime/internal/sys functions
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 16 May 2019 23:23:58 +0000 (23:23 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 16 May 2019 23:23:58 +0000 (23:23 +0000)
    runtime/internal/sys.Ctz32/64 and Bswap32/64 are currently
    implemented with compiler builtin functions. But if they are
    called from another package, the compiler does not know and
    therefore cannot turn them into compiler intrinsics. This CL
    makes the compiler recognize these functions and turn them into
    intrinsics directly, as the gc compiler does.

    This CL sets up a way for adding intrinsics in the compiler.
    More intrinsics will be added in later CLs.

    Also move the handling of runtime.getcallerpc/sp to the new way
    of generating intrinsics.

    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/176917

From-SVN: r271303

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/runtime.cc
gcc/go/gofrontend/runtime.def

index fba3721f23d578f9a3680e7c76f1d7343854246b..c3da5bfce87705b60d2c0a582bef2dea5f22e187 100644 (file)
@@ -1,4 +1,4 @@
-2df0879e7880057293c0a59be6868a3e6ea5105b
+c0c8ad50627e3a59267e6e3de233a0b30cf64150
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 8af0dd43a88c6f0c82432bd759f660a2f3c74708..d162b05621177888c4d608f9580670e25f353038 100644 (file)
@@ -10252,42 +10252,6 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
                                                  bme->location());
     }
 
-  // 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
-  // these by turning them into calls to GCC builtin functions.  We
-  // could implement them in normal code, but then we would have to
-  // explicitly unwind the stack.  These functions are intended to be
-  // efficient.  Note that this technique obviously only works for
-  // direct calls, but that is the only way they are used.
-  if (gogo->compiling_runtime() && gogo->package_name() == "runtime")
-    {
-      Func_expression* fe = this->fn_->func_expression();
-      if (fe != NULL
-         && fe->named_object()->is_function_declaration()
-         && fe->named_object()->package() == NULL)
-       {
-         std::string n = Gogo::unpack_hidden_name(fe->named_object()->name());
-         if ((this->args_ == NULL || this->args_->size() == 0)
-             && n == "getcallerpc")
-           {
-             static Named_object* builtin_return_address;
-              int arg = 0;
-             return this->lower_to_builtin(&builtin_return_address,
-                                           "__builtin_return_address",
-                                           &arg);
-           }
-         else if ((this->args_ == NULL || this->args_->size() == 0)
-                  && n == "getcallersp")
-           {
-             static Named_object* builtin_dwarf_cfa;
-             return this->lower_to_builtin(&builtin_dwarf_cfa,
-                                           "__builtin_dwarf_cfa",
-                                           NULL);
-           }
-       }
-    }
-
   // If this is a call to an imported function for which we have an
   // inlinable function body, add it to the list of functions to give
   // to the backend as inlining opportunities.
@@ -10401,31 +10365,6 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
   this->varargs_are_lowered_ = true;
 }
 
-// Return a call to __builtin_return_address or __builtin_dwarf_cfa.
-
-Expression*
-Call_expression::lower_to_builtin(Named_object** pno, const char* name,
-                                 int* arg)
-{
-  if (*pno == NULL)
-    *pno = Gogo::declare_builtin_rf_address(name, arg != NULL);
-
-  Location loc = this->location();
-
-  Expression* fn = Expression::make_func_reference(*pno, NULL, loc);
-  Expression_list *args = new Expression_list();
-  if (arg != NULL)
-    {
-      Expression* a = Expression::make_integer_ul(*arg, NULL, loc);
-      args->push_back(a);
-    }
-  Expression* call = Expression::make_call(fn, args, false, loc);
-
-  // The builtin functions return void*, but the Go functions return uintptr.
-  Type* uintptr_type = Type::lookup_integer_type("uintptr");
-  return Expression::make_cast(uintptr_type, call, loc);
-}
-
 // Flatten a call with multiple results into a temporary.
 
 Expression*
@@ -10491,9 +10430,125 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*,
       this->args_ = args;
     }
 
+  // Lower to compiler intrinsic if possible.
+  Func_expression* fe = this->fn_->func_expression();
+  if (fe != NULL
+      && (fe->named_object()->is_function_declaration()
+          || fe->named_object()->is_function()))
+    {
+      Expression* ret = this->intrinsify(gogo, inserter);
+      if (ret != NULL)
+        return ret;
+    }
+
   return this;
 }
 
+// Lower a call to a compiler intrinsic if possible.
+// Returns NULL if it is not an intrinsic.
+
+Expression*
+Call_expression::intrinsify(Gogo* gogo,
+                            Statement_inserter* inserter)
+{
+  Func_expression* fe = this->fn_->func_expression();
+  Named_object* no = fe->named_object();
+  std::string name = Gogo::unpack_hidden_name(no->name());
+  std::string package = (no->package() != NULL
+                         ? no->package()->pkgpath()
+                         : gogo->pkgpath());
+  Location loc = this->location();
+
+  Type* int_type = Type::lookup_integer_type("int");
+  Type* uint32_type = Type::lookup_integer_type("uint32");
+  Type* uint64_type = Type::lookup_integer_type("uint64");
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+  if (package == "runtime")
+    {
+      // 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
+      // these by turning them into calls to GCC builtin functions.  We
+      // could implement them in normal code, but then we would have to
+      // explicitly unwind the stack.  These functions are intended to be
+      // efficient.  Note that this technique obviously only works for
+      // direct calls, but that is the only way they are used.
+      if (name == "getcallerpc"
+          && (this->args_ == NULL || this->args_->size() == 0))
+        {
+          Expression* arg = Expression::make_integer_ul(0, uint32_type, loc);
+          Expression* call =
+            Runtime::make_call(Runtime::BUILTIN_RETURN_ADDRESS, loc,
+                               1, arg);
+          // The builtin functions return void*, but the Go functions return uintptr.
+          return Expression::make_cast(uintptr_type, call, loc);
+        }
+      else if (name == "getcallersp"
+               && (this->args_ == NULL || this->args_->size() == 0))
+
+        {
+          Expression* call =
+            Runtime::make_call(Runtime::BUILTIN_DWARF_CFA, loc, 0);
+          // The builtin functions return void*, but the Go functions return uintptr.
+          return Expression::make_cast(uintptr_type, call, loc);
+        }
+    }
+  else if (package == "runtime/internal/sys")
+    {
+      if (name == "Bswap32"
+          && this->args_ != NULL && this->args_->size() == 1)
+        {
+          Expression* arg = this->args_->front();
+          return Runtime::make_call(Runtime::BUILTIN_BSWAP32, loc, 1, arg);
+        }
+      else if (name == "Bswap64"
+               && this->args_ != NULL && this->args_->size() == 1)
+        {
+          Expression* arg = this->args_->front();
+          return Runtime::make_call(Runtime::BUILTIN_BSWAP64, loc, 1, arg);
+        }
+      else if (name == "Ctz32"
+               && this->args_ != NULL && this->args_->size() == 1)
+        {
+          Expression* arg = this->args_->front();
+          if (!arg->is_variable())
+            {
+              Temporary_statement* ts = Statement::make_temporary(uint32_type, arg, loc);
+              inserter->insert(ts);
+              arg = Expression::make_temporary_reference(ts, loc);
+            }
+          // arg == 0 ? 32 : __builtin_ctz(arg)
+          Expression* zero = Expression::make_integer_ul(0, uint32_type, loc);
+          Expression* cmp = Expression::make_binary(OPERATOR_EQEQ, arg, zero, loc);
+          Expression* c32 = Expression::make_integer_ul(32, int_type, loc);
+          Expression* call = Runtime::make_call(Runtime::BUILTIN_CTZ, loc, 1, arg->copy());
+          call = Expression::make_cast(int_type, call, loc);
+          return Expression::make_conditional(cmp, c32, call, loc);
+        }
+      else if (name == "Ctz64"
+               && this->args_ != NULL && this->args_->size() == 1)
+        {
+          Expression* arg = this->args_->front();
+          if (!arg->is_variable())
+            {
+              Temporary_statement* ts = Statement::make_temporary(uint64_type, arg, loc);
+              inserter->insert(ts);
+              arg = Expression::make_temporary_reference(ts, loc);
+            }
+          // arg == 0 ? 64 : __builtin_ctzll(arg)
+          Expression* zero = Expression::make_integer_ul(0, uint64_type, loc);
+          Expression* cmp = Expression::make_binary(OPERATOR_EQEQ, arg, zero, loc);
+          Expression* c64 = Expression::make_integer_ul(64, int_type, loc);
+          Expression* call = Runtime::make_call(Runtime::BUILTIN_CTZLL, loc, 1, arg->copy());
+          call = Expression::make_cast(int_type, call, loc);
+          return Expression::make_conditional(cmp, c64, call, loc);
+        }
+    }
+
+  return NULL;
+}
+
 // Make implicit type conversions explicit.
 
 void
index b1811ea2f1f85734d1c21773da6fcf744df07fea..21a214db632226e6c447881ddedcd0d843966f31 100644 (file)
@@ -2427,7 +2427,7 @@ class Call_expression : public Expression
   check_argument_type(int, const Type*, const Type*, Location, bool);
 
   Expression*
-  lower_to_builtin(Named_object**, const char*, int*);
+  intrinsify(Gogo*, Statement_inserter*);
 
   Expression*
   interface_method_function(Interface_field_reference_expression*,
index 06657cb2be4b569afd0bfc5343d314f49de30c4d..02120f2e1fdbca8e96a73474dad33fba7331db9e 100644 (file)
@@ -4566,11 +4566,6 @@ Build_recover_thunks::function(Named_object* orig_no)
 Expression*
 Build_recover_thunks::can_recover_arg(Location location)
 {
-  static Named_object* builtin_return_address;
-  if (builtin_return_address == NULL)
-    builtin_return_address =
-      Gogo::declare_builtin_rf_address("__builtin_return_address", true);
-
   Type* uintptr_type = Type::lookup_integer_type("uintptr");
   static Named_object* can_recover;
   if (can_recover == NULL)
@@ -4589,20 +4584,15 @@ Build_recover_thunks::can_recover_arg(Location location)
       can_recover->func_declaration_value()->set_asm_name("runtime.canrecover");
     }
 
-  Expression* fn = Expression::make_func_reference(builtin_return_address,
-                                                  NULL, location);
-
   Expression* zexpr = Expression::make_integer_ul(0, NULL, location);
-  Expression_list *args = new Expression_list();
-  args->push_back(zexpr);
-
-  Expression* call = Expression::make_call(fn, args, false, location);
+  Expression* call = Runtime::make_call(Runtime::BUILTIN_RETURN_ADDRESS,
+                                        location, 1, zexpr);
   call = Expression::make_unsafe_cast(uintptr_type, call, location);
 
-  args = new Expression_list();
+  Expression_list* args = new Expression_list();
   args->push_back(call);
 
-  fn = Expression::make_func_reference(can_recover, NULL, location);
+  Expression* fn = Expression::make_func_reference(can_recover, NULL, location);
   return Expression::make_call(fn, args, false, location);
 }
 
@@ -4622,33 +4612,6 @@ Gogo::build_recover_thunks()
   this->traverse(&build_recover_thunks);
 }
 
-// Return a declaration for __builtin_return_address or
-// __builtin_dwarf_cfa.
-
-Named_object*
-Gogo::declare_builtin_rf_address(const char* name, bool hasarg)
-{
-  const Location bloc = Linemap::predeclared_location();
-
-  Typed_identifier_list* param_types = new Typed_identifier_list();
-  if (hasarg)
-    {
-      Type* uint32_type = Type::lookup_integer_type("uint32");
-      param_types->push_back(Typed_identifier("l", uint32_type, bloc));
-    }
-
-  Typed_identifier_list* return_types = new Typed_identifier_list();
-  Type* voidptr_type = Type::make_pointer_type(Type::make_void_type());
-  return_types->push_back(Typed_identifier("", voidptr_type, bloc));
-
-  Function_type* fntype = Type::make_function_type(NULL, param_types,
-                                                  return_types, bloc);
-  Named_object* ret = Named_object::make_function_declaration(name, NULL,
-                                                             fntype, bloc);
-  ret->func_declaration_value()->set_asm_name(name);
-  return ret;
-}
-
 // Build a call to the runtime error function.
 
 Expression*
index 448da0473164d58cf8f66393bde9a80545de5ca1..e67a8a5db6c24e83964ebd4a2cf2720da86432aa 100644 (file)
@@ -764,11 +764,6 @@ class Gogo
   void
   build_recover_thunks();
 
-  // Return a declaration for __builtin_return_address or
-  // __builtin_dwarf_cfa.
-  static Named_object*
-  declare_builtin_rf_address(const char* name, bool hasarg);
-
   // Simplify statements which might use thunks: go and defer
   // statements.
   void
index 7ecbf6894090fc71edfffbccc4a666b164e6f29f..289d6bf8297dd5a42e03a6207a227d4671449ce1 100644 (file)
@@ -32,6 +32,8 @@ enum Runtime_function_type
   RFT_INT,
   // Go type int32, C type int32_t.
   RFT_INT32,
+  // Go type uint32, C type uint32_t.
+  RFT_UINT32,
   // Go type int64, C type int64_t.
   RFT_INT64,
   // Go type uint64, C type uint64_t.
@@ -111,6 +113,10 @@ runtime_function_type(Runtime_function_type bft)
          t = Type::lookup_integer_type("int32");
          break;
 
+       case RFT_UINT32:
+         t = Type::lookup_integer_type("uint32");
+         break;
+
        case RFT_INT64:
          t = Type::lookup_integer_type("int64");
          break;
@@ -245,6 +251,7 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
     case RFT_BOOLPTR:
     case RFT_INT:
     case RFT_INT32:
+    case RFT_UINT32:
     case RFT_INT64:
     case RFT_UINT64:
     case RFT_UINTPTR:
index c17b4816d871cd0b98d8d07ebd3f51d689c999bc..a5264eebadaf0117b187e6994d3a931ac7819ead 100644 (file)
@@ -376,6 +376,26 @@ DEF_GO_RUNTIME(UNREACHABLE, "__builtin_unreachable", P0(), R0())
 DEF_GO_RUNTIME(BUILTIN_MEMMOVE, "__builtin_memmove",
                P3(POINTER, POINTER, UINTPTR), R0())
 
+// Various intrinsics.
+
+// Get the caller's PC, used for runtime.getcallerpc.
+DEF_GO_RUNTIME(BUILTIN_RETURN_ADDRESS, "__builtin_return_address",
+               P1(UINT32), R1(POINTER))
+
+// Get the caller's SP, used for runtime.getcallersp.
+DEF_GO_RUNTIME(BUILTIN_DWARF_CFA, "__builtin_dwarf_cfa", P0(),
+               R1(POINTER))
+
+// Swap bytes.
+DEF_GO_RUNTIME(BUILTIN_BSWAP32, "__builtin_bswap32", P1(UINT32),
+               R1(UINT32))
+DEF_GO_RUNTIME(BUILTIN_BSWAP64, "__builtin_bswap64", P1(UINT64),
+               R1(UINT64))
+
+// Count trailing zeros.
+DEF_GO_RUNTIME(BUILTIN_CTZ, "__builtin_ctz", P1(UINT32), R1(INT32))
+DEF_GO_RUNTIME(BUILTIN_CTZLL, "__builtin_ctzll", P1(UINT64), R1(INT32))
+
 // Remove helper macros.
 #undef ABFT6
 #undef ABFT2