OSDN Git Service

Unify handling of runtime support functions.
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 13 Apr 2011 21:00:59 +0000 (21:00 +0000)
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@172396 138bc75d-0d04-0410-961f-82ee72b054a4

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 9f400f1..79f9a11 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 0dc8942..c5289c6 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 c516485..7f291d4 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 fa240a6..66aabeb 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 31549ac..e22de4b 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 f84b2d4..0b22e30 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 cd439bf..ac79174 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 91493b1..e501f30 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 1b9ac2d..ab9e283 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 df603bf..2c7958d 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 5aebae1..b3ced98 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 15497ea..5e459d0 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 998aeb9..05e16ac 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 c16589f..ec07b87 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 75b7473..01df5b4 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 3ddc205..028715e 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 519f38f..73e8d7d 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 8f25c57..657978c 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 9d9f728..5ea521d 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 43003e8..d6cc299 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 a0c834a..9c3fda2 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);