Unify handling of runtime support functions.
authorIan Lance Taylor <iant@google.com>
Wed, 13 Apr 2011 21:00:59 +0000 (21:00 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 13 Apr 2011 21:00:59 +0000 (21:00 +0000)
This introduces the new approach, and rewrites the lowering
code which uses runtime functions.  The code which calls
runtime functions at GENERIC conversion time is not yet
rewritten.

From-SVN: r172396

24 files changed:
gcc/go/ChangeLog
gcc/go/Make-lang.in
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/runtime.cc [new file with mode: 0644]
gcc/go/gofrontend/runtime.def [new file with mode: 0644]
gcc/go/gofrontend/runtime.h [new file with mode: 0644]
gcc/go/gofrontend/statements.cc
libgo/runtime/channel.h
libgo/runtime/go-append.c
libgo/runtime/go-byte-array-to-string.c
libgo/runtime/go-chan-cap.c
libgo/runtime/go-chan-len.c
libgo/runtime/go-construct-map.c
libgo/runtime/go-copy.c
libgo/runtime/go-int-array-to-string.c
libgo/runtime/go-map-len.c
libgo/runtime/go-new-channel.c
libgo/runtime/go-new-map.c
libgo/runtime/go-new.c
libgo/runtime/go-select.c
libgo/runtime/go-trampoline.c
libgo/runtime/map.h

index 9f400f118c518cbf5a533205475d2ff1e42180ee..79f9a111aabf09f945bc087a7dd0f3e9ef305e8c 100644 (file)
@@ -1,3 +1,11 @@
+2011-04-13  Ian Lance Taylor  <iant@google.com>
+
+       * Make-lang.in (GO_OBJS): Add go/runtime.o.
+       (GO_RUNTIME_H): New variable.
+       (go/runtime.o): New target.
+       (go/gogo.o): Depend on $(GO_RUNTIME_H).
+       (go/statements.o): Likewise.
+
 2011-04-12  Nathan Froyd  <froydnj@codesourcery.com>
 
        * go-lang.c (union lang_tree_node): Check for TS_COMMON before
index 0dc8942061ae69106c92b26f610d48b1559f9ee0..c5289c67884b759f5a58ee5113c52c82adba9a2f 100644 (file)
@@ -59,6 +59,7 @@ GO_OBJS = \
        go/import-archive.o \
        go/lex.o \
        go/parse.o \
+       go/runtime.o \
        go/statements.o \
        go/types.o \
        go/unsafe.o
@@ -220,6 +221,7 @@ GO_TYPES_H = go/gofrontend/types.h
 GO_STATEMENTS_H = go/gofrontend/statements.h go/gofrontend/operator.h
 GO_EXPRESSIONS_H = go/gofrontend/expressions.h go/gofrontend/operator.h
 GO_IMPORT_H = go/gofrontend/import.h go/gofrontend/export.h
+GO_RUNTIME_H = go/gofrontend/runtime.h go/gofrontend/runtime.def
 
 go/go-backend.o: go/go-backend.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
        $(TM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(TARGET_H)
@@ -263,8 +265,9 @@ go/gogo-tree.o: go/gofrontend/gogo-tree.cc $(GO_SYSTEM_H) $(TOPLEV_H) \
        $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_GOGO_H)
 go/gogo.o: go/gofrontend/gogo.cc $(GO_SYSTEM_H) $(GO_C_H) \
        go/gofrontend/go-dump.h $(GO_LEX_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) \
-       $(GO_EXPRESSIONS_H) go/gofrontend/dataflow.h $(GO_IMPORT_H) \
-       go/gofrontend/export.h go/gofrontend/backend.h $(GO_GOGO_H)
+       $(GO_EXPRESSIONS_H) go/gofrontend/dataflow.h $(GO_RUNTIME_H) \
+       $(GO_IMPORT_H) go/gofrontend/export.h go/gofrontend/backend.h \
+       $(GO_GOGO_H)
 go/import.o: go/gofrontend/import.cc $(GO_SYSTEM_H) \
        $(srcdir)/../include/filenames.h $(srcdir)/../include/simple-object.h \
        $(GO_C_H) $(GO_GOGO_H) $(GO_TYPES_H) go/gofrontend/export.h \
@@ -274,10 +277,13 @@ go/import-archive.o: go/gofrontend/import-archive.cc $(GO_SYSTEM_H) \
 go/lex.o: go/gofrontend/lex.cc $(GO_LEX_H) $(GO_SYSTEM_H)
 go/parse.o: go/gofrontend/parse.cc $(GO_SYSTEM_H) $(GO_LEX_H) $(GO_GOGO_H) \
        $(GO_TYPES_H) $(GO_STATEMENTS_H) $(GO_EXPRESSIONS_H) $(GO_PARSE_H)
+go/runtime.o: go/gofrontend/runtime.cc $(GO_SYSTEM_H) $(GO_GOGO_H) \
+       $(GO_TYPES_H) $(GO_EXPRESSIONS_H) $(GO_RUNTIME_H) \
+       go/gofrontend/runtime.def
 go/statements.o: go/gofrontend/statements.cc $(GO_SYSTEM_H) intl.h $(TREE_H) \
        $(GIMPLE_H) convert.h tree-iterator.h $(TREE_FLOW_H) $(REAL_H) \
        $(GO_C_H) $(GO_TYPES_H) $(GO_EXPRESSIONS_H) $(GO_GOGO_H) \
-       go/gofrontend/backend.h $(GO_STATEMENTS_H)
+       $(GO_RUNTIME_H) go/gofrontend/backend.h $(GO_STATEMENTS_H)
 go/types.o: go/gofrontend/types.cc $(GO_SYSTEM_H) $(TOPLEV_H) intl.h $(TREE_H) \
        $(GIMPLE_H) $(REAL_H) convert.h $(GO_C_H) $(GO_GOGO_H) \
        go/gofrontend/operator.h $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) \
index c516485f343cebc832581db365529f0e03049926..7f291d40a76d91dbf986c0879c598ac481542f60 100644 (file)
@@ -3410,7 +3410,7 @@ Type_conversion_expression::do_get_tree(Translate_context* context)
       tree valptr = fold_convert(const_ptr_type_node,
                                 a->value_pointer_tree(gogo, expr_tree));
       tree len = a->length_tree(gogo, expr_tree);
-      len = fold_convert_loc(this->location(), size_type_node, len);
+      len = fold_convert_loc(this->location(), integer_type_node, len);
       if (e->integer_type()->is_unsigned()
          && e->integer_type()->bits() == 8)
        {
@@ -3422,7 +3422,7 @@ Type_conversion_expression::do_get_tree(Translate_context* context)
                                   type_tree,
                                   const_ptr_type_node,
                                   valptr,
-                                  size_type_node,
+                                  integer_type_node,
                                   len);
        }
       else
@@ -3436,7 +3436,7 @@ Type_conversion_expression::do_get_tree(Translate_context* context)
                                   type_tree,
                                   const_ptr_type_node,
                                   valptr,
-                                  size_type_node,
+                                  integer_type_node,
                                   len);
        }
     }
@@ -3523,6 +3523,122 @@ Expression::make_cast(Type* type, Expression* val, source_location location)
   return new Type_conversion_expression(type, val, location);
 }
 
+// An unsafe type conversion, used to pass values to builtin functions.
+
+class Unsafe_type_conversion_expression : public Expression
+{
+ public:
+  Unsafe_type_conversion_expression(Type* type, Expression* expr,
+                                   source_location location)
+    : Expression(EXPRESSION_UNSAFE_CONVERSION, location),
+      type_(type), expr_(expr)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse* traverse);
+
+  Type*
+  do_type()
+  { return this->type_; }
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  {
+    return new Unsafe_type_conversion_expression(this->type_,
+                                                this->expr_->copy(),
+                                                this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context*);
+
+ private:
+  // The type to convert to.
+  Type* type_;
+  // The expression to convert.
+  Expression* expr_;
+};
+
+// Traversal.
+
+int
+Unsafe_type_conversion_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT
+      || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Convert to backend representation.
+
+tree
+Unsafe_type_conversion_expression::do_get_tree(Translate_context* context)
+{
+  // We are only called for a limited number of cases.
+
+  Type* t = this->type_;
+  Type* et = this->expr_->type();
+
+  tree type_tree = this->type_->get_tree(context->gogo());
+  tree expr_tree = this->expr_->get_tree(context);
+  if (type_tree == error_mark_node || expr_tree == error_mark_node)
+    return error_mark_node;
+
+  source_location loc = this->location();
+
+  bool use_view_convert = false;
+  if (t->is_open_array_type())
+    {
+      gcc_assert(et->is_open_array_type());
+      use_view_convert = true;
+    }
+  else if (t->map_type() != NULL)
+    gcc_assert(et->map_type() != NULL);
+  else if (t->channel_type() != NULL)
+    gcc_assert(et->channel_type() != NULL);
+  else if (t->points_to() != NULL && t->points_to()->channel_type() != NULL)
+    gcc_assert(et->points_to() != NULL
+              && et->points_to()->channel_type() != NULL);
+  else if (t->is_unsafe_pointer_type())
+    gcc_assert(et->points_to() != NULL);
+  else if (et->is_unsafe_pointer_type())
+    gcc_assert(t->points_to() != NULL);
+  else if (t->interface_type() != NULL && !t->interface_type()->is_empty())
+    {
+      gcc_assert(et->interface_type() != NULL
+                && !et->interface_type()->is_empty());
+      use_view_convert = true;
+    }
+  else if (t->interface_type() != NULL && t->interface_type()->is_empty())
+    {
+      gcc_assert(et->interface_type() != NULL
+                && et->interface_type()->is_empty());
+      use_view_convert = true;
+    }
+  else
+    gcc_unreachable();
+
+  if (use_view_convert)
+    return fold_build1_loc(loc, VIEW_CONVERT_EXPR, type_tree, expr_tree);
+  else
+    return fold_convert_loc(loc, type_tree, expr_tree);
+}
+
+// Make an unsafe type conversion expression.
+
+Expression*
+Expression::make_unsafe_cast(Type* type, Expression* expr,
+                            source_location location)
+{
+  return new Unsafe_type_conversion_expression(type, expr, location);
+}
+
 // Unary expressions.
 
 class Unary_expression : public Expression
@@ -7654,7 +7770,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
                                              location,
                                              "__go_map_len",
                                              1,
-                                             sizetype,
+                                             integer_type_node,
                                              arg_type->get_tree(gogo),
                                              arg_tree);
              }
@@ -7665,7 +7781,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
                                              location,
                                              "__go_chan_len",
                                              1,
-                                             sizetype,
+                                             integer_type_node,
                                              arg_type->get_tree(gogo),
                                              arg_tree);
              }
@@ -7693,7 +7809,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
                                              location,
                                              "__go_chan_cap",
                                              1,
-                                             sizetype,
+                                             integer_type_node,
                                              arg_type->get_tree(gogo),
                                              arg_tree);
              }
index fa240a69b8c139dc11979d4de3f7ee4511505884..66aabeb748cd47da1d5b487fe666cea74f1b7cb8 100644 (file)
@@ -81,6 +81,7 @@ class Expression
     EXPRESSION_MAKE,
     EXPRESSION_TYPE_GUARD,
     EXPRESSION_CONVERSION,
+    EXPRESSION_UNSAFE_CONVERSION,
     EXPRESSION_STRUCT_CONSTRUCTION,
     EXPRESSION_FIXED_ARRAY_CONSTRUCTION,
     EXPRESSION_OPEN_ARRAY_CONSTRUCTION,
@@ -247,6 +248,12 @@ class Expression
   static Expression*
   make_cast(Type*, Expression*, source_location);
 
+  // Make an unsafe type cast expression.  This is only used when
+  // passing parameter to builtin functions that are part of the Go
+  // runtime.
+  static Expression*
+  make_unsafe_cast(Type*, Expression*, source_location);
+
   // Make a composite literal.  The DEPTH parameter is how far down we
   // are in a list of composite literals with omitted types.
   static Expression*
index 31549ac233a94cff7f396f3e0303728c99b5928c..e22de4be4461dfc81b4b622c4fd95f1318b97236 100644 (file)
@@ -13,6 +13,7 @@
 #include "statements.h"
 #include "expressions.h"
 #include "dataflow.h"
+#include "runtime.h"
 #include "import.h"
 #include "export.h"
 #include "backend.h"
@@ -2598,6 +2599,8 @@ Gogo::convert_named_types()
   Interface_type::make_interface_type_descriptor_type();
   Type::convert_builtin_named_types(this);
 
+  Runtime::convert_types(this);
+
   this->named_types_are_converted_ = true;
 }
 
diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc
new file mode 100644 (file)
index 0000000..7249dff
--- /dev/null
@@ -0,0 +1,383 @@
+// runtime.cc -- runtime functions called by generated code
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include <gmp.h>
+
+#include "gogo.h"
+#include "types.h"
+#include "expressions.h"
+#include "runtime.h"
+
+// The frontend generates calls to various runtime functions.  They
+// are implemented in libgo/runtime.  This is how the runtime
+// functions are represented in the frontend.  Note that there is
+// currently nothing which ensures that the compiler's understanding
+// of the runtime function matches the actual implementation in
+// libgo/runtime.
+
+// Parameter and result types used by runtime functions.
+
+enum Runtime_function_type
+{
+  // General indicator that value is not used.
+  RFT_VOID,
+  // Go type bool, C type _Bool.
+  RFT_BOOL,
+  // Go type *bool, C type _Bool*.
+  RFT_BOOLPTR,
+  // Go type int, C type int.
+  RFT_INT,
+  // Go type int64, C type int64_t.
+  RFT_INT64,
+  // Go type uint64, C type uint64_t.
+  RFT_UINT64,
+  // Go type uintptr, C type uintptr_t.
+  RFT_UINTPTR,
+  // Go type float64, C type double.
+  RFT_FLOAT64,
+  // Go type complex128, C type __complex double.
+  RFT_COMPLEX128,
+  // Go type string, C type struct __go_string.
+  RFT_STRING,
+  // Go type unsafe.Pointer, C type "void *".
+  RFT_POINTER,
+  // Go type []any, C type struct __go_open_array.
+  RFT_SLICE,
+  // Go type map[any]any, C type struct __go_map *.
+  RFT_MAP,
+  // Pointer to map iteration type.
+  RFT_MAPITER,
+  // Go type chan any, C type struct __go_channel *.
+  RFT_CHAN,
+  // Go type *chan any, C type struct __go_channel **.
+  RFT_CHANPTR,
+  // Go type non-empty interface, C type struct __go_interface.
+  RFT_IFACE,
+  // Go type interface{}, C type struct __go_empty_interface.
+  RFT_EFACE,
+  // Go type func(unsafe.Pointer), C type void (*) (void *).
+  RFT_FUNC_PTR,
+  // Pointer to Go type descriptor.
+  RFT_TYPE,
+
+  NUMBER_OF_RUNTIME_FUNCTION_TYPES
+};
+
+// The Type structures for the runtime function types.
+
+static Type* runtime_function_types[NUMBER_OF_RUNTIME_FUNCTION_TYPES];
+
+// Get the Type for a Runtime_function_type code.
+
+static Type*
+runtime_function_type(Runtime_function_type bft)
+{
+  gcc_assert(bft < NUMBER_OF_RUNTIME_FUNCTION_TYPES);
+  if (runtime_function_types[bft] == NULL)
+    {
+      const source_location bloc = BUILTINS_LOCATION;
+      Type* t;
+      switch (bft)
+       {
+       default:
+       case RFT_VOID:
+         gcc_unreachable();
+
+       case RFT_BOOL:
+         t = Type::lookup_bool_type();
+         break;
+
+       case RFT_BOOLPTR:
+         t = Type::make_pointer_type(Type::lookup_bool_type());
+         break;
+
+       case RFT_INT:
+         t = Type::lookup_integer_type("int");
+         break;
+
+       case RFT_INT64:
+         t = Type::lookup_integer_type("int64");
+         break;
+
+       case RFT_UINT64:
+         t = Type::lookup_integer_type("uint64");
+         break;
+
+       case RFT_UINTPTR:
+         t = Type::lookup_integer_type("uintptr");
+         break;
+
+       case RFT_FLOAT64:
+         t = Type::lookup_float_type("float64");
+         break;
+
+       case RFT_COMPLEX128:
+         t = Type::lookup_complex_type("complex128");
+         break;
+
+       case RFT_STRING:
+         t = Type::lookup_string_type();
+         break;
+
+       case RFT_POINTER:
+         t = Type::make_pointer_type(Type::make_void_type());
+         break;
+
+       case RFT_SLICE:
+         t = Type::make_array_type(Type::make_void_type(), NULL);
+         break;
+
+       case RFT_MAP:
+         t = Type::make_map_type(Type::make_void_type(),
+                                 Type::make_void_type(),
+                                 bloc);
+         break;
+
+       case RFT_MAPITER:
+         t = Type::make_pointer_type(Runtime::map_iteration_type());
+         break;
+
+       case RFT_CHAN:
+         t = Type::make_channel_type(true, true, Type::make_void_type());
+         break;
+
+       case RFT_CHANPTR:
+         t = Type::make_pointer_type(runtime_function_type(RFT_CHAN));
+         break;
+
+       case RFT_IFACE:
+         {
+           Typed_identifier_list* methods = new Typed_identifier_list();
+           Type* mtype = Type::make_function_type(NULL, NULL, NULL, bloc);
+           methods->push_back(Typed_identifier("x", mtype, bloc));
+           t = Type::make_interface_type(methods, bloc);
+         }
+         break;
+
+       case RFT_EFACE:
+         t = Type::make_interface_type(NULL, bloc);
+         break;
+
+       case RFT_FUNC_PTR:
+         {
+           Typed_identifier_list* param_types = new Typed_identifier_list();
+           Type* ptrtype = runtime_function_type(RFT_POINTER);
+           param_types->push_back(Typed_identifier("", ptrtype, bloc));
+           t = Type::make_function_type(NULL, param_types, NULL, bloc);
+         }
+         break;
+
+       case RFT_TYPE:
+         t = Type::make_type_descriptor_ptr_type();
+         break;
+       }
+
+      runtime_function_types[bft] = t;
+    }
+
+  return runtime_function_types[bft];
+}
+
+// Convert an expression to the type to pass to a runtime function.
+
+static Expression*
+convert_to_runtime_function_type(Runtime_function_type bft, Expression* e,
+                                source_location loc)
+{
+  switch (bft)
+    {
+    default:
+    case RFT_VOID:
+      gcc_unreachable();
+
+    case RFT_BOOL:
+    case RFT_BOOLPTR:
+    case RFT_INT:
+    case RFT_INT64:
+    case RFT_UINT64:
+    case RFT_UINTPTR:
+    case RFT_FLOAT64:
+    case RFT_COMPLEX128:
+    case RFT_STRING:
+    case RFT_POINTER:
+    case RFT_MAPITER:
+    case RFT_FUNC_PTR:
+      {
+       Type* t = runtime_function_type(bft);
+       if (!Type::are_identical(t, e->type(), true, NULL))
+         e = Expression::make_cast(t, e, loc);
+       return e;
+      }
+
+    case RFT_SLICE:
+    case RFT_MAP:
+    case RFT_CHAN:
+    case RFT_CHANPTR:
+    case RFT_IFACE:
+    case RFT_EFACE:
+      return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc);
+
+    case RFT_TYPE:
+      gcc_assert(e->type() == Type::make_type_descriptor_ptr_type());
+      return e;
+    }
+}
+
+// Convert all the types used for runtime functions to the backend
+// representation.
+
+void
+Runtime::convert_types(Gogo* gogo)
+{
+  for (int i = 0; i < static_cast<int>(NUMBER_OF_RUNTIME_FUNCTION_TYPES); ++i)
+    {
+      Type* t = runtime_function_types[i];
+      if (t != NULL && t->named_type() != NULL)
+       {
+         bool r = t->verify();
+         gcc_assert(r);
+         t->named_type()->convert(gogo);
+       }
+    }
+}
+
+// The type used to define a runtime function.
+
+struct Runtime_function
+{
+  // Function name.
+  const char* name;
+  // Parameter types.  Never more than 6, as it happens.  RFT_VOID if
+  // not used.
+  Runtime_function_type parameter_types[6];
+  // Result types.  Never more than 2, as it happens.  RFT_VOID if not
+  // used.
+  Runtime_function_type result_types[2];
+};
+
+static const Runtime_function runtime_functions[] =
+{
+
+#define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) { NAME, PARAMS, RESULTS } ,
+
+#include "runtime.def"
+
+#undef DEF_GO_RUNTIME
+
+};
+
+static Named_object*
+runtime_function_declarations[Runtime::NUMBER_OF_FUNCTIONS];
+
+// Get the declaration of a runtime function.
+
+Named_object*
+Runtime::runtime_declaration(Function code)
+{
+  gcc_assert(code < Runtime::NUMBER_OF_FUNCTIONS);
+  if (runtime_function_declarations[code] == NULL)
+    {
+      const Runtime_function* pb = &runtime_functions[code];
+
+      source_location bloc = BUILTINS_LOCATION;
+
+      Typed_identifier_list* param_types = NULL;
+      if (pb->parameter_types[0] != RFT_VOID)
+       {
+         param_types = new Typed_identifier_list();
+         for (unsigned int i = 0;
+              i < (sizeof(pb->parameter_types)
+                   / sizeof (pb->parameter_types[0]));
+              i++)
+           {
+             if (pb->parameter_types[i] == RFT_VOID)
+               break;
+             Type* t = runtime_function_type(pb->parameter_types[i]);
+             param_types->push_back(Typed_identifier("", t, bloc));
+           }
+       }
+
+      Typed_identifier_list* result_types = NULL;
+      if (pb->result_types[0] != RFT_VOID)
+       {
+         result_types = new Typed_identifier_list();
+         for (unsigned int i = 0;
+              i < sizeof(pb->result_types) / sizeof(pb->result_types[0]);
+              i++)
+           {
+             if (pb->result_types[i] == RFT_VOID)
+               break;
+             Type* t = runtime_function_type(pb->result_types[i]);
+             result_types->push_back(Typed_identifier("", t, bloc));
+           }
+       }
+
+      Function_type* fntype = Type::make_function_type(NULL, param_types,
+                                                      result_types, bloc);
+      const char* n = pb->name;
+      const char* n1 = strchr(n, '.');
+      if (n1 != NULL)
+       n = n1 + 1;
+      Named_object* no = Named_object::make_function_declaration(n, NULL,
+                                                                fntype, bloc);
+      no->func_declaration_value()->set_asm_name(pb->name);
+
+      runtime_function_declarations[code] = no;
+    }
+
+  return runtime_function_declarations[code];
+}
+
+// Make a call to a runtime function.
+
+Call_expression*
+Runtime::make_call(Runtime::Function code, source_location loc,
+                  int param_count, ...)
+{
+  gcc_assert(code < Runtime::NUMBER_OF_FUNCTIONS);
+
+  const Runtime_function* pb = &runtime_functions[code];
+
+  gcc_assert(static_cast<size_t>(param_count)
+            <= sizeof(pb->parameter_types) / sizeof(pb->parameter_types[0]));
+
+  Named_object* no = runtime_declaration(code);
+  Expression* func = Expression::make_func_reference(no, NULL, loc);
+
+  Expression_list* args = new Expression_list();
+  args->reserve(param_count);
+
+  va_list ap;
+  va_start(ap, param_count);
+  for (int i = 0; i < param_count; ++i)
+    {
+      Expression* e = va_arg(ap, Expression*);
+      Runtime_function_type rft = pb->parameter_types[i];
+      args->push_back(convert_to_runtime_function_type(rft, e, loc));
+    }
+  va_end(ap);
+
+  return Expression::make_call(func, args, false, loc);
+}
+
+// The type we use for a map iteration.  This is really a struct which
+// is four pointers long.  This must match the runtime struct
+// __go_hash_iter.
+
+Type*
+Runtime::map_iteration_type()
+{
+  const unsigned long map_iteration_size = 4;
+
+  mpz_t ival;
+  mpz_init_set_ui(ival, map_iteration_size);
+  Expression* iexpr = Expression::make_integer(&ival, NULL, BUILTINS_LOCATION);
+  mpz_clear(ival);
+
+  return Type::make_array_type(runtime_function_type(RFT_POINTER), iexpr);
+}
diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def
new file mode 100644 (file)
index 0000000..6e7a807
--- /dev/null
@@ -0,0 +1,341 @@
+// runtime.def -- runtime functions called by generated code.  -*- C++ -*-
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Definitions for the Go runtime functions.
+
+// Parameter type helper macros.
+#define ABFT6(T1, T2, T3, T4, T5, T6) \
+  { RFT_ ## T1, RFT_ ## T2, RFT_ ## T3, RFT_ ## T4, RFT_ ## T5, RFT_ ## T6 }
+#define P0()                   ABFT6(VOID, VOID, VOID, VOID, VOID, VOID)
+#define P1(T)                  ABFT6(T, VOID, VOID, VOID, VOID, VOID)
+#define P2(T1, T2)             ABFT6(T1, T2, VOID, VOID, VOID, VOID)
+#define P3(T1, T2, T3)         ABFT6(T1, T2, T3, VOID, VOID, VOID)
+#define P4(T1, T2, T3, T4)     ABFT6(T1, T2, T3, T4, VOID, VOID)
+#define P5(T1, T2, T3, T4, T5) ABFT6(T1, T2, T3, T4, T5, VOID)
+#define P6(T1,T2,T3,T4,T5,T6)  ABFT6(T1, T2, T3, T4, T5, T6)
+
+// Result type helper macros.
+#define ABFT2(T1, T2) { RFT_ ## T1, RFT_ ## T2 }
+#define R0()                   ABFT2(VOID, VOID)
+#define R1(T)                  ABFT2(T, VOID)
+#define R2(T1, T2)             ABFT2(T1, T2)
+
+// Define all the Go runtime functions.  The first parameter is the
+// enum code used to refer to the function.  The second parameter is
+// the name.  The third is the parameter types and the fourth is the
+// result types.
+
+// Range over a string, returning the next index.
+DEF_GO_RUNTIME(STRINGITER, "runtime.stringiter", P2(STRING, INT), R1(INT))
+
+// Range over a string, returning the next index and character.
+DEF_GO_RUNTIME(STRINGITER2, "runtime.stringiter2", P2(STRING, INT),
+              R2(INT, INT))
+
+// Concatenate two strings.
+DEF_GO_RUNTIME(STRING_PLUS, "__go_string_plus", P2(STRING, STRING), R1(STRING))
+
+// Compare two strings.
+DEF_GO_RUNTIME(STRCMP, "__go_strcmp", P2(STRING, STRING), R1(INT))
+
+// Take a slice of a string.
+DEF_GO_RUNTIME(STRING_SLICE, "__go_string_slice", P3(STRING, INT, INT),
+              R1(STRING))
+
+// Convert an integer to a string.
+DEF_GO_RUNTIME(INT_TO_STRING, "__go_int_to_string", P1(INT), R1(STRING))
+
+// Convert a byte array to a string.
+DEF_GO_RUNTIME(BYTE_ARRAY_TO_STRING, "__go_byte_array_to_string",
+              P2(POINTER, INT), R1(STRING))
+
+// Convert an int array to a string.
+DEF_GO_RUNTIME(INT_ARRAY_TO_STRING, "__go_int_array_to_string",
+              P2(POINTER, INT), R1(STRING))
+
+// Convert a string to a byte slice.
+DEF_GO_RUNTIME(STRING_TO_BYTE_ARRAY, "__go_string_to_byte_array",
+              P1(STRING), R1(SLICE))
+
+// Convert a string to an int slice.
+DEF_GO_RUNTIME(STRING_TO_INT_ARRAY, "__go_string_to_int_array",
+              P1(STRING), R1(SLICE))
+
+
+// Make a map.
+DEF_GO_RUNTIME(NEW_MAP, "__go_new_map", P2(TYPE, UINTPTR), R1(MAP))
+
+// Build a map from a composite literal.
+DEF_GO_RUNTIME(CONSTRUCT_MAP, "__go_construct_map",
+              P6(POINTER, UINTPTR, UINTPTR, UINTPTR, UINTPTR, POINTER),
+              R1(MAP))
+
+// Get the length of a map (the number of entries).
+DEF_GO_RUNTIME(MAP_LEN, "__go_map_len", P1(MAP), R1(INT))
+
+// Look up a key in a map.
+DEF_GO_RUNTIME(MAP_INDEX, "__go_map_index", P3(MAP, POINTER, BOOL),
+              R1(POINTER))
+
+// Look up a key in a map returning whether it is present.
+DEF_GO_RUNTIME(MAPACCESS2, "runtime.mapaccess2", P3(MAP, POINTER, POINTER),
+              R1(BOOL))
+
+// Tuple assignment to a map element.
+DEF_GO_RUNTIME(MAPASSIGN2, "runtime.mapassign2",
+              P4(MAP, POINTER, POINTER, BOOL), R0())
+
+// Begin a range over a map.
+DEF_GO_RUNTIME(MAPITERINIT, "runtime.mapiterinit", P2(MAP, MAPITER), R0())
+
+// Range over a map, returning the next key.
+DEF_GO_RUNTIME(MAPITER1, "runtime.mapiter1", P2(MAPITER, POINTER), R0())
+
+// Range over a map, returning the next key and value.
+DEF_GO_RUNTIME(MAPITER2, "runtime.mapiter2", P3(MAPITER, POINTER, POINTER),
+              R0())
+
+// Range over a map, moving to the next map entry.
+DEF_GO_RUNTIME(MAPITERNEXT, "runtime.mapiternext", P1(MAPITER), R0())
+
+
+// Make a channel.
+DEF_GO_RUNTIME(NEW_CHANNEL, "__go_new_channel", P2(UINTPTR, UINTPTR), R1(CHAN))
+
+// Get the length of a channel (the number of unread values).
+DEF_GO_RUNTIME(CHAN_LEN, "__go_chan_len", P1(CHAN), R1(INT))
+
+// Get the capacity of a channel (the size of the buffer).
+DEF_GO_RUNTIME(CHAN_CAP, "__go_chan_cap", P1(CHAN), R1(INT))
+
+// Send a small value on a channel.
+DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(CHAN, UINT64, BOOL), R0())
+
+// Send a small value on a channel without blocking.
+DEF_GO_RUNTIME(SEND_NONBLOCKING_SMALL, "__go_send_nonblocking_small",
+              P2(CHAN, UINT64), R1(BOOL))
+
+// Send a big value on a channel.
+DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(CHAN, POINTER, BOOL), R0())
+
+// Send a big value on a channel without blocking.
+DEF_GO_RUNTIME(SEND_NONBLOCKING_BIG, "__go_send_nonblocking_big",
+              P2(CHAN, POINTER), R1(BOOL))
+
+// Receive a small value from a channel.
+DEF_GO_RUNTIME(RECEIVE_SMALL, "__go_receive_small", P2(CHAN, BOOL), R1(UINT64))
+
+// Receive a big value from a channel.
+DEF_GO_RUNTIME(RECEIVE_BIG, "__go_receive_big", P3(CHAN, POINTER, BOOL),
+              R1(BOOL))
+
+// Receive a value from a channel returning whether it is closed.
+DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P2(CHAN, POINTER), R1(BOOL))
+
+// Receive a value from a channel returning whether it is closed, for select.
+DEF_GO_RUNTIME(CHANRECV3, "runtime.chanrecv3", P2(CHAN, POINTER), R1(BOOL))
+
+
+// Panic.
+DEF_GO_RUNTIME(PANIC, "__go_panic", P1(EFACE), R0())
+
+// Recover.
+DEF_GO_RUNTIME(RECOVER, "__go_recover", P0(), R1(EFACE))
+
+// Recover when called directly from defer.
+DEF_GO_RUNTIME(DEFERRED_RECOVER, "__go_deferred_recover", P0(), R1(EFACE))
+
+// Decide whether this function can call recover.
+DEF_GO_RUNTIME(CAN_RECOVER, "__go_can_recover", P1(POINTER), R1(BOOL))
+
+// Get the return address of the function.
+DEF_GO_RUNTIME(RETURN_ADDRESS, "__go_return_address", P1(INT), R1(POINTER))
+
+// Set the return address for defer in a defer thunk.
+DEF_GO_RUNTIME(SET_DEFER_RETADDR, "__go_set_defer_retaddr", P1(POINTER),
+              R1(BOOL))
+
+// Check for a deferred function in an exception handler.
+DEF_GO_RUNTIME(CHECK_DEFER, "__go_check_defer", P1(POINTER), R0())
+
+// Run deferred functions.
+DEF_GO_RUNTIME(UNDEFER, "__go_undefer", P1(POINTER), R0())
+
+// Panic with a runtime error.
+DEF_GO_RUNTIME(RUNTIME_ERROR, "__go_runtime_error", P1(INT), R0())
+
+
+// Close.
+DEF_GO_RUNTIME(CLOSE, "__go_close", P1(CHAN), R0())
+
+
+// Copy.
+DEF_GO_RUNTIME(COPY, "__go_copy", P3(POINTER, POINTER, UINTPTR), R0())
+
+// Append.
+DEF_GO_RUNTIME(APPEND, "__go_append", P4(SLICE, POINTER, UINTPTR, UINTPTR),
+              R1(SLICE))
+
+
+// Register roots (global variables) for the garbage collector.
+DEF_GO_RUNTIME(REGISTER_GC_ROOTS, "__go_register_gc_roots", P1(POINTER), R0())
+
+
+// Allocate memory.
+DEF_GO_RUNTIME(NEW, "__go_new", P1(UINTPTR), R1(POINTER))
+
+// Allocate memory which can not contain pointers.
+DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P1(UINTPTR), R1(POINTER))
+
+
+// Allocate a trampoline for a function literal.
+DEF_GO_RUNTIME(ALLOCATE_GO_TRAMPOLINE, "__go_allocate_trampoline",
+              P2(UINTPTR, POINTER), R1(POINTER))
+
+
+// Start a new goroutine.
+DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0())
+
+
+// Defer a function.
+DEF_GO_RUNTIME(DEFER, "__go_defer", P3(POINTER, FUNC_PTR, POINTER), R0())
+
+
+// Run a select statement.
+DEF_GO_RUNTIME(SELECT, "__go_select", P4(UINTPTR, BOOL, CHANPTR, BOOLPTR),
+              R1(UINTPTR))
+
+
+// Convert an empty interface to an empty interface, returning ok.
+DEF_GO_RUNTIME(IFACEE2E2, "runtime.ifaceE2E2", P1(EFACE), R2(EFACE, BOOL))
+
+// Convert a non-empty interface to an empty interface, returning ok.
+DEF_GO_RUNTIME(IFACEI2E2, "runtime.ifaceI2E2", P1(IFACE), R2(EFACE, BOOL))
+
+// Convert an empty interface to a non-empty interface, returning ok.
+DEF_GO_RUNTIME(IFACEE2I2, "runtime.ifaceE2I2", P2(TYPE, EFACE),
+              R2(IFACE, BOOL))
+
+// Convert a non-empty interface to a non-empty interface, returning ok.
+DEF_GO_RUNTIME(IFACEI2I2, "runtime.ifaceI2I2", P2(TYPE, IFACE),
+              R2(IFACE, BOOL))
+
+// Convert an empty interface to a pointer type, returning ok.
+DEF_GO_RUNTIME(IFACEE2T2P, "runtime.ifaceE2T2P", P2(TYPE, EFACE),
+              R2(POINTER, BOOL))
+
+// Convert a non-empty interface to a pointer type, return ok.
+DEF_GO_RUNTIME(IFACEI2T2P, "runtime.ifaceI2T2P", P2(TYPE, IFACE),
+              R2(POINTER, BOOL))
+
+// Convert an empty interface to a non-pointer type, returning ok.
+DEF_GO_RUNTIME(IFACEE2T2, "runtime.ifaceE2T2", P3(TYPE, EFACE, POINTER),
+              R1(BOOL))
+
+// Convert a non-empty interface to a non-pointer type, returning ok.
+DEF_GO_RUNTIME(IFACEI2T2, "runtime.ifaceI2T2", P3(TYPE, IFACE, POINTER),
+              R1(BOOL))
+
+// A type assertion from one interface type to another.  This is
+// used for a type assertion.
+DEF_GO_RUNTIME(ASSERT_INTERFACE, "__go_assert_interface", P2(TYPE, TYPE), R0())
+
+// Convert one interface type to another.  This is used for an
+// assignment.
+DEF_GO_RUNTIME(CONVERT_INTERFACE, "__go_convert_interface", P2(TYPE, TYPE),
+              R1(POINTER))
+
+// Check whether an interface type may be converted to a
+// non-interface type.
+DEF_GO_RUNTIME(CHECK_INTERFACE_TYPE, "__go_check_interface_type",
+              P3(TYPE, TYPE, TYPE), R0())
+
+// Return whether we can convert an interface type to a type.
+DEF_GO_RUNTIME(IFACEI2TP, "runtime.ifaceI2Tp", P2(TYPE, TYPE), R1(BOOL))
+
+// Get the type descriptor of an empty interface.
+DEF_GO_RUNTIME(EFACETYPE, "runtime.efacetype", P1(EFACE), R1(TYPE))
+
+// Get the type descriptor of a non-empty interface.
+DEF_GO_RUNTIME(IFACETYPE, "runtime.ifacetype", P1(IFACE), R1(TYPE))
+
+
+// Compare two type descriptors for equality.
+DEF_GO_RUNTIME(IFACETYPEEQ, "runtime.ifacetypeeq", P2(TYPE, TYPE), R1(BOOL))
+
+// Compare two empty interface values.
+DEF_GO_RUNTIME(EMPTY_INTERFACE_COMPARE, "__go_empty_interface_compare",
+              P2(EFACE, EFACE), R1(INT))
+
+// Compare an empty interface value to a non-interface value.
+DEF_GO_RUNTIME(EMPTY_INTERFACE_VALUE_COMPARE,
+              "__go_empty_interface_value_compare",
+              P3(EFACE, TYPE, POINTER), R1(INT))
+
+// Compare two non-empty interface values.
+DEF_GO_RUNTIME(INTERFACE_COMPARE, "__go_interface_compare",
+              P2(IFACE, IFACE), R1(INT))
+
+// Compare a non-empty interface value to a non-interface value.
+DEF_GO_RUNTIME(INTERFACE_VALUE_COMPARE, "__go_interface_value_compare",
+              P3(IFACE, TYPE, POINTER), R1(INT))
+
+// Compare a non-empty interface value to an interface value.
+DEF_GO_RUNTIME(INTERFACE_EMPTY_COMPARE, "__go_interface_empty_compare",
+              P2(IFACE, EFACE), R1(INT))
+
+
+// Print a string (for print/println).
+DEF_GO_RUNTIME(PRINT_STRING, "__go_print_string", P1(STRING), R0())
+
+// Print a uint64 (for print/println).
+DEF_GO_RUNTIME(PRINT_UINT64, "__go_print_uint64", P1(UINT64), R0())
+
+// Print a int64 (for print/println).
+DEF_GO_RUNTIME(PRINT_INT64, "__go_print_int64", P1(INT64), R0())
+
+// Print a float64 (for print/println).
+DEF_GO_RUNTIME(PRINT_DOUBLE, "__go_print_double", P1(FLOAT64), R0())
+
+// Print a complex128 (for print/println).
+DEF_GO_RUNTIME(PRINT_COMPLEX, "__go_print_complex", P1(COMPLEX128), R0())
+
+// Print a bool (for print/println).
+DEF_GO_RUNTIME(PRINT_BOOL, "__go_print_bool", P1(BOOL), R0())
+
+// Print a pointer/map/channel/function (for print/println).
+DEF_GO_RUNTIME(PRINT_POINTER, "__go_print_pointer", P1(POINTER), R0())
+
+// Print an empty interface (for print/println).
+DEF_GO_RUNTIME(PRINT_EMPTY_INTERFACE, "__go_print_empty_interface",
+              P1(EFACE), R0())
+
+// Print a non-empty interface (for print/println).
+DEF_GO_RUNTIME(PRINT_INTERFACE, "__go_print_interface", P1(IFACE), R0())
+
+// Print a slice (for print/println).
+DEF_GO_RUNTIME(PRINT_SLICE, "__go_print_slice", P1(SLICE), R0())
+
+// Print a space (for println).
+DEF_GO_RUNTIME(PRINT_SPACE, "__go_print_space", P0(), R0())
+
+// Print a newline (for println).
+DEF_GO_RUNTIME(PRINT_NL, "__go_print_nl", P0(), R0())
+
+
+// Remove helper macros.
+#undef ABFT6
+#undef ABFT2
+#undef P0
+#undef P1
+#undef P2
+#undef P3
+#undef P4
+#undef P5
+#undef P6
+#undef R0
+#undef R1
+#undef R2
diff --git a/gcc/go/gofrontend/runtime.h b/gcc/go/gofrontend/runtime.h
new file mode 100644 (file)
index 0000000..d8fb00c
--- /dev/null
@@ -0,0 +1,47 @@
+// runtime.h -- runtime functions called by generated code  -*- C++ -*-
+
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_RUNTIME_H
+#define GO_RUNTIME_H
+
+class Gogo;
+class Type;
+class Named_object;
+class Call_expression;
+
+class Runtime
+{
+ public:
+
+  // The runtime functions which may be called by generated code.
+  enum Function
+  {
+
+#define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) CODE ,
+
+#include "runtime.def"
+
+#undef DEF_GO_RUNTIME
+
+    // Number of runtime functions.
+    NUMBER_OF_FUNCTIONS
+  };
+
+  static Call_expression*
+  make_call(Function, source_location, int, ...);
+
+  static void
+  convert_types(Gogo*);
+
+  static Type*
+  map_iteration_type();
+
+ private:
+  static Named_object*
+  runtime_declaration(Function);
+};
+
+#endif // !defined(GO_BUILTINS_H)
index f84b2d4ae92311d067cd22f1700b026e1c3bd452..0b22e307306c3966383ca0f59e1523361fd87aff 100644 (file)
@@ -29,6 +29,7 @@ extern "C"
 #include "types.h"
 #include "expressions.h"
 #include "gogo.h"
+#include "runtime.h"
 #include "backend.h"
 #include "statements.h"
 
@@ -958,33 +959,13 @@ Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*,
     Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
   b->add_statement(present_temp);
 
-  // func mapaccess2(hmap map[k]v, key *k, val *v) bool
-  source_location bloc = BUILTINS_LOCATION;
-  Typed_identifier_list* param_types = new Typed_identifier_list();
-  param_types->push_back(Typed_identifier("hmap", map_type, bloc));
-  Type* pkey_type = Type::make_pointer_type(map_type->key_type());
-  param_types->push_back(Typed_identifier("key", pkey_type, bloc));
-  Type* pval_type = Type::make_pointer_type(map_type->val_type());
-  param_types->push_back(Typed_identifier("val", pval_type, bloc));
-
-  Typed_identifier_list* ret_types = new Typed_identifier_list();
-  ret_types->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc));
-
-  Function_type* fntype = Type::make_function_type(NULL, param_types,
-                                                  ret_types, bloc);
-  Named_object* mapaccess2 =
-    Named_object::make_function_declaration("mapaccess2", NULL, fntype, bloc);
-  mapaccess2->func_declaration_value()->set_asm_name("runtime.mapaccess2");
-
   // present_temp = mapaccess2(MAP, &key_temp, &val_temp)
-  Expression* func = Expression::make_func_reference(mapaccess2, NULL, loc);
-  Expression_list* params = new Expression_list();
-  params->push_back(map_index->map());
   Expression* ref = Expression::make_temporary_reference(key_temp, loc);
-  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  Expression* a1 = Expression::make_unary(OPERATOR_AND, ref, loc);
   ref = Expression::make_temporary_reference(val_temp, loc);
-  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
-  Expression* call = Expression::make_call(func, params, false, loc);
+  Expression* a2 = Expression::make_unary(OPERATOR_AND, ref, loc);
+  Expression* call = Runtime::make_call(Runtime::MAPACCESS2, loc, 3,
+                                       map_index->map(), a1, a2);
 
   ref = Expression::make_temporary_reference(present_temp, loc);
   Statement* s = Statement::make_assignment(ref, call, loc);
@@ -1097,31 +1078,21 @@ Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
     Statement::make_temporary(map_type->val_type(), this->val_, loc);
   b->add_statement(val_temp);
 
-  // func mapassign2(hmap map[k]v, key *k, val *v, p)
-  source_location bloc = BUILTINS_LOCATION;
-  Typed_identifier_list* param_types = new Typed_identifier_list();
-  param_types->push_back(Typed_identifier("hmap", map_type, bloc));
-  Type* pkey_type = Type::make_pointer_type(map_type->key_type());
-  param_types->push_back(Typed_identifier("key", pkey_type, bloc));
-  Type* pval_type = Type::make_pointer_type(map_type->val_type());
-  param_types->push_back(Typed_identifier("val", pval_type, bloc));
-  param_types->push_back(Typed_identifier("p", Type::lookup_bool_type(), bloc));
-  Function_type* fntype = Type::make_function_type(NULL, param_types,
-                                                  NULL, bloc);
-  Named_object* mapassign2 =
-    Named_object::make_function_declaration("mapassign2", NULL, fntype, bloc);
-  mapassign2->func_declaration_value()->set_asm_name("runtime.mapassign2");
+  // var insert_temp bool = p
+  Temporary_statement* insert_temp =
+    Statement::make_temporary(Type::lookup_bool_type(), this->should_set_,
+                             loc);
+  b->add_statement(insert_temp);
 
   // mapassign2(map_temp, &key_temp, &val_temp, p)
-  Expression* func = Expression::make_func_reference(mapassign2, NULL, loc);
-  Expression_list* params = new Expression_list();
-  params->push_back(Expression::make_temporary_reference(map_temp, loc));
+  Expression* p1 = Expression::make_temporary_reference(map_temp, loc);
   Expression* ref = Expression::make_temporary_reference(key_temp, loc);
-  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
   ref = Expression::make_temporary_reference(val_temp, loc);
-  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
-  params->push_back(this->should_set_);
-  Expression* call = Expression::make_call(func, params, false, loc);
+  Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
+  Expression* p4 = Expression::make_temporary_reference(insert_temp, loc);
+  Expression* call = Runtime::make_call(Runtime::MAPASSIGN2, loc, 4,
+                                       p1, p2, p3, p4);
   Statement* s = Statement::make_statement(call);
   b->add_statement(s);
 
@@ -1225,40 +1196,13 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
     Statement::make_temporary(Type::lookup_bool_type(), NULL, loc);
   b->add_statement(closed_temp);
 
-  // func chanrecv2(c chan T, val *T) bool
-  // func chanrecv3(c chan T, val *T) bool (if for_select)
-  source_location bloc = BUILTINS_LOCATION;
-  Typed_identifier_list* param_types = new Typed_identifier_list();
-  param_types->push_back(Typed_identifier("c", channel_type, bloc));
-  Type* pelement_type = Type::make_pointer_type(channel_type->element_type());
-  param_types->push_back(Typed_identifier("val", pelement_type, bloc));
-
-  Typed_identifier_list* ret_types = new Typed_identifier_list();
-  ret_types->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc));
-
-  Function_type* fntype = Type::make_function_type(NULL, param_types,
-                                                  ret_types, bloc);
-  Named_object* chanrecv;
-  if (!this->for_select_)
-    {
-      chanrecv = Named_object::make_function_declaration("chanrecv2", NULL,
-                                                        fntype, bloc);
-      chanrecv->func_declaration_value()->set_asm_name("runtime.chanrecv2");
-    }
-  else
-    {
-      chanrecv = Named_object::make_function_declaration("chanrecv3", NULL,
-                                                        fntype, bloc);
-      chanrecv->func_declaration_value()->set_asm_name("runtime.chanrecv3");
-    }
-
   // closed_temp = chanrecv[23](channel, &val_temp)
-  Expression* func = Expression::make_func_reference(chanrecv, NULL, loc);
-  Expression_list* params = new Expression_list();
-  params->push_back(this->channel_);
   Expression* ref = Expression::make_temporary_reference(val_temp, loc);
-  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
-  Expression* call = Expression::make_call(func, params, false, loc);
+  Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
+  Expression* call = Runtime::make_call((this->for_select_
+                                        ? Runtime::CHANRECV3
+                                        : Runtime::CHANRECV2),
+                                       loc, 2, this->channel_, p2);
   ref = Expression::make_temporary_reference(closed_temp, loc);
   Statement* s = Statement::make_assignment(ref, call, loc);
   b->add_statement(s);
@@ -1318,13 +1262,10 @@ class Tuple_type_guard_assignment_statement : public Statement
 
  private:
   Call_expression*
-  lower_to_empty_interface(const char*);
-
-  Call_expression*
-  lower_to_type(const char*);
+  lower_to_type(Runtime::Function);
 
   void
-  lower_to_object_type(Block*, const char*);
+  lower_to_object_type(Block*, Runtime::Function);
 
   // The variable which recieves the converted value.
   Expression* val_;
@@ -1377,23 +1318,32 @@ Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
   if (this->type_->interface_type() != NULL)
     {
       if (this->type_->interface_type()->is_empty())
-       call = this->lower_to_empty_interface(expr_is_empty
-                                             ? "ifaceE2E2"
-                                             : "ifaceI2E2");
+       call = Runtime::make_call((expr_is_empty
+                                  ? Runtime::IFACEE2E2
+                                  : Runtime::IFACEI2E2),
+                                 loc, 1, this->expr_);
       else
-       call = this->lower_to_type(expr_is_empty ? "ifaceE2I2" : "ifaceI2I2");
+       call = this->lower_to_type(expr_is_empty
+                                  ? Runtime::IFACEE2I2
+                                  : Runtime::IFACEI2I2);
     }
   else if (this->type_->points_to() != NULL)
-    call = this->lower_to_type(expr_is_empty ? "ifaceE2T2P" : "ifaceI2T2P");
+    call = this->lower_to_type(expr_is_empty
+                              ? Runtime::IFACEE2T2P
+                              : Runtime::IFACEI2T2P);
   else
     {
-      this->lower_to_object_type(b, expr_is_empty ? "ifaceE2T2" : "ifaceI2T2");
+      this->lower_to_object_type(b,
+                                (expr_is_empty
+                                 ? Runtime::IFACEE2T2
+                                 : Runtime::IFACEI2T2));
       call = NULL;
     }
 
   if (call != NULL)
     {
       Expression* res = Expression::make_call_result(call, 0);
+      res = Expression::make_unsafe_cast(this->type_, res, loc);
       Statement* s = Statement::make_assignment(this->val_, res, loc);
       b->add_statement(s);
 
@@ -1405,74 +1355,23 @@ Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
   return Statement::make_block_statement(b, loc);
 }
 
-// Lower a conversion to an empty interface type.
-
-Call_expression*
-Tuple_type_guard_assignment_statement::lower_to_empty_interface(
-    const char *fnname)
-{
-  source_location loc = this->location();
-
-  // func FNNAME(interface) (empty, bool)
-  source_location bloc = BUILTINS_LOCATION;
-  Typed_identifier_list* param_types = new Typed_identifier_list();
-  param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc));
-  Typed_identifier_list* ret_types = new Typed_identifier_list();
-  ret_types->push_back(Typed_identifier("ret", this->type_, bloc));
-  ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
-  Function_type* fntype = Type::make_function_type(NULL, param_types,
-                                                  ret_types, bloc);
-  Named_object* fn =
-    Named_object::make_function_declaration(fnname, NULL, fntype, bloc);
-  std::string asm_name = "runtime.";
-  asm_name += fnname;
-  fn->func_declaration_value()->set_asm_name(asm_name);
-
-  // val, ok = FNNAME(expr)
-  Expression* func = Expression::make_func_reference(fn, NULL, loc);
-  Expression_list* params = new Expression_list();
-  params->push_back(this->expr_);
-  return Expression::make_call(func, params, false, loc);
-}
-
 // Lower a conversion to a non-empty interface type or a pointer type.
 
 Call_expression*
-Tuple_type_guard_assignment_statement::lower_to_type(const char* fnname)
+Tuple_type_guard_assignment_statement::lower_to_type(Runtime::Function code)
 {
   source_location loc = this->location();
-
-  // func FNNAME(*descriptor, interface) (interface, bool)
-  source_location bloc = BUILTINS_LOCATION;
-  Typed_identifier_list* param_types = new Typed_identifier_list();
-  param_types->push_back(Typed_identifier("inter",
-                                         Type::make_type_descriptor_ptr_type(),
-                                         bloc));
-  param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc));
-  Typed_identifier_list* ret_types = new Typed_identifier_list();
-  ret_types->push_back(Typed_identifier("ret", this->type_, bloc));
-  ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
-  Function_type* fntype = Type::make_function_type(NULL, param_types,
-                                                  ret_types, bloc);
-  Named_object* fn =
-    Named_object::make_function_declaration(fnname, NULL, fntype, bloc);
-  std::string asm_name = "runtime.";
-  asm_name += fnname;
-  fn->func_declaration_value()->set_asm_name(asm_name);
-
-  // val, ok = FNNAME(type_descriptor, expr)
-  Expression* func = Expression::make_func_reference(fn, NULL, loc);
-  Expression_list* params = new Expression_list();
-  params->push_back(Expression::make_type_descriptor(this->type_, loc));
-  params->push_back(this->expr_);
-  return Expression::make_call(func, params, false, loc);
+  return Runtime::make_call(code, loc, 2,
+                           Expression::make_type_descriptor(this->type_, loc),
+                           this->expr_);
 }
 
 // Lower a conversion to a non-interface non-pointer type.
 
 void
-Tuple_type_guard_assignment_statement::lower_to_object_type(Block* b,
-                                                           const char *fnname)
+Tuple_type_guard_assignment_statement::lower_to_object_type(
+    Block* b,
+    Runtime::Function code)
 {
   source_location loc = this->location();
 
@@ -1481,33 +1380,11 @@ Tuple_type_guard_assignment_statement::lower_to_object_type(Block* b,
                                                            NULL, loc);
   b->add_statement(val_temp);
 
-  // func FNNAME(*descriptor, interface, *T) bool
-  source_location bloc = BUILTINS_LOCATION;
-  Typed_identifier_list* param_types = new Typed_identifier_list();
-  param_types->push_back(Typed_identifier("inter",
-                                         Type::make_type_descriptor_ptr_type(),
-                                         bloc));
-  param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc));
-  Type* ptype = Type::make_pointer_type(this->type_);
-  param_types->push_back(Typed_identifier("v", ptype, bloc));
-  Typed_identifier_list* ret_types = new Typed_identifier_list();
-  ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
-  Function_type* fntype = Type::make_function_type(NULL, param_types,
-                                                  ret_types, bloc);
-  Named_object* fn =
-    Named_object::make_function_declaration(fnname, NULL, fntype, bloc);
-  std::string asm_name = "runtime.";
-  asm_name += fnname;
-  fn->func_declaration_value()->set_asm_name(asm_name);
-
-  // ok = FNNAME(type_descriptor, expr, &val_temp)
-  Expression* func = Expression::make_func_reference(fn, NULL, loc);
-  Expression_list* params = new Expression_list();
-  params->push_back(Expression::make_type_descriptor(this->type_, loc));
-  params->push_back(this->expr_);
+  // ok = CODE(type_descriptor, expr, &val_temp)
+  Expression* p1 = Expression::make_type_descriptor(this->type_, loc);
   Expression* ref = Expression::make_temporary_reference(val_temp, loc);
-  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
-  Expression* call = Expression::make_call(func, params, false, loc);
+  Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
+  Expression* call = Runtime::make_call(code, loc, 3, p1, this->expr_, p3);
   Statement* s = Statement::make_assignment(this->ok_, call, loc);
   b->add_statement(s);
 
@@ -2146,34 +2023,8 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name,
     {
       retaddr_label = gogo->add_label_reference("retaddr");
       Expression* arg = Expression::make_label_addr(retaddr_label, location);
-      Expression_list* args = new Expression_list();
-      args->push_back(arg);
-
-      static Named_object* set_defer_retaddr;
-      if (set_defer_retaddr == NULL)
-       {
-         const source_location bloc = BUILTINS_LOCATION;
-         Typed_identifier_list* param_types = new Typed_identifier_list();
-         Type *voidptr_type = Type::make_pointer_type(Type::make_void_type());
-         param_types->push_back(Typed_identifier("r", voidptr_type, bloc));
-
-         Typed_identifier_list* result_types = new Typed_identifier_list();
-         result_types->push_back(Typed_identifier("",
-                                                  Type::lookup_bool_type(),
-                                                  bloc));
-
-         Function_type* t = Type::make_function_type(NULL, param_types,
-                                                     result_types, bloc);
-         set_defer_retaddr =
-           Named_object::make_function_declaration("__go_set_defer_retaddr",
-                                                   NULL, t, bloc);
-         const char* n = "__go_set_defer_retaddr";
-         set_defer_retaddr->func_declaration_value()->set_asm_name(n);
-       }
-
-      Expression* fn = Expression::make_func_reference(set_defer_retaddr,
-                                                      NULL, location);
-      Expression* call = Expression::make_call(fn, args, false, location);
+      Expression* call = Runtime::make_call(Runtime::SET_DEFER_RETADDR,
+                                           location, 1, arg);
 
       // This is a hack to prevent the middle-end from deleting the
       // label.
@@ -3610,92 +3461,24 @@ Type_case_clauses::Type_case_clause::lower(Block* b,
     {
       Type* type = this->type_;
 
+      Expression* ref = Expression::make_temporary_reference(descriptor_temp,
+                                                            loc);
+
       Expression* cond;
       // The language permits case nil, which is of course a constant
       // rather than a type.  It will appear here as an invalid
       // forwarding type.
       if (type->is_nil_constant_as_type())
-       {
-         Expression* ref =
-           Expression::make_temporary_reference(descriptor_temp, loc);
-         cond = Expression::make_binary(OPERATOR_EQEQ, ref,
-                                        Expression::make_nil(loc),
-                                        loc);
-       }
+       cond = Expression::make_binary(OPERATOR_EQEQ, ref,
+                                      Expression::make_nil(loc),
+                                      loc);
       else
-       {
-         Expression* func;
-         if (type->interface_type() == NULL)
-           {
-             // func ifacetypeeq(*descriptor, *descriptor) bool
-             static Named_object* ifacetypeeq;
-             if (ifacetypeeq == NULL)
-               {
-                 const source_location bloc = BUILTINS_LOCATION;
-                 Typed_identifier_list* param_types =
-                   new Typed_identifier_list();
-                 Type* descriptor_type = Type::make_type_descriptor_ptr_type();
-                 param_types->push_back(Typed_identifier("a", descriptor_type,
-                                                         bloc));
-                 param_types->push_back(Typed_identifier("b", descriptor_type,
-                                                         bloc));
-                 Typed_identifier_list* ret_types =
-                   new Typed_identifier_list();
-                 Type* bool_type = Type::lookup_bool_type();
-                 ret_types->push_back(Typed_identifier("", bool_type, bloc));
-                 Function_type* fntype = Type::make_function_type(NULL,
-                                                                  param_types,
-                                                                  ret_types,
-                                                                  bloc);
-                 ifacetypeeq =
-                   Named_object::make_function_declaration("ifacetypeeq", NULL,
-                                                           fntype, bloc);
-                 const char* n = "runtime.ifacetypeeq";
-                 ifacetypeeq->func_declaration_value()->set_asm_name(n);
-               }
-
-             // ifacetypeeq(descriptor_temp, DESCRIPTOR)
-             func = Expression::make_func_reference(ifacetypeeq, NULL, loc);
-           }
-         else
-           {
-             // func ifaceI2Tp(*descriptor, *descriptor) bool
-             static Named_object* ifaceI2Tp;
-             if (ifaceI2Tp == NULL)
-               {
-                 const source_location bloc = BUILTINS_LOCATION;
-                 Typed_identifier_list* param_types =
-                   new Typed_identifier_list();
-                 Type* descriptor_type = Type::make_type_descriptor_ptr_type();
-                 param_types->push_back(Typed_identifier("a", descriptor_type,
-                                                         bloc));
-                 param_types->push_back(Typed_identifier("b", descriptor_type,
-                                                         bloc));
-                 Typed_identifier_list* ret_types =
-                   new Typed_identifier_list();
-                 Type* bool_type = Type::lookup_bool_type();
-                 ret_types->push_back(Typed_identifier("", bool_type, bloc));
-                 Function_type* fntype = Type::make_function_type(NULL,
-                                                                  param_types,
-                                                                  ret_types,
-                                                                  bloc);
-                 ifaceI2Tp =
-                   Named_object::make_function_declaration("ifaceI2Tp", NULL,
-                                                           fntype, bloc);
-                 const char* n = "runtime.ifaceI2Tp";
-                 ifaceI2Tp->func_declaration_value()->set_asm_name(n);
-               }
-
-             // ifaceI2Tp(descriptor_temp, DESCRIPTOR)
-             func = Expression::make_func_reference(ifaceI2Tp, NULL, loc);
-           }
-         Expression_list* params = new Expression_list();
-         params->push_back(Expression::make_type_descriptor(type, loc));
-         Expression* ref =
-           Expression::make_temporary_reference(descriptor_temp, loc);
-         params->push_back(ref);
-         cond = Expression::make_call(func, params, false, loc);
-       }
+       cond = Runtime::make_call((type->interface_type() == NULL
+                                  ? Runtime::IFACETYPEEQ
+                                  : Runtime::IFACEI2TP),
+                                 loc, 2,
+                                 Expression::make_type_descriptor(type, loc),
+                                 ref);
 
       Unnamed_label* dest;
       if (!this->is_fallthrough_)
@@ -3891,35 +3674,18 @@ Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing)
     }
   else
     {
-      const source_location bloc = BUILTINS_LOCATION;
-
-      // func {efacetype,ifacetype}(*interface) *descriptor
+      // descriptor_temp = ifacetype(val_temp)
       // FIXME: This should be inlined.
-      Typed_identifier_list* param_types = new Typed_identifier_list();
-      param_types->push_back(Typed_identifier("i", val_type, bloc));
-      Typed_identifier_list* ret_types = new Typed_identifier_list();
-      ret_types->push_back(Typed_identifier("", descriptor_type, bloc));
-      Function_type* fntype = Type::make_function_type(NULL, param_types,
-                                                      ret_types, bloc);
       bool is_empty = val_type->interface_type()->is_empty();
-      const char* fnname = is_empty ? "efacetype" : "ifacetype";
-      Named_object* fn =
-       Named_object::make_function_declaration(fnname, NULL, fntype, bloc);
-      const char* asm_name = (is_empty
-                             ? "runtime.efacetype"
-                             : "runtime.ifacetype");
-      fn->func_declaration_value()->set_asm_name(asm_name);
-
-      // descriptor_temp = ifacetype(val_temp)
-      Expression* func = Expression::make_func_reference(fn, NULL, loc);
-      Expression_list* params = new Expression_list();
       Expression* ref;
       if (this->var_ == NULL)
        ref = this->expr_;
       else
        ref = Expression::make_var_reference(this->var_, loc);
-      params->push_back(ref);
-      Expression* call = Expression::make_call(func, params, false, loc);
+      Expression* call = Runtime::make_call((is_empty
+                                            ? Runtime::EFACETYPE
+                                            : Runtime::IFACETYPE),
+                                           loc, 1, ref);
       Expression* lhs = Expression::make_temporary_reference(descriptor_temp,
                                                             loc);
       Statement* s = Statement::make_assignment(lhs, call, loc);
@@ -4935,7 +4701,7 @@ For_range_statement::lower_range_array(Gogo* gogo,
 // Lower a for range over a string.
 
 void
-For_range_statement::lower_range_string(Gogo* gogo,
+For_range_statement::lower_range_string(Gogo*,
                                        Block* enclosing,
                                        Block* body_block,
                                        Named_object* range_object,
@@ -4996,66 +4762,12 @@ For_range_statement::lower_range_string(Gogo* gogo,
 
   Block* iter_init = new Block(body_block, loc);
 
-  Named_object* no;
-  if (value_temp == NULL)
-    {
-      static Named_object* stringiter;
-      if (stringiter == NULL)
-       {
-         source_location bloc = BUILTINS_LOCATION;
-         Type* int_type = gogo->lookup_global("int")->type_value();
-
-         Typed_identifier_list* params = new Typed_identifier_list();
-         params->push_back(Typed_identifier("s", Type::make_string_type(),
-                                            bloc));
-         params->push_back(Typed_identifier("k", int_type, bloc));
-
-         Typed_identifier_list* results = new Typed_identifier_list();
-         results->push_back(Typed_identifier("", int_type, bloc));
-
-         Function_type* fntype = Type::make_function_type(NULL, params,
-                                                          results, bloc);
-         stringiter = Named_object::make_function_declaration("stringiter",
-                                                              NULL, fntype,
-                                                              bloc);
-         const char* n = "runtime.stringiter";
-         stringiter->func_declaration_value()->set_asm_name(n);
-       }
-      no = stringiter;
-    }
-  else
-    {
-      static Named_object* stringiter2;
-      if (stringiter2 == NULL)
-       {
-         source_location bloc = BUILTINS_LOCATION;
-         Type* int_type = gogo->lookup_global("int")->type_value();
-
-         Typed_identifier_list* params = new Typed_identifier_list();
-         params->push_back(Typed_identifier("s", Type::make_string_type(),
-                                            bloc));
-         params->push_back(Typed_identifier("k", int_type, bloc));
-
-         Typed_identifier_list* results = new Typed_identifier_list();
-         results->push_back(Typed_identifier("", int_type, bloc));
-         results->push_back(Typed_identifier("", int_type, bloc));
-
-         Function_type* fntype = Type::make_function_type(NULL, params,
-                                                          results, bloc);
-         stringiter2 = Named_object::make_function_declaration("stringiter",
-                                                               NULL, fntype,
-                                                               bloc);
-         const char* n = "runtime.stringiter2";
-         stringiter2->func_declaration_value()->set_asm_name(n);
-       }
-      no = stringiter2;
-    }
-
-  Expression* func = Expression::make_func_reference(no, NULL, loc);
-  Expression_list* params = new Expression_list();
-  params->push_back(this->make_range_ref(range_object, range_temp, loc));
-  params->push_back(Expression::make_temporary_reference(index_temp, loc));
-  Call_expression* call = Expression::make_call(func, params, false, loc);
+  Expression* p1 = this->make_range_ref(range_object, range_temp, loc);
+  Expression* p2 = Expression::make_temporary_reference(index_temp, loc);
+  Call_expression* call = Runtime::make_call((value_temp == NULL
+                                             ? Runtime::STRINGITER
+                                             : Runtime::STRINGITER2),
+                                            loc, 2, p1, p2);
 
   if (value_temp == NULL)
     {
@@ -5107,7 +4819,7 @@ For_range_statement::lower_range_string(Gogo* gogo,
 // Lower a for range over a map.
 
 void
-For_range_statement::lower_range_map(Gogo* gogo,
+For_range_statement::lower_range_map(Gogo*,
                                     Block* enclosing,
                                     Block* body_block,
                                     Named_object* range_object,
@@ -5140,41 +4852,15 @@ For_range_statement::lower_range_map(Gogo* gogo,
 
   Block* init = new Block(enclosing, loc);
 
-  const unsigned long map_iteration_size = 4;
-
-  mpz_t ival;
-  mpz_init_set_ui(ival, map_iteration_size);
-  Expression* iexpr = Expression::make_integer(&ival, NULL, loc);
-  mpz_clear(ival);
-
-  Type* byte_type = gogo->lookup_global("byte")->type_value();
-  Type* ptr_type = Type::make_pointer_type(byte_type);
-
-  Type* map_iteration_type = Type::make_array_type(ptr_type, iexpr);
-  Type* map_iteration_ptr = Type::make_pointer_type(map_iteration_type);
-
+  Type* map_iteration_type = Runtime::map_iteration_type();
   Temporary_statement* hiter = Statement::make_temporary(map_iteration_type,
                                                         NULL, loc);
   init->add_statement(hiter);
 
-  source_location bloc = BUILTINS_LOCATION;
-  Typed_identifier_list* param_types = new Typed_identifier_list();
-  param_types->push_back(Typed_identifier("map", this->range_->type(), bloc));
-  param_types->push_back(Typed_identifier("it", map_iteration_ptr, bloc));
-  Function_type* fntype = Type::make_function_type(NULL, param_types, NULL,
-                                                  bloc);
-
-  Named_object* mapiterinit =
-    Named_object::make_function_declaration("mapiterinit", NULL, fntype, bloc);
-  const char* n = "runtime.mapiterinit";
-  mapiterinit->func_declaration_value()->set_asm_name(n);
-
-  Expression* func = Expression::make_func_reference(mapiterinit, NULL, loc);
-  Expression_list* params = new Expression_list();
-  params->push_back(this->make_range_ref(range_object, range_temp, loc));
+  Expression* p1 = this->make_range_ref(range_object, range_temp, loc);
   Expression* ref = Expression::make_temporary_reference(hiter, loc);
-  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
-  Expression* call = Expression::make_call(func, params, false, loc);
+  Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
+  Expression* call = Runtime::make_call(Runtime::MAPITERINIT, loc, 2, p1, p2);
   init->add_statement(Statement::make_statement(call));
 
   *pinit = init;
@@ -5204,34 +4890,18 @@ For_range_statement::lower_range_map(Gogo* gogo,
 
   Block* iter_init = new Block(body_block, loc);
 
-  param_types = new Typed_identifier_list();
-  param_types->push_back(Typed_identifier("hiter", map_iteration_ptr, bloc));
-  Type* pkey_type = Type::make_pointer_type(index_temp->type());
-  param_types->push_back(Typed_identifier("key", pkey_type, bloc));
-  if (value_temp != NULL)
-    {
-      Type* pval_type = Type::make_pointer_type(value_temp->type());
-      param_types->push_back(Typed_identifier("val", pval_type, bloc));
-    }
-  fntype = Type::make_function_type(NULL, param_types, NULL, bloc);
-  n = value_temp == NULL ? "mapiter1" : "mapiter2";
-  Named_object* mapiter = Named_object::make_function_declaration(n, NULL,
-                                                                 fntype, bloc);
-  n = value_temp == NULL ? "runtime.mapiter1" : "runtime.mapiter2";
-  mapiter->func_declaration_value()->set_asm_name(n);
-
-  func = Expression::make_func_reference(mapiter, NULL, loc);
-  params = new Expression_list();
   ref = Expression::make_temporary_reference(hiter, loc);
-  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
   ref = Expression::make_temporary_reference(index_temp, loc);
-  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
-  if (value_temp != NULL)
+  p2 = Expression::make_unary(OPERATOR_AND, ref, loc);
+  if (value_temp == NULL)
+    call = Runtime::make_call(Runtime::MAPITER1, loc, 2, p1, p2);
+  else
     {
       ref = Expression::make_temporary_reference(value_temp, loc);
-      params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+      Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc);
+      call = Runtime::make_call(Runtime::MAPITER2, loc, 3, p1, p2, p3);
     }
-  call = Expression::make_call(func, params, false, loc);
   iter_init->add_statement(Statement::make_statement(call));
 
   *piter_init = iter_init;
@@ -5241,24 +4911,9 @@ For_range_statement::lower_range_map(Gogo* gogo,
 
   Block* post = new Block(enclosing, loc);
 
-  static Named_object* mapiternext;
-  if (mapiternext == NULL)
-    {
-      param_types = new Typed_identifier_list();
-      param_types->push_back(Typed_identifier("it", map_iteration_ptr, bloc));
-      fntype = Type::make_function_type(NULL, param_types, NULL, bloc);
-      mapiternext = Named_object::make_function_declaration("mapiternext",
-                                                           NULL, fntype,
-                                                           bloc);
-      const char* n = "runtime.mapiternext";
-      mapiternext->func_declaration_value()->set_asm_name(n);
-    }
-
-  func = Expression::make_func_reference(mapiternext, NULL, loc);
-  params = new Expression_list();
   ref = Expression::make_temporary_reference(hiter, loc);
-  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
-  call = Expression::make_call(func, params, false, loc);
+  p1 = Expression::make_unary(OPERATOR_AND, ref, loc);
+  call = Runtime::make_call(Runtime::MAPITERNEXT, loc, 1, p1);
   post->add_statement(Statement::make_statement(call));
 
   *ppost = post;
index cd439bf4ccb7a942b050c08c6bd0f363a3275d09..ac791746e179649bf3403aefb6a6a8d9f6ccb319 100644 (file)
@@ -79,7 +79,7 @@ struct __go_channel
    acquired while this mutex is held.  */
 extern pthread_mutex_t __go_select_data_mutex;
 
-extern struct __go_channel *__go_new_channel (size_t, size_t);
+extern struct __go_channel *__go_new_channel (uintptr_t, uintptr_t);
 
 extern _Bool __go_synch_with_select (struct __go_channel *, _Bool);
 
@@ -138,6 +138,6 @@ extern _Bool __go_builtin_closed (struct __go_channel *);
 
 extern void __go_builtin_close (struct __go_channel *);
 
-extern size_t __go_chan_len (struct __go_channel *);
+extern int __go_chan_len (struct __go_channel *);
 
-extern size_t __go_chan_cap (struct __go_channel *);
+extern int __go_chan_cap (struct __go_channel *);
index 91493b1b78d7ecb4082e1f0f99b0ec723eaa43c9..e501f3066a950db1cab11bc11fe153c880ea6340 100644 (file)
@@ -19,18 +19,18 @@ __go_append (struct __go_open_array, void *, size_t, size_t)
   __attribute__ ((no_split_stack));
 
 struct __go_open_array
-__go_append (struct __go_open_array a, void *bvalues, size_t bcount,
-            size_t element_size)
+__go_append (struct __go_open_array a, void *bvalues, uintptr_t bcount,
+            uintptr_t element_size)
 {
-  size_t ucount;
+  uintptr_t ucount;
   int count;
 
   if (bvalues == NULL || bcount == 0)
     return a;
 
-  ucount = (size_t) a.__count + bcount;
+  ucount = (uintptr_t) a.__count + bcount;
   count = (int) ucount;
-  if ((size_t) count != ucount || count <= a.__count)
+  if ((uintptr_t) count != ucount || count <= a.__count)
     __go_panic_msg ("append: slice overflow");
 
   if (count > a.__capacity)
index 1b9ac2d79649a80a28f1648e816e4dc99cd1dfaa..ab9e28388bc3efc29f2b18be2e5eefcabb286e51 100644 (file)
@@ -9,7 +9,7 @@
 #include "malloc.h"
 
 struct __go_string
-__go_byte_array_to_string (const void* p, size_t len)
+__go_byte_array_to_string (const void* p, int len)
 {
   const unsigned char *bytes;
   unsigned char *retdata;
index df603bf102f2ad5c70794f10f1001a4e410cdb24..2c7958dd9fc444518ebf841a71457d5969163789 100644 (file)
    buffer.  This could be done inline but I'm doing it as a function
    for now to make it easy to change the channel structure.  */
 
-size_t
+int
 __go_chan_cap (struct __go_channel *channel)
 {
   int i;
-  size_t ret;
+  int ret;
 
   if (channel == NULL)
     return 0;
index 5aebae141bcfc45ad3105b3909c327635503f492..b3ced98aa050ebafd172b50ae66948cd5ec1e9f4 100644 (file)
    as a function for now to make it easy to change the channel
    structure.  */
 
-size_t
+int
 __go_chan_len (struct __go_channel *channel)
 {
   int i;
-  size_t ret;
+  int ret;
 
   if (channel == NULL)
     return 0;
@@ -35,7 +35,7 @@ __go_chan_len (struct __go_channel *channel)
           % channel->num_entries);
 
   i = pthread_mutex_unlock (&channel->lock);
-  __go_assert  (i == 0);
+  __go_assert (i == 0);
 
   return ret;
 }
index 15497eadb5d219b516a8b6fb6c06ff8fc4d469a5..5e459d07ac4b63f251f75f8bd79e01ac044703d9 100644 (file)
@@ -5,18 +5,20 @@
    license that can be found in the LICENSE file.  */
 
 #include <stddef.h>
+#include <stdint.h>
 #include <stdlib.h>
 
 #include "map.h"
 
 struct __go_map *
 __go_construct_map (const struct __go_map_descriptor *descriptor,
-                   size_t count, size_t entry_size, size_t val_offset,
-                   size_t val_size, const void *ventries)
+                   uintptr_t count, uintptr_t entry_size,
+                   uintptr_t val_offset, uintptr_t val_size,
+                   const void *ventries)
 {
   struct __go_map *ret;
   const unsigned char *entries;
-  size_t i;
+  uintptr_t i;
 
   ret = __go_new_map (descriptor, count);
 
index 998aeb927d42d0d0b63def66539c1dfbdae296ca..05e16acbf1c48686ec76b7338473d537e5731723 100644 (file)
@@ -5,17 +5,18 @@
    license that can be found in the LICENSE file.  */
 
 #include <stddef.h>
+#include <stdint.h>
 
 /* We should be OK if we don't split the stack here, since we are just
    calling memmove which shouldn't need much stack.  If we don't do
    this we will always split the stack, because of memmove.  */
 
 extern void
-__go_copy (void *, void *, size_t)
+__go_copy (void *, void *, uintptr_t)
   __attribute__ ((no_split_stack));
 
 void
-__go_copy (void *a, void *b, size_t len)
+__go_copy (void *a, void *b, uintptr_t len)
 {
   __builtin_memmove (a, b, len);
 }
index c16589f01a2760f52f650a420a318de7ba3c67b7..ec07b873907d7fbf253038a4c8d895ef3fb7e835 100644 (file)
 #include "malloc.h"
 
 struct __go_string
-__go_int_array_to_string (const void* p, size_t len)
+__go_int_array_to_string (const void* p, int len)
 {
   const int *ints;
-  size_t slen;
-  size_t i;
+  int slen;
+  int i;
   unsigned char *retdata;
   struct __go_string ret;
   unsigned char *s;
@@ -79,7 +79,7 @@ __go_int_array_to_string (const void* p, size_t len)
        }
     }
 
-  __go_assert ((size_t) (s - retdata) == slen);
+  __go_assert (s - retdata == slen);
 
   return ret;
 }
index 75b7473390dd615a9a75b9adb27b75ec846d8e16..01df5b41c6c8f9d429d06e1b3241f9276c2be95c 100644 (file)
@@ -6,16 +6,18 @@
 
 #include <stddef.h>
 
+#include "go-assert.h"
 #include "map.h"
 
 /* Return the length of a map.  This could be done inline, of course,
-   but I'm doing it as a function for now to make it easy to chang the
-   map structure.  */
+   but I'm doing it as a function for now to make it easy to change
+   the map structure.  */
 
-size_t
+int
 __go_map_len (struct __go_map *map)
 {
   if (map == NULL)
     return 0;
+  __go_assert (map->__element_count == (size_t) (int) map->__element_count);
   return map->__element_count;
 }
index 3ddc205e05d01e09b276d573660417af3a1da375..028715e3b1de384933a645b838660297420c2fce 100644 (file)
@@ -5,6 +5,7 @@
    license that can be found in the LICENSE file.  */
 
 #include <stddef.h>
+#include <stdint.h>
 
 #include "go-alloc.h"
 #include "go-assert.h"
 #include "channel.h"
 
 struct __go_channel*
-__go_new_channel (size_t element_size, size_t entries)
+__go_new_channel (uintptr_t element_size, uintptr_t entries)
 {
   struct __go_channel* ret;
   size_t alloc_size;
   int i;
 
-  if ((size_t) (int) entries != entries || entries > (size_t) -1 / element_size)
+  if ((uintptr_t) (int) entries != entries
+      || entries > (uintptr_t) -1 / element_size)
     __go_panic_msg ("chan size out of range");
 
   alloc_size = (element_size + sizeof (uint64_t) - 1) / sizeof (uint64_t);
index 519f38f788adab499f8ab4683eefac0725ae815a..73e8d7dfe794d16fb9f7521904cb8a44dcb9d1e8 100644 (file)
@@ -104,11 +104,11 @@ __go_map_next_prime (unsigned long n)
 /* Allocate a new map.  */
 
 struct __go_map *
-__go_new_map (const struct __go_map_descriptor *descriptor, size_t entries)
+__go_new_map (const struct __go_map_descriptor *descriptor, uintptr_t entries)
 {
   struct __go_map *ret;
 
-  if ((size_t) (int) entries != entries)
+  if ((uintptr_t) (int) entries != entries)
     __go_panic_msg ("map size out of range");
 
   if (entries == 0)
index 8f25c5730ef0f2c7f76e4cfd02c12e725da9105b..657978c30a82433744fdb73a5bcdf14aabe25c22 100644 (file)
@@ -9,13 +9,13 @@
 #include "malloc.h"
 
 void *
-__go_new (size_t size)
+__go_new (uintptr_t size)
 {
   return runtime_mallocgc (size, 0, 1, 1);
 }
 
 void *
-__go_new_nopointers (size_t size)
+__go_new_nopointers (uintptr_t size)
 {
   return runtime_mallocgc (size, FlagNoPointers, 1, 1);
 }
index 9d9f728f2bc43b4a9cb629c8dab2067ea53f8ee0..5ea521d423dc2ad04ddcf12e8a1cb6cbde6a51b7 100644 (file)
@@ -22,11 +22,11 @@ struct select_channel
   /* The channel being selected.  */
   struct __go_channel* channel;
   /* If this channel is selected, the value to return.  */
-  size_t retval;
+  uintptr_t retval;
   /* If this channel is a duplicate of one which appears earlier in
      the array, this is the array index of the earlier channel.  This
      is -1UL if this is not a dup.  */
-  size_t dup_index;
+  uintptr_t dup_index;
   /* An entry to put on the send or receive queue.  */
   struct __go_channel_select queue_entry;
   /* True if selected for send.  */
@@ -321,24 +321,24 @@ clear_select_waiting (struct select_channel *sc,
    Lock each channels, and set the is_ready flag.  Return the number
    of ready channels.  */
 
-static size_t
-lock_channels_find_ready (struct select_channel *channels, size_t count)
+static uintptr_t
+lock_channels_find_ready (struct select_channel *channels, uintptr_t count)
 {
-  size_t ready_count;
-  size_t i;
+  uintptr_t ready_count;
+  uintptr_t i;
 
   ready_count = 0;
   for (i = 0; i < count; ++i)
     {
       struct __go_channel *channel = channels[i].channel;
       _Bool is_send = channels[i].is_send;
-      size_t dup_index = channels[i].dup_index;
+      uintptr_t dup_index = channels[i].dup_index;
       int x;
 
       if (channel == NULL)
        continue;
 
-      if (dup_index != (size_t) -1UL)
+      if (dup_index != (uintptr_t) -1UL)
        {
          if (channels[dup_index].is_ready)
            {
@@ -370,13 +370,13 @@ lock_channels_find_ready (struct select_channel *channels, size_t count)
    All the channels are locked before this routine is called.  This
    returns the number of ready channels.  */
 
-size_t
-force_selected_channel_ready (struct select_channel *channels, size_t count,
+uintptr_t
+force_selected_channel_ready (struct select_channel *channels, uintptr_t count,
                              struct __go_channel *selected_channel,
                              _Bool selected_for_read)
 {
-  size_t ready_count;
-  size_t i;
+  uintptr_t ready_count;
+  uintptr_t i;
 
   ready_count = 0;
   for (i = 0; i < count; ++i)
@@ -403,9 +403,9 @@ force_selected_channel_ready (struct select_channel *channels, size_t count,
 /* Unlock all the channels.  */
 
 static void
-unlock_channels (struct select_channel *channels, size_t count)
+unlock_channels (struct select_channel *channels, uintptr_t count)
 {
-  size_t i;
+  uintptr_t i;
   int x;
 
   for (i = 0; i < count; ++i)
@@ -415,7 +415,7 @@ unlock_channels (struct select_channel *channels, size_t count)
       if (channel == NULL)
        continue;
 
-      if (channels[i].dup_index != (size_t) -1UL)
+      if (channels[i].dup_index != (uintptr_t) -1UL)
        continue;
 
       x = pthread_mutex_unlock (&channel->lock);
@@ -432,23 +432,23 @@ unlock_channels (struct select_channel *channels, size_t count)
    with some other select, and that select already synchronized with a
    different channel.  */
 
-static size_t
+static uintptr_t
 unlock_channels_and_select (struct select_channel *channels,
-                           size_t count, size_t ready_count,
+                           uintptr_t count, uintptr_t ready_count,
                            _Bool is_selected,
                            struct __go_channel **selected_pointer)
 {
-  size_t selected;
-  size_t ret;
+  uintptr_t selected;
+  uintptr_t ret;
   _Bool needs_broadcast;
-  size_t i;
+  uintptr_t i;
   int x;
 
   /* Pick which channel we are going to return.  */
 #if defined(HAVE_RANDOM)
-  selected = (size_t) random () % ready_count;
+  selected = (uintptr_t) random () % ready_count;
 #else
-  selected = (size_t) rand () % ready_count;
+  selected = (uintptr_t) rand () % ready_count;
 #endif
   ret = 0;
   needs_broadcast = 0;
@@ -457,7 +457,7 @@ unlock_channels_and_select (struct select_channel *channels,
      duplicated channel until we have seen all its dups.  */
   for (i = 0; i < count; ++i)
     {
-      size_t j = count - i - 1;
+      uintptr_t j = count - i - 1;
       struct __go_channel *channel = channels[j].channel;
       _Bool is_send = channels[j].is_send;
 
@@ -476,7 +476,7 @@ unlock_channels_and_select (struct select_channel *channels,
          --selected;
        }
 
-      if (channels[j].dup_index == (size_t) -1UL)
+      if (channels[j].dup_index == (uintptr_t) -1UL)
        {
          if (selected_pointer != NULL)
            clear_select_waiting (&channels[j], selected_pointer);
@@ -511,13 +511,13 @@ unlock_channels_and_select (struct select_channel *channels,
    ready.  */
 
 static _Bool
-mark_all_channels_waiting (struct select_channel* channels, size_t count,
+mark_all_channels_waiting (struct select_channel* channels, uintptr_t count,
                           struct __go_channel **selected_pointer,
                           _Bool *selected_for_read_pointer)
 {
   _Bool ret;
   int x;
-  size_t i;
+  uintptr_t i;
 
   ret = 0;
   for (i = 0; i < count; ++i)
@@ -528,9 +528,9 @@ mark_all_channels_waiting (struct select_channel* channels, size_t count,
       if (channel == NULL)
        continue;
 
-      if (channels[i].dup_index != (size_t) -1UL)
+      if (channels[i].dup_index != (uintptr_t) -1UL)
        {
-         size_t j;
+         uintptr_t j;
 
          /* A channel may be selected for both read and write.  */
          if (channels[channels[i].dup_index].is_send != is_send)
@@ -574,14 +574,14 @@ mark_all_channels_waiting (struct select_channel* channels, size_t count,
    with pairs of arguments: a pointer to a channel, and an int which
    is non-zero for send, zero for receive.  */
 
-size_t
-__go_select (size_t count, _Bool has_default,
+uintptr_t
+__go_select (uintptr_t count, _Bool has_default,
             struct __go_channel **channel_args, _Bool *is_send_args)
 {
   struct select_channel stack_buffer[16];
   struct select_channel *allocated_buffer;
   struct select_channel *channels;
-  size_t i;
+  uintptr_t i;
   int x;
   struct __go_channel *selected_channel;
   _Bool selected_for_read;
@@ -606,7 +606,7 @@ __go_select (size_t count, _Bool has_default,
 
       channels[i].channel = (struct __go_channel*) channel_arg;
       channels[i].retval = i + 1;
-      channels[i].dup_index = (size_t) -1UL;
+      channels[i].dup_index = (uintptr_t) -1UL;
       channels[i].queue_entry.next = NULL;
       channels[i].queue_entry.selected = NULL;
       channels[i].is_send = is_send;
@@ -617,7 +617,7 @@ __go_select (size_t count, _Bool has_default,
 
   for (i = 0; i < count; ++i)
     {
-      size_t j;
+      uintptr_t j;
 
       for (j = 0; j < i; ++j)
        {
@@ -667,7 +667,7 @@ __go_select (size_t count, _Bool has_default,
 
       if (ready_count > 0)
        {
-         size_t ret;
+         uintptr_t ret;
 
          ret = unlock_channels_and_select (channels, count, ready_count,
                                            is_selected,
index 43003e81c93f0408b7f8063595be32dacb088359..d6cc29922e85eae6eb026dcf8066fc92b9b198a0 100644 (file)
@@ -22,7 +22,7 @@
    needs to be more system dependent.  */
 
 void *
-__go_allocate_trampoline (size_t size, void *closure)
+__go_allocate_trampoline (uintptr_t size, void *closure)
 {
   unsigned int page_size;
   void *ret;
index a0c834a54acd1581402733f3a1fae63b04c01194..9c3fda263a0455a5f276d1d8e4715d010a701650 100644 (file)
@@ -68,7 +68,7 @@ struct __go_hash_iter
 };
 
 extern struct __go_map *__go_new_map (const struct __go_map_descriptor *,
-                                     size_t);
+                                     uintptr_t);
 
 extern unsigned long __go_map_next_prime (unsigned long);