diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index 689578e2064..0d153fa02e6 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,22 @@
+2014-04-14  Chris Manghane  <cmang@google.com>
+
+	* go-gcc.cc: Include "convert.h".
+	(Gcc_backend::string_constant_expression): New function.
+	(Gcc_backend::real_part_expression): Likewise.
+	(Gcc_backend::imag_part_expression): Likewise.
+	(Gcc_backend::complex_expression): Likewise.
+	(Gcc_backend::constructor_expression): Likewise.
+	(Gcc_backend::array_constructor_expression): Likewise.
+	(Gcc_backend::pointer_offset_expression): Likewise.
+	(Gcc_backend::array_index_expression): Likewise.
+	(Gcc_backend::call_expression): Likewise.
+	(Gcc_backend::exception_handler_statement): Likewise.
+	(Gcc_backend::function_defer_statement): Likewise.
+	(Gcc_backend::function_set_parameters): Likewise.
+	(Gcc_backend::function_set_body): Likewise.
+	(Gcc_backend::convert_expression): Handle various type
+	conversions.
+
 2014-03-03  Ian Lance Taylor  <iant@google.com>
 
 	* go-gcc.cc (Gcc_backend::immutable_struct): If IS_COMMON, set
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 6aec2877d7b..3abefaee9e6 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -29,6 +29,7 @@
 #include "stor-layout.h"
 #include "varasm.h"
 #include "tree-iterator.h"
+#include "convert.h"
 #include "basic-block.h"
 #include "gimple-expr.h"
 #include "toplev.h"
@@ -234,6 +235,18 @@ class Gcc_backend : public Backend
   Bexpression*
   complex_constant_expression(Btype* btype, mpfr_t real, mpfr_t imag);
 
+  Bexpression*
+  string_constant_expression(const std::string& val);
+
+  Bexpression*
+  real_part_expression(Bexpression* bcomplex, Location);
+
+  Bexpression*
+  imag_part_expression(Bexpression* bcomplex, Location);
+
+  Bexpression*
+  complex_expression(Bexpression* breal, Bexpression* bimag, Location);
+
   Bexpression*
   convert_expression(Btype* type, Bexpression* expr, Location);
 
@@ -259,6 +272,23 @@ class Gcc_backend : public Backend
   Bexpression*
   binary_expression(Operator, Bexpression*, Bexpression*, Location);
 
+  Bexpression*
+  constructor_expression(Btype*, const std::vector<Bexpression*>&, Location);
+
+  Bexpression*
+  array_constructor_expression(Btype*, const std::vector<unsigned long>&,
+                               const std::vector<Bexpression*>&, Location);
+
+  Bexpression*
+  pointer_offset_expression(Bexpression* base, Bexpression* offset, Location);
+
+  Bexpression*
+  array_index_expression(Bexpression* array, Bexpression* index, Location);
+
+  Bexpression*
+  call_expression(Bexpression* fn, const std::vector<Bexpression*>& args,
+                  Location);
+
   // Statements.
 
   Bstatement*
@@ -294,6 +324,10 @@ class Gcc_backend : public Backend
   Bstatement*
   statement_list(const std::vector<Bstatement*>&);
 
+  Bstatement*
+  exception_handler_statement(Bstatement* bstat, Bstatement* except_stmt,
+                              Bstatement* finally_stmt, Location);
+
   // Blocks.
 
   Bblock*
@@ -372,6 +406,16 @@ class Gcc_backend : public Backend
            bool is_visible, bool is_declaration, bool is_inlinable,
            bool disable_split_stack, bool in_unique_section, Location);
 
+  Bstatement*
+  function_defer_statement(Bfunction* function, Bexpression* undefer,
+                           Bexpression* defer, Location);
+
+  bool
+  function_set_parameters(Bfunction* function, const std::vector<Bvariable*>&);
+
+  bool
+  function_set_body(Bfunction* function, Bstatement* code_stmt);
+
  private:
   // Make a Bexpression from a tree.
   Bexpression*
@@ -974,18 +1018,108 @@ Gcc_backend::complex_constant_expression(Btype* btype, mpfr_t real, mpfr_t imag)
   return tree_to_expr(ret);
 }
 
+// Make a constant string expression.
+
+Bexpression*
+Gcc_backend::string_constant_expression(const std::string& val)
+{
+  tree index_type = build_index_type(size_int(val.length()));
+  tree const_char_type = build_qualified_type(unsigned_char_type_node,
+					      TYPE_QUAL_CONST);
+  tree string_type = build_array_type(const_char_type, index_type);
+  string_type = build_variant_type_copy(string_type);
+  TYPE_STRING_FLAG(string_type) = 1;
+  tree string_val = build_string(val.length(), val.data());
+  TREE_TYPE(string_val) = string_type;
+
+  return this->make_expression(string_val);
+}
+
+// Return the real part of a complex expression.
+
+Bexpression*
+Gcc_backend::real_part_expression(Bexpression* bcomplex, Location location)
+{
+  tree complex_tree = bcomplex->get_tree();
+  if (complex_tree == error_mark_node)
+    return this->error_expression();
+  gcc_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(complex_tree)));
+  tree ret = fold_build1_loc(location.gcc_location(), REALPART_EXPR,
+                             TREE_TYPE(TREE_TYPE(complex_tree)),
+                             complex_tree);
+  return this->make_expression(ret);
+}
+
+// Return the imaginary part of a complex expression.
+
+Bexpression*
+Gcc_backend::imag_part_expression(Bexpression* bcomplex, Location location)
+{
+  tree complex_tree = bcomplex->get_tree();
+  if (complex_tree == error_mark_node)
+    return this->error_expression();
+  gcc_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(complex_tree)));
+  tree ret = fold_build1_loc(location.gcc_location(), IMAGPART_EXPR,
+                             TREE_TYPE(TREE_TYPE(complex_tree)),
+                             complex_tree);
+  return this->make_expression(ret);
+}
+
+// Make a complex expression given its real and imaginary parts.
+
+Bexpression*
+Gcc_backend::complex_expression(Bexpression* breal, Bexpression* bimag,
+                                Location location)
+{
+  tree real_tree = breal->get_tree();
+  tree imag_tree = bimag->get_tree();
+  if (real_tree == error_mark_node || imag_tree == error_mark_node)
+    return this->error_expression();
+  gcc_assert(TYPE_MAIN_VARIANT(TREE_TYPE(real_tree))
+            == TYPE_MAIN_VARIANT(TREE_TYPE(imag_tree)));
+  gcc_assert(SCALAR_FLOAT_TYPE_P(TREE_TYPE(real_tree)));
+  tree ret = fold_build2_loc(location.gcc_location(), COMPLEX_EXPR,
+                             build_complex_type(TREE_TYPE(real_tree)),
+                             real_tree, imag_tree);
+  return this->make_expression(ret);
+}
+
 // An expression that converts an expression to a different type.
 
 Bexpression*
-Gcc_backend::convert_expression(Btype* type, Bexpression* expr, Location)
+Gcc_backend::convert_expression(Btype* type, Bexpression* expr,
+				Location location)
 {
   tree type_tree = type->get_tree();
   tree expr_tree = expr->get_tree();
-  if (type_tree == error_mark_node || expr_tree == error_mark_node)
+  if (type_tree == error_mark_node
+      || expr_tree == error_mark_node
+      || TREE_TYPE(expr_tree) == error_mark_node)
     return this->error_expression();
 
-  tree ret = fold_convert(type_tree, expr_tree);
-  return tree_to_expr(ret);
+  tree ret;
+  if (this->type_size(type) == 0)
+    {
+      // Do not convert zero-sized types.
+      ret = expr_tree;
+    }
+  else if (TREE_CODE(type_tree) == INTEGER_TYPE)
+    ret = fold(convert_to_integer(type_tree, expr_tree));
+  else if (TREE_CODE(type_tree) == REAL_TYPE)
+    ret = fold(convert_to_real(type_tree, expr_tree));
+  else if (TREE_CODE(type_tree) == COMPLEX_TYPE)
+    ret = fold(convert_to_complex(type_tree, expr_tree));
+  else if (TREE_CODE(type_tree) == POINTER_TYPE
+           && TREE_CODE(TREE_TYPE(expr_tree)) == INTEGER_TYPE)
+    ret = fold(convert_to_pointer(type_tree, expr_tree));
+  else if (TREE_CODE(type_tree) == RECORD_TYPE
+           || TREE_CODE(type_tree) == ARRAY_TYPE)
+    ret = fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR,
+                          type_tree, expr_tree);
+  else
+    ret = fold_convert_loc(location.gcc_location(), type_tree, expr_tree);
+
+  return this->make_expression(ret);
 }
 
 // Get the address of a function.
@@ -1243,6 +1377,205 @@ Gcc_backend::binary_expression(Operator op, Bexpression* left,
   return this->make_expression(ret);
 }
 
+// Return an expression that constructs BTYPE with VALS.
+
+Bexpression*
+Gcc_backend::constructor_expression(Btype* btype,
+                                    const std::vector<Bexpression*>& vals,
+                                    Location location)
+{
+  tree type_tree = btype->get_tree();
+  if (type_tree == error_mark_node)
+    return this->error_expression();
+
+  vec<constructor_elt, va_gc> *init;
+  vec_alloc(init, vals.size());
+
+  bool is_constant = true;
+  tree field = TYPE_FIELDS(type_tree);
+  for (std::vector<Bexpression*>::const_iterator p = vals.begin();
+       p != vals.end();
+       ++p, field = DECL_CHAIN(field))
+    {
+      gcc_assert(field != NULL_TREE);
+      tree val = (*p)->get_tree();
+      if (TREE_TYPE(field) == error_mark_node
+          || val == error_mark_node
+          || TREE_TYPE(val) == error_mark_node)
+        return this->error_expression();
+
+      constructor_elt empty = {NULL, NULL};
+      constructor_elt* elt = init->quick_push(empty);
+      elt->index = field;
+      elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
+                                    val);
+      if (!TREE_CONSTANT(elt->value))
+	is_constant = false;
+    }
+  gcc_assert(field == NULL_TREE);
+  tree ret = build_constructor(type_tree, init);
+  if (is_constant)
+    TREE_CONSTANT(ret) = 1;
+
+  return this->make_expression(ret);
+}
+
+Bexpression*
+Gcc_backend::array_constructor_expression(
+    Btype* array_btype, const std::vector<unsigned long>& indexes,
+    const std::vector<Bexpression*>& vals, Location)
+{
+  tree type_tree = array_btype->get_tree();
+  if (type_tree == error_mark_node)
+    return this->error_expression();
+
+  gcc_assert(indexes.size() == vals.size());
+  vec<constructor_elt, va_gc> *init;
+  vec_alloc(init, vals.size());
+
+  bool is_constant = true;
+  for (size_t i = 0; i < vals.size(); ++i)
+    {
+      tree index = size_int(indexes[i]);
+      tree val = (vals[i])->get_tree();
+
+      if (index == error_mark_node
+          || val == error_mark_node)
+        return this->error_expression();
+
+      if (!TREE_CONSTANT(val))
+        is_constant = false;
+
+      constructor_elt empty = {NULL, NULL};
+      constructor_elt* elt = init->quick_push(empty);
+      elt->index = index;
+      elt->value = val;
+    }
+
+  tree ret = build_constructor(type_tree, init);
+  if (is_constant)
+    TREE_CONSTANT(ret) = 1;
+  return this->make_expression(ret);
+}
+
+// Return an expression for the address of BASE[INDEX].
+
+Bexpression*
+Gcc_backend::pointer_offset_expression(Bexpression* base, Bexpression* index,
+                                       Location location)
+{
+  tree base_tree = base->get_tree();
+  tree index_tree = index->get_tree();
+  tree element_type_tree = TREE_TYPE(TREE_TYPE(base_tree));
+  if (base_tree == error_mark_node
+      || TREE_TYPE(base_tree) == error_mark_node
+      || index_tree == error_mark_node
+      || element_type_tree == error_mark_node)
+    return this->error_expression();
+
+  tree element_size = TYPE_SIZE_UNIT(element_type_tree);
+  index_tree = fold_convert_loc(location.gcc_location(), sizetype, index_tree);
+  tree offset = fold_build2_loc(location.gcc_location(), MULT_EXPR, sizetype,
+                                index_tree, element_size);
+  tree ptr = fold_build2_loc(location.gcc_location(), POINTER_PLUS_EXPR,
+                             TREE_TYPE(base_tree), base_tree, offset);
+  return this->make_expression(ptr);
+}
+
+// Return an expression representing ARRAY[INDEX]
+
+Bexpression*
+Gcc_backend::array_index_expression(Bexpression* array, Bexpression* index,
+                                    Location location)
+{
+  tree array_tree = array->get_tree();
+  tree index_tree = index->get_tree();
+  if (array_tree == error_mark_node
+      || TREE_TYPE(array_tree) == error_mark_node
+      || index_tree == error_mark_node)
+    return this->error_expression();
+
+  tree ret = build4_loc(location.gcc_location(), ARRAY_REF,
+			TREE_TYPE(TREE_TYPE(array_tree)), array_tree,
+                        index_tree, NULL_TREE, NULL_TREE);
+  return this->make_expression(ret);
+}
+
+// Create an expression for a call to FN_EXPR with FN_ARGS.
+Bexpression*
+Gcc_backend::call_expression(Bexpression* fn_expr,
+                             const std::vector<Bexpression*>& fn_args,
+                             Location location)
+{
+  tree fn = fn_expr->get_tree();
+  if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
+    return this->error_expression();
+
+  gcc_assert(FUNCTION_POINTER_TYPE_P(TREE_TYPE(fn)));
+  tree rettype = TREE_TYPE(TREE_TYPE(TREE_TYPE(fn)));
+
+  size_t nargs = fn_args.size();
+  tree* args = nargs == 0 ? NULL : new tree[nargs];
+  for (size_t i = 0; i < nargs; ++i)
+    {
+      args[i] = fn_args.at(i)->get_tree();
+      if (args[i] == error_mark_node)
+        return this->error_expression();
+    }
+
+  tree fndecl = fn;
+  if (TREE_CODE(fndecl) == ADDR_EXPR)
+    fndecl = TREE_OPERAND(fndecl, 0);
+
+  // This is to support builtin math functions when using 80387 math.
+  tree excess_type = NULL_TREE;
+  if (optimize
+      && TREE_CODE(fndecl) == FUNCTION_DECL
+      && DECL_IS_BUILTIN(fndecl)
+      && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL
+      && nargs > 0
+      && ((SCALAR_FLOAT_TYPE_P(rettype)
+	   && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0])))
+	  || (COMPLEX_FLOAT_TYPE_P(rettype)
+	      && COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[0])))))
+    {
+      excess_type = excess_precision_type(TREE_TYPE(args[0]));
+      if (excess_type != NULL_TREE)
+	{
+	  tree excess_fndecl = mathfn_built_in(excess_type,
+					       DECL_FUNCTION_CODE(fndecl));
+	  if (excess_fndecl == NULL_TREE)
+	    excess_type = NULL_TREE;
+	  else
+	    {
+	      fn = build_fold_addr_expr_loc(location.gcc_location(),
+                                            excess_fndecl);
+	      for (size_t i = 0; i < nargs; ++i)
+		{
+		  if (SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[i]))
+		      || COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[i])))
+		    args[i] = ::convert(excess_type, args[i]);
+		}
+	    }
+	}
+    }
+
+  tree ret =
+      build_call_array_loc(location.gcc_location(),
+                           excess_type != NULL_TREE ? excess_type : rettype,
+                           fn, nargs, args);
+
+  if (excess_type != NULL_TREE)
+    {
+      // Calling convert here can undo our excess precision change.
+      // That may or may not be a bug in convert_to_real.
+      ret = build1_loc(location.gcc_location(), NOP_EXPR, rettype, ret);
+    }
+
+  delete[] args;
+  return this->make_expression(ret);
+}
+
 // An expression as a statement.
 
 Bstatement*
@@ -1402,6 +1735,40 @@ Gcc_backend::return_statement(Bfunction* bfunction,
   return this->make_statement(ret);
 }
 
+// Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if an
+// error occurs.  EXCEPT_STMT may be NULL.  FINALLY_STMT may be NULL and if not
+// NULL, it will always be executed.  This is used for handling defers in Go
+// functions.  In C++, the resulting code is of this form:
+//   try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; }
+
+Bstatement*
+Gcc_backend::exception_handler_statement(Bstatement* bstat,
+                                         Bstatement* except_stmt,
+                                         Bstatement* finally_stmt,
+                                         Location location)
+{
+  tree stat_tree = bstat->get_tree();
+  tree except_tree = except_stmt == NULL ? NULL_TREE : except_stmt->get_tree();
+  tree finally_tree = finally_stmt == NULL
+      ? NULL_TREE
+      : finally_stmt->get_tree();
+
+  if (stat_tree == error_mark_node
+      || except_tree == error_mark_node
+      || finally_tree == error_mark_node)
+    return this->error_statement();
+
+  if (except_tree != NULL_TREE)
+    stat_tree = build2_loc(location.gcc_location(), TRY_CATCH_EXPR,
+                           void_type_node, stat_tree,
+                           build2_loc(location.gcc_location(), CATCH_EXPR,
+                                      void_type_node, NULL, except_tree));
+  if (finally_tree != NULL_TREE)
+    stat_tree = build2_loc(location.gcc_location(), TRY_FINALLY_EXPR,
+                           void_type_node, stat_tree, finally_tree);
+  return this->make_statement(stat_tree);
+}
+
 // If.
 
 Bstatement*
@@ -2070,6 +2437,78 @@ Gcc_backend::function(Btype* fntype, const std::string& name,
   return new Bfunction(decl);
 }
 
+// Create a statement that runs all deferred calls for FUNCTION.  This should
+// be a statement that looks like this in C++:
+//   finish:
+//     try { UNDEFER; } catch { CHECK_DEFER; goto finish; }
+
+Bstatement*
+Gcc_backend::function_defer_statement(Bfunction* function, Bexpression* undefer,
+                                      Bexpression* defer, Location location)
+{
+  tree undefer_tree = undefer->get_tree();
+  tree defer_tree = defer->get_tree();
+
+  if (undefer_tree == error_mark_node
+      || defer_tree == error_mark_node)
+    return this->error_statement();
+
+  tree stmt_list = NULL;
+  Blabel* blabel = this->label(function, "", location);
+  Bstatement* label_def = this->label_definition_statement(blabel);
+  append_to_statement_list(label_def->get_tree(), &stmt_list);
+
+  Bstatement* jump_stmt = this->goto_statement(blabel, location);
+  tree jump = jump_stmt->get_tree();
+  tree catch_body = build2(COMPOUND_EXPR, void_type_node, defer_tree, jump);
+  catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body);
+  tree try_catch =
+      build2(TRY_CATCH_EXPR, void_type_node, undefer_tree, catch_body);
+  append_to_statement_list(try_catch, &stmt_list);
+
+  return this->make_statement(stmt_list);
+}
+
+// Record PARAM_VARS as the variables to use for the parameters of FUNCTION.
+// This will only be called for a function definition.
+
+bool
+Gcc_backend::function_set_parameters(Bfunction* function,
+                                     const std::vector<Bvariable*>& param_vars)
+{
+  tree func_tree = function->get_tree();
+  if (func_tree == error_mark_node)
+    return false;
+
+  tree params = NULL_TREE;
+  tree *pp = &params;
+  for (std::vector<Bvariable*>::const_iterator pv = param_vars.begin();
+       pv != param_vars.end();
+       ++pv)
+    {
+      *pp = (*pv)->get_tree();
+      gcc_assert(*pp != error_mark_node);
+      pp = &DECL_CHAIN(*pp);
+    }
+  *pp = NULL_TREE;
+  DECL_ARGUMENTS(func_tree) = params;
+  return true;
+}
+
+// Set the function body for FUNCTION using the code in CODE_BLOCK.
+
+bool
+Gcc_backend::function_set_body(Bfunction* function, Bstatement* code_stmt)
+{
+  tree func_tree = function->get_tree();
+  tree code = code_stmt->get_tree();
+
+  if (func_tree == error_mark_node || code == error_mark_node)
+    return false;
+  DECL_SAVED_TREE(func_tree) = code;
+  return true;
+}
+
 // The single backend.
 
 static Gcc_backend gcc_backend;
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index cbe5f22b6ad..fd657ecc989 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/gcc/go/gofrontend/backend.h
@@ -269,6 +269,22 @@ class Backend
   virtual Bexpression*
   complex_constant_expression(Btype* btype, mpfr_t real, mpfr_t imag) = 0;
 
+  // Return an expression for the string value VAL.
+  virtual Bexpression*
+  string_constant_expression(const std::string& val) = 0;
+
+  // Return an expression for the real part of BCOMPLEX.
+  virtual Bexpression*
+  real_part_expression(Bexpression* bcomplex, Location) = 0;
+
+  // Return an expression for the imaginary part of BCOMPLEX.
+  virtual Bexpression*
+  imag_part_expression(Bexpression* bcomplex, Location) = 0;
+
+  // Return an expression for the complex number (BREAL, BIMAG).
+  virtual Bexpression*
+  complex_expression(Bexpression* breal, Bexpression* bimag, Location) = 0;
+
   // Return an expression that converts EXPR to TYPE.
   virtual Bexpression*
   convert_expression(Btype* type, Bexpression* expr, Location) = 0;
@@ -312,6 +328,38 @@ class Backend
   binary_expression(Operator op, Bexpression* left, Bexpression* right,
                     Location) = 0;
 
+  // Return an expression that constructs BTYPE with VALS.  BTYPE must be the
+  // backend representation a of struct.  VALS must be in the same order as the
+  // corresponding fields in BTYPE.
+  virtual Bexpression*
+  constructor_expression(Btype* btype, const std::vector<Bexpression*>& vals,
+                         Location) = 0;
+
+  // Return an expression that constructs an array of BTYPE with INDEXES and
+  // VALS.  INDEXES and VALS must have the same amount of elements. Each index
+  // in INDEXES must be in the same order as the corresponding value in VALS.
+  virtual Bexpression*
+  array_constructor_expression(Btype* btype,
+                               const std::vector<unsigned long>& indexes,
+                               const std::vector<Bexpression*>& vals,
+                               Location) = 0;
+
+  // Return an expression for the address of BASE[INDEX].
+  // BASE has a pointer type.  This is used for slice indexing.
+  virtual Bexpression*
+  pointer_offset_expression(Bexpression* base, Bexpression* index,
+                            Location) = 0;
+
+  // Return an expression for ARRAY[INDEX] as an l-value.  ARRAY is a valid
+  // fixed-length array, not a slice.
+  virtual Bexpression*
+  array_index_expression(Bexpression* array, Bexpression* index, Location) = 0;
+
+  // Create an expression for a call to FN with ARGS.
+  virtual Bexpression*
+  call_expression(Bexpression* fn, const std::vector<Bexpression*>& args,
+                  Location) = 0;
+
   // Statements.
 
   // Create an error statement.  This is used for cases which should
@@ -367,6 +415,15 @@ class Backend
   virtual Bstatement*
   statement_list(const std::vector<Bstatement*>&) = 0;
 
+  // Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if
+  // an exception occurs. EXCEPT_STMT may be NULL.  FINALLY_STMT may be NULL and
+  // if not NULL, it will always be executed.  This is used for handling defers
+  // in Go functions.  In C++, the resulting code is of this form:
+  //   try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; }
+  virtual Bstatement*
+  exception_handler_statement(Bstatement* bstat, Bstatement* except_stmt,
+                              Bstatement* finally_stmt, Location) = 0;
+
   // Blocks.
 
   // Create a block.  The frontend will call this function when it
@@ -570,6 +627,26 @@ class Backend
   function(Btype* fntype, const std::string& name, const std::string& asm_name,
            bool is_visible, bool is_declaration, bool is_inlinable,
            bool disable_split_stack, bool in_unique_section, Location) = 0;
+
+  // Create a statement that runs all deferred calls for FUNCTION.  This should
+  // be a statement that looks like this in C++:
+  //   finish:
+  //     try { UNDEFER; } catch { CHECK_DEFER; goto finish; }
+  virtual Bstatement*
+  function_defer_statement(Bfunction* function, Bexpression* undefer,
+                           Bexpression* check_defer, Location) = 0;
+
+  // Record PARAM_VARS as the variables to use for the parameters of FUNCTION.
+  // This will only be called for a function definition.  Returns true on
+  // success, false on failure.
+  virtual bool
+  function_set_parameters(Bfunction* function,
+                         const std::vector<Bvariable*>& param_vars) = 0;
+
+  // Set the function body for FUNCTION using the code in CODE_STMT.  Returns
+  // true on success, false on failure.
+  virtual bool
+  function_set_body(Bfunction* function, Bstatement* code_stmt) = 0;
 };
 
 // The backend interface has to define this function.
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index f45b4a22709..bd2e3183bfe 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -140,128 +140,81 @@ Expression::determine_type_no_context()
   this->do_determine_type(&context);
 }
 
-// Return a tree handling any conversions which must be done during
+// Return an expression handling any conversions which must be done during
 // assignment.
 
-tree
-Expression::convert_for_assignment(Translate_context* context, Type* lhs_type,
-				   Type* rhs_type, tree rhs_tree,
-				   Location location)
+Expression*
+Expression::convert_for_assignment(Gogo* gogo, Type* lhs_type,
+				   Expression* rhs, Location location)
 {
-  if (lhs_type->is_error() || rhs_type->is_error())
-    return error_mark_node;
-
-  if (rhs_tree == error_mark_node || TREE_TYPE(rhs_tree) == error_mark_node)
-    return error_mark_node;
-
-  Gogo* gogo = context->gogo();
-
-  tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo));
-  if (lhs_type_tree == error_mark_node)
-    return error_mark_node;
+  Type* rhs_type = rhs->type();
+  if (lhs_type->is_error()
+      || rhs_type->is_error()
+      || rhs->is_error_expression())
+    return Expression::make_error(location);
 
   if (lhs_type->forwarded() != rhs_type->forwarded()
       && lhs_type->interface_type() != NULL)
     {
       if (rhs_type->interface_type() == NULL)
-	return Expression::convert_type_to_interface(context, lhs_type,
-						     rhs_type, rhs_tree,
-						     location);
+        return Expression::convert_type_to_interface(lhs_type, rhs, location);
       else
-	return Expression::convert_interface_to_interface(context, lhs_type,
-							  rhs_type, rhs_tree,
-							  false, location);
+        return Expression::convert_interface_to_interface(lhs_type, rhs, false,
+                                                          location);
     }
   else if (lhs_type->forwarded() != rhs_type->forwarded()
 	   && rhs_type->interface_type() != NULL)
-    return Expression::convert_interface_to_type(context, lhs_type, rhs_type,
-						 rhs_tree, location);
+    return Expression::convert_interface_to_type(lhs_type, rhs, location);
   else if (lhs_type->is_slice_type() && rhs_type->is_nil_type())
     {
-      // Assigning nil to an open array.
-      go_assert(TREE_CODE(lhs_type_tree) == RECORD_TYPE);
-
-      vec<constructor_elt, va_gc> *init;
-      vec_alloc(init, 3);
-
-      constructor_elt empty = {NULL, NULL};
-      constructor_elt* elt = init->quick_push(empty);
-      tree field = TYPE_FIELDS(lhs_type_tree);
-      go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
-			"__values") == 0);
-      elt->index = field;
-      elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
-
-      elt = init->quick_push(empty);
-      field = DECL_CHAIN(field);
-      go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
-			"__count") == 0);
-      elt->index = field;
-      elt->value = fold_convert(TREE_TYPE(field), integer_zero_node);
-
-      elt = init->quick_push(empty);
-      field = DECL_CHAIN(field);
-      go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
-			"__capacity") == 0);
-      elt->index = field;
-      elt->value = fold_convert(TREE_TYPE(field), integer_zero_node);
-
-      tree val = build_constructor(lhs_type_tree, init);
-      TREE_CONSTANT(val) = 1;
-
-      return val;
+      // Assigning nil to a slice.
+      mpz_t zval;
+      mpz_init_set_ui(zval, 0UL);
+      Expression* zero = Expression::make_integer(&zval, NULL, location);
+      mpz_clear(zval);
+      Expression* nil = Expression::make_nil(location);
+      return Expression::make_slice_value(lhs_type, nil, zero, zero, location);
     }
   else if (rhs_type->is_nil_type())
-    {
-      // The left hand side should be a pointer type at the tree
-      // level.
-      go_assert(POINTER_TYPE_P(lhs_type_tree));
-      return fold_convert(lhs_type_tree, null_pointer_node);
-    }
-  else if (lhs_type_tree == TREE_TYPE(rhs_tree))
+    return Expression::make_nil(location);
+  else if (Type::are_identical(lhs_type, rhs_type, false, NULL))
     {
       // No conversion is needed.
-      return rhs_tree;
+      return rhs;
     }
-  else if (POINTER_TYPE_P(lhs_type_tree)
-	   || INTEGRAL_TYPE_P(lhs_type_tree)
-	   || SCALAR_FLOAT_TYPE_P(lhs_type_tree)
-	   || COMPLEX_FLOAT_TYPE_P(lhs_type_tree))
-    return fold_convert_loc(location.gcc_location(), lhs_type_tree, rhs_tree);
-  else if ((TREE_CODE(lhs_type_tree) == RECORD_TYPE
-	    && TREE_CODE(TREE_TYPE(rhs_tree)) == RECORD_TYPE)
-	   || (TREE_CODE(lhs_type_tree) == ARRAY_TYPE
-	       && TREE_CODE(TREE_TYPE(rhs_tree)) == ARRAY_TYPE))
+  else if (lhs_type->points_to() != NULL)
+    return Expression::make_unsafe_cast(lhs_type, rhs, location);
+  else if (lhs_type->is_numeric_type())
+    return Expression::make_cast(lhs_type, rhs, location);
+  else if ((lhs_type->struct_type() != NULL
+            && rhs_type->struct_type() != NULL)
+           || (lhs_type->array_type() != NULL
+               && rhs_type->array_type() != NULL))
     {
       // Avoid confusion from zero sized variables which may be
       // represented as non-zero-sized.
-      if (int_size_in_bytes(lhs_type_tree) == 0
-	  || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0)
-	return rhs_tree;
+      // TODO(cmang): This check is for a GCC-specific issue, and should be
+      // removed from the frontend.  FIXME.
+      size_t lhs_size = gogo->backend()->type_size(lhs_type->get_backend(gogo));
+      size_t rhs_size = gogo->backend()->type_size(rhs_type->get_backend(gogo));
+      if (rhs_size == 0 || lhs_size == 0)
+	return rhs;
 
       // This conversion must be permitted by Go, or we wouldn't have
       // gotten here.
-      go_assert(int_size_in_bytes(lhs_type_tree)
-		== int_size_in_bytes(TREE_TYPE(rhs_tree)));
-      return fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR,
-                             lhs_type_tree, rhs_tree);
+      return Expression::make_unsafe_cast(lhs_type, rhs, location);
     }
   else
-    {
-      go_assert(useless_type_conversion_p(lhs_type_tree, TREE_TYPE(rhs_tree)));
-      return rhs_tree;
-    }
+    return rhs;
 }
 
-// Return a tree for a conversion from a non-interface type to an
+// Return an expression for a conversion from a non-interface type to an
 // interface type.
 
-tree
-Expression::convert_type_to_interface(Translate_context* context,
-				      Type* lhs_type, Type* rhs_type,
-				      tree rhs_tree, Location location)
+Expression*
+Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs,
+                                      Location location)
 {
-  Gogo* gogo = context->gogo();
   Interface_type* lhs_interface_type = lhs_type->interface_type();
   bool lhs_is_empty = lhs_interface_type->is_empty();
 
@@ -270,29 +223,22 @@ Expression::convert_type_to_interface(Translate_context* context,
 
   // When setting an interface to nil, we just set both fields to
   // NULL.
+  Type* rhs_type = rhs->type();
   if (rhs_type->is_nil_type())
     {
-      Btype* lhs_btype = lhs_type->get_backend(gogo);
-      return expr_to_tree(gogo->backend()->zero_expression(lhs_btype));
+      Expression* nil = Expression::make_nil(location);
+      return Expression::make_interface_value(lhs_type, nil, nil, location);
     }
 
   // This should have been checked already.
   go_assert(lhs_interface_type->implements_interface(rhs_type, NULL));
 
-  tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo));
-  if (lhs_type_tree == error_mark_node)
-    return error_mark_node;
-
   // An interface is a tuple.  If LHS_TYPE is an empty interface type,
   // then the first field is the type descriptor for RHS_TYPE.
   // Otherwise it is the interface method table for RHS_TYPE.
-  tree first_field_value;
+  Expression* first_field;
   if (lhs_is_empty)
-    {
-      Bexpression* rhs_bexpr =
-          rhs_type->type_descriptor_pointer(gogo, location);
-      first_field_value = expr_to_tree(rhs_bexpr);
-    }
+    first_field = Expression::make_type_descriptor(rhs_type, location);
   else
     {
       // Build the interface method table for this interface and this
@@ -307,131 +253,72 @@ Expression::convert_type_to_interface(Translate_context* context,
 	  rhs_struct_type = rhs_type->deref()->struct_type();
 	  is_pointer = true;
 	}
-      tree method_table;
       if (rhs_named_type != NULL)
-	method_table =
-	  rhs_named_type->interface_method_table(gogo, lhs_interface_type,
-						 is_pointer);
+	first_field =
+	  rhs_named_type->interface_method_table(lhs_interface_type,
+                                                 is_pointer);
       else if (rhs_struct_type != NULL)
-	method_table =
-	  rhs_struct_type->interface_method_table(gogo, lhs_interface_type,
-						  is_pointer);
+	first_field =
+	  rhs_struct_type->interface_method_table(lhs_interface_type,
+                                                  is_pointer);
       else
-	method_table = null_pointer_node;
-      first_field_value = fold_convert_loc(location.gcc_location(),
-                                           const_ptr_type_node, method_table);
+	first_field = Expression::make_nil(location);
     }
-  if (first_field_value == error_mark_node)
-    return error_mark_node;
-
-  // Start building a constructor for the value we will return.
-
-  vec<constructor_elt, va_gc> *init;
-  vec_alloc(init, 2);
-
-  constructor_elt empty = {NULL, NULL};
-  constructor_elt* elt = init->quick_push(empty);
-  tree field = TYPE_FIELDS(lhs_type_tree);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
-		    (lhs_is_empty ? "__type_descriptor" : "__methods")) == 0);
-  elt->index = field;
-  elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
-                                first_field_value);
-
-  elt = init->quick_push(empty);
-  field = DECL_CHAIN(field);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
-  elt->index = field;
 
+  Expression* obj;
   if (rhs_type->points_to() != NULL)
     {
-      //  We are assigning a pointer to the interface; the interface
+      // We are assigning a pointer to the interface; the interface
       // holds the pointer itself.
-      elt->value = rhs_tree;
-      return build_constructor(lhs_type_tree, init);
+      obj = rhs;
     }
-
-  // We are assigning a non-pointer value to the interface; the
-  // interface gets a copy of the value in the heap.
-
-  tree object_size = TYPE_SIZE_UNIT(TREE_TYPE(rhs_tree));
-
-  tree space = gogo->allocate_memory(rhs_type, object_size, location);
-  space = fold_convert_loc(location.gcc_location(),
-                           build_pointer_type(TREE_TYPE(rhs_tree)), space);
-  space = save_expr(space);
-
-  tree ref = build_fold_indirect_ref_loc(location.gcc_location(), space);
-  TREE_THIS_NOTRAP(ref) = 1;
-  tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR,
-                             void_type_node, ref, rhs_tree);
-
-  elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
-                                space);
-
-  return build2(COMPOUND_EXPR, lhs_type_tree, set,
-		build_constructor(lhs_type_tree, init));
-}
-
-// Return a tree for the type descriptor of RHS_TREE, which has
-// interface type RHS_TYPE.  If RHS_TREE is nil the result will be
-// NULL.
-
-tree
-Expression::get_interface_type_descriptor(Translate_context*,
-					  Type* rhs_type, tree rhs_tree,
-					  Location location)
-{
-  tree rhs_type_tree = TREE_TYPE(rhs_tree);
-  go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
-  tree rhs_field = TYPE_FIELDS(rhs_type_tree);
-  tree v = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
-		  NULL_TREE);
-  if (rhs_type->interface_type()->is_empty())
+  else
     {
-      go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)),
-			"__type_descriptor") == 0);
-      return v;
+      // We are assigning a non-pointer value to the interface; the
+      // interface gets a copy of the value in the heap.
+      obj = Expression::make_heap_expression(rhs, location);
     }
 
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__methods")
-	     == 0);
-  go_assert(POINTER_TYPE_P(TREE_TYPE(v)));
-  v = save_expr(v);
-  tree v1 = build_fold_indirect_ref_loc(location.gcc_location(), v);
-  go_assert(TREE_CODE(TREE_TYPE(v1)) == RECORD_TYPE);
-  tree f = TYPE_FIELDS(TREE_TYPE(v1));
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(f)), "__type_descriptor")
-	     == 0);
-  v1 = build3(COMPONENT_REF, TREE_TYPE(f), v1, f, NULL_TREE);
-
-  tree eq = fold_build2_loc(location.gcc_location(), EQ_EXPR, boolean_type_node,
-                            v, fold_convert_loc(location.gcc_location(),
-                                                TREE_TYPE(v),
-                                                null_pointer_node));
-  tree n = fold_convert_loc(location.gcc_location(), TREE_TYPE(v1),
-                            null_pointer_node);
-  return fold_build3_loc(location.gcc_location(), COND_EXPR, TREE_TYPE(v1),
-			 eq, n, v1);
+  return Expression::make_interface_value(lhs_type, first_field, obj, location);
 }
 
-// Return a tree for the conversion of an interface type to an
+// Return an expression for the type descriptor of RHS.
+
+Expression*
+Expression::get_interface_type_descriptor(Expression* rhs)
+{
+  go_assert(rhs->type()->interface_type() != NULL);
+  Location location = rhs->location();
+
+  // The type descriptor is the first field of an empty interface.
+  if (rhs->type()->interface_type()->is_empty())
+    return Expression::make_interface_info(rhs, INTERFACE_INFO_TYPE_DESCRIPTOR,
+                                           location);
+
+  Expression* mtable =
+      Expression::make_interface_info(rhs, INTERFACE_INFO_METHODS, location);
+
+  Expression* descriptor =
+      Expression::make_unary(OPERATOR_MULT, mtable, location);
+  descriptor = Expression::make_field_reference(descriptor, 0, location);
+  Expression* nil = Expression::make_nil(location);
+
+  Expression* eq =
+      Expression::make_binary(OPERATOR_EQEQ, mtable, nil, location);
+  return Expression::make_conditional(eq, nil, descriptor, location);
+}
+
+// Return an expression for the conversion of an interface type to an
 // interface type.
 
-tree
-Expression::convert_interface_to_interface(Translate_context* context,
-					   Type *lhs_type, Type *rhs_type,
-					   tree rhs_tree, bool for_type_guard,
-					   Location location)
+Expression*
+Expression::convert_interface_to_interface(Type *lhs_type, Expression* rhs,
+                                           bool for_type_guard,
+                                           Location location)
 {
-  Gogo* gogo = context->gogo();
   Interface_type* lhs_interface_type = lhs_type->interface_type();
   bool lhs_is_empty = lhs_interface_type->is_empty();
 
-  tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo));
-  if (lhs_type_tree == error_mark_node)
-    return error_mark_node;
-
   // In the general case this requires runtime examination of the type
   // method table to match it up with the interface methods.
 
@@ -442,169 +329,75 @@ Expression::convert_interface_to_interface(Translate_context* context,
 
   // Get the type descriptor for the right hand side.  This will be
   // NULL for a nil interface.
+  Expression* rhs_type_expr = Expression::get_interface_type_descriptor(rhs);
+  Expression* lhs_type_expr =
+      Expression::make_type_descriptor(lhs_type, location);
 
-  if (!DECL_P(rhs_tree))
-    rhs_tree = save_expr(rhs_tree);
-
-  tree rhs_type_descriptor =
-    Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree,
-					      location);
-
-  // The result is going to be a two element constructor.
-
-  vec<constructor_elt, va_gc> *init;
-  vec_alloc (init, 2);
-
-  constructor_elt empty = {NULL, NULL};
-  constructor_elt* elt = init->quick_push(empty);
-  tree field = TYPE_FIELDS(lhs_type_tree);
-  elt->index = field;
-
+  Expression* first_field;
   if (for_type_guard)
     {
       // A type assertion fails when converting a nil interface.
-      Bexpression* lhs_type_expr = lhs_type->type_descriptor_pointer(gogo,
-                                                                     location);
-      tree lhs_type_descriptor = expr_to_tree(lhs_type_expr);
-      static tree assert_interface_decl;
-      tree call = Gogo::call_builtin(&assert_interface_decl,
-				     location,
-				     "__go_assert_interface",
-				     2,
-				     ptr_type_node,
-				     TREE_TYPE(lhs_type_descriptor),
-				     lhs_type_descriptor,
-				     TREE_TYPE(rhs_type_descriptor),
-				     rhs_type_descriptor);
-      if (call == error_mark_node)
-	return error_mark_node;
-      // This will panic if the interface conversion fails.
-      TREE_NOTHROW(assert_interface_decl) = 0;
-      elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
-                                    call);
+      first_field =
+          Runtime::make_call(Runtime::ASSERT_INTERFACE, location, 2,
+                             lhs_type_expr, rhs_type_expr);
     }
   else if (lhs_is_empty)
     {
-      // A convertion to an empty interface always succeeds, and the
+      // A conversion to an empty interface always succeeds, and the
       // first field is just the type descriptor of the object.
-      go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
-			"__type_descriptor") == 0);
-      elt->value = fold_convert_loc(location.gcc_location(),
-				    TREE_TYPE(field), rhs_type_descriptor);
+      first_field = rhs_type_expr;
     }
   else
     {
       // A conversion to a non-empty interface may fail, but unlike a
       // type assertion converting nil will always succeed.
-      go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods")
-		 == 0);
-      Bexpression* lhs_type_expr = lhs_type->type_descriptor_pointer(gogo,
-                                                                     location);
-      tree lhs_type_descriptor = expr_to_tree(lhs_type_expr);
-
-      static tree convert_interface_decl;
-      tree call = Gogo::call_builtin(&convert_interface_decl,
-				     location,
-				     "__go_convert_interface",
-				     2,
-				     ptr_type_node,
-				     TREE_TYPE(lhs_type_descriptor),
-				     lhs_type_descriptor,
-				     TREE_TYPE(rhs_type_descriptor),
-				     rhs_type_descriptor);
-      if (call == error_mark_node)
-	return error_mark_node;
-      // This will panic if the interface conversion fails.
-      TREE_NOTHROW(convert_interface_decl) = 0;
-      elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field),
-                                    call);
+      first_field =
+          Runtime::make_call(Runtime::CONVERT_INTERFACE, location, 2,
+                             lhs_type_expr, rhs_type_expr);
     }
 
   // The second field is simply the object pointer.
-
-  elt = init->quick_push(empty);
-  field = DECL_CHAIN(field);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
-  elt->index = field;
-
-  tree rhs_type_tree = TREE_TYPE(rhs_tree);
-  go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
-  tree rhs_field = DECL_CHAIN(TYPE_FIELDS(rhs_type_tree));
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0);
-  elt->value = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
-		      NULL_TREE);
-
-  return build_constructor(lhs_type_tree, init);
+  Expression* obj =
+      Expression::make_interface_info(rhs, INTERFACE_INFO_OBJECT, location);
+  return Expression::make_interface_value(lhs_type, first_field, obj, location);
 }
 
-// Return a tree for the conversion of an interface type to a
+// Return an expression for the conversion of an interface type to a
 // non-interface type.
 
-tree
-Expression::convert_interface_to_type(Translate_context* context,
-				      Type *lhs_type, Type* rhs_type,
-				      tree rhs_tree, Location location)
+Expression*
+Expression::convert_interface_to_type(Type *lhs_type, Expression* rhs,
+                                      Location location)
 {
-  Gogo* gogo = context->gogo();
-  tree rhs_type_tree = TREE_TYPE(rhs_tree);
-
-  tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo));
-  if (lhs_type_tree == error_mark_node)
-    return error_mark_node;
-
   // Call a function to check that the type is valid.  The function
   // will panic with an appropriate runtime type error if the type is
   // not valid.
-  Bexpression* lhs_type_expr = lhs_type->type_descriptor_pointer(gogo,
-                                                                 location);
-  tree lhs_type_descriptor = expr_to_tree(lhs_type_expr);
+  Expression* lhs_type_expr = Expression::make_type_descriptor(lhs_type,
+                                                                location);
+  Expression* rhs_descriptor =
+      Expression::get_interface_type_descriptor(rhs);
 
-  if (!DECL_P(rhs_tree))
-    rhs_tree = save_expr(rhs_tree);
+  Type* rhs_type = rhs->type();
+  Expression* rhs_inter_expr = Expression::make_type_descriptor(rhs_type,
+                                                                location);
 
-  tree rhs_type_descriptor =
-    Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree,
-					      location);
-
-  Bexpression* rhs_inter_expr = rhs_type->type_descriptor_pointer(gogo,
-                                                                  location);
-  tree rhs_inter_descriptor = expr_to_tree(rhs_inter_expr);
-
-  static tree check_interface_type_decl;
-  tree call = Gogo::call_builtin(&check_interface_type_decl,
-				 location,
-				 "__go_check_interface_type",
-				 3,
-				 void_type_node,
-				 TREE_TYPE(lhs_type_descriptor),
-				 lhs_type_descriptor,
-				 TREE_TYPE(rhs_type_descriptor),
-				 rhs_type_descriptor,
-				 TREE_TYPE(rhs_inter_descriptor),
-				 rhs_inter_descriptor);
-  if (call == error_mark_node)
-    return error_mark_node;
-  // This call will panic if the conversion is invalid.
-  TREE_NOTHROW(check_interface_type_decl) = 0;
+  Expression* check_iface = Runtime::make_call(Runtime::CHECK_INTERFACE_TYPE,
+                                               location, 3, lhs_type_expr,
+                                               rhs_descriptor, rhs_inter_expr);
 
   // If the call succeeds, pull out the value.
-  go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE);
-  tree rhs_field = DECL_CHAIN(TYPE_FIELDS(rhs_type_tree));
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0);
-  tree val = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field,
-		    NULL_TREE);
+  Expression* obj = Expression::make_interface_info(rhs, INTERFACE_INFO_OBJECT,
+                                                    location);
 
   // If the value is a pointer, then it is the value we want.
   // Otherwise it points to the value.
   if (lhs_type->points_to() == NULL)
     {
-      val = fold_convert_loc(location.gcc_location(),
-                             build_pointer_type(lhs_type_tree), val);
-      val = build_fold_indirect_ref_loc(location.gcc_location(), val);
+      obj = Expression::make_unsafe_cast(Type::make_pointer_type(lhs_type), obj,
+                                         location);
+      obj = Expression::make_unary(OPERATOR_MULT, obj, location);
     }
-
-  return build2(COMPOUND_EXPR, lhs_type_tree, call,
-		fold_convert_loc(location.gcc_location(), lhs_type_tree, val));
+  return Expression::make_compound(check_iface, obj, location);
 }
 
 // Convert an expression to a tree.  This is implemented by the child
@@ -674,54 +467,71 @@ Expression::backend_numeric_constant_expression(Translate_context* context,
   return ret;
 }
 
-// Return a tree which evaluates to true if VAL, of arbitrary integer
-// type, is negative or is more than the maximum value of BOUND_TYPE.
-// If SOFAR is not NULL, it is or'red into the result.  The return
-// value may be NULL if SOFAR is NULL.
+// Return an expression which evaluates to true if VAL, of arbitrary integer
+// type, is negative or is more than the maximum value of the Go type "int".
 
-tree
-Expression::check_bounds(tree val, tree bound_type, tree sofar,
-			 Location loc)
+Expression*
+Expression::check_bounds(Expression* val, Location loc)
 {
-  tree val_type = TREE_TYPE(val);
-  tree ret = NULL_TREE;
+  Type* val_type = val->type();
+  Type* bound_type = Type::lookup_integer_type("int");
 
-  if (!TYPE_UNSIGNED(val_type))
+  int val_type_size;
+  bool val_is_unsigned = false;
+  if (val_type->integer_type() != NULL)
     {
-      ret = fold_build2_loc(loc.gcc_location(), LT_EXPR, boolean_type_node, val,
-			    build_int_cst(val_type, 0));
-      if (ret == boolean_false_node)
-	ret = NULL_TREE;
+      val_type_size = val_type->integer_type()->bits();
+      val_is_unsigned = val_type->integer_type()->is_unsigned();
+    }
+  else
+    {
+      if (!val_type->is_numeric_type()
+          || !Type::are_convertible(bound_type, val_type, NULL))
+        {
+          go_assert(saw_errors());
+          return Expression::make_boolean(true, loc);
+        }
+
+      if (val_type->complex_type() != NULL)
+        val_type_size = val_type->complex_type()->bits();
+      else
+        val_type_size = val_type->float_type()->bits();
     }
 
-  HOST_WIDE_INT val_type_size = int_size_in_bytes(val_type);
-  HOST_WIDE_INT bound_type_size = int_size_in_bytes(bound_type);
-  go_assert(val_type_size != -1 && bound_type_size != -1);
+  Expression* negative_index = Expression::make_boolean(false, loc);
+  Expression* index_overflows = Expression::make_boolean(false, loc);
+  if (!val_is_unsigned)
+    {
+      mpz_t zval;
+      mpz_init_set_ui(zval, 0UL);
+      Expression* zero = Expression::make_integer(&zval, val_type, loc);
+      mpz_clear(zval);
+
+      negative_index = Expression::make_binary(OPERATOR_LT, val, zero, loc);
+    }
+
+  int bound_type_size = bound_type->integer_type()->bits();
   if (val_type_size > bound_type_size
       || (val_type_size == bound_type_size
-	  && TYPE_UNSIGNED(val_type)
-	  && !TYPE_UNSIGNED(bound_type)))
+	  && val_is_unsigned))
     {
-      tree max = TYPE_MAX_VALUE(bound_type);
-      tree big = fold_build2_loc(loc.gcc_location(), GT_EXPR, boolean_type_node,
-                                 val, fold_convert_loc(loc.gcc_location(),
-                                                       val_type, max));
-      if (big == boolean_false_node)
-	;
-      else if (ret == NULL_TREE)
-	ret = big;
-      else
-	ret = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
-                              boolean_type_node, ret, big);
+      mpz_t one;
+      mpz_init_set_ui(one, 1UL);
+
+      // maxval = 2^(bound_type_size - 1) - 1
+      mpz_t maxval;
+      mpz_init(maxval);
+      mpz_mul_2exp(maxval, one, bound_type_size - 1);
+      mpz_sub_ui(maxval, maxval, 1);
+      Expression* max = Expression::make_integer(&maxval, val_type, loc);
+      mpz_clear(one);
+      mpz_clear(maxval);
+
+      index_overflows = Expression::make_binary(OPERATOR_GT, val, max, loc);
     }
 
-  if (ret == NULL_TREE)
-    return sofar;
-  else if (sofar == NULL_TREE)
-    return ret;
-  else
-    return fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, boolean_type_node,
-			   sofar, ret);
+  return Expression::make_binary(OPERATOR_OROR, negative_index, index_overflows,
+                                 loc);
 }
 
 void
@@ -1719,7 +1529,23 @@ String_expression::do_determine_type(const Type_context* context)
 tree
 String_expression::do_get_tree(Translate_context* context)
 {
-  return context->gogo()->go_string_constant_tree(this->val_);
+  Gogo* gogo = context->gogo();
+  Btype* btype = Type::make_string_type()->get_backend(gogo);
+
+  Location loc = this->location();
+  std::vector<Bexpression*> init(2);
+  Bexpression* str_cst =
+      gogo->backend()->string_constant_expression(this->val_);
+  init[0] = gogo->backend()->address_expression(str_cst, loc);
+
+  Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
+  mpz_t lenval;
+  mpz_init_set_ui(lenval, this->val_.length());
+  init[1] = gogo->backend()->integer_constant_expression(int_btype, lenval);
+  mpz_clear(lenval);
+
+  Bexpression* ret = gogo->backend()->constructor_expression(btype, init, loc);
+  return expr_to_tree(ret);
 }
 
  // Write string literal to string dump.
@@ -1826,6 +1652,116 @@ Expression::make_string(const std::string& val, Location location)
   return new String_expression(val, location);
 }
 
+// An expression that evaluates to some characteristic of a string.
+// This is used when indexing, bound-checking, or nil checking a string.
+
+class String_info_expression : public Expression
+{
+ public:
+  String_info_expression(Expression* string, String_info string_info,
+                        Location location)
+    : Expression(EXPRESSION_STRING_INFO, location),
+      string_(string), string_info_(string_info)
+  { }
+
+ protected:
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*)
+  { go_unreachable(); }
+
+  Expression*
+  do_copy()
+  {
+    return new String_info_expression(this->string_->copy(), this->string_info_,
+				      this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context* context);
+
+  void
+  do_dump_expression(Ast_dump_context*) const;
+
+  void
+  do_issue_nil_check()
+  { this->string_->issue_nil_check(); }
+
+ private:
+  // The string for which we are getting information.
+  Expression* string_;
+  // What information we want.
+  String_info string_info_;
+};
+
+// Return the type of the string info.
+
+Type*
+String_info_expression::do_type()
+{
+  switch (this->string_info_)
+    {
+    case STRING_INFO_DATA:
+      {
+	Type* byte_type = Type::lookup_integer_type("uint8");
+	return Type::make_pointer_type(byte_type);
+      }
+    case STRING_INFO_LENGTH:
+        return Type::lookup_integer_type("int");
+    default:
+      go_unreachable();
+    }
+}
+
+// Return string information in GENERIC.
+
+tree
+String_info_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+
+  Bexpression* bstring = tree_to_expr(this->string_->get_tree(context));
+  Bexpression* ret;
+  switch (this->string_info_)
+    {
+    case STRING_INFO_DATA:
+    case STRING_INFO_LENGTH:
+      ret = gogo->backend()->struct_field_expression(bstring, this->string_info_,
+                                                     this->location());
+      break;
+    default:
+      go_unreachable();
+    }
+  return expr_to_tree(ret);
+}
+
+// Dump ast representation for a type info expression.
+
+void
+String_info_expression::do_dump_expression(
+    Ast_dump_context* ast_dump_context) const
+{
+  ast_dump_context->ostream() << "stringinfo(";
+  this->string_->dump_expression(ast_dump_context);
+  ast_dump_context->ostream() << ",";
+  ast_dump_context->ostream() << 
+      (this->string_info_ == STRING_INFO_DATA ? "data" 
+    : this->string_info_ == STRING_INFO_LENGTH ? "length"
+    : "unknown");
+  ast_dump_context->ostream() << ")";
+}
+
+// Make a string info expression.
+
+Expression*
+Expression::make_string_info(Expression* string, String_info string_info,
+                            Location location)
+{
+  return new String_info_expression(string, string_info, location);
+}
+
 // Make an integer expression.
 
 class Integer_expression : public Expression
@@ -2826,16 +2762,8 @@ Const_expression::do_check_types(Gogo*)
 tree
 Const_expression::do_get_tree(Translate_context* context)
 {
-  Gogo* gogo = context->gogo();
-  tree type_tree;
-  if (this->type_ == NULL)
-    type_tree = NULL_TREE;
-  else
-    {
-      type_tree = type_to_tree(this->type_->get_backend(gogo));
-      if (type_tree == error_mark_node)
-	return error_mark_node;
-    }
+  if (this->type_ != NULL && this->type_->is_error())
+    return error_mark_node;
 
   // If the type has been set for this expression, but the underlying
   // object is an abstract int or float, we try to get the abstract
@@ -2855,24 +2783,15 @@ Const_expression::do_get_tree(Translate_context* context)
 	}
     }
 
-  tree const_tree = this->constant_->get_tree(gogo, context->function());
-  if (this->type_ == NULL
-      || const_tree == error_mark_node
-      || TREE_TYPE(const_tree) == error_mark_node)
-    return const_tree;
-
-  tree ret;
-  if (TYPE_MAIN_VARIANT(type_tree) == TYPE_MAIN_VARIANT(TREE_TYPE(const_tree)))
-    ret = fold_convert(type_tree, const_tree);
-  else if (TREE_CODE(type_tree) == INTEGER_TYPE)
-    ret = fold(convert_to_integer(type_tree, const_tree));
-  else if (TREE_CODE(type_tree) == REAL_TYPE)
-    ret = fold(convert_to_real(type_tree, const_tree));
-  else if (TREE_CODE(type_tree) == COMPLEX_TYPE)
-    ret = fold(convert_to_complex(type_tree, const_tree));
-  else
-    go_unreachable();
-  return ret;
+  Gogo* gogo = context->gogo();
+  Bexpression* ret =
+      tree_to_expr(this->constant_->get_tree(gogo, context->function()));
+  if (this->type_ != NULL)
+    {
+      Btype* btype = this->type_->get_backend(gogo);
+      ret = gogo->backend()->convert_expression(btype, ret, this->location());
+    }
+  return expr_to_tree(ret);
 }
 
 // Dump ast representation for constant expression.
@@ -3221,8 +3140,10 @@ Expression*
 Type_conversion_expression::do_flatten(Gogo*, Named_object*,
                                        Statement_inserter* inserter)
 {
-  if (this->type()->is_string_type()
-      && this->expr_->type()->is_slice_type()
+  if (((this->type()->is_string_type()
+        && this->expr_->type()->is_slice_type())
+       || (this->type()->interface_type() != NULL
+           && this->expr_->type()->interface_type() != NULL))
       && !this->expr_->is_variable())
     {
       Temporary_statement* temp =
@@ -3325,73 +3246,50 @@ Type_conversion_expression::do_check_types(Gogo*)
 tree
 Type_conversion_expression::do_get_tree(Translate_context* context)
 {
-  Gogo* gogo = context->gogo();
-  tree type_tree = type_to_tree(this->type_->get_backend(gogo));
-  tree expr_tree = this->expr_->get_tree(context);
-
-  if (type_tree == error_mark_node
-      || expr_tree == error_mark_node
-      || TREE_TYPE(expr_tree) == error_mark_node)
-    return error_mark_node;
-
-  if (TYPE_MAIN_VARIANT(type_tree) == TYPE_MAIN_VARIANT(TREE_TYPE(expr_tree)))
-    return fold_convert(type_tree, expr_tree);
-
   Type* type = this->type_;
   Type* expr_type = this->expr_->type();
-  tree ret;
-  if (type->interface_type() != NULL || expr_type->interface_type() != NULL)
-    ret = Expression::convert_for_assignment(context, type, expr_type,
-					     expr_tree, this->location());
-  else if (type->integer_type() != NULL)
+
+  Gogo* gogo = context->gogo();
+  Btype* btype = type->get_backend(gogo);
+  Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context));
+  Location loc = this->location();
+
+  if (Type::are_identical(type, expr_type, false, NULL))
     {
-      if (expr_type->integer_type() != NULL
-	  || expr_type->float_type() != NULL
-	  || expr_type->is_unsafe_pointer_type())
-	ret = fold(convert_to_integer(type_tree, expr_tree));
-      else
-	go_unreachable();
+      Bexpression* bconvert =
+        gogo->backend()->convert_expression(btype, bexpr, loc);
+      return expr_to_tree(bconvert);
     }
-  else if (type->float_type() != NULL)
+  else if (type->interface_type() != NULL
+	   || expr_type->interface_type() != NULL)
     {
-      if (expr_type->integer_type() != NULL
-	  || expr_type->float_type() != NULL)
-	ret = fold(convert_to_real(type_tree, expr_tree));
-      else
-	go_unreachable();
-    }
-  else if (type->complex_type() != NULL)
-    {
-      if (expr_type->complex_type() != NULL)
-	ret = fold(convert_to_complex(type_tree, expr_tree));
-      else
-	go_unreachable();
+      Expression* conversion =
+          Expression::convert_for_assignment(gogo, type, this->expr_,
+                                             this->location());
+      return conversion->get_tree(context);
     }
   else if (type->is_string_type()
 	   && expr_type->integer_type() != NULL)
     {
-      Type* int_type = Type::lookup_integer_type("int");
-      tree int_type_tree = type_to_tree(int_type->get_backend(gogo));
-
-      expr_tree = fold_convert(int_type_tree, expr_tree);
-      if (tree_fits_shwi_p (expr_tree))
+      mpz_t intval;
+      Numeric_constant nc;
+      if (this->expr_->numeric_constant_value(&nc)
+	  && nc.to_int(&intval)
+	  && mpz_fits_ushort_p(intval))
 	{
-	  HOST_WIDE_INT intval = tree_to_shwi (expr_tree);
 	  std::string s;
-	  Lex::append_char(intval, true, &s, this->location());
-	  Expression* se = Expression::make_string(s, this->location());
+	  Lex::append_char(mpz_get_ui(intval), true, &s, loc);
+	  mpz_clear(intval);
+	  Expression* se = Expression::make_string(s, loc);
 	  return se->get_tree(context);
 	}
 
       Expression* i2s_expr =
-          Runtime::make_call(Runtime::INT_TO_STRING, this->location(), 1,
-                             this->expr_);
-      i2s_expr = Expression::make_cast(type, i2s_expr, this->location());
-      ret = i2s_expr->get_tree(context);
+          Runtime::make_call(Runtime::INT_TO_STRING, loc, 1, this->expr_);
+      return Expression::make_cast(type, i2s_expr, loc)->get_tree(context);
     }
   else if (type->is_string_type() && expr_type->is_slice_type())
     {
-      Location location = this->location();
       Array_type* a = expr_type->array_type();
       Type* e = a->element_type()->forwarded();
       go_assert(e->integer_type() != NULL);
@@ -3407,46 +3305,50 @@ Type_conversion_expression::do_get_tree(Translate_context* context)
         }
       Expression* valptr = a->get_value_pointer(gogo, this->expr_);
       Expression* len = a->get_length(gogo, this->expr_);
-      Expression* a2s_expr = Runtime::make_call(code, location, 2, valptr, len);
-      ret = a2s_expr->get_tree(context);
+      return Runtime::make_call(code, loc, 2, valptr, len)->get_tree(context);
     }
   else if (type->is_slice_type() && expr_type->is_string_type())
     {
       Type* e = type->array_type()->element_type()->forwarded();
       go_assert(e->integer_type() != NULL);
 
-      Expression* s2a_expr;
+      Runtime::Function code;
       if (e->integer_type()->is_byte())
-        s2a_expr = Runtime::make_call(Runtime::STRING_TO_BYTE_ARRAY,
-                                      this->location(), 1, this->expr_);
+	code = Runtime::STRING_TO_BYTE_ARRAY;
       else
 	{
 	  go_assert(e->integer_type()->is_rune());
-          s2a_expr = Runtime::make_call(Runtime::STRING_TO_INT_ARRAY,
-                                        this->location(), 1, this->expr_);
+	  code = Runtime::STRING_TO_INT_ARRAY;
 	}
-      s2a_expr = Expression::make_unsafe_cast(type, s2a_expr,
-					      this->location());
-      ret = s2a_expr->get_tree(context);
+      Expression* s2a = Runtime::make_call(code, loc, 1, this->expr_);
+      return Expression::make_unsafe_cast(type, s2a, loc)->get_tree(context);
+    }
+  else if (type->is_numeric_type())
+    {
+      go_assert(Type::are_convertible(type, expr_type, NULL));
+      Bexpression* bconvert =
+	gogo->backend()->convert_expression(btype, bexpr, loc);
+      return expr_to_tree(bconvert);
     }
   else if ((type->is_unsafe_pointer_type()
-	    && expr_type->points_to() != NULL)
-	   || (expr_type->is_unsafe_pointer_type()
-	       && type->points_to() != NULL))
-    ret = fold_convert(type_tree, expr_tree);
-  else if (type->is_unsafe_pointer_type()
-	   && expr_type->integer_type() != NULL)
-    ret = convert_to_pointer(type_tree, expr_tree);
-  else if (this->may_convert_function_types_
-	   && type->function_type() != NULL
-	   && expr_type->function_type() != NULL)
-    ret = fold_convert_loc(this->location().gcc_location(), type_tree,
-                           expr_tree);
+	    && (expr_type->points_to() != NULL
+                || expr_type->integer_type()))
+           || (expr_type->is_unsafe_pointer_type()
+	       && type->points_to() != NULL)
+           || (this->may_convert_function_types_
+               && type->function_type() != NULL
+               && expr_type->function_type() != NULL))
+    {
+      Bexpression* bconvert =
+	gogo->backend()->convert_expression(btype, bexpr, loc);
+      return expr_to_tree(bconvert);
+    }
   else
-    ret = Expression::convert_for_assignment(context, type, expr_type,
-					     expr_tree, this->location());
-
-  return ret;
+    {
+      Expression* conversion =
+          Expression::convert_for_assignment(gogo, type, this->expr_, loc);
+      return conversion->get_tree(context);
+    }
 }
 
 // Output a type conversion in a constant expression.
@@ -3560,58 +3462,57 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context)
 
   Type* t = this->type_;
   Type* et = this->expr_->type();
-
-  tree type_tree = type_to_tree(this->type_->get_backend(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;
-
-  Location loc = this->location();
-
-  bool use_view_convert = false;
-  if (t->is_slice_type())
+  if (t->array_type() != NULL)
+    go_assert(et->array_type() != NULL
+              && t->is_slice_type() == et->is_slice_type());
+  else if (t->struct_type() != NULL)
     {
-      go_assert(et->is_slice_type());
-      use_view_convert = true;
+      if (t->named_type() != NULL
+          && et->named_type() != NULL
+          && !Type::are_convertible(t, et, NULL))
+	{
+	  go_assert(saw_errors());
+	  return error_mark_node;
+	}
+
+      go_assert(et->struct_type() != NULL
+                && Type::are_convertible(t, et, NULL));
     }
   else if (t->map_type() != NULL)
     go_assert(et->map_type() != NULL);
   else if (t->channel_type() != NULL)
     go_assert(et->channel_type() != NULL);
   else if (t->points_to() != NULL)
-    go_assert(et->points_to() != NULL || et->is_nil_type());
+    go_assert(et->points_to() != NULL
+              || et->channel_type() != NULL
+              || et->map_type() != NULL
+              || et->function_type() != NULL
+              || et->is_nil_type());
   else if (et->is_unsafe_pointer_type())
     go_assert(t->points_to() != NULL);
-  else if (t->interface_type() != NULL && !t->interface_type()->is_empty())
+  else if (t->interface_type() != NULL)
     {
+      bool empty_iface = t->interface_type()->is_empty();
       go_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())
-    {
-      go_assert(et->interface_type() != NULL
-		 && et->interface_type()->is_empty());
-      use_view_convert = true;
+                && et->interface_type()->is_empty() == empty_iface);
     }
   else if (t->integer_type() != NULL)
-    {
-      go_assert(et->is_boolean_type()
-		 || et->integer_type() != NULL
-		 || et->function_type() != NULL
-		 || et->points_to() != NULL
-		 || et->map_type() != NULL
-		 || et->channel_type() != NULL);
-      return convert_to_integer(type_tree, expr_tree);
-    }
+    go_assert(et->is_boolean_type()
+              || et->integer_type() != NULL
+              || et->function_type() != NULL
+              || et->points_to() != NULL
+              || et->map_type() != NULL
+              || et->channel_type() != NULL);
   else
     go_unreachable();
 
-  if (use_view_convert)
-    return fold_build1_loc(loc.gcc_location(), VIEW_CONVERT_EXPR, type_tree,
-                           expr_tree);
-  else
-    return fold_convert_loc(loc.gcc_location(), type_tree, expr_tree);
+  Gogo* gogo = context->gogo();
+  Btype* btype = t->get_backend(gogo);
+  Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context));
+  Location loc = this->location();
+  Bexpression* ret =
+    gogo->backend()->convert_expression(btype, bexpr, loc);
+  return expr_to_tree(ret);
 }
 
 // Dump ast representation for an unsafe type conversion expression.
@@ -3757,7 +3658,7 @@ class Unary_expression : public Expression
 };
 
 // If we are taking the address of a composite literal, and the
-// contents are not constant, then we want to make a heap composite
+// contents are not constant, then we want to make a heap expression
 // instead.
 
 Expression*
@@ -4758,9 +4659,19 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
     {
     case OPERATOR_PLUS:
       mpz_add(val, left_val, right_val);
+      if (mpz_sizeinbase(val, 2) > 0x100000)
+	{
+	  error_at(location, "constant addition overflow");
+	  mpz_set_ui(val, 1);
+	}
       break;
     case OPERATOR_MINUS:
       mpz_sub(val, left_val, right_val);
+      if (mpz_sizeinbase(val, 2) > 0x100000)
+	{
+	  error_at(location, "constant subtraction overflow");
+	  mpz_set_ui(val, 1);
+	}
       break;
     case OPERATOR_OR:
       mpz_ior(val, left_val, right_val);
@@ -4770,6 +4681,11 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
       break;
     case OPERATOR_MULT:
       mpz_mul(val, left_val, right_val);
+      if (mpz_sizeinbase(val, 2) > 0x100000)
+	{
+	  error_at(location, "constant multiplication overflow");
+	  mpz_set_ui(val, 1);
+	}
       break;
     case OPERATOR_DIV:
       if (mpz_sgn(right_val) != 0)
@@ -4797,7 +4713,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
 	else
 	  {
 	    error_at(location, "shift count overflow");
-	    mpz_set_ui(val, 0);
+	    mpz_set_ui(val, 1);
 	  }
 	break;
       }
@@ -4808,7 +4724,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc,
 	if (mpz_cmp_ui(right_val, shift) != 0)
 	  {
 	    error_at(location, "shift count overflow");
-	    mpz_set_ui(val, 0);
+	    mpz_set_ui(val, 1);
 	  }
 	else
 	  {
@@ -6888,7 +6804,7 @@ Bound_method_expression::do_get_tree(Translate_context* context)
   vals->push_back(val);
 
   Expression* ret = Expression::make_struct_composite_literal(st, vals, loc);
-  ret = Expression::make_heap_composite(ret, loc);
+  ret = Expression::make_heap_expression(ret, loc);
 
   tree ret_tree = ret->get_tree(context);
 
@@ -7776,27 +7692,33 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
 	return false;
       if (arg_type->is_abstract())
 	return false;
+      if (this->seen_)
+        return false;
 
       unsigned int ret;
       if (this->code_ == BUILTIN_SIZEOF)
 	{
-	  if (!arg_type->backend_type_size(this->gogo_, &ret))
+          this->seen_ = true;
+	  bool ok = arg_type->backend_type_size(this->gogo_, &ret);
+          this->seen_ = false;
+	  if (!ok)
 	    return false;
 	}
       else if (this->code_ == BUILTIN_ALIGNOF)
 	{
+	  bool ok;
+          this->seen_ = true;
 	  if (arg->field_reference_expression() == NULL)
-	    {
-	      if (!arg_type->backend_type_align(this->gogo_, &ret))
-		return false;
-	    }
+	    ok = arg_type->backend_type_align(this->gogo_, &ret);
 	  else
 	    {
 	      // Calling unsafe.Alignof(s.f) returns the alignment of
 	      // the type of f when it is used as a field in a struct.
-	      if (!arg_type->backend_type_field_align(this->gogo_, &ret))
-		return false;
+	      ok = arg_type->backend_type_field_align(this->gogo_, &ret);
 	    }
+          this->seen_ = false;
+	  if (!ok)
+	    return false;
 	}
       else
 	go_unreachable();
@@ -7813,6 +7735,9 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
       Field_reference_expression* farg = arg->field_reference_expression();
       if (farg == NULL)
 	return false;
+      if (this->seen_)
+        return false;
+
       unsigned int total_offset = 0;
       while (true)
         {
@@ -7823,10 +7748,13 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
           if (st->named_type() != NULL)
             st->named_type()->convert(this->gogo_);
           unsigned int offset;
-          if (!st->struct_type()->backend_field_offset(this->gogo_,
-						       farg->field_index(),
-						       &offset))
-            return false;
+          this->seen_ = true;
+          bool ok = st->struct_type()->backend_field_offset(this->gogo_,
+							    farg->field_index(),
+							    &offset);
+          this->seen_ = false;
+	  if (!ok)
+	    return false;
           total_offset += offset;
           if (farg->implicit() && struct_expr->field_reference_expression() != NULL)
             {
@@ -8439,7 +8367,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
       {
 	const Expression_list* args = this->args();
 	go_assert(args != NULL && args->size() == 1);
-	Expression* arg = *args->begin();
+	Expression* arg = args->front();
 	Type* arg_type = arg->type();
 
 	if (this->seen_)
@@ -8448,31 +8376,22 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
 	    return error_mark_node;
 	  }
 	this->seen_ = true;
-
-	tree arg_tree = arg->get_tree(context);
-
 	this->seen_ = false;
-
-	if (arg_tree == error_mark_node)
-	  return error_mark_node;
-
 	if (arg_type->points_to() != NULL)
 	  {
 	    arg_type = arg_type->points_to();
 	    go_assert(arg_type->array_type() != NULL
 		       && !arg_type->is_slice_type());
-	    go_assert(POINTER_TYPE_P(TREE_TYPE(arg_tree)));
-	    arg_tree = build_fold_indirect_ref(arg_tree);
+            arg = Expression::make_unary(OPERATOR_MULT, arg, location);
 	  }
 
 	Type* int_type = Type::lookup_integer_type("int");
-	tree int_type_tree = type_to_tree(int_type->get_backend(gogo));
-
-	tree val_tree;
+        Expression* val;
 	if (this->code_ == BUILTIN_LEN)
 	  {
 	    if (arg_type->is_string_type())
-	      val_tree = String_type::length_tree(gogo, arg_tree);
+	      val = Expression::make_string_info(arg, STRING_INFO_LENGTH,
+						 location);
 	    else if (arg_type->array_type() != NULL)
 	      {
 		if (this->seen_)
@@ -8481,34 +8400,13 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
 		    return error_mark_node;
 		  }
 		this->seen_ = true;
-		Expression* len = arg_type->array_type()->get_length(gogo, arg);
-		val_tree = len->get_tree(context);
+	        val = arg_type->array_type()->get_length(gogo, arg);
 		this->seen_ = false;
 	      }
 	    else if (arg_type->map_type() != NULL)
-	      {
-		tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo));
-		static tree map_len_fndecl;
-		val_tree = Gogo::call_builtin(&map_len_fndecl,
-					      location,
-					      "__go_map_len",
-					      1,
-					      int_type_tree,
-					      arg_type_tree,
-					      arg_tree);
-	      }
+              val = Runtime::make_call(Runtime::MAP_LEN, location, 1, arg);
 	    else if (arg_type->channel_type() != NULL)
-	      {
-		tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo));
-		static tree chan_len_fndecl;
-		val_tree = Gogo::call_builtin(&chan_len_fndecl,
-					      location,
-					      "__go_chan_len",
-					      1,
-					      int_type_tree,
-					      arg_type_tree,
-					      arg_tree);
-	      }
+              val = Runtime::make_call(Runtime::CHAN_LEN, location, 1, arg);
 	    else
 	      go_unreachable();
 	  }
@@ -8522,36 +8420,24 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
 		    return error_mark_node;
 		  }
 		this->seen_ = true;
-		Expression* cap =
-		    arg_type->array_type()->get_capacity(gogo, arg);
-		val_tree = cap->get_tree(context);
+                val = arg_type->array_type()->get_capacity(gogo, arg);
 		this->seen_ = false;
 	      }
 	    else if (arg_type->channel_type() != NULL)
-	      {
-		tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo));
-		static tree chan_cap_fndecl;
-		val_tree = Gogo::call_builtin(&chan_cap_fndecl,
-					      location,
-					      "__go_chan_cap",
-					      1,
-					      int_type_tree,
-					      arg_type_tree,
-					      arg_tree);
-	      }
+              val = Runtime::make_call(Runtime::CHAN_CAP, location, 1, arg);
 	    else
 	      go_unreachable();
 	  }
 
-	return fold_convert_loc(location.gcc_location(), int_type_tree,
-				val_tree);
+	return Expression::make_cast(int_type, val,
+				     location)->get_tree(context);
       }
 
     case BUILTIN_PRINT:
     case BUILTIN_PRINTLN:
       {
 	const bool is_ln = this->code_ == BUILTIN_PRINTLN;
-	tree stmt_list = NULL_TREE;
+        Expression* print_stmts = NULL;
 
 	const Expression_list* call_args = this->args();
 	if (call_args != NULL)
@@ -8562,139 +8448,91 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
 	      {
 		if (is_ln && p != call_args->begin())
 		  {
-		    static tree print_space_fndecl;
-		    tree call = Gogo::call_builtin(&print_space_fndecl,
-						   location,
-						   "__go_print_space",
-						   0,
-						   void_type_node);
-		    if (call == error_mark_node)
-		      return error_mark_node;
-		    append_to_statement_list(call, &stmt_list);
+                    Expression* print_space =
+                        Runtime::make_call(Runtime::PRINT_SPACE,
+                                           this->location(), 0);
+
+                    print_stmts =
+                        Expression::make_compound(print_stmts, print_space,
+                                                  location);
 		  }
 
-		Type* type = (*p)->type();
-
-		tree arg = (*p)->get_tree(context);
-		if (arg == error_mark_node)
-		  return error_mark_node;
-
-		tree* pfndecl;
-		const char* fnname;
+                Expression* arg = *p;
+		Type* type = arg->type();
+                Runtime::Function code;
 		if (type->is_string_type())
-		  {
-		    static tree print_string_fndecl;
-		    pfndecl = &print_string_fndecl;
-		    fnname = "__go_print_string";
-		  }
+                  code = Runtime::PRINT_STRING;
 		else if (type->integer_type() != NULL
 			 && type->integer_type()->is_unsigned())
 		  {
-		    static tree print_uint64_fndecl;
-		    pfndecl = &print_uint64_fndecl;
-		    fnname = "__go_print_uint64";
 		    Type* itype = Type::lookup_integer_type("uint64");
-		    Btype* bitype = itype->get_backend(gogo);
-		    arg = fold_convert_loc(location.gcc_location(),
-                                           type_to_tree(bitype), arg);
+		    arg = Expression::make_cast(itype, arg, location);
+                    code = Runtime::PRINT_UINT64;
 		  }
 		else if (type->integer_type() != NULL)
 		  {
-		    static tree print_int64_fndecl;
-		    pfndecl = &print_int64_fndecl;
-		    fnname = "__go_print_int64";
 		    Type* itype = Type::lookup_integer_type("int64");
-		    Btype* bitype = itype->get_backend(gogo);
-		    arg = fold_convert_loc(location.gcc_location(),
-                                           type_to_tree(bitype), arg);
+		    arg = Expression::make_cast(itype, arg, location);
+                    code = Runtime::PRINT_INT64;
 		  }
 		else if (type->float_type() != NULL)
 		  {
-		    static tree print_double_fndecl;
-		    pfndecl = &print_double_fndecl;
-		    fnname = "__go_print_double";
-		    arg = fold_convert_loc(location.gcc_location(),
-                                           double_type_node, arg);
+                    Type* dtype = Type::lookup_float_type("float64");
+                    arg = Expression::make_cast(dtype, arg, location);
+                    code = Runtime::PRINT_DOUBLE;
 		  }
 		else if (type->complex_type() != NULL)
 		  {
-		    static tree print_complex_fndecl;
-		    pfndecl = &print_complex_fndecl;
-		    fnname = "__go_print_complex";
-		    arg = fold_convert_loc(location.gcc_location(),
-                                           complex_double_type_node, arg);
+                    Type* ctype = Type::lookup_complex_type("complex128");
+                    arg = Expression::make_cast(ctype, arg, location);
+                    code = Runtime::PRINT_COMPLEX;
 		  }
 		else if (type->is_boolean_type())
-		  {
-		    static tree print_bool_fndecl;
-		    pfndecl = &print_bool_fndecl;
-		    fnname = "__go_print_bool";
-		  }
+                  code = Runtime::PRINT_BOOL;
 		else if (type->points_to() != NULL
 			 || type->channel_type() != NULL
 			 || type->map_type() != NULL
 			 || type->function_type() != NULL)
 		  {
-		    static tree print_pointer_fndecl;
-		    pfndecl = &print_pointer_fndecl;
-		    fnname = "__go_print_pointer";
-		    arg = fold_convert_loc(location.gcc_location(),
-                                           ptr_type_node, arg);
+                    arg = Expression::make_cast(type, arg, location);
+                    code = Runtime::PRINT_POINTER;
 		  }
 		else if (type->interface_type() != NULL)
 		  {
 		    if (type->interface_type()->is_empty())
-		      {
-			static tree print_empty_interface_fndecl;
-			pfndecl = &print_empty_interface_fndecl;
-			fnname = "__go_print_empty_interface";
-		      }
+                      code = Runtime::PRINT_EMPTY_INTERFACE;
 		    else
-		      {
-			static tree print_interface_fndecl;
-			pfndecl = &print_interface_fndecl;
-			fnname = "__go_print_interface";
-		      }
+                      code = Runtime::PRINT_INTERFACE;
 		  }
 		else if (type->is_slice_type())
-		  {
-		    static tree print_slice_fndecl;
-		    pfndecl = &print_slice_fndecl;
-		    fnname = "__go_print_slice";
-		  }
+                  code = Runtime::PRINT_SLICE;
 		else
 		  {
 		    go_assert(saw_errors());
 		    return error_mark_node;
 		  }
 
-		tree call = Gogo::call_builtin(pfndecl,
-					       location,
-					       fnname,
-					       1,
-					       void_type_node,
-					       TREE_TYPE(arg),
-					       arg);
-		if (call == error_mark_node)
-		  return error_mark_node;
-		append_to_statement_list(call, &stmt_list);
+                Expression* call = Runtime::make_call(code, location, 1, arg);
+                if (print_stmts == NULL)
+                  print_stmts = call;
+                else
+                  print_stmts = Expression::make_compound(print_stmts, call,
+                                                          location);
 	      }
 	  }
 
 	if (is_ln)
 	  {
-	    static tree print_nl_fndecl;
-	    tree call = Gogo::call_builtin(&print_nl_fndecl,
-					   location,
-					   "__go_print_nl",
-					   0,
-					   void_type_node);
-	    if (call == error_mark_node)
-	      return error_mark_node;
-	    append_to_statement_list(call, &stmt_list);
+            Expression* print_nl =
+                Runtime::make_call(Runtime::PRINT_NL, location, 0);
+            if (print_stmts == NULL)
+              print_stmts = print_nl;
+            else
+              print_stmts = Expression::make_compound(print_stmts, print_nl,
+                                                      location);
 	  }
 
-	return stmt_list;
+        return print_stmts->get_tree(context);
       }
 
     case BUILTIN_PANIC:
@@ -8702,29 +8540,13 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
 	const Expression_list* args = this->args();
 	go_assert(args != NULL && args->size() == 1);
 	Expression* arg = args->front();
-	tree arg_tree = arg->get_tree(context);
-	if (arg_tree == error_mark_node)
-	  return error_mark_node;
 	Type *empty =
 	  Type::make_empty_interface_type(Linemap::predeclared_location());
-	arg_tree = Expression::convert_for_assignment(context, empty,
-						      arg->type(),
-						      arg_tree, location);
-	static tree panic_fndecl;
-	tree call = Gogo::call_builtin(&panic_fndecl,
-				       location,
-				       "__go_panic",
-				       1,
-				       void_type_node,
-				       TREE_TYPE(arg_tree),
-				       arg_tree);
-	if (call == error_mark_node)
-	  return error_mark_node;
-	// This function will throw an exception.
-	TREE_NOTHROW(panic_fndecl) = 0;
-	// This function will not return.
-	TREE_THIS_VOLATILE(panic_fndecl) = 1;
-	return call;
+        arg = Expression::convert_for_assignment(gogo, empty, arg, location);
+
+        Expression* panic =
+            Runtime::make_call(Runtime::PANIC, location, 1, arg);
+        return panic->get_tree(context);
       }
 
     case BUILTIN_RECOVER:
@@ -8734,49 +8556,22 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
 	const Expression_list* args = this->args();
 	go_assert(args != NULL && args->size() == 1);
 	Expression* arg = args->front();
-	tree arg_tree = arg->get_tree(context);
-	if (arg_tree == error_mark_node)
-	  return error_mark_node;
-
 	Type *empty =
 	  Type::make_empty_interface_type(Linemap::predeclared_location());
-	tree empty_tree = type_to_tree(empty->get_backend(context->gogo()));
 
-	Type* nil_type = Type::make_nil_type();
 	Expression* nil = Expression::make_nil(location);
-	tree nil_tree = nil->get_tree(context);
-	tree empty_nil_tree = Expression::convert_for_assignment(context,
-								 empty,
-								 nil_type,
-								 nil_tree,
-								 location);
+	nil = Expression::convert_for_assignment(gogo, empty, nil, location);
 
 	// We need to handle a deferred call to recover specially,
 	// because it changes whether it can recover a panic or not.
 	// See test7 in test/recover1.go.
-	tree call;
-	if (this->is_deferred())
-	  {
-	    static tree deferred_recover_fndecl;
-	    call = Gogo::call_builtin(&deferred_recover_fndecl,
-				      location,
-				      "__go_deferred_recover",
-				      0,
-				      empty_tree);
-	  }
-	else
-	  {
-	    static tree recover_fndecl;
-	    call = Gogo::call_builtin(&recover_fndecl,
-				      location,
-				      "__go_recover",
-				      0,
-				      empty_tree);
-	  }
-	if (call == error_mark_node)
-	  return error_mark_node;
-	return fold_build3_loc(location.gcc_location(), COND_EXPR, empty_tree,
-                               arg_tree, call, empty_nil_tree);
+        Expression* recover = Runtime::make_call((this->is_deferred()
+                                                  ? Runtime::DEFERRED_RECOVER
+                                                  : Runtime::RECOVER),
+                                                 location, 0);
+        Expression* cond =
+            Expression::make_conditional(arg, recover, nil, location);
+        return cond->get_tree(context);
       }
 
     case BUILTIN_CLOSE:
@@ -8784,17 +8579,9 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
 	const Expression_list* args = this->args();
 	go_assert(args != NULL && args->size() == 1);
 	Expression* arg = args->front();
-	tree arg_tree = arg->get_tree(context);
-	if (arg_tree == error_mark_node)
-	  return error_mark_node;
-	static tree close_fndecl;
-	return Gogo::call_builtin(&close_fndecl,
-				  location,
-				  "__go_builtin_close",
-				  1,
-				  void_type_node,
-				  TREE_TYPE(arg_tree),
-				  arg_tree);
+        Expression* close = Runtime::make_call(Runtime::CLOSE, location,
+					       1, arg);
+        return close->get_tree(context);
       }
 
     case BUILTIN_SIZEOF:
@@ -8810,8 +8597,12 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
 	    return error_mark_node;
 	  }
 	Type* uintptr_type = Type::lookup_integer_type("uintptr");
-	tree type = type_to_tree(uintptr_type->get_backend(gogo));
-	return build_int_cst(type, val);
+        mpz_t ival;
+        nc.get_int(&ival);
+        Expression* int_cst =
+            Expression::make_integer(&ival, uintptr_type, location);
+        mpz_clear(ival);
+        return int_cst->get_tree(context);
       }
 
     case BUILTIN_COPY:
@@ -8821,88 +8612,51 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
 	Expression* arg1 = args->front();
 	Expression* arg2 = args->back();
 
-	tree arg1_tree = arg1->get_tree(context);
-	tree arg2_tree = arg2->get_tree(context);
-	if (arg1_tree == error_mark_node || arg2_tree == error_mark_node)
-	  return error_mark_node;
-
 	Type* arg1_type = arg1->type();
 	Array_type* at = arg1_type->array_type();
 	go_assert(arg1->is_variable());
-	Expression* arg1_valptr = at->get_value_pointer(gogo, arg1);
-	Expression* arg1_len_expr = at->get_length(gogo, arg1);
-	tree arg1_val = arg1_valptr->get_tree(context);
-	tree arg1_len = arg1_len_expr->get_tree(context);
-	if (arg1_val == error_mark_node || arg1_len == error_mark_node)
-	  return error_mark_node;
+	Expression* arg1_val = at->get_value_pointer(gogo, arg1);
+	Expression* arg1_len = at->get_length(gogo, arg1);
 
 	Type* arg2_type = arg2->type();
-	tree arg2_val;
-	tree arg2_len;
+        go_assert(arg2->is_variable());
+	Expression* arg2_val;
+	Expression* arg2_len;
 	if (arg2_type->is_slice_type())
 	  {
 	    at = arg2_type->array_type();
-	    go_assert(arg2->is_variable());
-	    Expression* arg2_valptr = at->get_value_pointer(gogo, arg2);
-	    Expression* arg2_len_expr = at->get_length(gogo, arg2);
-	    arg2_val = arg2_valptr->get_tree(context);
-	    arg2_len = arg2_len_expr->get_tree(context);
+	    arg2_val = at->get_value_pointer(gogo, arg2);
+	    arg2_len = at->get_length(gogo, arg2);
 	  }
 	else
 	  {
-	    arg2_tree = save_expr(arg2_tree);
-	    arg2_val = String_type::bytes_tree(gogo, arg2_tree);
-	    arg2_len = String_type::length_tree(gogo, arg2_tree);
+	    go_assert(arg2->is_variable());
+            arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA,
+                                                    location);
+	    arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH,
+                                                    location);
 	  }
-	if (arg2_val == error_mark_node || arg2_len == error_mark_node)
-	  return error_mark_node;
-
-	arg1_len = save_expr(arg1_len);
-	arg2_len = save_expr(arg2_len);
-	tree len = fold_build3_loc(location.gcc_location(), COND_EXPR,
-                                   TREE_TYPE(arg1_len),
-				   fold_build2_loc(location.gcc_location(),
-                                                   LT_EXPR, boolean_type_node,
-						   arg1_len, arg2_len),
-				   arg1_len, arg2_len);
-	len = save_expr(len);
+        Expression* cond =
+            Expression::make_binary(OPERATOR_LT, arg1_len, arg2_len, location);
+        Expression* length =
+            Expression::make_conditional(cond, arg1_len, arg2_len, location);
 
 	Type* element_type = at->element_type();
 	Btype* element_btype = element_type->get_backend(gogo);
-	tree element_type_tree = type_to_tree(element_btype);
-	if (element_type_tree == error_mark_node)
-	  return error_mark_node;
-	tree element_size = TYPE_SIZE_UNIT(element_type_tree);
-	tree bytecount = fold_convert_loc(location.gcc_location(),
-                                          TREE_TYPE(element_size), len);
-	bytecount = fold_build2_loc(location.gcc_location(), MULT_EXPR,
-				    TREE_TYPE(element_size),
-				    bytecount, element_size);
-	bytecount = fold_convert_loc(location.gcc_location(), size_type_node,
-                                     bytecount);
 
-	arg1_val = fold_convert_loc(location.gcc_location(), ptr_type_node,
-                                    arg1_val);
-	arg2_val = fold_convert_loc(location.gcc_location(), ptr_type_node,
-                                    arg2_val);
+        mpz_t size;
+        size_t element_size = gogo->backend()->type_size(element_btype);
+        mpz_init_set_ui(size, element_size);
+        Expression* size_expr = Expression::make_integer(&size, length->type(), location);
+        mpz_clear(size);
 
-	static tree copy_fndecl;
-	tree call = Gogo::call_builtin(&copy_fndecl,
-				       location,
-				       "__go_copy",
-				       3,
-				       void_type_node,
-				       ptr_type_node,
-				       arg1_val,
-				       ptr_type_node,
-				       arg2_val,
-				       size_type_node,
-				       bytecount);
-	if (call == error_mark_node)
-	  return error_mark_node;
+        Expression* bytecount =
+            Expression::make_binary(OPERATOR_MULT, size_expr, length, location);
+        Expression* copy = Runtime::make_call(Runtime::COPY, location, 3,
+                                              arg1_val, arg2_val, bytecount);
 
-	return fold_build2_loc(location.gcc_location(), COMPOUND_EXPR,
-                               TREE_TYPE(len), call, len);
+        Expression* compound = Expression::make_compound(copy, length, location);
+        return compound->get_tree(context);
       }
 
     case BUILTIN_APPEND:
@@ -8912,67 +8666,40 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
 	Expression* arg1 = args->front();
 	Expression* arg2 = args->back();
 
-	tree arg1_tree = arg1->get_tree(context);
-	tree arg2_tree = arg2->get_tree(context);
-	if (arg1_tree == error_mark_node || arg2_tree == error_mark_node)
-	  return error_mark_node;
-
 	Array_type* at = arg1->type()->array_type();
 	Type* element_type = at->element_type()->forwarded();
 
-	tree arg2_val;
-	tree arg2_len;
-	tree element_size;
+        go_assert(arg2->is_variable());
+	Expression* arg2_val;
+	Expression* arg2_len;
+        mpz_t size;
 	if (arg2->type()->is_string_type()
 	    && element_type->integer_type() != NULL
 	    && element_type->integer_type()->is_byte())
 	  {
-	    arg2_tree = save_expr(arg2_tree);
-	    arg2_val = String_type::bytes_tree(gogo, arg2_tree);
-	    arg2_len = String_type::length_tree(gogo, arg2_tree);
-	    element_size = size_int(1);
+	    arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA,
+						    location);
+	    arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH,
+						    location);
+            mpz_init_set_ui(size, 1UL);
 	  }
 	else
 	  {
-	    go_assert(arg2->is_variable());
-	    arg2_val =
-		at->get_value_pointer(gogo, arg2)->get_tree(context);
-	    arg2_len = at->get_length(gogo, arg2)->get_tree(context);
+	    arg2_val = at->get_value_pointer(gogo, arg2);
+	    arg2_len = at->get_length(gogo, arg2);
 	    Btype* element_btype = element_type->get_backend(gogo);
-	    tree element_type_tree = type_to_tree(element_btype);
-	    if (element_type_tree == error_mark_node)
-	      return error_mark_node;
-	    element_size = TYPE_SIZE_UNIT(element_type_tree);
+            size_t element_size = gogo->backend()->type_size(element_btype);
+            mpz_init_set_ui(size, element_size);
 	  }
+        Expression* element_size =
+            Expression::make_integer(&size, NULL, location);
+        mpz_clear(size);
 
-	arg2_val = fold_convert_loc(location.gcc_location(), ptr_type_node,
-                                    arg2_val);
-	arg2_len = fold_convert_loc(location.gcc_location(), size_type_node,
-                                    arg2_len);
-	element_size = fold_convert_loc(location.gcc_location(), size_type_node,
-					element_size);
-
-	if (arg2_val == error_mark_node
-	    || arg2_len == error_mark_node
-	    || element_size == error_mark_node)
-	  return error_mark_node;
-
-	// We rebuild the decl each time since the slice types may
-	// change.
-	tree append_fndecl = NULL_TREE;
-	return Gogo::call_builtin(&append_fndecl,
-				  location,
-				  "__go_append",
-				  4,
-				  TREE_TYPE(arg1_tree),
-				  TREE_TYPE(arg1_tree),
-				  arg1_tree,
-				  ptr_type_node,
-				  arg2_val,
-				  size_type_node,
-				  arg2_len,
-				  size_type_node,
-				  element_size);
+        Expression* append = Runtime::make_call(Runtime::APPEND, location, 4,
+                                                arg1, arg2_val, arg2_len,
+                                                element_size);
+        append = Expression::make_unsafe_cast(arg1->type(), append, location);
+        return append->get_tree(context);
       }
 
     case BUILTIN_REAL:
@@ -8981,34 +8708,25 @@ Builtin_call_expression::do_get_tree(Translate_context* context)
 	const Expression_list* args = this->args();
 	go_assert(args != NULL && args->size() == 1);
 	Expression* arg = args->front();
-	tree arg_tree = arg->get_tree(context);
-	if (arg_tree == error_mark_node)
-	  return error_mark_node;
-	go_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(arg_tree)));
-	if (this->code_ == BUILTIN_REAL)
-	  return fold_build1_loc(location.gcc_location(), REALPART_EXPR,
-				 TREE_TYPE(TREE_TYPE(arg_tree)),
-				 arg_tree);
-	else
-	  return fold_build1_loc(location.gcc_location(), IMAGPART_EXPR,
-				 TREE_TYPE(TREE_TYPE(arg_tree)),
-				 arg_tree);
+
+        Bexpression* ret;
+        Bexpression* bcomplex = tree_to_expr(arg->get_tree(context));
+        if (this->code_ == BUILTIN_REAL)
+          ret = gogo->backend()->real_part_expression(bcomplex, location);
+        else
+          ret = gogo->backend()->imag_part_expression(bcomplex, location);
+        return expr_to_tree(ret);
       }
 
     case BUILTIN_COMPLEX:
       {
 	const Expression_list* args = this->args();
 	go_assert(args != NULL && args->size() == 2);
-	tree r = args->front()->get_tree(context);
-	tree i = args->back()->get_tree(context);
-	if (r == error_mark_node || i == error_mark_node)
-	  return error_mark_node;
-	go_assert(TYPE_MAIN_VARIANT(TREE_TYPE(r))
-		   == TYPE_MAIN_VARIANT(TREE_TYPE(i)));
-	go_assert(SCALAR_FLOAT_TYPE_P(TREE_TYPE(r)));
-	return fold_build2_loc(location.gcc_location(), COMPLEX_EXPR,
-			       build_complex_type(TREE_TYPE(r)),
-			       r, i);
+	Bexpression* breal = tree_to_expr(args->front()->get_tree(context));
+	Bexpression* bimag = tree_to_expr(args->back()->get_tree(context));
+        Bexpression* ret =
+            gogo->backend()->complex_expression(breal, bimag, location);
+        return expr_to_tree(ret);
       }
 
     default:
@@ -9382,6 +9100,37 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function,
   this->varargs_are_lowered_ = true;
 }
 
+// Flatten a call with multiple results into a temporary.
+
+Expression*
+Call_expression::do_flatten(Gogo*, Named_object*, Statement_inserter* inserter)
+{
+  size_t rc = this->result_count();
+  if (rc > 1 && this->call_temp_ == NULL)
+    {
+      Struct_field_list* sfl = new Struct_field_list();
+      Function_type* fntype = this->get_function_type();
+      const Typed_identifier_list* results = fntype->results();
+      Location loc = this->location();
+
+      int i = 0;
+      char buf[10];
+      for (Typed_identifier_list::const_iterator p = results->begin();
+           p != results->end();
+           ++p, ++i)
+        {
+          snprintf(buf, sizeof buf, "res%d", i);
+          sfl->push_back(Struct_field(Typed_identifier(buf, p->type(), loc)));
+        }
+
+      Struct_type* st = Type::make_struct_type(sfl, loc);
+      this->call_temp_ = Statement::make_temporary(st, NULL, loc);
+      inserter->insert(this->call_temp_);
+    }
+
+  return this;
+}
+
 // Get the function type.  This can return NULL in error cases.
 
 Function_type*
@@ -9703,8 +9452,8 @@ Call_expression::interface_method_function(
 tree
 Call_expression::do_get_tree(Translate_context* context)
 {
-  if (this->tree_ != NULL_TREE)
-    return this->tree_;
+  if (this->call_ != NULL)
+    return expr_to_tree(this->call_);
 
   Function_type* fntype = this->get_function_type();
   if (fntype == NULL)
@@ -9733,11 +9482,12 @@ Call_expression::do_get_tree(Translate_context* context)
     has_closure_arg = true;
 
   int nargs;
-  tree* args;
+  std::vector<Bexpression*> fn_args;
   if (this->args_ == NULL || this->args_->empty())
     {
       nargs = is_interface_method ? 1 : 0;
-      args = nargs == 0 ? NULL : new tree[nargs];
+      if (nargs > 0)
+        fn_args.resize(1);
     }
   else if (fntype->parameters() == NULL || fntype->parameters()->empty())
     {
@@ -9746,8 +9496,8 @@ Call_expression::do_get_tree(Translate_context* context)
 		&& fntype->is_method()
 		&& this->args_->size() == 1);
       nargs = 1;
-      args = new tree[nargs];
-      args[0] = this->args_->front()->get_tree(context);
+      fn_args.resize(1);
+      fn_args[0] = tree_to_expr(this->args_->front()->get_tree(context));
     }
   else
     {
@@ -9756,239 +9506,138 @@ Call_expression::do_get_tree(Translate_context* context)
       nargs = this->args_->size();
       int i = is_interface_method ? 1 : 0;
       nargs += i;
-      args = new tree[nargs];
+      fn_args.resize(nargs);
 
       Typed_identifier_list::const_iterator pp = params->begin();
       Expression_list::const_iterator pe = this->args_->begin();
       if (!is_interface_method && fntype->is_method())
 	{
-	  args[i] = (*pe)->get_tree(context);
+          fn_args[i] = tree_to_expr((*pe)->get_tree(context));
 	  ++pe;
 	  ++i;
 	}
       for (; pe != this->args_->end(); ++pe, ++pp, ++i)
 	{
 	  go_assert(pp != params->end());
-	  tree arg_val = (*pe)->get_tree(context);
-	  args[i] = Expression::convert_for_assignment(context,
-						       pp->type(),
-						       (*pe)->type(),
-						       arg_val,
-						       location);
-	  if (args[i] == error_mark_node)
-	    return error_mark_node;
+          Expression* arg =
+              Expression::convert_for_assignment(gogo, pp->type(), *pe,
+                                                 location);
+          fn_args[i] = tree_to_expr(arg->get_tree(context));
 	}
       go_assert(pp == params->end());
       go_assert(i == nargs);
     }
 
-  tree fntype_tree = type_to_tree(fntype->get_backend(gogo));
-  tree fnfield_type = type_to_tree(fntype->get_backend_fntype(gogo));
-  if (fntype_tree == error_mark_node || fnfield_type == error_mark_node)
-    return error_mark_node;
-  go_assert(FUNCTION_POINTER_TYPE_P(fnfield_type));
-  tree rettype = TREE_TYPE(TREE_TYPE(fnfield_type));
-  if (rettype == error_mark_node)
-    return error_mark_node;
-
-  tree fn;
-  tree closure_tree;
+  Expression* fn;
+  Expression* closure = NULL;
   if (func != NULL)
     {
       Named_object* no = func->named_object();
-      fn = expr_to_tree(Func_expression::get_code_pointer(gogo, no, location));
-      if (!has_closure)
-	closure_tree = NULL_TREE;
-      else
-	{
-	  closure_tree = func->closure()->get_tree(context);
-	  if (closure_tree == error_mark_node)
-	    return error_mark_node;
-	}
+      fn = Expression::make_func_code_reference(no, location);
+      if (has_closure)
+        closure = func->closure();
     }
   else if (!is_interface_method)
     {
-      closure_tree = this->fn_->get_tree(context);
-      if (closure_tree == error_mark_node)
-	return error_mark_node;
-      tree fnc = fold_convert_loc(location.gcc_location(), fntype_tree,
-				  closure_tree);
-      go_assert(POINTER_TYPE_P(TREE_TYPE(fnc))
-		&& (TREE_CODE(TREE_TYPE(TREE_TYPE(fnc)))
-		    == RECORD_TYPE));
-      tree field = TYPE_FIELDS(TREE_TYPE(TREE_TYPE(fnc)));
-      fn = fold_build3_loc(location.gcc_location(), COMPONENT_REF,
-			   TREE_TYPE(field),
-			   build_fold_indirect_ref_loc(location.gcc_location(),
-						       fnc),
-			   field, NULL_TREE);
-    }      
+      closure = this->fn_;
+
+      // The backend representation of this function type is a pointer
+      // to a struct whose first field is the actual function to call.
+      Type* pfntype =
+          Type::make_pointer_type(
+              Type::make_pointer_type(Type::make_void_type()));
+      fn = Expression::make_unsafe_cast(pfntype, this->fn_, location);
+      fn = Expression::make_unary(OPERATOR_MULT, fn, location);
+    }
   else
     {
       Expression* first_arg;
-      Expression* fn_expr =
-          this->interface_method_function(interface_method, &first_arg);
-      args[0] = first_arg->get_tree(context);
-      fn = fn_expr->get_tree(context);
-
-      if (fn == error_mark_node)
-	return error_mark_node;
-      closure_tree = NULL_TREE;
+      fn = this->interface_method_function(interface_method, &first_arg);
+      fn_args[0] = tree_to_expr(first_arg->get_tree(context));
     }
 
-  if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node)
-    return error_mark_node;
-
-  tree fndecl = fn;
-  if (TREE_CODE(fndecl) == ADDR_EXPR)
-    fndecl = TREE_OPERAND(fndecl, 0);
-
-  // Add a type cast in case the type of the function is a recursive
-  // type which refers to itself.  We don't do this for an interface
-  // method because 1) an interface method never refers to itself, so
-  // we always have a function type here; 2) we pass an extra first
-  // argument to an interface method, so fnfield_type is not correct.
-  if ((!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl)) && !is_interface_method)
-    fn = fold_convert_loc(location.gcc_location(), fnfield_type, fn);
-
-  // This is to support builtin math functions when using 80387 math.
-  tree excess_type = NULL_TREE;
-  if (optimize
-      && TREE_CODE(fndecl) == FUNCTION_DECL
-      && DECL_IS_BUILTIN(fndecl)
-      && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL
-      && nargs > 0
-      && ((SCALAR_FLOAT_TYPE_P(rettype)
-	   && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0])))
-	  || (COMPLEX_FLOAT_TYPE_P(rettype)
-	      && COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[0])))))
-    {
-      excess_type = excess_precision_type(TREE_TYPE(args[0]));
-      if (excess_type != NULL_TREE)
-	{
-	  tree excess_fndecl = mathfn_built_in(excess_type,
-					       DECL_FUNCTION_CODE(fndecl));
-	  if (excess_fndecl == NULL_TREE)
-	    excess_type = NULL_TREE;
-	  else
-	    {
-	      fn = build_fold_addr_expr_loc(location.gcc_location(),
-                                            excess_fndecl);
-	      for (int i = 0; i < nargs; ++i)
-		{
-		  if (SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[i]))
-		      || COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[i])))
-		    args[i] = ::convert(excess_type, args[i]);
-		}
-	    }
-	}
-    }
-
-  if (func == NULL)
-    fn = save_expr(fn);
-
   if (!has_closure_arg)
-    go_assert(closure_tree == NULL_TREE);
+    go_assert(closure == NULL);
   else
     {
       // Pass the closure argument by calling the function function
       // __go_set_closure.  In the order_evaluations pass we have
       // ensured that if any parameters contain call expressions, they
       // will have been moved out to temporary variables.
-
-      go_assert(closure_tree != NULL_TREE);
-      closure_tree = fold_convert_loc(location.gcc_location(), ptr_type_node,
-				      closure_tree);
-      static tree set_closure_fndecl;
-      tree set_closure = Gogo::call_builtin(&set_closure_fndecl,
-					    location,
-					    "__go_set_closure",
-					    1,
-					    void_type_node,
-					    ptr_type_node,
-					    closure_tree);
-      if (set_closure == error_mark_node)
-	return error_mark_node;
-      fn = build2_loc(location.gcc_location(), COMPOUND_EXPR,
-		      TREE_TYPE(fn), set_closure, fn);
+      go_assert(closure != NULL);
+      Expression* set_closure =
+          Runtime::make_call(Runtime::SET_CLOSURE, location, 1, closure);
+      fn = Expression::make_compound(set_closure, fn, location);
     }
 
-  tree ret = build_call_array(excess_type != NULL_TREE ? excess_type : rettype,
-			      fn, nargs, args);
-  delete[] args;
-
-  SET_EXPR_LOCATION(ret, location.gcc_location());
-
-  // If this is a recursive function type which returns itself, as in
-  //   type F func() F
-  // we have used ptr_type_node for the return type.  Add a cast here
-  // to the correct type.
-  if (TREE_TYPE(ret) == ptr_type_node)
-    {
-      tree t = type_to_tree(this->type()->base()->get_backend(gogo));
-      ret = fold_convert_loc(location.gcc_location(), t, ret);
-    }
-
-  if (excess_type != NULL_TREE)
-    {
-      // Calling convert here can undo our excess precision change.
-      // That may or may not be a bug in convert_to_real.
-      ret = build1(NOP_EXPR, rettype, ret);
-    }
+  Btype* bft = fntype->get_backend_fntype(gogo);
+  Bexpression* bfn = tree_to_expr(fn->get_tree(context));
+  bfn = gogo->backend()->convert_expression(bft, bfn, location);
+  Bexpression* call = gogo->backend()->call_expression(bfn, fn_args, location);
 
   if (this->results_ != NULL)
-    ret = this->set_results(context, ret);
+    {
+      go_assert(this->call_temp_ != NULL);
+      Expression* call_ref =
+          Expression::make_temporary_reference(this->call_temp_, location);
+      Bexpression* bcall_ref = tree_to_expr(call_ref->get_tree(context));
+      Bstatement* assn_stmt =
+          gogo->backend()->assignment_statement(bcall_ref, call, location);
 
-  this->tree_ = ret;
+      this->call_ = this->set_results(context, bcall_ref);
 
-  return ret;
+      Bexpression* set_and_call =
+          gogo->backend()->compound_expression(assn_stmt, this->call_,
+                                               location);
+      return expr_to_tree(set_and_call);
+    }
+
+  this->call_ = call;
+  return expr_to_tree(this->call_);
 }
 
 // Set the result variables if this call returns multiple results.
 
-tree
-Call_expression::set_results(Translate_context* context, tree call_tree)
+Bexpression*
+Call_expression::set_results(Translate_context* context, Bexpression* call)
 {
-  tree stmt_list = NULL_TREE;
-
-  call_tree = save_expr(call_tree);
-
-  if (TREE_CODE(TREE_TYPE(call_tree)) != RECORD_TYPE)
-    {
-      go_assert(saw_errors());
-      return call_tree;
-    }
+  Gogo* gogo = context->gogo();
 
+  Bexpression* results = NULL;
   Location loc = this->location();
-  tree field = TYPE_FIELDS(TREE_TYPE(call_tree));
-  size_t rc = this->result_count();
-  for (size_t i = 0; i < rc; ++i, field = DECL_CHAIN(field))
-    {
-      go_assert(field != NULL_TREE);
 
+  size_t rc = this->result_count();
+  for (size_t i = 0; i < rc; ++i)
+    {
       Temporary_statement* temp = this->result(i);
       if (temp == NULL)
 	{
 	  go_assert(saw_errors());
-	  return error_mark_node;
+	  return gogo->backend()->error_expression();
 	}
       Temporary_reference_expression* ref =
 	Expression::make_temporary_reference(temp, loc);
       ref->set_is_lvalue();
-      tree temp_tree = ref->get_tree(context);
-      if (temp_tree == error_mark_node)
-	return error_mark_node;
 
-      tree val_tree = build3_loc(loc.gcc_location(), COMPONENT_REF,
-                                 TREE_TYPE(field), call_tree, field, NULL_TREE);
-      tree set_tree = build2_loc(loc.gcc_location(), MODIFY_EXPR,
-                                 void_type_node, temp_tree, val_tree);
+      Bexpression* result_ref = tree_to_expr(ref->get_tree(context));
+      Bexpression* call_result =
+          gogo->backend()->struct_field_expression(call, i, loc);
+      Bstatement* assn_stmt =
+           gogo->backend()->assignment_statement(result_ref, call_result, loc);
 
-      append_to_statement_list(set_tree, &stmt_list);
+      Bexpression* result =
+          gogo->backend()->compound_expression(assn_stmt, call_result, loc);
+
+      if (results == NULL)
+        results = result;
+      else
+        {
+          Bstatement* expr_stmt = gogo->backend()->expression_statement(result);
+          results =
+              gogo->backend()->compound_expression(expr_stmt, results, loc);
+        }
     }
-  go_assert(field == NULL_TREE);
-
-  return save_expr(stmt_list);
+  return results;
 }
 
 // Dump ast representation for a call expressin.
@@ -10333,6 +9982,9 @@ class Array_index_expression : public Expression
   int
   do_traverse(Traverse*);
 
+  Expression*
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
   Type*
   do_type();
 
@@ -10342,9 +9994,6 @@ class Array_index_expression : public Expression
   void
   do_check_types(Gogo*);
 
-  Expression*
-  do_flatten(Gogo*, Named_object*, Statement_inserter*);
-
   Expression*
   do_copy()
   {
@@ -10586,19 +10235,41 @@ Array_index_expression::do_check_types(Gogo*)
     }
 }
 
-// Flatten array indexing by using a temporary variable for slices.
+// Flatten array indexing by using temporary variables for slices and indexes.
 
 Expression*
 Array_index_expression::do_flatten(Gogo*, Named_object*,
                                    Statement_inserter* inserter)
 {
   Location loc = this->location();
+  Temporary_statement* temp;
   if (this->array_->type()->is_slice_type() && !this->array_->is_variable())
     {
-      Temporary_statement* temp = Statement::make_temporary(NULL, this->array_, loc);
+      temp = Statement::make_temporary(NULL, this->array_, loc);
       inserter->insert(temp);
       this->array_ = Expression::make_temporary_reference(temp, loc);
     }
+  if (!this->start_->is_variable())
+    {
+      temp = Statement::make_temporary(NULL, this->start_, loc);
+      inserter->insert(temp);
+      this->start_ = Expression::make_temporary_reference(temp, loc);
+    }
+  if (this->end_ != NULL
+      && !this->end_->is_nil_expression()
+      && !this->end_->is_variable())
+    {
+      temp = Statement::make_temporary(NULL, this->end_, loc);
+      inserter->insert(temp);
+      this->end_ = Expression::make_temporary_reference(temp, loc);
+    }
+  if (this->cap_ != NULL && !this->cap_->is_variable())
+    {
+      temp = Statement::make_temporary(NULL, this->cap_, loc);
+      inserter->insert(temp);
+      this->cap_ = Expression::make_temporary_reference(temp, loc);
+    }
+
   return this;
 }
 
@@ -10625,9 +10296,6 @@ Array_index_expression::do_is_addressable() const
 tree
 Array_index_expression::do_get_tree(Translate_context* context)
 {
-  Gogo* gogo = context->gogo();
-  Location loc = this->location();
-
   Array_type* array_type = this->array_->type()->array_type();
   if (array_type == NULL)
     {
@@ -10636,66 +10304,40 @@ Array_index_expression::do_get_tree(Translate_context* context)
     }
   go_assert(!array_type->is_slice_type() || this->array_->is_variable());
 
-  tree type_tree = type_to_tree(array_type->get_backend(gogo));
-  if (type_tree == error_mark_node)
-    return error_mark_node;
+  Location loc = this->location();
+  Gogo* gogo = context->gogo();
 
-  tree length_tree = NULL_TREE;
+  Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
+
+  // We need to convert the length and capacity to the Go "int" type here
+  // because the length of a fixed-length array could be of type "uintptr"
+  // and gimple disallows binary operations between "uintptr" and other
+  // integer types. FIXME.
+  Bexpression* length = NULL;
   if (this->end_ == NULL || this->end_->is_nil_expression())
     {
       Expression* len = array_type->get_length(gogo, this->array_);
-      length_tree = len->get_tree(context);
-      if (length_tree == error_mark_node)
-	return error_mark_node;
-      length_tree = save_expr(length_tree);
+      length = tree_to_expr(len->get_tree(context));
+      length = gogo->backend()->convert_expression(int_btype, length, loc);
     }
 
-  tree capacity_tree = NULL_TREE;
+  Bexpression* capacity = NULL;
   if (this->end_ != NULL)
     {
       Expression* cap = array_type->get_capacity(gogo, this->array_);
-      capacity_tree = cap->get_tree(context);
-      if (capacity_tree == error_mark_node)
-	return error_mark_node;
-      capacity_tree = save_expr(capacity_tree);
+      capacity = tree_to_expr(cap->get_tree(context));
+      capacity = gogo->backend()->convert_expression(int_btype, capacity, loc);
     }
 
-  tree cap_arg = capacity_tree;
+  Bexpression* cap_arg = capacity;
   if (this->cap_ != NULL)
     {
-      cap_arg = this->cap_->get_tree(context);
-      if (cap_arg == error_mark_node)
-        return error_mark_node;
+      cap_arg = tree_to_expr(this->cap_->get_tree(context));
+      cap_arg = gogo->backend()->convert_expression(int_btype, cap_arg, loc);
     }
 
-  tree length_type = (length_tree != NULL_TREE
-		      ? TREE_TYPE(length_tree)
-		      : TREE_TYPE(cap_arg));
-
-  tree bad_index = boolean_false_node;
-
-  tree start_tree = this->start_->get_tree(context);
-  if (start_tree == error_mark_node)
-    return error_mark_node;
-  if (!DECL_P(start_tree))
-    start_tree = save_expr(start_tree);
-  if (!INTEGRAL_TYPE_P(TREE_TYPE(start_tree)))
-    start_tree = convert_to_integer(length_type, start_tree);
-
-  bad_index = Expression::check_bounds(start_tree, length_type, bad_index,
-				       loc);
-
-  start_tree = fold_convert_loc(loc.gcc_location(), length_type, start_tree);
-  bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
-                              boolean_type_node, bad_index,
-			      fold_build2_loc(loc.gcc_location(),
-					      (this->end_ == NULL
-					       ? GE_EXPR
-					       : GT_EXPR),
-					      boolean_type_node, start_tree,
-					      (this->end_ == NULL
-					       ? length_tree
-					       : capacity_tree)));
+  if (length == NULL)
+    length = cap_arg;
 
   int code = (array_type->length() != NULL
 	      ? (this->end_ == NULL
@@ -10704,168 +10346,124 @@ Array_index_expression::do_get_tree(Translate_context* context)
 	      : (this->end_ == NULL
 		 ? RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS
 		 : RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS));
-  tree crash = gogo->runtime_error(code, loc)->get_tree(context);
+  Bexpression* crash =
+      tree_to_expr(gogo->runtime_error(code, loc)->get_tree(context));
+
+  Expression* bounds_check = Expression::check_bounds(this->start_, loc);
+  Bexpression* bad_index = tree_to_expr(bounds_check->get_tree(context));
+
+  Bexpression* start = tree_to_expr(this->start_->get_tree(context));
+  start = gogo->backend()->convert_expression(int_btype, start, loc);
+  Bexpression* start_too_large =
+    gogo->backend()->binary_expression((this->end_ == NULL
+					? OPERATOR_GE
+					: OPERATOR_GT),
+                                       start,
+				       (this->end_ == NULL
+					? length
+					: capacity),
+                                       loc);
+  bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, start_too_large,
+						 bad_index, loc);
 
   if (this->end_ == NULL)
     {
       // Simple array indexing.  This has to return an l-value, so
-      // wrap the index check into START_TREE.
-      start_tree = build2(COMPOUND_EXPR, TREE_TYPE(start_tree),
-			  build3(COND_EXPR, void_type_node,
-				 bad_index, crash, NULL_TREE),
-			  start_tree);
-      start_tree = fold_convert_loc(loc.gcc_location(), sizetype, start_tree);
+      // wrap the index check into START.
+      start =
+	gogo->backend()->conditional_expression(int_btype, bad_index,
+						crash, start, loc);
 
+      Bexpression* ret;
       if (array_type->length() != NULL)
 	{
-	  // Fixed array.
-	  tree array_tree = this->array_->get_tree(context);
-	  if (array_tree == error_mark_node)
-	    return error_mark_node;
-	  return build4(ARRAY_REF, TREE_TYPE(type_tree), array_tree,
-			start_tree, NULL_TREE, NULL_TREE);
+	  Bexpression* array = tree_to_expr(this->array_->get_tree(context));
+	  ret = gogo->backend()->array_index_expression(array, start, loc);
 	}
       else
 	{
-	  // Open array.
-          Expression* valptr =
+	  // Slice.
+	  Expression* valptr =
               array_type->get_value_pointer(gogo, this->array_);
-	  tree values = valptr->get_tree(context);
-	  Type* element_type = array_type->element_type();
-	  Btype* belement_type = element_type->get_backend(gogo);
-	  tree element_type_tree = type_to_tree(belement_type);
-	  if (element_type_tree == error_mark_node)
-	    return error_mark_node;
-	  tree element_size = TYPE_SIZE_UNIT(element_type_tree);
-	  tree offset = fold_build2_loc(loc.gcc_location(), MULT_EXPR, sizetype,
-					start_tree, element_size);
-	  tree ptr = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR,
-				     TREE_TYPE(values), values, offset);
-	  return build_fold_indirect_ref(ptr);
+	  Bexpression* ptr = tree_to_expr(valptr->get_tree(context));
+          ptr = gogo->backend()->pointer_offset_expression(ptr, start, loc);
+	  ret = gogo->backend()->indirect_expression(ptr, true, loc);
 	}
+      return expr_to_tree(ret);
     }
 
   // Array slice.
 
   if (this->cap_ != NULL)
     {
-      if (!DECL_P(cap_arg))
-        cap_arg = save_expr(cap_arg);
-      if (!INTEGRAL_TYPE_P(TREE_TYPE(cap_arg)))
-        cap_arg = convert_to_integer(length_type, cap_arg);
+      bounds_check = Expression::check_bounds(this->cap_, loc);
+      Bexpression* bounds_bcheck =
+	tree_to_expr(bounds_check->get_tree(context));
+      bad_index =
+	gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck,
+					   bad_index, loc);
+      cap_arg = gogo->backend()->convert_expression(int_btype, cap_arg, loc);
 
-      bad_index = Expression::check_bounds(cap_arg, length_type, bad_index,
-                                           loc);
-      cap_arg = fold_convert_loc(loc.gcc_location(), length_type, cap_arg);
-
-      tree bad_cap = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
-                                     boolean_type_node,
-                                     fold_build2_loc(loc.gcc_location(),
-                                                     LT_EXPR, boolean_type_node,
-                                                     cap_arg, start_tree),
-                                     fold_build2_loc(loc.gcc_location(),
-                                                     GT_EXPR, boolean_type_node,
-                                                     cap_arg, capacity_tree));
-      bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
-                                  boolean_type_node, bad_index, bad_cap);
+      Bexpression* cap_too_small =
+	gogo->backend()->binary_expression(OPERATOR_LT, cap_arg, start, loc);
+      Bexpression* cap_too_large =
+	gogo->backend()->binary_expression(OPERATOR_GT, cap_arg, capacity, loc);
+      Bexpression* bad_cap =
+	gogo->backend()->binary_expression(OPERATOR_OROR, cap_too_small,
+					   cap_too_large, loc);
+      bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_cap,
+						     bad_index, loc);
     }
 
-  tree end_tree;
+  Bexpression* end;
   if (this->end_->is_nil_expression())
-    end_tree = length_tree;
+    end = length;
   else
     {
-      end_tree = this->end_->get_tree(context);
-      if (end_tree == error_mark_node)
-	return error_mark_node;
-      if (!DECL_P(end_tree))
-	end_tree = save_expr(end_tree);
-      if (!INTEGRAL_TYPE_P(TREE_TYPE(end_tree)))
-	end_tree = convert_to_integer(length_type, end_tree);
+      bounds_check = Expression::check_bounds(this->end_, loc);
+      Bexpression* bounds_bcheck =
+	tree_to_expr(bounds_check->get_tree(context));
 
-      bad_index = Expression::check_bounds(end_tree, length_type, bad_index,
-					   loc);
+      bad_index =
+	gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck,
+					   bad_index, loc);
 
-      end_tree = fold_convert_loc(loc.gcc_location(), length_type, end_tree);
-
-      tree bad_end = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
-                                     boolean_type_node,
-				     fold_build2_loc(loc.gcc_location(),
-                                                     LT_EXPR, boolean_type_node,
-						     end_tree, start_tree),
-				     fold_build2_loc(loc.gcc_location(),
-                                                     GT_EXPR, boolean_type_node,
-						     end_tree, cap_arg));
-      bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
-                                  boolean_type_node, bad_index, bad_end);
+      end = tree_to_expr(this->end_->get_tree(context));
+      end = gogo->backend()->convert_expression(int_btype, end, loc);
+      Bexpression* end_too_small =
+	gogo->backend()->binary_expression(OPERATOR_LT, end, start, loc);
+      Bexpression* end_too_large =
+	gogo->backend()->binary_expression(OPERATOR_GT, end, cap_arg, loc);
+      Bexpression* bad_end =
+	gogo->backend()->binary_expression(OPERATOR_OROR, end_too_small,
+					   end_too_large, loc);
+      bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_end,
+						     bad_index, loc);
     }
 
-
-  Type* element_type = array_type->element_type();
-  tree element_type_tree = type_to_tree(element_type->get_backend(gogo));
-  if (element_type_tree == error_mark_node)
-    return error_mark_node;
-  tree element_size = TYPE_SIZE_UNIT(element_type_tree);
-
-  tree offset = fold_build2_loc(loc.gcc_location(), MULT_EXPR, sizetype,
-				fold_convert_loc(loc.gcc_location(), sizetype,
-                                                 start_tree),
-				element_size);
-
   Expression* valptr = array_type->get_value_pointer(gogo, this->array_);
-  tree value_pointer = valptr->get_tree(context);
-  if (value_pointer == error_mark_node)
-    return error_mark_node;
+  Bexpression* val = tree_to_expr(valptr->get_tree(context));
+  val = gogo->backend()->pointer_offset_expression(val, start, loc);
 
-  value_pointer = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR,
-				  TREE_TYPE(value_pointer),
-				  value_pointer, offset);
+  Bexpression* result_length =
+    gogo->backend()->binary_expression(OPERATOR_MINUS, end, start, loc);
 
-  tree result_length_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR,
-                                            length_type, end_tree, start_tree);
+  Bexpression* result_capacity =
+    gogo->backend()->binary_expression(OPERATOR_MINUS, cap_arg, start, loc);
 
-  tree result_capacity_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR,
-                                              length_type, cap_arg, start_tree);
+  Btype* struct_btype = this->type()->get_backend(gogo);
+  std::vector<Bexpression*> init;
+  init.push_back(val);
+  init.push_back(result_length);
+  init.push_back(result_capacity);
 
-  tree struct_tree = type_to_tree(this->type()->get_backend(gogo));
-  go_assert(TREE_CODE(struct_tree) == RECORD_TYPE);
+  Bexpression* ctor =
+    gogo->backend()->constructor_expression(struct_btype, init, loc);
+  Bexpression* ret =
+    gogo->backend()->conditional_expression(struct_btype, bad_index,
+					    crash, ctor, loc);
 
-  vec<constructor_elt, va_gc> *init;
-  vec_alloc (init, 3);
-
-  constructor_elt empty = {NULL, NULL};
-  constructor_elt* elt = init->quick_push(empty);
-  tree field = TYPE_FIELDS(struct_tree);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
-  elt->index = field;
-  elt->value = value_pointer;
-
-  elt = init->quick_push(empty);
-  field = DECL_CHAIN(field);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
-  elt->index = field;
-  elt->value = fold_convert_loc(loc.gcc_location(), TREE_TYPE(field),
-                                result_length_tree);
-
-  elt = init->quick_push(empty);
-  field = DECL_CHAIN(field);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0);
-  elt->index = field;
-  elt->value = fold_convert_loc(loc.gcc_location(), TREE_TYPE(field),
-                                result_capacity_tree);
-
-  tree constructor = build_constructor(struct_tree, init);
-
-  if (TREE_CONSTANT(value_pointer)
-      && TREE_CONSTANT(result_length_tree)
-      && TREE_CONSTANT(result_capacity_tree))
-    TREE_CONSTANT(constructor) = 1;
-
-  return fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR,
-                         TREE_TYPE(constructor),
-			 build3(COND_EXPR, void_type_node,
-				bad_index, crash, NULL_TREE),
-			 constructor);
+  return expr_to_tree(ret);
 }
 
 // Dump ast representation for an array index expression.
@@ -10903,6 +10501,9 @@ class String_index_expression : public Expression
   int
   do_traverse(Traverse*);
 
+  Expression*
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
   Type*
   do_type();
 
@@ -10963,6 +10564,36 @@ String_index_expression::do_traverse(Traverse* traverse)
   return TRAVERSE_CONTINUE;
 }
 
+Expression*
+String_index_expression::do_flatten(Gogo*, Named_object*,
+                                    Statement_inserter* inserter)
+{
+  Temporary_statement* temp;
+  Location loc = this->location();
+  if (!this->string_->is_variable())
+    {
+      temp = Statement::make_temporary(NULL, this->string_, loc);
+      inserter->insert(temp);
+      this->string_ = Expression::make_temporary_reference(temp, loc);
+    }
+  if (!this->start_->is_variable())
+    {
+      temp = Statement::make_temporary(NULL, this->start_, loc);
+      inserter->insert(temp);
+      this->start_ = Expression::make_temporary_reference(temp, loc);
+    }
+  if (this->end_ != NULL
+      && !this->end_->is_nil_expression()
+      && !this->end_->is_variable())
+    {
+      temp = Statement::make_temporary(NULL, this->end_, loc);
+      inserter->insert(temp);
+      this->end_ = Expression::make_temporary_reference(temp, loc);
+    }
+
+  return this;
+}
+
 // Return the type of a string index.
 
 Type*
@@ -11049,112 +10680,87 @@ tree
 String_index_expression::do_get_tree(Translate_context* context)
 {
   Location loc = this->location();
-
-  tree string_tree = this->string_->get_tree(context);
-  if (string_tree == error_mark_node)
-    return error_mark_node;
-
+  Expression* string_arg = this->string_;
   if (this->string_->type()->points_to() != NULL)
-    string_tree = build_fold_indirect_ref(string_tree);
-  if (!DECL_P(string_tree))
-    string_tree = save_expr(string_tree);
-  tree string_type = TREE_TYPE(string_tree);
+    string_arg = Expression::make_unary(OPERATOR_MULT, this->string_, loc);
 
-  tree length_tree = String_type::length_tree(context->gogo(), string_tree);
-  length_tree = save_expr(length_tree);
-
-  Type* int_type = Type::lookup_integer_type("int");
-  tree length_type = type_to_tree(int_type->get_backend(context->gogo()));
-
-  tree bad_index = boolean_false_node;
-
-  tree start_tree = this->start_->get_tree(context);
-  if (start_tree == error_mark_node)
-    return error_mark_node;
-  if (!DECL_P(start_tree))
-    start_tree = save_expr(start_tree);
-  if (!INTEGRAL_TYPE_P(TREE_TYPE(start_tree)))
-    start_tree = convert_to_integer(length_type, start_tree);
-
-  bad_index = Expression::check_bounds(start_tree, length_type, bad_index,
-				       loc);
-
-  start_tree = fold_convert_loc(loc.gcc_location(), length_type, start_tree);
+  Expression* bad_index = Expression::check_bounds(this->start_, loc);
 
   int code = (this->end_ == NULL
 	      ? RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS
 	      : RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS);
-  tree crash = context->gogo()->runtime_error(code, loc)->get_tree(context);
+
+  Gogo* gogo = context->gogo();
+  Bexpression* crash =
+      tree_to_expr(gogo->runtime_error(code, loc)->get_tree(context));
+
+  Type* int_type = Type::lookup_integer_type("int");
+
+  // It is possible that an error occurred earlier because the start index
+  // cannot be represented as an integer type.  In this case, we shouldn't
+  // try casting the starting index into an integer since
+  // Type_conversion_expression will fail to get the backend representation.
+  // FIXME.
+  if (this->start_->type()->integer_type() == NULL
+      && !Type::are_convertible(int_type, this->start_->type(), NULL))
+    {
+      go_assert(saw_errors());
+      return error_mark_node;
+    }
+
+  Expression* start = Expression::make_cast(int_type, this->start_, loc);
 
   if (this->end_ == NULL)
     {
-      bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR,
-                                  boolean_type_node, bad_index,
-				  fold_build2_loc(loc.gcc_location(), GE_EXPR,
-						  boolean_type_node,
-						  start_tree, length_tree));
+      Expression* length =
+          Expression::make_string_info(this->string_, STRING_INFO_LENGTH, loc);
 
-      tree bytes_tree = String_type::bytes_tree(context->gogo(), string_tree);
-      tree ptr = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR,
-                                 TREE_TYPE(bytes_tree),
-				 bytes_tree,
-				 fold_convert_loc(loc.gcc_location(), sizetype,
-                                                  start_tree));
-      tree index = build_fold_indirect_ref_loc(loc.gcc_location(), ptr);
+      Expression* start_too_large =
+          Expression::make_binary(OPERATOR_GE, start, length, loc);
+      bad_index = Expression::make_binary(OPERATOR_OROR, start_too_large,
+                                          bad_index, loc);
+      Expression* bytes =
+	Expression::make_string_info(this->string_, STRING_INFO_DATA, loc);
 
-      return build2(COMPOUND_EXPR, TREE_TYPE(index),
-		    build3(COND_EXPR, void_type_node,
-			   bad_index, crash, NULL_TREE),
-		    index);
+      Bexpression* bstart = tree_to_expr(start->get_tree(context));
+      Bexpression* ptr = tree_to_expr(bytes->get_tree(context));
+      ptr = gogo->backend()->pointer_offset_expression(ptr, bstart, loc);
+      Bexpression* index = gogo->backend()->indirect_expression(ptr, true, loc);
+
+      Btype* byte_btype = bytes->type()->points_to()->get_backend(gogo);
+      Bexpression* index_error = tree_to_expr(bad_index->get_tree(context));
+      Bexpression* ret =
+          gogo->backend()->conditional_expression(byte_btype, index_error,
+                                                  crash, index, loc);
+      return expr_to_tree(ret);
+    }
+
+  Expression* end = NULL;
+  if (this->end_->is_nil_expression())
+    {
+      mpz_t neg_one;
+      mpz_init_set_si(neg_one, -1);
+      end = Expression::make_integer(&neg_one, int_type, loc);
+      mpz_clear(neg_one);
     }
   else
     {
-      tree end_tree;
-      if (this->end_->is_nil_expression())
-	end_tree = build_int_cst(length_type, -1);
-      else
-	{
-	  end_tree = this->end_->get_tree(context);
-	  if (end_tree == error_mark_node)
-	    return error_mark_node;
-	  if (!DECL_P(end_tree))
-	    end_tree = save_expr(end_tree);
-	  if (!INTEGRAL_TYPE_P(TREE_TYPE(end_tree)))
-	    end_tree = convert_to_integer(length_type, end_tree);
-
-	  bad_index = Expression::check_bounds(end_tree, length_type,
-					       bad_index, loc);
-
-	  end_tree = fold_convert_loc(loc.gcc_location(), length_type,
-                                      end_tree);
-	}
-
-      static tree strslice_fndecl;
-      tree ret = Gogo::call_builtin(&strslice_fndecl,
-				    loc,
-				    "__go_string_slice",
-				    3,
-				    string_type,
-				    string_type,
-				    string_tree,
-				    length_type,
-				    start_tree,
-				    length_type,
-				    end_tree);
-      if (ret == error_mark_node)
-	return error_mark_node;
-      // This will panic if the bounds are out of range for the
-      // string.
-      TREE_NOTHROW(strslice_fndecl) = 0;
-
-      if (bad_index == boolean_false_node)
-	return ret;
-      else
-	return build2(COMPOUND_EXPR, TREE_TYPE(ret),
-		      build3(COND_EXPR, void_type_node,
-			     bad_index, crash, NULL_TREE),
-		      ret);
+      Expression* bounds_check = Expression::check_bounds(this->end_, loc);
+      bad_index =
+          Expression::make_binary(OPERATOR_OROR, bounds_check, bad_index, loc);
+      end = Expression::make_cast(int_type, this->end_, loc);
     }
+
+  Expression* strslice = Runtime::make_call(Runtime::STRING_SLICE, loc, 3,
+                                            string_arg, start, end);
+  Bexpression* bstrslice = tree_to_expr(strslice->get_tree(context));
+
+  Btype* str_btype = strslice->type()->get_backend(gogo);
+  Bexpression* index_error = tree_to_expr(bad_index->get_tree(context));
+  Bexpression* ret =
+      gogo->backend()->conditional_expression(str_btype, index_error,
+                                              crash, bstrslice, loc);
+  return expr_to_tree(ret);
 }
 
 // Dump ast representation for a string index expression.
@@ -11199,6 +10805,44 @@ Map_index_expression::do_traverse(Traverse* traverse)
   return Expression::traverse(&this->index_, traverse);
 }
 
+// We need to pass in a pointer to the key, so flatten the index into a
+// temporary variable if it isn't already.  The value pointer will be
+// dereferenced and checked for nil, so flatten into a temporary to avoid
+// recomputation.
+
+Expression*
+Map_index_expression::do_flatten(Gogo*, Named_object*,
+				 Statement_inserter* inserter)
+{
+  Map_type* mt = this->get_map_type();
+  if (this->index_->type() != mt->key_type())
+    this->index_ = Expression::make_cast(mt->key_type(), this->index_,
+                                         this->location());
+
+  if (!this->index_->is_variable())
+    {
+      Temporary_statement* temp = Statement::make_temporary(NULL, this->index_,
+                                                            this->location());
+      inserter->insert(temp);
+      this->index_ = Expression::make_temporary_reference(temp,
+                                                          this->location());
+    }
+
+  if (this->value_pointer_ == NULL)
+    this->get_value_pointer(this->is_lvalue_);
+  if (!this->value_pointer_->is_variable())
+    {
+      Temporary_statement* temp =
+          Statement::make_temporary(NULL, this->value_pointer_,
+                                    this->location());
+      inserter->insert(temp);
+      this->value_pointer_ =
+          Expression::make_temporary_reference(temp, this->location());
+    }
+
+  return this;
+}
+
 // Return the type of a map index.
 
 Type*
@@ -11258,131 +10902,84 @@ Map_index_expression::do_get_tree(Translate_context* context)
 {
   Map_type* type = this->get_map_type();
   if (type == NULL)
-    return error_mark_node;
+    {
+      go_assert(saw_errors());
+      return error_mark_node;
+    }
 
-  tree valptr = this->get_value_pointer(context, this->is_lvalue_);
-  if (valptr == error_mark_node)
-    return error_mark_node;
-  valptr = save_expr(valptr);
-
-  tree val_type_tree = TREE_TYPE(TREE_TYPE(valptr));
+  go_assert(this->value_pointer_ != NULL
+            && this->value_pointer_->is_variable());
 
+  Bexpression* ret;
   if (this->is_lvalue_)
-    return build_fold_indirect_ref(valptr);
+    {
+      Expression* val =
+          Expression::make_unary(OPERATOR_MULT, this->value_pointer_,
+                                 this->location());
+      ret = tree_to_expr(val->get_tree(context));
+    }
   else if (this->is_in_tuple_assignment_)
     {
       // Tuple_map_assignment_statement is responsible for using this
       // appropriately.
-      return valptr;
+      ret = tree_to_expr(this->value_pointer_->get_tree(context));
     }
   else
     {
+      Location loc = this->location();
+
+      Expression* nil_check =
+          Expression::make_binary(OPERATOR_EQEQ, this->value_pointer_,
+                                  Expression::make_nil(loc), loc);
+      Bexpression* bnil_check = tree_to_expr(nil_check->get_tree(context));
+      Expression* val =
+          Expression::make_unary(OPERATOR_MULT, this->value_pointer_, loc);
+      Bexpression* bval = tree_to_expr(val->get_tree(context));
+
       Gogo* gogo = context->gogo();
       Btype* val_btype = type->val_type()->get_backend(gogo);
       Bexpression* val_zero = gogo->backend()->zero_expression(val_btype);
-      return fold_build3(COND_EXPR, val_type_tree,
-			 fold_build2(EQ_EXPR, boolean_type_node, valptr,
-				     fold_convert(TREE_TYPE(valptr),
-						  null_pointer_node)),
-			 expr_to_tree(val_zero),
-			 build_fold_indirect_ref(valptr));
+      ret = gogo->backend()->conditional_expression(val_btype, bnil_check,
+                                                    val_zero, bval, loc);
     }
+
+  return expr_to_tree(ret);
 }
 
-// Get a tree for the map index.  This returns a tree which evaluates
-// to a pointer to a value.  The pointer will be NULL if the key is
+// Get an expression for the map index.  This returns an expression which
+// evaluates to a pointer to a value.  The pointer will be NULL if the key is
 // not in the map.
 
-tree
-Map_index_expression::get_value_pointer(Translate_context* context,
-					bool insert)
+Expression*
+Map_index_expression::get_value_pointer(bool insert)
 {
-  Map_type* type = this->get_map_type();
-  if (type == NULL)
-    return error_mark_node;
-
-  tree map_tree = this->map_->get_tree(context);
-  tree index_tree = this->index_->get_tree(context);
-  index_tree = Expression::convert_for_assignment(context, type->key_type(),
-						  this->index_->type(),
-						  index_tree,
-						  this->location());
-  if (map_tree == error_mark_node || index_tree == error_mark_node)
-    return error_mark_node;
-
-  if (this->map_->type()->points_to() != NULL)
-    map_tree = build_fold_indirect_ref(map_tree);
-
-  // We need to pass in a pointer to the key, so stuff it into a
-  // variable.
-  tree tmp;
-  tree make_tmp;
-  if (current_function_decl != NULL)
+  if (this->value_pointer_ == NULL)
     {
-      tmp = create_tmp_var(TREE_TYPE(index_tree), get_name(index_tree));
-      DECL_IGNORED_P(tmp) = 0;
-      DECL_INITIAL(tmp) = index_tree;
-      make_tmp = build1(DECL_EXPR, void_type_node, tmp);
-      TREE_ADDRESSABLE(tmp) = 1;
-    }
-  else
-    {
-      tmp = build_decl(this->location().gcc_location(), VAR_DECL,
-                       create_tmp_var_name("M"),
-		       TREE_TYPE(index_tree));
-      DECL_EXTERNAL(tmp) = 0;
-      TREE_PUBLIC(tmp) = 0;
-      TREE_STATIC(tmp) = 1;
-      DECL_ARTIFICIAL(tmp) = 1;
-      if (!TREE_CONSTANT(index_tree))
-	make_tmp = fold_build2_loc(this->location().gcc_location(),
-                                   INIT_EXPR, void_type_node,
-				   tmp, index_tree);
-      else
+      Map_type* type = this->get_map_type();
+      if (type == NULL)
 	{
-	  TREE_READONLY(tmp) = 1;
-	  TREE_CONSTANT(tmp) = 1;
-	  DECL_INITIAL(tmp) = index_tree;
-	  make_tmp = NULL_TREE;
+	  go_assert(saw_errors());
+	  return Expression::make_error(this->location());
 	}
-      rest_of_decl_compilation(tmp, 1, 0);
+
+      Location loc = this->location();
+      Expression* map_ref = this->map_;
+      if (this->map_->type()->points_to() != NULL)
+        map_ref = Expression::make_unary(OPERATOR_MULT, map_ref, loc);
+
+      Expression* index_ptr = Expression::make_unary(OPERATOR_AND, this->index_,
+                                                     loc);
+      Expression* map_index =
+          Runtime::make_call(Runtime::MAP_INDEX, loc, 3,
+                             map_ref, index_ptr,
+                             Expression::make_boolean(insert, loc));
+
+      Type* val_type = type->val_type();
+      this->value_pointer_ =
+          Expression::make_unsafe_cast(Type::make_pointer_type(val_type),
+                                       map_index, this->location());
     }
-  tree tmpref =
-    fold_convert_loc(this->location().gcc_location(), const_ptr_type_node,
-                     build_fold_addr_expr_loc(this->location().gcc_location(),
-                                              tmp));
-
-  static tree map_index_fndecl;
-  tree call = Gogo::call_builtin(&map_index_fndecl,
-				 this->location(),
-				 "__go_map_index",
-				 3,
-				 const_ptr_type_node,
-				 TREE_TYPE(map_tree),
-				 map_tree,
-				 const_ptr_type_node,
-				 tmpref,
-				 boolean_type_node,
-				 (insert
-				  ? boolean_true_node
-				  : boolean_false_node));
-  if (call == error_mark_node)
-    return error_mark_node;
-  // This can panic on a map of interface type if the interface holds
-  // an uncomparable or unhashable type.
-  TREE_NOTHROW(map_index_fndecl) = 0;
-
-  Type* val_type = type->val_type();
-  tree val_type_tree = type_to_tree(val_type->get_backend(context->gogo()));
-  if (val_type_tree == error_mark_node)
-    return error_mark_node;
-  tree ptr_val_type_tree = build_pointer_type(val_type_tree);
-
-  tree ret = fold_convert_loc(this->location().gcc_location(),
-                              ptr_val_type_tree, call);
-  if (make_tmp != NULL_TREE)
-    ret = build2(COMPOUND_EXPR, ptr_val_type_tree, make_tmp, ret);
-  return ret;
+  return this->value_pointer_;
 }
 
 // Dump ast representation for a map index expression
@@ -11841,7 +11438,7 @@ Interface_field_reference_expression::do_get_tree(Translate_context* context)
   vals->push_back(this->expr_);
 
   Expression* expr = Expression::make_struct_composite_literal(st, vals, loc);
-  expr = Expression::make_heap_composite(expr, loc);
+  expr = Expression::make_heap_expression(expr, loc);
 
   Bexpression* bclosure = tree_to_expr(expr->get_tree(context));
   Expression* nil_check =
@@ -12193,15 +11790,13 @@ class Allocation_expression : public Expression
 tree
 Allocation_expression::do_get_tree(Translate_context* context)
 {
-  tree type_tree = type_to_tree(this->type_->get_backend(context->gogo()));
-  if (type_tree == error_mark_node)
-    return error_mark_node;
-  tree size_tree = TYPE_SIZE_UNIT(type_tree);
-  tree space = context->gogo()->allocate_memory(this->type_, size_tree,
-						this->location());
-  if (space == error_mark_node)
-    return error_mark_node;
-  return fold_convert(build_pointer_type(type_tree), space);
+  Gogo* gogo = context->gogo();
+  Location loc = this->location();
+  Expression* space = gogo->allocate_memory(this->type_, loc);
+  Bexpression* bspace = tree_to_expr(space->get_tree(context));
+  Btype* pbtype = gogo->backend()->pointer_type(this->type_->get_backend(gogo));
+  Bexpression* ret = gogo->backend()->convert_expression(pbtype, bspace, loc);
+  return expr_to_tree(ret);
 }
 
 // Dump ast representation for an allocation expression.
@@ -12453,64 +12048,38 @@ Struct_construction_expression::do_get_tree(Translate_context* context)
 {
   Gogo* gogo = context->gogo();
 
+  Btype* btype = this->type_->get_backend(gogo);
   if (this->vals_ == NULL)
-    {
-      Btype* btype = this->type_->get_backend(gogo);
-      return expr_to_tree(gogo->backend()->zero_expression(btype));
-    }
+    return expr_to_tree(gogo->backend()->zero_expression(btype));
 
-  tree type_tree = type_to_tree(this->type_->get_backend(gogo));
-  if (type_tree == error_mark_node)
-    return error_mark_node;
-  go_assert(TREE_CODE(type_tree) == RECORD_TYPE);
-
-  bool is_constant = true;
   const Struct_field_list* fields = this->type_->struct_type()->fields();
-  vec<constructor_elt, va_gc> *elts;
-  vec_alloc (elts, fields->size());
-  Struct_field_list::const_iterator pf = fields->begin();
   Expression_list::const_iterator pv = this->vals_->begin();
-  for (tree field = TYPE_FIELDS(type_tree);
-       field != NULL_TREE;
-       field = DECL_CHAIN(field), ++pf)
+  std::vector<Bexpression*> init;
+  for (Struct_field_list::const_iterator pf = fields->begin();
+       pf != fields->end();
+       ++pf)
     {
-      go_assert(pf != fields->end());
-
       Btype* fbtype = pf->type()->get_backend(gogo);
-
-      tree val;
       if (pv == this->vals_->end())
-	val = expr_to_tree(gogo->backend()->zero_expression(fbtype));
+        init.push_back(gogo->backend()->zero_expression(fbtype));
       else if (*pv == NULL)
 	{
-	  val = expr_to_tree(gogo->backend()->zero_expression(fbtype));
+          init.push_back(gogo->backend()->zero_expression(fbtype));
 	  ++pv;
 	}
       else
 	{
-	  val = Expression::convert_for_assignment(context, pf->type(),
-						   (*pv)->type(),
-						   (*pv)->get_tree(context),
-						   this->location());
+          Expression* val =
+              Expression::convert_for_assignment(gogo, pf->type(),
+                                                 *pv, this->location());
+          init.push_back(tree_to_expr(val->get_tree(context)));
 	  ++pv;
 	}
-
-      if (val == error_mark_node || TREE_TYPE(val) == error_mark_node)
-	return error_mark_node;
-
-      constructor_elt empty = {NULL, NULL};
-      constructor_elt* elt = elts->quick_push(empty);
-      elt->index = field;
-      elt->value = val;
-      if (!TREE_CONSTANT(val))
-	is_constant = false;
     }
-  go_assert(pf == fields->end());
 
-  tree ret = build_constructor(type_tree, elts);
-  if (is_constant)
-    TREE_CONSTANT(ret) = 1;
-  return ret;
+  Bexpression* ret =
+      gogo->backend()->constructor_expression(btype, init, this->location());
+  return expr_to_tree(ret);
 }
 
 // Export a struct construction.
@@ -12555,7 +12124,7 @@ Expression::make_struct_composite_literal(Type* type, Expression_list* vals,
 
 // Construct an array.  This class is not used directly; instead we
 // use the child classes, Fixed_array_construction_expression and
-// Open_array_construction_expression.
+// Slice_construction_expression.
 
 class Array_construction_expression : public Expression
 {
@@ -12608,9 +12177,9 @@ protected:
   vals()
   { return this->vals_; }
 
-  // Get a constructor tree for the array values.
-  tree
-  get_constructor_tree(Translate_context* context, tree type_tree);
+  // Get the backend constructor for the array values.
+  Bexpression*
+  get_constructor(Translate_context* context, Btype* btype);
 
   void
   do_dump_expression(Ast_dump_context*) const;
@@ -12723,16 +12292,17 @@ Array_construction_expression::do_check_types(Gogo*)
     }
 }
 
-// Get a constructor tree for the array values.
+// Get a constructor expression for the array values.
 
-tree
-Array_construction_expression::get_constructor_tree(Translate_context* context,
-						    tree type_tree)
+Bexpression*
+Array_construction_expression::get_constructor(Translate_context* context,
+                                               Btype* array_btype)
 {
-  vec<constructor_elt, va_gc> *values;
-  vec_alloc (values, (this->vals_ == NULL ? 0 : this->vals_->size()));
   Type* element_type = this->type_->array_type()->element_type();
-  bool is_constant = true;
+
+  std::vector<unsigned long> indexes;
+  std::vector<Bexpression*> vals;
+  Gogo* gogo = context->gogo();
   if (this->vals_ != NULL)
     {
       size_t i = 0;
@@ -12745,45 +12315,32 @@ Array_construction_expression::get_constructor_tree(Translate_context* context,
 	{
 	  if (this->indexes_ != NULL)
 	    go_assert(pi != this->indexes_->end());
-	  constructor_elt empty = {NULL, NULL};
-	  constructor_elt* elt = values->quick_push(empty);
 
 	  if (this->indexes_ == NULL)
-	    elt->index = size_int(i);
+	    indexes.push_back(i);
 	  else
-	    elt->index = size_int(*pi);
-
+	    indexes.push_back(*pi);
 	  if (*pv == NULL)
 	    {
-	      Gogo* gogo = context->gogo();
 	      Btype* ebtype = element_type->get_backend(gogo);
 	      Bexpression *zv = gogo->backend()->zero_expression(ebtype);
-	      elt->value = expr_to_tree(zv);
+	      vals.push_back(zv);
 	    }
 	  else
 	    {
-	      tree value_tree = (*pv)->get_tree(context);
-	      elt->value = Expression::convert_for_assignment(context,
-							      element_type,
-							      (*pv)->type(),
-							      value_tree,
-							      this->location());
+              Expression* val_expr =
+                  Expression::convert_for_assignment(gogo, element_type, *pv,
+                                                     this->location());
+	      vals.push_back(tree_to_expr(val_expr->get_tree(context)));
 	    }
-	  if (elt->value == error_mark_node)
-	    return error_mark_node;
-	  if (!TREE_CONSTANT(elt->value))
-	    is_constant = false;
 	  if (this->indexes_ != NULL)
 	    ++pi;
 	}
       if (this->indexes_ != NULL)
 	go_assert(pi == this->indexes_->end());
     }
-
-  tree ret = build_constructor(type_tree, values);
-  if (is_constant)
-    TREE_CONSTANT(ret) = 1;
-  return ret;
+  return gogo->backend()->array_constructor_expression(array_btype, indexes,
+                                                       vals, this->location());
 }
 
 // Export an array construction.
@@ -12894,43 +12451,47 @@ Fixed_array_construction_expression::do_get_tree(Translate_context* context)
 {
   Type* type = this->type();
   Btype* btype = type->get_backend(context->gogo());
-  return this->get_constructor_tree(context, type_to_tree(btype));
+  return expr_to_tree(this->get_constructor(context, btype));
 }
 
-// Construct an open array.
+// Construct a slice.
 
-class Open_array_construction_expression : public Array_construction_expression
+class Slice_construction_expression : public Array_construction_expression
 {
  public:
-  Open_array_construction_expression(Type* type,
-				     const std::vector<unsigned long>* indexes,
-				     Expression_list* vals, Location location)
-    : Array_construction_expression(EXPRESSION_OPEN_ARRAY_CONSTRUCTION,
-				    type, indexes, vals, location)
+  Slice_construction_expression(Type* type,
+				const std::vector<unsigned long>* indexes,
+				Expression_list* vals, Location location)
+    : Array_construction_expression(EXPRESSION_SLICE_CONSTRUCTION,
+				    type, indexes, vals, location),
+      valtype_(NULL)
   { go_assert(type->is_slice_type()); }
 
  protected:
-  // Note that taking the address of an open array literal is invalid.
+  // Note that taking the address of a slice literal is invalid.
 
   Expression*
   do_copy()
   {
-    return new Open_array_construction_expression(this->type(),
-						  this->indexes(),
-						  (this->vals() == NULL
-						   ? NULL
-						   : this->vals()->copy()),
-						  this->location());
+    return new Slice_construction_expression(this->type(), this->indexes(),
+					     (this->vals() == NULL
+					      ? NULL
+					      : this->vals()->copy()),
+					     this->location());
   }
 
   tree
   do_get_tree(Translate_context*);
+
+ private:
+  // The type of the values in this slice.
+  Type* valtype_;
 };
 
-// Return a tree for constructing an open array.
+// Return a tree for constructing a slice.
 
 tree
-Open_array_construction_expression::do_get_tree(Translate_context* context)
+Slice_construction_expression::do_get_tree(Translate_context* context)
 {
   Array_type* array_type = this->type()->array_type();
   if (array_type == NULL)
@@ -12940,49 +12501,43 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
     }
 
   Type* element_type = array_type->element_type();
-  Btype* belement_type = element_type->get_backend(context->gogo());
-  tree element_type_tree = type_to_tree(belement_type);
-  if (element_type_tree == error_mark_node)
-    return error_mark_node;
+  if (this->valtype_ == NULL)
+    {
+      mpz_t lenval;
+      Expression* length;
+      if (this->vals() == NULL || this->vals()->empty())
+        mpz_init_set_ui(lenval, 0);
+      else
+        {
+          if (this->indexes() == NULL)
+            mpz_init_set_ui(lenval, this->vals()->size());
+          else
+            mpz_init_set_ui(lenval, this->indexes()->back() + 1);
+        }
+      Location loc = this->location();
+      Type* int_type = Type::lookup_integer_type("int");
+      length = Expression::make_integer(&lenval, int_type, loc);
+      mpz_clear(lenval);
+      this->valtype_ = Type::make_array_type(element_type, length);
+    }
 
   tree values;
-  tree length_tree;
+  Gogo* gogo = context->gogo();
+  Btype* val_btype = this->valtype_->get_backend(gogo);
   if (this->vals() == NULL || this->vals()->empty())
     {
       // We need to create a unique value.
-      tree max = size_int(0);
-      tree constructor_type = build_array_type(element_type_tree,
-					       build_index_type(max));
-      if (constructor_type == error_mark_node)
-	return error_mark_node;
-      vec<constructor_elt, va_gc> *vec;
-      vec_alloc(vec, 1);
-      constructor_elt empty = {NULL, NULL};
-      constructor_elt* elt = vec->quick_push(empty);
-      elt->index = size_int(0);
-      Gogo* gogo = context->gogo();
-      Btype* btype = element_type->get_backend(gogo);
-      elt->value = expr_to_tree(gogo->backend()->zero_expression(btype));
-      values = build_constructor(constructor_type, vec);
-      if (TREE_CONSTANT(elt->value))
-	TREE_CONSTANT(values) = 1;
-      length_tree = size_int(0);
+      Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
+      Bexpression* zero = gogo->backend()->zero_expression(int_btype);
+      std::vector<unsigned long> index(1, 0);
+      std::vector<Bexpression*> val(1, zero);
+      Bexpression* ctor =
+	gogo->backend()->array_constructor_expression(val_btype, index, val,
+						      this->location());
+      values = expr_to_tree(ctor);
     }
   else
-    {
-      unsigned long max_index;
-      if (this->indexes() == NULL)
-	max_index = this->vals()->size() - 1;
-      else
-	max_index = this->indexes()->back();
-      tree max_tree = size_int(max_index);
-      tree constructor_type = build_array_type(element_type_tree,
-					       build_index_type(max_tree));
-      if (constructor_type == error_mark_node)
-	return error_mark_node;
-      values = this->get_constructor_tree(context, constructor_type);
-      length_tree = size_int(max_index + 1);
-    }
+    values = expr_to_tree(this->get_constructor(context, val_btype));
 
   if (values == error_mark_node)
     return error_mark_node;
@@ -13030,10 +12585,9 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
     }
   else
     {
-      tree memsize = TYPE_SIZE_UNIT(TREE_TYPE(values));
-      space = context->gogo()->allocate_memory(element_type, memsize,
-					       this->location());
-      space = save_expr(space);
+      Expression* alloc =
+          context->gogo()->allocate_memory(this->valtype_, this->location());
+      space = save_expr(alloc->get_tree(context));
 
       tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space);
       tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(),
@@ -13042,7 +12596,7 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
       set = build2(MODIFY_EXPR, void_type_node, ref, values);
     }
 
-  // Build a constructor for the open array.
+  // Build a constructor for the slice.
 
   tree type_tree = type_to_tree(this->type()->get_backend(context->gogo()));
   if (type_tree == error_mark_node)
@@ -13059,6 +12613,7 @@ Open_array_construction_expression::do_get_tree(Translate_context* context)
   elt->index = field;
   elt->value = fold_convert(TREE_TYPE(field), space);
 
+  tree length_tree = this->valtype_->array_type()->length()->get_tree(context);
   elt = init->quick_push(empty);
   field = DECL_CHAIN(field);
   go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
@@ -13091,7 +12646,7 @@ Expression::make_slice_composite_literal(Type* type, Expression_list* vals,
 					 Location location)
 {
   go_assert(type->is_slice_type());
-  return new Open_array_construction_expression(type, NULL, vals, location);
+  return new Slice_construction_expression(type, NULL, vals, location);
 }
 
 // Construct a map.
@@ -13102,13 +12657,16 @@ class Map_construction_expression : public Expression
   Map_construction_expression(Type* type, Expression_list* vals,
 			      Location location)
     : Expression(EXPRESSION_MAP_CONSTRUCTION, location),
-      type_(type), vals_(vals)
+      type_(type), vals_(vals), element_type_(NULL), constructor_temp_(NULL)
   { go_assert(vals == NULL || vals->size() % 2 == 0); }
 
  protected:
   int
   do_traverse(Traverse* traverse);
 
+  Expression*
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
   Type*
   do_type()
   { return this->type_; }
@@ -13140,6 +12698,10 @@ class Map_construction_expression : public Expression
   Type* type_;
   // The list of values.
   Expression_list* vals_;
+  // The type of the key-value pair struct for each map element.
+  Struct_type* element_type_;
+  // A temporary reference to the variable storing the constructor initializer.
+  Temporary_statement* constructor_temp_;
 };
 
 // Traversal.
@@ -13155,6 +12717,69 @@ Map_construction_expression::do_traverse(Traverse* traverse)
   return TRAVERSE_CONTINUE;
 }
 
+// Flatten constructor initializer into a temporary variable since
+// we need to take its address for __go_construct_map.
+
+Expression*
+Map_construction_expression::do_flatten(Gogo* gogo, Named_object*,
+                                        Statement_inserter* inserter)
+{
+  if (!this->is_error_expression()
+      && this->vals_ != NULL
+      && !this->vals_->empty()
+      && this->constructor_temp_ == NULL)
+    {
+      Map_type* mt = this->type_->map_type();
+      Type* key_type = mt->key_type();
+      Type* val_type = mt->val_type();
+      this->element_type_ = Type::make_builtin_struct_type(2,
+                                                           "__key", key_type,
+                                                           "__val", val_type);
+
+      Expression_list* value_pairs = new Expression_list();
+      Location loc = this->location();
+
+      size_t i = 0;
+      for (Expression_list::const_iterator pv = this->vals_->begin();
+           pv != this->vals_->end();
+           ++pv, ++i)
+        {
+          Expression_list* key_value_pair = new Expression_list();
+          Expression* key =
+              Expression::convert_for_assignment(gogo, key_type, *pv, loc);
+
+          ++pv;
+          Expression* val =
+              Expression::convert_for_assignment(gogo, val_type, *pv, loc);
+
+          key_value_pair->push_back(key);
+          key_value_pair->push_back(val);
+          value_pairs->push_back(
+              Expression::make_struct_composite_literal(this->element_type_,
+                                                        key_value_pair, loc));
+        }
+
+      mpz_t lenval;
+      mpz_init_set_ui(lenval, i);
+      Expression* element_count = Expression::make_integer(&lenval, NULL, loc);
+      mpz_clear(lenval);
+
+      Type* ctor_type =
+          Type::make_array_type(this->element_type_, element_count);
+      Expression* constructor =
+          new Fixed_array_construction_expression(ctor_type, NULL,
+                                                  value_pairs, loc);
+
+      this->constructor_temp_ =
+          Statement::make_temporary(NULL, constructor, loc);
+      constructor->issue_nil_check();
+      this->constructor_temp_->set_is_address_taken();
+      inserter->insert(this->constructor_temp_);
+    }
+
+  return this;
+}
+
 // Final type determination.
 
 void
@@ -13216,167 +12841,53 @@ Map_construction_expression::do_check_types(Gogo*)
 tree
 Map_construction_expression::do_get_tree(Translate_context* context)
 {
-  Gogo* gogo = context->gogo();
+  if (this->is_error_expression())
+    return error_mark_node;
   Location loc = this->location();
 
-  Map_type* mt = this->type_->map_type();
-
-  // Build a struct to hold the key and value.
-  tree struct_type = make_node(RECORD_TYPE);
-
-  Type* key_type = mt->key_type();
-  tree id = get_identifier("__key");
-  tree key_type_tree = type_to_tree(key_type->get_backend(gogo));
-  if (key_type_tree == error_mark_node)
-    return error_mark_node;
-  tree key_field = build_decl(loc.gcc_location(), FIELD_DECL, id,
-                              key_type_tree);
-  DECL_CONTEXT(key_field) = struct_type;
-  TYPE_FIELDS(struct_type) = key_field;
-
-  Type* val_type = mt->val_type();
-  id = get_identifier("__val");
-  tree val_type_tree = type_to_tree(val_type->get_backend(gogo));
-  if (val_type_tree == error_mark_node)
-    return error_mark_node;
-  tree val_field = build_decl(loc.gcc_location(), FIELD_DECL, id,
-                              val_type_tree);
-  DECL_CONTEXT(val_field) = struct_type;
-  DECL_CHAIN(key_field) = val_field;
-
-  layout_type(struct_type);
-
-  bool is_constant = true;
   size_t i = 0;
-  tree valaddr;
-  tree make_tmp;
-
+  Expression* ventries;
   if (this->vals_ == NULL || this->vals_->empty())
-    {
-      valaddr = null_pointer_node;
-      make_tmp = NULL_TREE;
-    }
+    ventries = Expression::make_nil(loc);
   else
     {
-      vec<constructor_elt, va_gc> *values;
-      vec_alloc(values, this->vals_->size() / 2);
+      go_assert(this->constructor_temp_ != NULL);
+      i = this->vals_->size() / 2;
 
-      for (Expression_list::const_iterator pv = this->vals_->begin();
-	   pv != this->vals_->end();
-	   ++pv, ++i)
-	{
-	  bool one_is_constant = true;
-
-	  vec<constructor_elt, va_gc> *one;
-	  vec_alloc(one, 2);
-
-	  constructor_elt empty = {NULL, NULL};
-	  constructor_elt* elt = one->quick_push(empty);
-	  elt->index = key_field;
-	  tree val_tree = (*pv)->get_tree(context);
-	  elt->value = Expression::convert_for_assignment(context, key_type,
-							  (*pv)->type(),
-							  val_tree, loc);
-	  if (elt->value == error_mark_node)
-	    return error_mark_node;
-	  if (!TREE_CONSTANT(elt->value))
-	    one_is_constant = false;
-
-	  ++pv;
-
-	  elt = one->quick_push(empty);
-	  elt->index = val_field;
-	  val_tree = (*pv)->get_tree(context);
-	  elt->value = Expression::convert_for_assignment(context, val_type,
-							  (*pv)->type(),
-							  val_tree, loc);
-	  if (elt->value == error_mark_node)
-	    return error_mark_node;
-	  if (!TREE_CONSTANT(elt->value))
-	    one_is_constant = false;
-
-	  elt = values->quick_push(empty);
-	  elt->index = size_int(i);
-	  elt->value = build_constructor(struct_type, one);
-	  if (one_is_constant)
-	    TREE_CONSTANT(elt->value) = 1;
-	  else
-	    is_constant = false;
-	}
-
-      tree index_type = build_index_type(size_int(i - 1));
-      tree array_type = build_array_type(struct_type, index_type);
-      tree init = build_constructor(array_type, values);
-      if (is_constant)
-	TREE_CONSTANT(init) = 1;
-      tree tmp;
-      if (current_function_decl != NULL)
-	{
-	  tmp = create_tmp_var(array_type, get_name(array_type));
-	  DECL_INITIAL(tmp) = init;
-	  make_tmp = fold_build1_loc(loc.gcc_location(), DECL_EXPR,
-                                     void_type_node, tmp);
-	  TREE_ADDRESSABLE(tmp) = 1;
-	}
-      else
-	{
-	  tmp = build_decl(loc.gcc_location(), VAR_DECL,
-                           create_tmp_var_name("M"), array_type);
-	  DECL_EXTERNAL(tmp) = 0;
-	  TREE_PUBLIC(tmp) = 0;
-	  TREE_STATIC(tmp) = 1;
-	  DECL_ARTIFICIAL(tmp) = 1;
-	  if (!TREE_CONSTANT(init))
-	    make_tmp = fold_build2_loc(loc.gcc_location(), INIT_EXPR,
-                                       void_type_node, tmp, init);
-	  else
-	    {
-	      TREE_READONLY(tmp) = 1;
-	      TREE_CONSTANT(tmp) = 1;
-	      DECL_INITIAL(tmp) = init;
-	      make_tmp = NULL_TREE;
-	    }
-	  rest_of_decl_compilation(tmp, 1, 0);
-	}
-
-      valaddr = build_fold_addr_expr(tmp);
+      Expression* ctor_ref =
+          Expression::make_temporary_reference(this->constructor_temp_, loc);
+      ventries = Expression::make_unary(OPERATOR_AND, ctor_ref, loc);
     }
 
-  Bexpression* bdescriptor = mt->map_descriptor_pointer(gogo, loc);
-  tree descriptor = expr_to_tree(bdescriptor);
+  Map_type* mt = this->type_->map_type();
+  if (this->element_type_ == NULL)
+      this->element_type_ =
+          Type::make_builtin_struct_type(2,
+                                         "__key", mt->key_type(),
+                                         "__val", mt->val_type());
+  Expression* descriptor = Expression::make_map_descriptor(mt, loc);
 
-  tree type_tree = type_to_tree(this->type_->get_backend(gogo));
-  if (type_tree == error_mark_node)
-    return error_mark_node;
+  Type* uintptr_t = Type::lookup_integer_type("uintptr");
+  mpz_t countval;
+  mpz_init_set_ui(countval, i);
+  Expression* count = Expression::make_integer(&countval, uintptr_t, loc);
+  mpz_clear(countval);
 
-  static tree construct_map_fndecl;
-  tree call = Gogo::call_builtin(&construct_map_fndecl,
-				 loc,
-				 "__go_construct_map",
-				 6,
-				 type_tree,
-				 TREE_TYPE(descriptor),
-				 descriptor,
-				 sizetype,
-				 size_int(i),
-				 sizetype,
-				 TYPE_SIZE_UNIT(struct_type),
-				 sizetype,
-				 byte_position(val_field),
-				 sizetype,
-				 TYPE_SIZE_UNIT(TREE_TYPE(val_field)),
-				 const_ptr_type_node,
-				 fold_convert(const_ptr_type_node, valaddr));
-  if (call == error_mark_node)
-    return error_mark_node;
+  Expression* entry_size =
+      Expression::make_type_info(this->element_type_, TYPE_INFO_SIZE);
 
-  tree ret;
-  if (make_tmp == NULL)
-    ret = call;
-  else
-    ret = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, type_tree,
-                          make_tmp, call);
-  return ret;
+  unsigned int field_index;
+  const Struct_field* valfield =
+      this->element_type_->find_local_field("__val", &field_index);
+  Expression* val_offset =
+      Expression::make_struct_field_offset(this->element_type_, valfield);
+  Expression* val_size =
+      Expression::make_type_info(mt->val_type(), TYPE_INFO_SIZE);
+
+  Expression* map_ctor =
+      Runtime::make_call(Runtime::CONSTRUCT_MAP, loc, 6, descriptor, count,
+                         entry_size, val_offset, val_size, ventries);
+  return map_ctor->get_tree(context);
 }
 
 // Export an array construction.
@@ -13589,7 +13100,7 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function,
     }
 
   if (is_pointer)
-    ret = Expression::make_heap_composite(ret, this->location());
+    ret = Expression::make_heap_expression(ret, this->location());
 
   return ret;
 }
@@ -14031,8 +13542,7 @@ Composite_literal_expression::make_array(
     return new Fixed_array_construction_expression(type, indexes, vals,
 						   location);
   else
-    return new Open_array_construction_expression(type, indexes, vals,
-						  location);
+    return new Slice_construction_expression(type, indexes, vals, location);
 }
 
 // Lower a map composite literal.
@@ -14112,7 +13622,7 @@ Expression::is_composite_literal() const
     case EXPRESSION_COMPOSITE_LITERAL:
     case EXPRESSION_STRUCT_CONSTRUCTION:
     case EXPRESSION_FIXED_ARRAY_CONSTRUCTION:
-    case EXPRESSION_OPEN_ARRAY_CONSTRUCTION:
+    case EXPRESSION_SLICE_CONSTRUCTION:
     case EXPRESSION_MAP_CONSTRUCTION:
       return true;
     default:
@@ -14140,10 +13650,10 @@ Expression::is_nonconstant_composite_literal() const
 	  static_cast<const Fixed_array_construction_expression*>(this);
 	return !pace->is_constant_array();
       }
-    case EXPRESSION_OPEN_ARRAY_CONSTRUCTION:
+    case EXPRESSION_SLICE_CONSTRUCTION:
       {
-	const Open_array_construction_expression *pace =
-	  static_cast<const Open_array_construction_expression*>(this);
+	const Slice_construction_expression *pace =
+	  static_cast<const Slice_construction_expression*>(this);
 	return !pace->is_constant_array();
       }
     case EXPRESSION_MAP_CONSTRUCTION:
@@ -14195,6 +13705,21 @@ Type_guard_expression::do_traverse(Traverse* traverse)
   return TRAVERSE_CONTINUE;
 }
 
+Expression*
+Type_guard_expression::do_flatten(Gogo*, Named_object*,
+                                  Statement_inserter* inserter)
+{
+  if (!this->expr_->is_variable())
+    {
+      Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_,
+                                                            this->location());
+      inserter->insert(temp);
+      this->expr_ =
+          Expression::make_temporary_reference(temp, this->location());
+    }
+  return this;
+}
+
 // Check types of a type guard expression.  The expression must have
 // an interface type, but the actual type conversion is checked at run
 // time.
@@ -14236,24 +13761,23 @@ Type_guard_expression::do_check_types(Gogo*)
 tree
 Type_guard_expression::do_get_tree(Translate_context* context)
 {
-  tree expr_tree = this->expr_->get_tree(context);
-  if (expr_tree == error_mark_node)
-    return error_mark_node;
+  Expression* conversion;
   if (this->type_->interface_type() != NULL)
-    return Expression::convert_interface_to_interface(context, this->type_,
-						      this->expr_->type(),
-						      expr_tree, true,
-						      this->location());
+    conversion =
+        Expression::convert_interface_to_interface(this->type_, this->expr_,
+                                                   true, this->location());
   else
-    return Expression::convert_for_assignment(context, this->type_,
-					      this->expr_->type(), expr_tree,
-					      this->location());
+    conversion =
+        Expression::convert_for_assignment(context->gogo(), this->type_,
+                                           this->expr_, this->location());
+
+  return conversion->get_tree(context);
 }
 
 // Dump ast representation for a type guard expression.
 
 void
-Type_guard_expression::do_dump_expression(Ast_dump_context* ast_dump_context) 
+Type_guard_expression::do_dump_expression(Ast_dump_context* ast_dump_context)
     const
 {
   this->expr_->dump_expression(ast_dump_context);
@@ -14270,16 +13794,16 @@ Expression::make_type_guard(Expression* expr, Type* type,
   return new Type_guard_expression(expr, type, location);
 }
 
-// Class Heap_composite_expression.
+// Class Heap_expression.
 
-// When you take the address of a composite literal, it is allocated
+// When you take the address of an escaping expression, it is allocated
 // on the heap.  This class implements that.
 
-class Heap_composite_expression : public Expression
+class Heap_expression : public Expression
 {
  public:
-  Heap_composite_expression(Expression* expr, Location location)
-    : Expression(EXPRESSION_HEAP_COMPOSITE, location),
+  Heap_expression(Expression* expr, Location location)
+    : Expression(EXPRESSION_HEAP, location),
       expr_(expr)
   { }
 
@@ -14299,8 +13823,8 @@ class Heap_composite_expression : public Expression
   Expression*
   do_copy()
   {
-    return Expression::make_heap_composite(this->expr_->copy(),
-					   this->location());
+    return Expression::make_heap_expression(this->expr_->copy(),
+                                            this->location());
   }
 
   tree
@@ -14316,38 +13840,45 @@ class Heap_composite_expression : public Expression
   do_dump_expression(Ast_dump_context*) const;
 
  private:
-  // The composite literal which is being put on the heap.
+  // The expression which is being put on the heap.
   Expression* expr_;
 };
 
-// Return a tree which allocates a composite literal on the heap.
+// Return a tree which allocates an expression on the heap.
 
 tree
-Heap_composite_expression::do_get_tree(Translate_context* context)
+Heap_expression::do_get_tree(Translate_context* context)
 {
   tree expr_tree = this->expr_->get_tree(context);
   if (expr_tree == error_mark_node || TREE_TYPE(expr_tree) == error_mark_node)
     return error_mark_node;
-  tree expr_size = TYPE_SIZE_UNIT(TREE_TYPE(expr_tree));
-  go_assert(TREE_CODE(expr_size) == INTEGER_CST);
-  tree space = context->gogo()->allocate_memory(this->expr_->type(),
-						expr_size, this->location());
-  space = fold_convert(build_pointer_type(TREE_TYPE(expr_tree)), space);
+
+  Expression* alloc =
+      Expression::make_allocation(this->expr_->type(), this->location());
+
+  Gogo* gogo = context->gogo();
+  Btype* btype = this->expr_->type()->get_backend(gogo);
+  size_t expr_size = gogo->backend()->type_size(btype);
+  tree space = alloc->get_tree(context);
+  if (expr_size == 0)
+    return space;
+
   space = save_expr(space);
   tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(),
                                          space);
   TREE_THIS_NOTRAP(ref) = 1;
-  tree ret = build2(COMPOUND_EXPR, TREE_TYPE(space),
+  tree ret = build2(COMPOUND_EXPR,
+                    type_to_tree(this->type()->get_backend(gogo)),
 		    build2(MODIFY_EXPR, void_type_node, ref, expr_tree),
 		    space);
   SET_EXPR_LOCATION(ret, this->location().gcc_location());
   return ret;
 }
 
-// Dump ast representation for a heap composite expression.
+// Dump ast representation for a heap expression.
 
 void
-Heap_composite_expression::do_dump_expression(
+Heap_expression::do_dump_expression(
     Ast_dump_context* ast_dump_context) const
 {
   ast_dump_context->ostream() << "&(";
@@ -14355,12 +13886,12 @@ Heap_composite_expression::do_dump_expression(
   ast_dump_context->ostream() << ")";
 }
 
-// Allocate a composite literal on the heap.
+// Allocate an expression on the heap.
 
 Expression*
-Expression::make_heap_composite(Expression* expr, Location location)
+Expression::make_heap_expression(Expression* expr, Location location)
 {
-  return new Heap_composite_expression(expr, location);
+  return new Heap_expression(expr, location);
 }
 
 // Class Receive_expression.
@@ -14399,6 +13930,32 @@ Receive_expression::do_check_types(Gogo*)
     }
 }
 
+// Flattening for receive expressions creates a temporary variable to store
+// received data in for receives.
+
+Expression*
+Receive_expression::do_flatten(Gogo*, Named_object*,
+                               Statement_inserter* inserter)
+{
+  Channel_type* channel_type = this->channel_->type()->channel_type();
+  if (channel_type == NULL)
+    {
+      go_assert(saw_errors());
+      return this;
+    }
+
+  Type* element_type = channel_type->element_type();
+  if (this->temp_receiver_ == NULL)
+    {
+      this->temp_receiver_ = Statement::make_temporary(element_type, NULL,
+						       this->location());
+      this->temp_receiver_->set_is_address_taken();
+      inserter->insert(this->temp_receiver_);
+    }
+
+  return this;
+}
+
 // Get a tree for a receive expression.
 
 tree
@@ -14412,19 +13969,18 @@ Receive_expression::do_get_tree(Translate_context* context)
       go_assert(this->channel_->type()->is_error());
       return error_mark_node;
     }
-
   Expression* td = Expression::make_type_descriptor(channel_type, loc);
-  tree td_tree = td->get_tree(context);
 
-  Type* element_type = channel_type->element_type();
-  Btype* element_type_btype = element_type->get_backend(context->gogo());
-  tree element_type_tree = type_to_tree(element_type_btype);
-
-  tree channel = this->channel_->get_tree(context);
-  if (element_type_tree == error_mark_node || channel == error_mark_node)
-    return error_mark_node;
-
-  return Gogo::receive_from_channel(element_type_tree, td_tree, channel, loc);
+  Expression* recv_ref =
+    Expression::make_temporary_reference(this->temp_receiver_, loc);
+  Expression* recv_addr =
+    Expression::make_temporary_reference(this->temp_receiver_, loc);
+  recv_addr = Expression::make_unary(OPERATOR_AND, recv_addr, loc);
+  Expression* recv =
+    Runtime::make_call(Runtime::RECEIVE, loc, 3,
+		       td, this->channel_, recv_addr);
+  recv = Expression::make_compound(recv, recv_ref, loc);
+  return recv->get_tree(context);
 }
 
 // Dump ast representation for a receive expression.
@@ -14725,6 +14281,101 @@ Expression::make_slice_info(Expression* slice, Slice_info slice_info,
   return new Slice_info_expression(slice, slice_info, location);
 }
 
+// An expression that represents a slice value: a struct with value pointer,
+// length, and capacity fields.
+
+class Slice_value_expression : public Expression
+{
+ public:
+  Slice_value_expression(Type* type, Expression* valptr, Expression* len,
+                         Expression* cap, Location location)
+      : Expression(EXPRESSION_SLICE_VALUE, location),
+        type_(type), valptr_(valptr), len_(len), cap_(cap)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Type*
+  do_type()
+  { return this->type_; }
+
+  void
+  do_determine_type(const Type_context*)
+  { go_unreachable(); }
+
+  Expression*
+  do_copy()
+  {
+    return new Slice_value_expression(this->type_, this->valptr_->copy(),
+                                      this->len_->copy(), this->cap_->copy(),
+                                      this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context* context);
+
+  void
+  do_dump_expression(Ast_dump_context*) const;
+
+ private:
+  // The type of the slice value.
+  Type* type_;
+  // The pointer to the values in the slice.
+  Expression* valptr_;
+  // The length of the slice.
+  Expression* len_;
+  // The capacity of the slice.
+  Expression* cap_;
+};
+
+int
+Slice_value_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->valptr_, traverse) == TRAVERSE_EXIT
+      || Expression::traverse(&this->len_, traverse) == TRAVERSE_EXIT
+      || Expression::traverse(&this->cap_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+tree
+Slice_value_expression::do_get_tree(Translate_context* context)
+{
+  std::vector<Bexpression*> vals(3);
+  vals[0] = tree_to_expr(this->valptr_->get_tree(context));
+  vals[1] = tree_to_expr(this->len_->get_tree(context));
+  vals[2] = tree_to_expr(this->cap_->get_tree(context));
+
+  Gogo* gogo = context->gogo();
+  Btype* btype = this->type_->get_backend(gogo);
+  Bexpression* ret =
+      gogo->backend()->constructor_expression(btype, vals, this->location());
+  return expr_to_tree(ret);
+}
+
+void
+Slice_value_expression::do_dump_expression(
+    Ast_dump_context* ast_dump_context) const
+{
+  ast_dump_context->ostream() << "slicevalue(";
+  ast_dump_context->ostream() << "values: ";
+  this->valptr_->dump_expression(ast_dump_context);
+  ast_dump_context->ostream() << ", length: ";
+  this->len_->dump_expression(ast_dump_context);
+  ast_dump_context->ostream() << ", capacity: ";
+  this->cap_->dump_expression(ast_dump_context);
+  ast_dump_context->ostream() << ")";
+}
+
+Expression*
+Expression::make_slice_value(Type* at, Expression* valptr, Expression* len,
+                             Expression* cap, Location location)
+{
+  go_assert(at->is_slice_type());
+  return new Slice_value_expression(at, valptr, len, cap, location);
+}
 
 // An expression that evaluates to some characteristic of a non-empty interface.
 // This is used to access the method table or underlying object of an interface.
@@ -14733,7 +14384,7 @@ class Interface_info_expression : public Expression
 {
  public:
   Interface_info_expression(Expression* iface, Interface_info iface_info,
-                        Location location)
+                            Location location)
     : Expression(EXPRESSION_INTERFACE_INFO, location),
       iface_(iface), iface_info_(iface_info)
   { }
@@ -14779,9 +14430,12 @@ Interface_info_expression::do_type()
     {
     case INTERFACE_INFO_METHODS:
       {
+        Type* pdt = Type::make_type_descriptor_ptr_type();
+        if (this->iface_->type()->interface_type()->is_empty())
+          return pdt;
+
         Location loc = this->location();
         Struct_field_list* sfl = new Struct_field_list();
-        Type* pdt = Type::make_type_descriptor_ptr_type();
         sfl->push_back(
             Struct_field(Typed_identifier("__type_descriptor", pdt, loc)));
 
@@ -14855,11 +14509,13 @@ void
 Interface_info_expression::do_dump_expression(
     Ast_dump_context* ast_dump_context) const
 {
+  bool is_empty = this->iface_->type()->interface_type()->is_empty();
   ast_dump_context->ostream() << "interfaceinfo(";
   this->iface_->dump_expression(ast_dump_context);
   ast_dump_context->ostream() << ",";
   ast_dump_context->ostream() <<
-      (this->iface_info_ == INTERFACE_INFO_METHODS ? "methods"
+      (this->iface_info_ == INTERFACE_INFO_METHODS && !is_empty ? "methods"
+    : this->iface_info_ == INTERFACE_INFO_TYPE_DESCRIPTOR ? "type_descriptor"
     : this->iface_info_ == INTERFACE_INFO_OBJECT ? "object"
     : "unknown");
   ast_dump_context->ostream() << ")";
@@ -14874,6 +14530,303 @@ Expression::make_interface_info(Expression* iface, Interface_info iface_info,
   return new Interface_info_expression(iface, iface_info, location);
 }
 
+// An expression that represents an interface value.  The first field is either
+// a type descriptor for an empty interface or a pointer to the interface method
+// table for a non-empty interface.  The second field is always the object.
+
+class Interface_value_expression : public Expression
+{
+ public:
+  Interface_value_expression(Type* type, Expression* first_field,
+                             Expression* obj, Location location)
+      : Expression(EXPRESSION_INTERFACE_VALUE, location),
+        type_(type), first_field_(first_field), obj_(obj)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Type*
+  do_type()
+  { return this->type_; }
+
+  void
+  do_determine_type(const Type_context*)
+  { go_unreachable(); }
+
+  Expression*
+  do_copy()
+  {
+    return new Interface_value_expression(this->type_,
+                                          this->first_field_->copy(),
+                                          this->obj_->copy(), this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context* context);
+
+  void
+  do_dump_expression(Ast_dump_context*) const;
+
+ private:
+  // The type of the interface value.
+  Type* type_;
+  // The first field of the interface (either a type descriptor or a pointer
+  // to the method table.
+  Expression* first_field_;
+  // The underlying object of the interface.
+  Expression* obj_;
+};
+
+int
+Interface_value_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->first_field_, traverse) == TRAVERSE_EXIT
+      || Expression::traverse(&this->obj_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+tree
+Interface_value_expression::do_get_tree(Translate_context* context)
+{
+  std::vector<Bexpression*> vals(2);
+  vals[0] = tree_to_expr(this->first_field_->get_tree(context));
+  vals[1] = tree_to_expr(this->obj_->get_tree(context));
+
+  Gogo* gogo = context->gogo();
+  Btype* btype = this->type_->get_backend(gogo);
+  Bexpression* ret =
+      gogo->backend()->constructor_expression(btype, vals, this->location());
+  return expr_to_tree(ret);
+}
+
+void
+Interface_value_expression::do_dump_expression(
+    Ast_dump_context* ast_dump_context) const
+{
+  ast_dump_context->ostream() << "interfacevalue(";
+  ast_dump_context->ostream() <<
+      (this->type_->interface_type()->is_empty()
+       ? "type_descriptor: "
+       : "methods: ");
+  this->first_field_->dump_expression(ast_dump_context);
+  ast_dump_context->ostream() << ", object: ";
+  this->obj_->dump_expression(ast_dump_context);
+  ast_dump_context->ostream() << ")";
+}
+
+Expression*
+Expression::make_interface_value(Type* type, Expression* first_value,
+                                 Expression* object, Location location)
+{
+  return new Interface_value_expression(type, first_value, object, location);
+}
+
+// An interface method table for a pair of types: an interface type and a type
+// that implements that interface.
+
+class Interface_mtable_expression : public Expression
+{
+ public:
+  Interface_mtable_expression(Interface_type* itype, Type* type,
+                              bool is_pointer, Location location)
+      : Expression(EXPRESSION_INTERFACE_MTABLE, location),
+        itype_(itype), type_(type), is_pointer_(is_pointer),
+	method_table_type_(NULL), bvar_(NULL)
+  { }
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Type*
+  do_type();
+
+  bool
+  is_immutable() const
+  { return true; }
+
+  void
+  do_determine_type(const Type_context*)
+  { go_unreachable(); }
+
+  Expression*
+  do_copy()
+  {
+    return new Interface_mtable_expression(this->itype_, this->type_,
+                                           this->is_pointer_, this->location());
+  }
+
+  bool
+  do_is_addressable() const
+  { return true; }
+
+  tree
+  do_get_tree(Translate_context* context);
+
+  void
+  do_dump_expression(Ast_dump_context*) const;
+
+ private:
+  // The interface type for which the methods are defined.
+  Interface_type* itype_;
+  // The type to construct the interface method table for.
+  Type* type_;
+  // Whether this table contains the method set for the receiver type or the
+  // pointer receiver type.
+  bool is_pointer_;
+  // The type of the method table.
+  Type* method_table_type_;
+  // The backend variable that refers to the interface method table.
+  Bvariable* bvar_;
+};
+
+int
+Interface_mtable_expression::do_traverse(Traverse* traverse)
+{
+  if (Type::traverse(this->itype_, traverse) == TRAVERSE_EXIT
+      || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+Type*
+Interface_mtable_expression::do_type()
+{
+  if (this->method_table_type_ != NULL)
+    return this->method_table_type_;
+
+  const Typed_identifier_list* interface_methods = this->itype_->methods();
+  go_assert(!interface_methods->empty());
+
+  Struct_field_list* sfl = new Struct_field_list;
+  Typed_identifier tid("__type_descriptor", Type::make_type_descriptor_ptr_type(),
+                       this->location());
+  sfl->push_back(Struct_field(tid));
+  for (Typed_identifier_list::const_iterator p = interface_methods->begin();
+       p != interface_methods->end();
+       ++p)
+    sfl->push_back(Struct_field(*p));
+  this->method_table_type_ = Type::make_struct_type(sfl, this->location());
+  return this->method_table_type_;
+}
+
+tree
+Interface_mtable_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+  Bexpression* ret;
+  Location loc = Linemap::predeclared_location();
+  if (this->bvar_ != NULL)
+    {
+      ret = gogo->backend()->var_expression(this->bvar_, this->location());
+      return expr_to_tree(ret);
+    }
+
+  const Typed_identifier_list* interface_methods = this->itype_->methods();
+  go_assert(!interface_methods->empty());
+
+  std::string mangled_name = ((this->is_pointer_ ? "__go_pimt__" : "__go_imt_")
+			      + this->itype_->mangled_name(gogo)
+			      + "__"
+			      + this->type_->mangled_name(gogo));
+
+  // See whether this interface has any hidden methods.
+  bool has_hidden_methods = false;
+  for (Typed_identifier_list::const_iterator p = interface_methods->begin();
+       p != interface_methods->end();
+       ++p)
+    {
+      if (Gogo::is_hidden_name(p->name()))
+	{
+	  has_hidden_methods = true;
+	  break;
+	}
+    }
+
+  // We already know that the named type is convertible to the
+  // interface.  If the interface has hidden methods, and the named
+  // type is defined in a different package, then the interface
+  // conversion table will be defined by that other package.
+  if (has_hidden_methods
+      && this->type_->named_type() != NULL
+      && this->type_->named_type()->named_object()->package() != NULL)
+    {
+      Btype* btype = this->type()->get_backend(gogo);
+      this->bvar_ =
+          gogo->backend()->immutable_struct_reference(mangled_name, btype, loc);
+      ret = gogo->backend()->var_expression(this->bvar_, this->location());
+      return expr_to_tree(ret);
+    }
+
+  // The first element is the type descriptor.
+  Type* td_type;
+  if (!this->is_pointer_)
+    td_type = this->type_;
+  else
+    td_type = Type::make_pointer_type(this->type_);
+
+  // Build an interface method table for a type: a type descriptor followed by a
+  // list of function pointers, one for each interface method.  This is used for
+  // interfaces.
+  Expression_list* svals = new Expression_list();
+  svals->push_back(Expression::make_type_descriptor(td_type, loc));
+
+  Named_type* nt = this->type_->named_type();
+  Struct_type* st = this->type_->struct_type();
+  go_assert(nt != NULL || st != NULL);
+
+  for (Typed_identifier_list::const_iterator p = interface_methods->begin();
+       p != interface_methods->end();
+       ++p)
+    {
+      bool is_ambiguous;
+      Method* m;
+      if (nt != NULL)
+	m = nt->method_function(p->name(), &is_ambiguous);
+      else
+	m = st->method_function(p->name(), &is_ambiguous);
+      go_assert(m != NULL);
+      Named_object* no = m->named_object();
+
+      go_assert(no->is_function() || no->is_function_declaration());
+      svals->push_back(Expression::make_func_code_reference(no, loc));
+    }
+
+  Btype* btype = this->type()->get_backend(gogo);
+  Expression* mtable = Expression::make_struct_composite_literal(this->type(),
+                                                                 svals, loc);
+  Bexpression* ctor = tree_to_expr(mtable->get_tree(context));
+
+  bool is_public = has_hidden_methods && this->type_->named_type() != NULL;
+  this->bvar_ = gogo->backend()->immutable_struct(mangled_name, false,
+						  !is_public, btype, loc);
+  gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, false,
+                                             !is_public, btype, loc, ctor);
+  ret = gogo->backend()->var_expression(this->bvar_, loc);
+  return expr_to_tree(ret);
+}
+
+void
+Interface_mtable_expression::do_dump_expression(
+    Ast_dump_context* ast_dump_context) const
+{
+  ast_dump_context->ostream() << "__go_"
+                              << (this->is_pointer_ ? "pimt__" : "imt_");
+  ast_dump_context->dump_type(this->itype_);
+  ast_dump_context->ostream() << "__";
+  ast_dump_context->dump_type(this->type_);
+}
+
+Expression*
+Expression::make_interface_mtable_ref(Interface_type* itype, Type* type,
+                                      bool is_pointer, Location location)
+{
+  return new Interface_mtable_expression(itype, type, is_pointer, location);
+}
+
 // An expression which evaluates to the offset of a field within a
 // struct.  This, like Type_info_expression, q.v., is only used to
 // initialize fields of a type descriptor.
@@ -15082,12 +15035,14 @@ class Conditional_expression : public Expression
   {}
 
  protected:
+  int
+  do_traverse(Traverse*);
+
   Type*
   do_type();
 
   void
-  do_determine_type(const Type_context*)
-  { }
+  do_determine_type(const Type_context*);
 
   Expression*
   do_copy()
@@ -15111,13 +15066,26 @@ class Conditional_expression : public Expression
   Expression* else_;
 };
 
+// Traversal.
+
+int
+Conditional_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->cond_, traverse) == TRAVERSE_EXIT
+      || Expression::traverse(&this->then_, traverse) == TRAVERSE_EXIT
+      || Expression::traverse(&this->else_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
 // Return the type of the conditional expression.
 
 Type*
 Conditional_expression::do_type()
 {
   Type* result_type = Type::make_void_type();
-  if (this->then_->type() == this->else_->type())
+  if (Type::are_identical(this->then_->type(), this->else_->type(), false,
+                          NULL))
     result_type = this->then_->type();
   else if (this->then_->is_nil_expression()
            || this->else_->is_nil_expression())
@@ -15127,6 +15095,16 @@ Conditional_expression::do_type()
   return result_type;
 }
 
+// Determine type for a conditional expression.
+
+void
+Conditional_expression::do_determine_type(const Type_context* context)
+{
+  this->cond_->determine_type_no_context();
+  this->then_->determine_type(context);
+  this->else_->determine_type(context);
+}
+
 // Get the backend representation of a conditional expression.
 
 tree
@@ -15167,6 +15145,108 @@ Expression::make_conditional(Expression* cond, Expression* then,
   return new Conditional_expression(cond, then, else_expr, location);
 }
 
+// Compound expressions.
+
+class Compound_expression : public Expression
+{
+ public:
+  Compound_expression(Expression* init, Expression* expr, Location location)
+      : Expression(EXPRESSION_COMPOUND, location), init_(init), expr_(expr)
+  {}
+
+ protected:
+  int
+  do_traverse(Traverse*);
+
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*);
+
+  Expression*
+  do_copy()
+  {
+    return new Compound_expression(this->init_->copy(), this->expr_->copy(),
+                                   this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context* context);
+
+  void
+  do_dump_expression(Ast_dump_context*) const;
+
+ private:
+  // The expression that is evaluated first and discarded.
+  Expression* init_;
+  // The expression that is evaluated and returned.
+  Expression* expr_;
+};
+
+// Traversal.
+
+int
+Compound_expression::do_traverse(Traverse* traverse)
+{
+  if (Expression::traverse(&this->init_, traverse) == TRAVERSE_EXIT
+      || Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
+  return TRAVERSE_CONTINUE;
+}
+
+// Return the type of the compound expression.
+
+Type*
+Compound_expression::do_type()
+{
+  return this->expr_->type();
+}
+
+// Determine type for a compound expression.
+
+void
+Compound_expression::do_determine_type(const Type_context* context)
+{
+  this->init_->determine_type_no_context();
+  this->expr_->determine_type(context);
+}
+
+// Get the backend representation of a compound expression.
+
+tree
+Compound_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+  Bexpression* binit = tree_to_expr(this->init_->get_tree(context));
+  Bstatement* init_stmt = gogo->backend()->expression_statement(binit);
+  Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context));
+  Bexpression* ret = gogo->backend()->compound_expression(init_stmt, bexpr,
+                                                          this->location());
+  return expr_to_tree(ret);
+}
+
+// Dump ast representation of a conditional expression.
+
+void
+Compound_expression::do_dump_expression(
+    Ast_dump_context* ast_dump_context) const
+{
+  ast_dump_context->ostream() << "(";
+  ast_dump_context->dump_expression(this->init_);
+  ast_dump_context->ostream() << ",";
+  ast_dump_context->dump_expression(this->expr_);
+  ast_dump_context->ostream() << ") ";
+}
+
+// Make a compound expression.
+
+Expression*
+Expression::make_compound(Expression* init, Expression* expr, Location location)
+{
+  return new Compound_expression(init, expr, location);
+}
+
 // Import an expression.  This comes at the end in order to see the
 // various class definitions.
 
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 99a0d0720eb..dc9ad71c820 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -74,6 +74,7 @@ class Expression
     EXPRESSION_UNKNOWN_REFERENCE,
     EXPRESSION_BOOLEAN,
     EXPRESSION_STRING,
+    EXPRESSION_STRING_INFO,
     EXPRESSION_INTEGER,
     EXPRESSION_FLOAT,
     EXPRESSION_COMPLEX,
@@ -95,19 +96,23 @@ class Expression
     EXPRESSION_UNSAFE_CONVERSION,
     EXPRESSION_STRUCT_CONSTRUCTION,
     EXPRESSION_FIXED_ARRAY_CONSTRUCTION,
-    EXPRESSION_OPEN_ARRAY_CONSTRUCTION,
+    EXPRESSION_SLICE_CONSTRUCTION,
     EXPRESSION_MAP_CONSTRUCTION,
     EXPRESSION_COMPOSITE_LITERAL,
-    EXPRESSION_HEAP_COMPOSITE,
+    EXPRESSION_HEAP,
     EXPRESSION_RECEIVE,
     EXPRESSION_TYPE_DESCRIPTOR,
     EXPRESSION_TYPE_INFO,
     EXPRESSION_SLICE_INFO,
+    EXPRESSION_SLICE_VALUE,
     EXPRESSION_INTERFACE_INFO,
+    EXPRESSION_INTERFACE_VALUE,
+    EXPRESSION_INTERFACE_MTABLE,
     EXPRESSION_STRUCT_FIELD_OFFSET,
     EXPRESSION_MAP_DESCRIPTOR,
     EXPRESSION_LABEL_ADDR,
-    EXPRESSION_CONDITIONAL
+    EXPRESSION_CONDITIONAL,
+    EXPRESSION_COMPOUND
   };
 
   Expression(Expression_classification, Location);
@@ -188,6 +193,20 @@ class Expression
   static Expression*
   make_string(const std::string&, Location);
 
+  // Make an expression that evaluates to some characteristic of an string.
+  // For simplicity, the enum values must match the field indexes in the
+  // underlying struct.
+  enum String_info
+    {
+      // The underlying data in the string.
+      STRING_INFO_DATA,
+      // The length of the string.
+      STRING_INFO_LENGTH
+    };
+
+  static Expression*
+  make_string_info(Expression* string, String_info, Location);
+
   // Make a character constant expression.  TYPE should be NULL for an
   // abstract type.
   static Expression*
@@ -312,9 +331,9 @@ class Expression
   static Expression*
   make_slice_composite_literal(Type*, Expression_list*, Location);
 
-  // Take a composite literal and allocate it on the heap.
+  // Take an expression and allocate it on the heap.
   static Expression*
-  make_heap_composite(Expression*, Location);
+  make_heap_expression(Expression*, Location);
 
   // Make a receive expression.  VAL is NULL for a unary receive.
   static Receive_expression*
@@ -358,14 +377,20 @@ class Expression
   static Expression*
   make_slice_info(Expression* slice, Slice_info, Location);
 
+  // Make an expression for a slice value.
+  static Expression*
+  make_slice_value(Type*, Expression* valptr, Expression* len, Expression* cap,
+                   Location);
 
-  // Make an expression that evaluates to some characteristic of a
+  // Make an expression that evaluates to some characteristic of an
   // interface.  For simplicity, the enum values must match the field indexes
-  // of a non-empty interface in the underlying struct.
+  // in the underlying struct.
   enum Interface_info
     {
+      // The type descriptor of an empty interface.
+      INTERFACE_INFO_TYPE_DESCRIPTOR = 0,
       // The methods of an interface.
-      INTERFACE_INFO_METHODS,
+      INTERFACE_INFO_METHODS = 0,
       // The first argument to pass to an interface method.
       INTERFACE_INFO_OBJECT
     };
@@ -373,6 +398,17 @@ class Expression
   static Expression*
   make_interface_info(Expression* iface, Interface_info, Location);
 
+  // Make an expression for an interface value.
+  static Expression*
+  make_interface_value(Type*, Expression*, Expression*, Location);
+
+  // Make an expression that builds a reference to the interface method table
+  // for TYPE that satisfies interface ITYPE. IS_POINTER is true if this is a
+  // reference to the interface method table for the pointer receiver type.
+  static Expression*
+  make_interface_mtable_ref(Interface_type* itype, Type* type,
+                            bool is_pointer, Location);
+
   // Make an expression which evaluates to the offset of a field in a
   // struct.  This is only used for type descriptors, so there is no
   // location parameter.
@@ -393,6 +429,10 @@ class Expression
   static Expression*
   make_conditional(Expression*, Expression*, Expression*, Location);
 
+  // Make a compound expression.
+  static Expression*
+  make_compound(Expression*, Expression*, Location);
+
   // Return the expression classification.
   Expression_classification
   classification() const
@@ -700,19 +740,19 @@ class Expression
   tree
   get_tree(Translate_context*);
 
-  // Return a tree handling any conversions which must be done during
+  // Return an expression handling any conversions which must be done during
   // assignment.
-  static tree
-  convert_for_assignment(Translate_context*, Type* lhs_type, Type* rhs_type,
-			 tree rhs_tree, Location location);
+  static Expression*
+  convert_for_assignment(Gogo*, Type* lhs_type, Expression* rhs,
+                         Location location);
 
-  // Return a tree converting a value of one interface type to another
+  // Return an expression converting a value of one interface type to another
   // interface type.  If FOR_TYPE_GUARD is true this is for a type
   // assertion.
-  static tree
-  convert_interface_to_interface(Translate_context*, Type* lhs_type,
-				 Type* rhs_type, tree rhs_tree,
-				 bool for_type_guard, Location);
+  static Expression*
+  convert_interface_to_interface(Type* lhs_type,
+                                 Expression* rhs, bool for_type_guard,
+                                 Location);
 
   // Return a backend expression implementing the comparison LEFT OP RIGHT.
   // TYPE is the type of both sides.
@@ -736,12 +776,10 @@ class Expression
   static Expression*
   import_expression(Import*);
 
-  // Return a tree which checks that VAL, of arbitrary integer type,
-  // is non-negative and is not more than the maximum value of
-  // BOUND_TYPE.  If SOFAR is not NULL, it is or'red into the result.
-  // The return value may be NULL if SOFAR is NULL.
-  static tree
-  check_bounds(tree val, tree bound_type, tree sofar, Location);
+  // Return an expression which checks that VAL, of arbitrary integer type,
+  // is non-negative and is not more than the maximum integer value.
+  static Expression*
+  check_bounds(Expression* val, Location);
 
   // Dump an expression to a dump constext.
   void
@@ -881,17 +919,14 @@ class Expression
 	    : NULL);
   }
 
-  static tree
-  convert_type_to_interface(Translate_context*, Type*, Type*, tree,
-			    Location);
+  static Expression*
+  convert_type_to_interface(Type*, Expression*, Location);
 
-  static tree
-  get_interface_type_descriptor(Translate_context*, Type*, tree,
-				Location);
+  static Expression*
+  get_interface_type_descriptor(Expression*);
 
-  static tree
-  convert_interface_to_type(Translate_context*, Type*, Type*, tree,
-			    Location);
+  static Expression*
+  convert_interface_to_type(Type*, Expression*, Location);
 
   // The expression classification.
   Expression_classification classification_;
@@ -1408,8 +1443,8 @@ class Call_expression : public Expression
   Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
 		  Location location)
     : Expression(EXPRESSION_CALL, location),
-      fn_(fn), args_(args), type_(NULL), results_(NULL), tree_(NULL),
-      is_varargs_(is_varargs), are_hidden_fields_ok_(false),
+      fn_(fn), args_(args), type_(NULL), results_(NULL), call_(NULL),
+      call_temp_(NULL), is_varargs_(is_varargs), are_hidden_fields_ok_(false),
       varargs_are_lowered_(false), types_are_determined_(false),
       is_deferred_(false), issued_error_(false)
   { }
@@ -1489,6 +1524,9 @@ class Call_expression : public Expression
   virtual Expression*
   do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
+  virtual Expression*
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
   bool
   do_discarding_value()
   { return true; }
@@ -1550,8 +1588,8 @@ class Call_expression : public Expression
   interface_method_function(Interface_field_reference_expression*,
 			    Expression**);
 
-  tree
-  set_results(Translate_context*, tree);
+  Bexpression*
+  set_results(Translate_context*, Bexpression*);
 
   // The function to call.
   Expression* fn_;
@@ -1563,8 +1601,10 @@ class Call_expression : public Expression
   // The list of temporaries which will hold the results if the
   // function returns a tuple.
   std::vector<Temporary_statement*>* results_;
-  // The tree for the call, used for a call which returns a tuple.
-  tree tree_;
+  // The backend expression for the call, used for a call which returns a tuple.
+  Bexpression* call_;
+  // A temporary variable to store this call if the function returns a tuple.
+  Temporary_statement* call_temp_;
   // True if the last argument is a varargs argument (f(a...)).
   bool is_varargs_;
   // True if this statement may pass hidden fields in the arguments.
@@ -1838,7 +1878,7 @@ class Map_index_expression : public Expression
 		       Location location)
     : Expression(EXPRESSION_MAP_INDEX, location),
       map_(map), index_(index), is_lvalue_(false),
-      is_in_tuple_assignment_(false)
+      is_in_tuple_assignment_(false), value_pointer_(NULL)
   { }
 
   // Return the map.
@@ -1881,18 +1921,21 @@ class Map_index_expression : public Expression
   set_is_in_tuple_assignment()
   { this->is_in_tuple_assignment_ = true; }
 
-  // Return a tree for the map index.  This returns a tree which
+  // Return an expression for the map index.  This returns an expression which
   // evaluates to a pointer to a value in the map.  If INSERT is true,
   // the key will be inserted if not present, and the value pointer
   // will be zero initialized.  If INSERT is false, and the key is not
   // present in the map, the pointer will be NULL.
-  tree
-  get_value_pointer(Translate_context*, bool insert);
+  Expression*
+  get_value_pointer(bool insert);
 
  protected:
   int
   do_traverse(Traverse*);
 
+  Expression*
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
   Type*
   do_type();
 
@@ -1934,6 +1977,8 @@ class Map_index_expression : public Expression
   bool is_lvalue_;
   // Whether this is in a tuple assignment to a pair of values.
   bool is_in_tuple_assignment_;
+  // A pointer to the value at this index.
+  Expression* value_pointer_;
 };
 
 // An expression which represents a method bound to its first
@@ -2230,6 +2275,9 @@ class Type_guard_expression : public Expression
   int
   do_traverse(Traverse* traverse);
 
+  Expression*
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
   Type*
   do_type()
   { return this->type_; }
@@ -2268,7 +2316,7 @@ class Receive_expression : public Expression
  public:
   Receive_expression(Expression* channel, Location location)
     : Expression(EXPRESSION_RECEIVE, location),
-      channel_(channel)
+      channel_(channel), temp_receiver_(NULL)
   { }
 
   // Return the channel.
@@ -2288,6 +2336,9 @@ class Receive_expression : public Expression
   Type*
   do_type();
 
+  Expression*
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
   void
   do_determine_type(const Type_context*)
   { this->channel_->determine_type_no_context(); }
@@ -2314,6 +2365,8 @@ class Receive_expression : public Expression
  private:
   // The channel from which we are receiving.
   Expression* channel_;
+  // A temporary reference to the variable storing the received data.
+  Temporary_statement* temp_receiver_;
 };
 
 // A numeric constant.  This is used both for untyped constants and
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
index 1950090b9e0..e92acae7af4 100644
--- a/gcc/go/gofrontend/gogo-tree.cc
+++ b/gcc/go/gofrontend/gogo-tree.cc
@@ -636,10 +636,10 @@ class Var_init
 {
  public:
   Var_init()
-    : var_(NULL), init_(NULL_TREE)
+    : var_(NULL), init_(NULL)
   { }
 
-  Var_init(Named_object* var, tree init)
+  Var_init(Named_object* var, Bstatement* init)
     : var_(var), init_(init)
   { }
 
@@ -649,15 +649,15 @@ class Var_init
   { return this->var_; }
 
   // Return the initialization expression.
-  tree
+  Bstatement*
   init() const
   { return this->init_; }
 
  private:
   // The variable being initialized.
   Named_object* var_;
-  // The initialization expression to run.
-  tree init_;
+  // The initialization statement.
+  Bstatement* init_;
 };
 
 typedef std::list<Var_init> Var_inits;
@@ -868,15 +868,13 @@ Gogo::write_globals()
 	  // initializer purely for its side effects.
 	  bool is_sink = no->name()[0] == '_' && no->name()[1] == '.';
 
-	  tree var_init_tree = NULL_TREE;
+          Bstatement* var_init_stmt = NULL;
 	  if (!no->var_value()->has_pre_init())
 	    {
-	      tree init = no->var_value()->get_init_tree(this, NULL);
-	      if (init == error_mark_node)
-		go_assert(saw_errors());
-	      else if (init == NULL_TREE)
+              Bexpression* var_binit = no->var_value()->get_init(this, NULL);
+              if (var_binit == NULL)
 		;
-	      else if (TREE_CONSTANT(init))
+	      else if (TREE_CONSTANT(expr_to_tree(var_binit)))
 		{
 		  if (expression_requires(no->var_value()->init(), NULL,
 					  this->var_depends_on(no->var_value()),
@@ -885,17 +883,20 @@ Gogo::write_globals()
 			     "initialization expression for %qs depends "
 			     "upon itself",
 			     no->message_name().c_str());
-		  this->backend()->global_variable_set_init(var,
-							    tree_to_expr(init));
+		  this->backend()->global_variable_set_init(var, var_binit);
 		}
-	      else if (is_sink
-		       || int_size_in_bytes(TREE_TYPE(init)) == 0
-		       || int_size_in_bytes(TREE_TYPE(vec[i])) == 0)
-		var_init_tree = init;
+	      else if (is_sink)
+		var_init_stmt =
+                    this->backend()->expression_statement(var_binit);
 	      else
-		var_init_tree = fold_build2_loc(no->location().gcc_location(),
-                                                MODIFY_EXPR, void_type_node,
-                                                vec[i], init);
+                {
+                  Location loc = no->var_value()->location();
+                  Bexpression* var_expr =
+                      this->backend()->var_expression(var, loc);
+                  var_init_stmt =
+                      this->backend()->assignment_statement(var_expr, var_binit,
+                                                            loc);
+                }
 	    }
 	  else
 	    {
@@ -907,19 +908,21 @@ Gogo::write_globals()
 		push_struct_function(init_fndecl);
 	      else
 		push_cfun(DECL_STRUCT_FUNCTION(init_fndecl));
-	      tree var_decl = is_sink ? NULL_TREE : vec[i];
-	      var_init_tree = no->var_value()->get_init_block(this, NULL,
-							      var_decl);
+	      Bvariable* var_decl = is_sink ? NULL : var;
+              var_init_stmt =
+                  no->var_value()->get_init_block(this, NULL, var_decl);
+
 	      pop_cfun();
 	    }
 
-	  if (var_init_tree != NULL_TREE && var_init_tree != error_mark_node)
+	  if (var_init_stmt != NULL)
 	    {
 	      if (no->var_value()->init() == NULL
 		  && !no->var_value()->has_pre_init())
-		append_to_statement_list(var_init_tree, &var_init_stmt_list);
+		append_to_statement_list(stat_to_tree(var_init_stmt),
+                                         &var_init_stmt_list);
 	      else
-		var_inits.push_back(Var_init(no, var_init_tree));
+		var_inits.push_back(Var_init(no, var_init_stmt));
 	    }
 	  else if (this->var_depends_on(no->var_value()) != NULL)
 	    {
@@ -927,7 +930,12 @@ Gogo::write_globals()
 	      // not in its init or preinit.  This variable needs to
 	      // participate in dependency analysis sorting, in case
 	      // some other variable depends on this one.
-	      var_inits.push_back(Var_init(no, integer_zero_node));
+              Btype* int_btype =
+                  Type::lookup_integer_type("int")->get_backend(this);
+              Bexpression* zero = this->backend()->zero_expression(int_btype);
+              Bstatement* zero_stmt =
+                  this->backend()->expression_statement(zero);
+	      var_inits.push_back(Var_init(no, zero_stmt));
 	    }
 
 	  if (!is_sink && no->var_value()->type()->has_pointer())
@@ -950,7 +958,7 @@ Gogo::write_globals()
       for (Var_inits::const_iterator p = var_inits.begin();
 	   p != var_inits.end();
 	   ++p)
-	append_to_statement_list(p->init(), &init_stmt_list);
+	append_to_statement_list(stat_to_tree(p->init()), &init_stmt_list);
     }
 
   // After all the variables are initialized, call the "init"
@@ -1106,7 +1114,7 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
 		cfun->function_end_locus =
                   func->block()->end_location().gcc_location();
 
-		func->build_tree(gogo, this);
+		func->build(gogo, this);
 
 		gimplify_function_tree(decl);
 
@@ -1139,84 +1147,6 @@ Named_object::get_tree(Gogo* gogo, Named_object* function)
   return ret;
 }
 
-// Get the initial value of a variable as a tree.  This does not
-// consider whether the variable is in the heap--it returns the
-// initial value as though it were always stored in the stack.
-
-tree
-Variable::get_init_tree(Gogo* gogo, Named_object* function)
-{
-  go_assert(this->preinit_ == NULL);
-  if (this->init_ == NULL)
-    {
-      go_assert(!this->is_parameter_);
-      if (this->is_global_ || this->is_in_heap())
-	return NULL;
-      Btype* btype = this->type_->get_backend(gogo);
-      return expr_to_tree(gogo->backend()->zero_expression(btype));
-    }
-  else
-    {
-      Translate_context context(gogo, function, NULL, NULL);
-      tree rhs_tree = this->init_->get_tree(&context);
-      return Expression::convert_for_assignment(&context, this->type(),
-						this->init_->type(),
-						rhs_tree, this->location());
-    }
-}
-
-// Get the initial value of a variable when a block is required.
-// VAR_DECL is the decl to set; it may be NULL for a sink variable.
-
-tree
-Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
-{
-  go_assert(this->preinit_ != NULL);
-
-  // We want to add the variable assignment to the end of the preinit
-  // block.  The preinit block may have a TRY_FINALLY_EXPR and a
-  // TRY_CATCH_EXPR; if it does, we want to add to the end of the
-  // regular statements.
-
-  Translate_context context(gogo, function, NULL, NULL);
-  Bblock* bblock = this->preinit_->get_backend(&context);
-  tree block_tree = block_to_tree(bblock);
-  if (block_tree == error_mark_node)
-    return error_mark_node;
-  go_assert(TREE_CODE(block_tree) == BIND_EXPR);
-  tree statements = BIND_EXPR_BODY(block_tree);
-  while (statements != NULL_TREE
-	 && (TREE_CODE(statements) == TRY_FINALLY_EXPR
-	     || TREE_CODE(statements) == TRY_CATCH_EXPR))
-    statements = TREE_OPERAND(statements, 0);
-
-  // It's possible to have pre-init statements without an initializer
-  // if the pre-init statements set the variable.
-  if (this->init_ != NULL)
-    {
-      tree rhs_tree = this->init_->get_tree(&context);
-      if (rhs_tree == error_mark_node)
-	return error_mark_node;
-      if (var_decl == NULL_TREE)
-	append_to_statement_list(rhs_tree, &statements);
-      else
-	{
-	  tree val = Expression::convert_for_assignment(&context, this->type(),
-							this->init_->type(),
-							rhs_tree,
-							this->location());
-	  if (val == error_mark_node)
-	    return error_mark_node;
-	  tree set = fold_build2_loc(this->location().gcc_location(),
-                                     MODIFY_EXPR, void_type_node, var_decl,
-                                     val);
-	  append_to_statement_list(set, &statements);
-	}
-    }
-
-  return block_tree;
-}
-
 // Get the backend representation.
 
 Bfunction*
@@ -1272,469 +1202,6 @@ Function::get_decl() const
   return function_to_tree(this->fndecl_);
 }
 
-// We always pass the receiver to a method as a pointer.  If the
-// receiver is actually declared as a non-pointer type, then we copy
-// the value into a local variable, so that it has the right type.  In
-// this function we create the real PARM_DECL to use, and set
-// DEC_INITIAL of the var_decl to be the value passed in.
-
-tree
-Function::make_receiver_parm_decl(Gogo* gogo, Named_object* no, tree var_decl)
-{
-  if (var_decl == error_mark_node)
-    return error_mark_node;
-  go_assert(TREE_CODE(var_decl) == VAR_DECL);
-  tree val_type = TREE_TYPE(var_decl);
-  bool is_in_heap = no->var_value()->is_in_heap();
-  if (is_in_heap)
-    {
-      go_assert(POINTER_TYPE_P(val_type));
-      val_type = TREE_TYPE(val_type);
-    }
-
-  source_location loc = DECL_SOURCE_LOCATION(var_decl);
-  std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl));
-  name += ".pointer";
-  tree id = get_identifier_from_string(name);
-  tree parm_decl = build_decl(loc, PARM_DECL, id, build_pointer_type(val_type));
-  DECL_CONTEXT(parm_decl) = current_function_decl;
-  DECL_ARG_TYPE(parm_decl) = TREE_TYPE(parm_decl);
-
-  go_assert(DECL_INITIAL(var_decl) == NULL_TREE);
-  tree init = build_fold_indirect_ref_loc(loc, parm_decl);
-
-  if (is_in_heap)
-    {
-      tree size = TYPE_SIZE_UNIT(val_type);
-      tree space = gogo->allocate_memory(no->var_value()->type(), size,
-					 no->location());
-      space = save_expr(space);
-      space = fold_convert(build_pointer_type(val_type), space);
-      tree spaceref = build_fold_indirect_ref_loc(no->location().gcc_location(),
-                                                  space);
-      TREE_THIS_NOTRAP(spaceref) = 1;
-      tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node,
-				 spaceref, init);
-      init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space), set, space);
-    }
-
-  DECL_INITIAL(var_decl) = init;
-
-  return parm_decl;
-}
-
-// If we take the address of a parameter, then we need to copy it into
-// the heap.  We will access it as a local variable via an
-// indirection.
-
-tree
-Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree var_decl)
-{
-  if (var_decl == error_mark_node)
-    return error_mark_node;
-  go_assert(TREE_CODE(var_decl) == VAR_DECL);
-  Location loc(DECL_SOURCE_LOCATION(var_decl));
-
-  std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl));
-  name += ".param";
-  tree id = get_identifier_from_string(name);
-
-  tree type = TREE_TYPE(var_decl);
-  go_assert(POINTER_TYPE_P(type));
-  type = TREE_TYPE(type);
-
-  tree parm_decl = build_decl(loc.gcc_location(), PARM_DECL, id, type);
-  DECL_CONTEXT(parm_decl) = current_function_decl;
-  DECL_ARG_TYPE(parm_decl) = type;
-
-  tree size = TYPE_SIZE_UNIT(type);
-  tree space = gogo->allocate_memory(no->var_value()->type(), size, loc);
-  space = save_expr(space);
-  space = fold_convert(TREE_TYPE(var_decl), space);
-  tree spaceref = build_fold_indirect_ref_loc(loc.gcc_location(), space);
-  TREE_THIS_NOTRAP(spaceref) = 1;
-  tree init = build2(COMPOUND_EXPR, TREE_TYPE(space),
-		     build2(MODIFY_EXPR, void_type_node, spaceref, parm_decl),
-		     space);
-  DECL_INITIAL(var_decl) = init;
-
-  return parm_decl;
-}
-
-// Get a tree for function code.
-
-void
-Function::build_tree(Gogo* gogo, Named_object* named_function)
-{
-  tree fndecl = this->get_decl();
-  go_assert(fndecl != NULL_TREE);
-
-  tree params = NULL_TREE;
-  tree* pp = &params;
-
-  tree declare_vars = NULL_TREE;
-  for (Bindings::const_definitions_iterator p =
-	 this->block_->bindings()->begin_definitions();
-       p != this->block_->bindings()->end_definitions();
-       ++p)
-    {
-      if ((*p)->is_variable() && (*p)->var_value()->is_parameter())
-	{
-	  Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function);
-	  *pp = var_to_tree(bvar);
-
-	  // We always pass the receiver to a method as a pointer.  If
-	  // the receiver is declared as a non-pointer type, then we
-	  // copy the value into a local variable.
-	  if ((*p)->var_value()->is_receiver()
-	      && (*p)->var_value()->type()->points_to() == NULL)
-	    {
-	      tree parm_decl = this->make_receiver_parm_decl(gogo, *p, *pp);
-	      tree var = *pp;
-	      if (var != error_mark_node)
-		{
-		  go_assert(TREE_CODE(var) == VAR_DECL);
-		  DECL_CHAIN(var) = declare_vars;
-		  declare_vars = var;
-		}
-	      *pp = parm_decl;
-	    }
-	  else if ((*p)->var_value()->is_in_heap())
-	    {
-	      // If we take the address of a parameter, then we need
-	      // to copy it into the heap.
-	      tree parm_decl = this->copy_parm_to_heap(gogo, *p, *pp);
-	      tree var = *pp;
-	      if (var != error_mark_node)
-		{
-		  go_assert(TREE_CODE(var) == VAR_DECL);
-		  DECL_CHAIN(var) = declare_vars;
-		  declare_vars = var;
-		}
-	      *pp = parm_decl;
-	    }
-
-	  if (*pp != error_mark_node)
-	    {
-	      go_assert(TREE_CODE(*pp) == PARM_DECL);
-	      pp = &DECL_CHAIN(*pp);
-	    }
-	}
-      else if ((*p)->is_result_variable())
-	{
-	  Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function);
-	  tree var_decl = var_to_tree(bvar);
-
-	  Type* type = (*p)->result_var_value()->type();
-	  tree init;
-	  if (!(*p)->result_var_value()->is_in_heap())
-	    {
-	      Btype* btype = type->get_backend(gogo);
-	      init = expr_to_tree(gogo->backend()->zero_expression(btype));
-	    }
-	  else
-	    {
-	      Location loc = (*p)->location();
-	      tree type_tree = type_to_tree(type->get_backend(gogo));
-	      tree space = gogo->allocate_memory(type,
-						 TYPE_SIZE_UNIT(type_tree),
-						 loc);
-	      tree ptr_type_tree = build_pointer_type(type_tree);
-	      init = fold_convert_loc(loc.gcc_location(), ptr_type_tree, space);
-	    }
-
-	  if (var_decl != error_mark_node)
-	    {
-	      go_assert(TREE_CODE(var_decl) == VAR_DECL);
-	      DECL_INITIAL(var_decl) = init;
-	      DECL_CHAIN(var_decl) = declare_vars;
-	      declare_vars = var_decl;
-	    }
-	}
-    }
-
-  *pp = NULL_TREE;
-
-  DECL_ARGUMENTS(fndecl) = params;
-
-  // If we need a closure variable, fetch it by calling a runtime
-  // function.  The caller will have called __go_set_closure before
-  // the function call.
-  if (this->closure_var_ != NULL)
-    {
-      Bvariable* bvar =
-	this->closure_var_->get_backend_variable(gogo, named_function);
-      tree var_decl = var_to_tree(bvar);
-      if (var_decl != error_mark_node)
-	{
-	  go_assert(TREE_CODE(var_decl) == VAR_DECL);
-	  static tree get_closure_fndecl;
-	  tree get_closure = Gogo::call_builtin(&get_closure_fndecl,
-						this->location_,
-						"__go_get_closure",
-						0,
-						ptr_type_node);
-
-	  // Mark the __go_get_closure function as pure, since it
-	  // depends only on the global variable g.
-	  DECL_PURE_P(get_closure_fndecl) = 1;
-
-	  get_closure = fold_convert_loc(this->location_.gcc_location(),
-					 TREE_TYPE(var_decl), get_closure);
-	  DECL_INITIAL(var_decl) = get_closure;
-	  DECL_CHAIN(var_decl) = declare_vars;
-	  declare_vars = var_decl;
-	}
-    }
-
-  if (this->block_ != NULL)
-    {
-      go_assert(DECL_INITIAL(fndecl) == NULL_TREE);
-
-      // Declare variables if necessary.
-      tree bind = NULL_TREE;
-      tree defer_init = NULL_TREE;
-      if (declare_vars != NULL_TREE || this->defer_stack_ != NULL)
-	{
-	  tree block = make_node(BLOCK);
-	  BLOCK_SUPERCONTEXT(block) = fndecl;
-	  DECL_INITIAL(fndecl) = block;
-	  BLOCK_VARS(block) = declare_vars;
-	  TREE_USED(block) = 1;
-
-	  bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block),
-			NULL_TREE, block);
-	  TREE_SIDE_EFFECTS(bind) = 1;
-
-	  if (this->defer_stack_ != NULL)
-	    {
-	      Translate_context dcontext(gogo, named_function, this->block_,
-					 tree_to_block(bind));
-	      Bstatement* bdi = this->defer_stack_->get_backend(&dcontext);
-	      defer_init = stat_to_tree(bdi);
-	    }
-	}
-
-      // Build the trees for all the statements in the function.
-      Translate_context context(gogo, named_function, NULL, NULL);
-      Bblock* bblock = this->block_->get_backend(&context);
-      tree code = block_to_tree(bblock);
-
-      tree init = NULL_TREE;
-      tree except = NULL_TREE;
-      tree fini = NULL_TREE;
-
-      // Initialize variables if necessary.
-      for (tree v = declare_vars; v != NULL_TREE; v = DECL_CHAIN(v))
-	{
-	  tree dv = build1(DECL_EXPR, void_type_node, v);
-	  SET_EXPR_LOCATION(dv, DECL_SOURCE_LOCATION(v));
-	  append_to_statement_list(dv, &init);
-	}
-
-      // If we have a defer stack, initialize it at the start of a
-      // function.
-      if (defer_init != NULL_TREE && defer_init != error_mark_node)
-	{
-	  SET_EXPR_LOCATION(defer_init,
-                            this->block_->start_location().gcc_location());
-	  append_to_statement_list(defer_init, &init);
-
-	  // Clean up the defer stack when we leave the function.
-	  this->build_defer_wrapper(gogo, named_function, &except, &fini);
-	}
-
-      if (code != NULL_TREE && code != error_mark_node)
-	{
-	  if (init != NULL_TREE)
-	    code = build2(COMPOUND_EXPR, void_type_node, init, code);
-	  if (except != NULL_TREE)
-	    code = build2(TRY_CATCH_EXPR, void_type_node, code,
-			  build2(CATCH_EXPR, void_type_node, NULL, except));
-	  if (fini != NULL_TREE)
-	    code = build2(TRY_FINALLY_EXPR, void_type_node, code, fini);
-	}
-
-      // Stick the code into the block we built for the receiver, if
-      // we built on.
-      if (bind != NULL_TREE && code != NULL_TREE && code != error_mark_node)
-	{
-	  BIND_EXPR_BODY(bind) = code;
-	  code = bind;
-	}
-
-      DECL_SAVED_TREE(fndecl) = code;
-    }
-
-  // If we created a descriptor for the function, make sure we emit it.
-  if (this->descriptor_ != NULL)
-    {
-      Translate_context context(gogo, NULL, NULL, NULL);
-      this->descriptor_->get_tree(&context);
-    }
-}
-
-// Build the wrappers around function code needed if the function has
-// any defer statements.  This sets *EXCEPT to an exception handler
-// and *FINI to a finally handler.
-
-void
-Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
-			      tree *except, tree *fini)
-{
-  Location end_loc = this->block_->end_location();
-
-  // Add an exception handler.  This is used if a panic occurs.  Its
-  // purpose is to stop the stack unwinding if a deferred function
-  // calls recover.  There are more details in
-  // libgo/runtime/go-unwind.c.
-
-  tree stmt_list = NULL_TREE;
-
-  Expression* call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1,
-					this->defer_stack(end_loc));
-  Translate_context context(gogo, named_function, NULL, NULL);
-  tree call_tree = call->get_tree(&context);
-  if (call_tree != error_mark_node)
-    append_to_statement_list(call_tree, &stmt_list);
-
-  tree retval = this->return_value(gogo, named_function, end_loc, &stmt_list);
-  tree set;
-  if (retval == NULL_TREE)
-    set = NULL_TREE;
-  else
-    set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node,
-			  DECL_RESULT(this->get_decl()), retval);
-  tree ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR,
-                                  void_type_node, set);
-  append_to_statement_list(ret_stmt, &stmt_list);
-
-  go_assert(*except == NULL_TREE);
-  *except = stmt_list;
-
-  // Add some finally code to run the defer functions.  This is used
-  // both in the normal case, when no panic occurs, and also if a
-  // panic occurs to run any further defer functions.  Of course, it
-  // is possible for a defer function to call panic which should be
-  // caught by another defer function.  To handle that we use a loop.
-  //  finish:
-  //   try { __go_undefer(); } catch { __go_check_defer(); goto finish; }
-  //   if (return values are named) return named_vals;
-
-  stmt_list = NULL;
-
-  tree label = create_artificial_label(end_loc.gcc_location());
-  tree define_label = fold_build1_loc(end_loc.gcc_location(), LABEL_EXPR,
-                                      void_type_node, label);
-  append_to_statement_list(define_label, &stmt_list);
-
-  call = Runtime::make_call(Runtime::UNDEFER, end_loc, 1,
-			    this->defer_stack(end_loc));
-  tree undefer = call->get_tree(&context);
-
-  call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1,
-			    this->defer_stack(end_loc));
-  tree defer = call->get_tree(&context);
-
-  if (undefer == error_mark_node || defer == error_mark_node)
-    return;
-
-  tree jump = fold_build1_loc(end_loc.gcc_location(), GOTO_EXPR, void_type_node,
-                              label);
-  tree catch_body = build2(COMPOUND_EXPR, void_type_node, defer, jump);
-  catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body);
-  tree try_catch = build2(TRY_CATCH_EXPR, void_type_node, undefer, catch_body);
-
-  append_to_statement_list(try_catch, &stmt_list);
-
-  if (this->type_->results() != NULL
-      && !this->type_->results()->empty()
-      && !this->type_->results()->front().name().empty())
-    {
-      // If the result variables are named, and we are returning from
-      // this function rather than panicing through it, we need to
-      // return them again, because they might have been changed by a
-      // defer function.  The runtime routines set the defer_stack
-      // variable to true if we are returning from this function.
-      retval = this->return_value(gogo, named_function, end_loc,
-				  &stmt_list);
-      set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node,
-			    DECL_RESULT(this->get_decl()), retval);
-      ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR,
-                                 void_type_node, set);
-
-      Expression* ref =
-	Expression::make_temporary_reference(this->defer_stack_, end_loc);
-      tree tref = ref->get_tree(&context);
-      tree s = build3_loc(end_loc.gcc_location(), COND_EXPR, void_type_node,
-                          tref, ret_stmt, NULL_TREE);
-
-      append_to_statement_list(s, &stmt_list);
-
-    }
-  
-  go_assert(*fini == NULL_TREE);
-  *fini = stmt_list;
-}
-
-// Return the value to assign to DECL_RESULT(this->get_decl()).  This may
-// also add statements to STMT_LIST, which need to be executed before
-// the assignment.  This is used for a return statement with no
-// explicit values.
-
-tree
-Function::return_value(Gogo* gogo, Named_object* named_function,
-		       Location location, tree* stmt_list) const
-{
-  const Typed_identifier_list* results = this->type_->results();
-  if (results == NULL || results->empty())
-    return NULL_TREE;
-
-  go_assert(this->results_ != NULL);
-  if (this->results_->size() != results->size())
-    {
-      go_assert(saw_errors());
-      return error_mark_node;
-    }
-
-  tree retval;
-  if (results->size() == 1)
-    {
-      Bvariable* bvar =
-	this->results_->front()->get_backend_variable(gogo,
-						      named_function);
-      tree ret = var_to_tree(bvar);
-      if (this->results_->front()->result_var_value()->is_in_heap())
-	ret = build_fold_indirect_ref_loc(location.gcc_location(), ret);
-      return ret;
-    }
-  else
-    {
-      tree rettype = TREE_TYPE(DECL_RESULT(this->get_decl()));
-      retval = create_tmp_var(rettype, "RESULT");
-      tree field = TYPE_FIELDS(rettype);
-      int index = 0;
-      for (Typed_identifier_list::const_iterator pr = results->begin();
-	   pr != results->end();
-	   ++pr, ++index, field = DECL_CHAIN(field))
-	{
-	  go_assert(field != NULL);
-	  Named_object* no = (*this->results_)[index];
-	  Bvariable* bvar = no->get_backend_variable(gogo, named_function);
-	  tree val = var_to_tree(bvar);
-	  if (no->result_var_value()->is_in_heap())
-	    val = build_fold_indirect_ref_loc(location.gcc_location(), val);
-	  tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR,
-                                     void_type_node,
-				     build3(COMPONENT_REF, TREE_TYPE(field),
-					    retval, field, NULL_TREE),
-				     val);
-	  append_to_statement_list(set, stmt_list);
-	}
-      return retval;
-    }
-}
-
 // Build the descriptor for a function declaration.  This won't
 // necessarily happen if the package has just a declaration for the
 // function and no other reference to it, but we may still need the
@@ -1834,38 +1301,6 @@ go_type_for_mode(enum machine_mode mode, int unsignedp)
     return NULL_TREE;
 }
 
-// Return a tree which allocates SIZE bytes which will holds value of
-// type TYPE.
-
-tree
-Gogo::allocate_memory(Type* type, tree size, Location location)
-{
-  // If the package imports unsafe, then it may play games with
-  // pointers that look like integers.
-  if (this->imported_unsafe_ || type->has_pointer())
-    {
-      static tree new_fndecl;
-      return Gogo::call_builtin(&new_fndecl,
-				location,
-				"__go_new",
-				1,
-				ptr_type_node,
-				sizetype,
-				size);
-    }
-  else
-    {
-      static tree new_nopointers_fndecl;
-      return Gogo::call_builtin(&new_nopointers_fndecl,
-				location,
-				"__go_new_nopointers",
-				1,
-				ptr_type_node,
-				sizetype,
-				size);
-    }
-}
-
 // Build a builtin struct with a list of fields.  The name is
 // STRUCT_NAME.  STRUCT_TYPE is NULL_TREE or an empty RECORD_TYPE
 // node; this exists so that the struct can have fields which point to
@@ -1915,94 +1350,6 @@ Gogo::builtin_struct(tree* ptype, const char* struct_name, tree struct_type,
   return struct_type;
 }
 
-// Return a type to use for pointer to const char for a string.
-
-tree
-Gogo::const_char_pointer_type_tree()
-{
-  static tree type;
-  if (type == NULL_TREE)
-    {
-      tree const_char_type = build_qualified_type(unsigned_char_type_node,
-						  TYPE_QUAL_CONST);
-      type = build_pointer_type(const_char_type);
-      go_preserve_from_gc(type);
-    }
-  return type;
-}
-
-// Return a tree for a string constant.
-
-tree
-Gogo::string_constant_tree(const std::string& val)
-{
-  tree index_type = build_index_type(size_int(val.length()));
-  tree const_char_type = build_qualified_type(unsigned_char_type_node,
-					      TYPE_QUAL_CONST);
-  tree string_type = build_array_type(const_char_type, index_type);
-  string_type = build_variant_type_copy(string_type);
-  TYPE_STRING_FLAG(string_type) = 1;
-  tree string_val = build_string(val.length(), val.data());
-  TREE_TYPE(string_val) = string_type;
-  return string_val;
-}
-
-// Return a tree for a Go string constant.
-
-tree
-Gogo::go_string_constant_tree(const std::string& val)
-{
-  tree string_type = type_to_tree(Type::make_string_type()->get_backend(this));
-
-  vec<constructor_elt, va_gc> *init;
-  vec_alloc(init, 2);
-
-  constructor_elt empty = {NULL, NULL};
-  constructor_elt* elt = init->quick_push(empty);
-  tree field = TYPE_FIELDS(string_type);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__data") == 0);
-  elt->index = field;
-  tree str = Gogo::string_constant_tree(val);
-  elt->value = fold_convert(TREE_TYPE(field),
-			    build_fold_addr_expr(str));
-
-  elt = init->quick_push(empty);
-  field = DECL_CHAIN(field);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__length") == 0);
-  elt->index = field;
-  elt->value = build_int_cst_type(TREE_TYPE(field), val.length());
-
-  tree constructor = build_constructor(string_type, init);
-  TREE_READONLY(constructor) = 1;
-  TREE_CONSTANT(constructor) = 1;
-
-  return constructor;
-}
-
-// Return a tree for a pointer to a Go string constant.  This is only
-// used for type descriptors, so we return a pointer to a constant
-// decl.
-
-tree
-Gogo::ptr_go_string_constant_tree(const std::string& val)
-{
-  tree pval = this->go_string_constant_tree(val);
-
-  tree decl = build_decl(UNKNOWN_LOCATION, VAR_DECL,
-			 create_tmp_var_name("SP"), TREE_TYPE(pval));
-  DECL_EXTERNAL(decl) = 0;
-  TREE_PUBLIC(decl) = 0;
-  TREE_USED(decl) = 1;
-  TREE_READONLY(decl) = 1;
-  TREE_CONSTANT(decl) = 1;
-  TREE_STATIC(decl) = 1;
-  DECL_ARTIFICIAL(decl) = 1;
-  DECL_INITIAL(decl) = pval;
-  rest_of_decl_compilation(decl, 1, 0);
-
-  return build_fold_addr_expr(decl);
-}
-
 // Build a constructor for a slice.  SLICE_TYPE_TREE is the type of
 // the slice.  VALUES is the value pointer and COUNT is the number of
 // entries.  If CAPACITY is not NULL, it is the capacity; otherwise
@@ -2048,136 +1395,6 @@ Gogo::slice_constructor(tree slice_type_tree, tree values, tree count,
   return build_constructor(slice_type_tree, init);
 }
 
-// Build an interface method table for a type: a list of function
-// pointers, one for each interface method.  This is used for
-// interfaces.
-
-tree
-Gogo::interface_method_table_for_type(const Interface_type* interface,
-				      Type* type, bool is_pointer)
-{
-  const Typed_identifier_list* interface_methods = interface->methods();
-  go_assert(!interface_methods->empty());
-
-  std::string mangled_name = ((is_pointer ? "__go_pimt__" : "__go_imt_")
-			      + interface->mangled_name(this)
-			      + "__"
-			      + type->mangled_name(this));
-
-  tree id = get_identifier_from_string(mangled_name);
-
-  // See whether this interface has any hidden methods.
-  bool has_hidden_methods = false;
-  for (Typed_identifier_list::const_iterator p = interface_methods->begin();
-       p != interface_methods->end();
-       ++p)
-    {
-      if (Gogo::is_hidden_name(p->name()))
-	{
-	  has_hidden_methods = true;
-	  break;
-	}
-    }
-
-  // We already know that the named type is convertible to the
-  // interface.  If the interface has hidden methods, and the named
-  // type is defined in a different package, then the interface
-  // conversion table will be defined by that other package.
-  if (has_hidden_methods
-      && type->named_type() != NULL
-      && type->named_type()->named_object()->package() != NULL)
-    {
-      tree array_type = build_array_type(const_ptr_type_node, NULL);
-      tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type);
-      TREE_READONLY(decl) = 1;
-      TREE_CONSTANT(decl) = 1;
-      TREE_PUBLIC(decl) = 1;
-      DECL_EXTERNAL(decl) = 1;
-      go_preserve_from_gc(decl);
-      return decl;
-    }
-
-  size_t count = interface_methods->size();
-  vec<constructor_elt, va_gc> *pointers;
-  vec_alloc(pointers, count + 1);
-
-  // The first element is the type descriptor.
-  constructor_elt empty = {NULL, NULL};
-  constructor_elt* elt = pointers->quick_push(empty);
-  elt->index = size_zero_node;
-  Type* td_type;
-  if (!is_pointer)
-    td_type = type;
-  else
-    td_type = Type::make_pointer_type(type);
-
-  Location loc = Linemap::predeclared_location();
-  Bexpression* tdp_bexpr = td_type->type_descriptor_pointer(this, loc);
-  tree tdp = expr_to_tree(tdp_bexpr);
-  elt->value = fold_convert(const_ptr_type_node, tdp);
-
-  Named_type* nt = type->named_type();
-  Struct_type* st = type->struct_type();
-  go_assert(nt != NULL || st != NULL);
-  size_t i = 1;
-  for (Typed_identifier_list::const_iterator p = interface_methods->begin();
-       p != interface_methods->end();
-       ++p, ++i)
-    {
-      bool is_ambiguous;
-      Method* m;
-      if (nt != NULL)
-	m = nt->method_function(p->name(), &is_ambiguous);
-      else
-	m = st->method_function(p->name(), &is_ambiguous);
-      go_assert(m != NULL);
-
-      Named_object* no = m->named_object();
-      Bfunction* bf;
-      if (no->is_function())
-	bf = no->func_value()->get_or_make_decl(this, no);
-      else if (no->is_function_declaration())
-	bf = no->func_declaration_value()->get_or_make_decl(this, no);
-      else
-	go_unreachable();
-      tree fndecl = build_fold_addr_expr(function_to_tree(bf));
-
-      elt = pointers->quick_push(empty);
-      elt->index = size_int(i);
-      elt->value = fold_convert(const_ptr_type_node, fndecl);
-    }
-  go_assert(i == count + 1);
-
-  tree array_type = build_array_type(const_ptr_type_node,
-				     build_index_type(size_int(count)));
-  tree constructor = build_constructor(array_type, pointers);
-
-  tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type);
-  TREE_STATIC(decl) = 1;
-  TREE_USED(decl) = 1;
-  TREE_READONLY(decl) = 1;
-  TREE_CONSTANT(decl) = 1;
-  DECL_INITIAL(decl) = constructor;
-
-  // If the interface type has hidden methods, and the table is for a
-  // named type, then this is the only definition of the table.
-  // Otherwise it is a comdat table which may be defined in multiple
-  // packages.
-  if (has_hidden_methods && type->named_type() != NULL)
-    TREE_PUBLIC(decl) = 1;
-  else
-    {
-      make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
-      resolve_unique_section(decl, 1, 0);
-    }
-
-  rest_of_decl_compilation(decl, 1, 0);
-
-  go_preserve_from_gc(decl);
-
-  return decl;
-}
-
 // Mark a function as a builtin library function.
 
 void
@@ -2250,70 +1467,3 @@ Gogo::call_builtin(tree* pdecl, Location location, const char* name,
 
   return ret;
 }
-
-// Return a tree for receiving a value of type TYPE_TREE on CHANNEL.
-// TYPE_DESCRIPTOR_TREE is the channel's type descriptor.  This does a
-// blocking receive and returns the value read from the channel.
-
-tree
-Gogo::receive_from_channel(tree type_tree, tree type_descriptor_tree,
-			   tree channel, Location location)
-{
-  if (type_tree == error_mark_node || channel == error_mark_node)
-    return error_mark_node;
-
-  if (int_size_in_bytes(type_tree) <= 8
-      && !AGGREGATE_TYPE_P(type_tree)
-      && !FLOAT_TYPE_P(type_tree))
-    {
-      static tree receive_small_fndecl;
-      tree call = Gogo::call_builtin(&receive_small_fndecl,
-				     location,
-				     "__go_receive_small",
-				     2,
-				     uint64_type_node,
-				     TREE_TYPE(type_descriptor_tree),
-				     type_descriptor_tree,
-				     ptr_type_node,
-				     channel);
-      if (call == error_mark_node)
-	return error_mark_node;
-      // This can panic if there are too many operations on a closed
-      // channel.
-      TREE_NOTHROW(receive_small_fndecl) = 0;
-      int bitsize = GET_MODE_BITSIZE(TYPE_MODE(type_tree));
-      tree int_type_tree = go_type_for_size(bitsize, 1);
-      return fold_convert_loc(location.gcc_location(), type_tree,
-			      fold_convert_loc(location.gcc_location(),
-                                               int_type_tree, call));
-    }
-  else
-    {
-      tree tmp = create_tmp_var(type_tree, get_name(type_tree));
-      DECL_IGNORED_P(tmp) = 0;
-      TREE_ADDRESSABLE(tmp) = 1;
-      tree make_tmp = build1(DECL_EXPR, void_type_node, tmp);
-      SET_EXPR_LOCATION(make_tmp, location.gcc_location());
-      tree tmpaddr = build_fold_addr_expr(tmp);
-      tmpaddr = fold_convert(ptr_type_node, tmpaddr);
-      static tree receive_big_fndecl;
-      tree call = Gogo::call_builtin(&receive_big_fndecl,
-				     location,
-				     "__go_receive_big",
-				     3,
-				     void_type_node,
-				     TREE_TYPE(type_descriptor_tree),
-				     type_descriptor_tree,
-				     ptr_type_node,
-				     channel,
-				     ptr_type_node,
-				     tmpaddr);
-      if (call == error_mark_node)
-	return error_mark_node;
-      // This can panic if there are too many operations on a closed
-      // channel.
-      TREE_NOTHROW(receive_big_fndecl) = 0;
-      return build2(COMPOUND_EXPR, type_tree, make_tmp,
-		    build2(COMPOUND_EXPR, type_tree, call, tmp));
-    }
-}
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 9739f289f4d..6df4b6bf325 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -1005,6 +1005,10 @@ Label*
 Gogo::add_label_definition(const std::string& label_name,
 			   Location location)
 {
+  // A label with a blank identifier is never declared or defined.
+  if (label_name == "_")
+    return NULL;
+
   go_assert(!this->functions_.empty());
   Function* func = this->functions_.back().function->func_value();
   Label* label = func->add_label_definition(this, label_name, location);
@@ -3330,6 +3334,7 @@ Build_method_tables::type(Type* type)
   Struct_type* st = type->struct_type();
   if (nt != NULL || st != NULL)
     {
+      Translate_context context(this->gogo_, NULL, NULL, NULL);
       for (std::vector<Interface_type*>::const_iterator p =
 	     this->interfaces_.begin();
 	   p != this->interfaces_.end();
@@ -3343,8 +3348,8 @@ Build_method_tables::type(Type* type)
 	      if ((*p)->implements_interface(Type::make_pointer_type(nt),
 					     NULL))
 		{
-		  nt->interface_method_table(this->gogo_, *p, false);
-		  nt->interface_method_table(this->gogo_, *p, true);
+		  nt->interface_method_table(*p, false)->get_tree(&context);
+                  nt->interface_method_table(*p, true)->get_tree(&context);
 		}
 	    }
 	  else
@@ -3352,8 +3357,8 @@ Build_method_tables::type(Type* type)
 	      if ((*p)->implements_interface(Type::make_pointer_type(st),
 					     NULL))
 		{
-		  st->interface_method_table(this->gogo_, *p, false);
-		  st->interface_method_table(this->gogo_, *p, true);
+		  st->interface_method_table(*p, false)->get_tree(&context);
+		  st->interface_method_table(*p, true)->get_tree(&context);
 		}
 	    }
 	}
@@ -3361,6 +3366,28 @@ Build_method_tables::type(Type* type)
   return TRAVERSE_CONTINUE;
 }
 
+// Return an expression which allocates memory to hold values of type TYPE.
+
+Expression*
+Gogo::allocate_memory(Type* type, Location location)
+{
+  Btype* btype = type->get_backend(this);
+  size_t size = this->backend()->type_size(btype);
+  mpz_t size_val;
+  mpz_init_set_ui(size_val, size);
+  Type* uintptr = Type::lookup_integer_type("uintptr");
+  Expression* size_expr =
+    Expression::make_integer(&size_val, uintptr, location);
+
+  // If the package imports unsafe, then it may play games with
+  // pointers that look like integers.
+  bool use_new_pointers = this->imported_unsafe_ || type->has_pointer();
+  return Runtime::make_call((use_new_pointers
+			     ? Runtime::NEW
+			     : Runtime::NEW_NOPOINTERS),
+                            location, 1, size_expr);
+}
+
 // Traversal class used to check for return statements.
 
 class Check_return_statements_traverse : public Traverse
@@ -4111,6 +4138,293 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no)
   return this->fndecl_;
 }
 
+// Build the backend representation for the function code.
+
+void
+Function::build(Gogo* gogo, Named_object* named_function)
+{
+  Translate_context context(gogo, named_function, NULL, NULL);
+
+  // A list of parameter variables for this function.
+  std::vector<Bvariable*> param_vars;
+
+  // Variables that need to be declared for this function and their
+  // initial values.
+  std::vector<Bvariable*> vars;
+  std::vector<Bexpression*> var_inits;
+  for (Bindings::const_definitions_iterator p =
+	 this->block_->bindings()->begin_definitions();
+       p != this->block_->bindings()->end_definitions();
+       ++p)
+    {
+      Location loc = (*p)->location();
+      if ((*p)->is_variable() && (*p)->var_value()->is_parameter())
+	{
+	  Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function);
+          Bvariable* parm_bvar = bvar;
+
+	  // We always pass the receiver to a method as a pointer.  If
+	  // the receiver is declared as a non-pointer type, then we
+	  // copy the value into a local variable.
+	  if ((*p)->var_value()->is_receiver()
+	      && (*p)->var_value()->type()->points_to() == NULL)
+	    {
+	      std::string name = (*p)->name() + ".pointer";
+	      Type* var_type = (*p)->var_value()->type();
+	      Variable* parm_var =
+		  new Variable(Type::make_pointer_type(var_type), NULL, false,
+			       true, false, loc);
+	      Named_object* parm_no =
+                  Named_object::make_variable(name, NULL, parm_var);
+              parm_bvar = parm_no->get_backend_variable(gogo, named_function);
+
+              vars.push_back(bvar);
+	      Expression* parm_ref =
+                  Expression::make_var_reference(parm_no, loc);
+	      parm_ref = Expression::make_unary(OPERATOR_MULT, parm_ref, loc);
+	      if ((*p)->var_value()->is_in_heap())
+		parm_ref = Expression::make_heap_expression(parm_ref, loc);
+              var_inits.push_back(tree_to_expr(parm_ref->get_tree(&context)));
+	    }
+	  else if ((*p)->var_value()->is_in_heap())
+	    {
+	      // If we take the address of a parameter, then we need
+	      // to copy it into the heap.
+	      std::string parm_name = (*p)->name() + ".param";
+	      Variable* parm_var = new Variable((*p)->var_value()->type(), NULL,
+						false, true, false, loc);
+	      Named_object* parm_no =
+		  Named_object::make_variable(parm_name, NULL, parm_var);
+	      parm_bvar = parm_no->get_backend_variable(gogo, named_function);
+
+              vars.push_back(bvar);
+	      Expression* var_ref =
+		  Expression::make_var_reference(parm_no, loc);
+	      var_ref = Expression::make_heap_expression(var_ref, loc);
+              var_inits.push_back(tree_to_expr(var_ref->get_tree(&context)));
+	    }
+          param_vars.push_back(parm_bvar);
+	}
+      else if ((*p)->is_result_variable())
+	{
+	  Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function);
+
+	  Type* type = (*p)->result_var_value()->type();
+	  Bexpression* init;
+	  if (!(*p)->result_var_value()->is_in_heap())
+	    {
+	      Btype* btype = type->get_backend(gogo);
+	      init = gogo->backend()->zero_expression(btype);
+	    }
+	  else
+            {
+              Expression* alloc = Expression::make_allocation(type, loc);
+              init = tree_to_expr(alloc->get_tree(&context));
+            }
+
+          vars.push_back(bvar);
+          var_inits.push_back(init);
+	}
+    }
+  if (!gogo->backend()->function_set_parameters(this->fndecl_, param_vars))
+    {
+      go_assert(saw_errors());
+      return;
+    }
+
+  // If we need a closure variable, fetch it by calling a runtime
+  // function.  The caller will have called __go_set_closure before
+  // the function call.
+  if (this->closure_var_ != NULL)
+    {
+      Bvariable* closure_bvar =
+	this->closure_var_->get_backend_variable(gogo, named_function);
+      vars.push_back(closure_bvar);
+
+      Expression* closure =
+          Runtime::make_call(Runtime::GET_CLOSURE, this->location_, 0);
+      var_inits.push_back(tree_to_expr(closure->get_tree(&context)));
+    }
+
+  if (this->block_ != NULL)
+    {
+      // Declare variables if necessary.
+      Bblock* var_decls = NULL;
+
+      Bstatement* defer_init = NULL;
+      if (!vars.empty() || this->defer_stack_ != NULL)
+	{
+          var_decls =
+              gogo->backend()->block(this->fndecl_, NULL, vars,
+                                     this->block_->start_location(),
+                                     this->block_->end_location());
+
+	  if (this->defer_stack_ != NULL)
+	    {
+	      Translate_context dcontext(gogo, named_function, this->block_,
+                                         var_decls);
+              defer_init = this->defer_stack_->get_backend(&dcontext);
+	    }
+	}
+
+      // Build the backend representation for all the statements in the
+      // function.
+      Translate_context context(gogo, named_function, NULL, NULL);
+      Bblock* code_block = this->block_->get_backend(&context);
+
+      // Initialize variables if necessary.
+      std::vector<Bstatement*> init;
+      go_assert(vars.size() == var_inits.size());
+      for (size_t i = 0; i < vars.size(); ++i)
+	{
+          Bstatement* init_stmt =
+              gogo->backend()->init_statement(vars[i], var_inits[i]);
+          init.push_back(init_stmt);
+	}
+      Bstatement* var_init = gogo->backend()->statement_list(init);
+
+      // Initialize all variables before executing this code block.
+      Bstatement* code_stmt = gogo->backend()->block_statement(code_block);
+      code_stmt = gogo->backend()->compound_statement(var_init, code_stmt);
+
+      // If we have a defer stack, initialize it at the start of a
+      // function.
+      Bstatement* except = NULL;
+      Bstatement* fini = NULL;
+      if (defer_init != NULL)
+	{
+	  // Clean up the defer stack when we leave the function.
+	  this->build_defer_wrapper(gogo, named_function, &except, &fini);
+
+          // Wrap the code for this function in an exception handler to handle
+          // defer calls.
+          code_stmt =
+              gogo->backend()->exception_handler_statement(code_stmt,
+                                                           except, fini,
+                                                           this->location_);
+	}
+
+      // Stick the code into the block we built for the receiver, if
+      // we built one.
+      if (var_decls != NULL)
+        {
+          std::vector<Bstatement*> code_stmt_list(1, code_stmt);
+          gogo->backend()->block_add_statements(var_decls, code_stmt_list);
+          code_stmt = gogo->backend()->block_statement(var_decls);
+        }
+
+      if (!gogo->backend()->function_set_body(this->fndecl_, code_stmt))
+        {
+          go_assert(saw_errors());
+          return;
+        }
+    }
+
+  // If we created a descriptor for the function, make sure we emit it.
+  if (this->descriptor_ != NULL)
+    {
+      Translate_context context(gogo, NULL, NULL, NULL);
+      this->descriptor_->get_tree(&context);
+    }
+}
+
+// Build the wrappers around function code needed if the function has
+// any defer statements.  This sets *EXCEPT to an exception handler
+// and *FINI to a finally handler.
+
+void
+Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
+			      Bstatement** except, Bstatement** fini)
+{
+  Location end_loc = this->block_->end_location();
+
+  // Add an exception handler.  This is used if a panic occurs.  Its
+  // purpose is to stop the stack unwinding if a deferred function
+  // calls recover.  There are more details in
+  // libgo/runtime/go-unwind.c.
+
+  std::vector<Bstatement*> stmts;
+  Expression* call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1,
+					this->defer_stack(end_loc));
+  Translate_context context(gogo, named_function, NULL, NULL);
+  Bexpression* defer = tree_to_expr(call->get_tree(&context));
+  stmts.push_back(gogo->backend()->expression_statement(defer));
+
+  Bstatement* ret_bstmt = this->return_value(gogo, named_function, end_loc);
+  if (ret_bstmt != NULL)
+    stmts.push_back(ret_bstmt);
+
+  go_assert(*except == NULL);
+  *except = gogo->backend()->statement_list(stmts);
+
+  call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1,
+                            this->defer_stack(end_loc));
+  defer = tree_to_expr(call->get_tree(&context));
+
+  call = Runtime::make_call(Runtime::UNDEFER, end_loc, 1,
+        		    this->defer_stack(end_loc));
+  Bexpression* undefer = tree_to_expr(call->get_tree(&context));
+  Bstatement* function_defer =
+      gogo->backend()->function_defer_statement(this->fndecl_, undefer, defer,
+                                                end_loc);
+  stmts = std::vector<Bstatement*>(1, function_defer);
+  if (this->type_->results() != NULL
+      && !this->type_->results()->empty()
+      && !this->type_->results()->front().name().empty())
+    {
+      // If the result variables are named, and we are returning from
+      // this function rather than panicing through it, we need to
+      // return them again, because they might have been changed by a
+      // defer function.  The runtime routines set the defer_stack
+      // variable to true if we are returning from this function.
+
+      ret_bstmt = this->return_value(gogo, named_function, end_loc);
+      Bexpression* nil =
+          tree_to_expr(Expression::make_nil(end_loc)->get_tree(&context));
+      Bexpression* ret =
+          gogo->backend()->compound_expression(ret_bstmt, nil, end_loc);
+      Expression* ref =
+	Expression::make_temporary_reference(this->defer_stack_, end_loc);
+      Bexpression* bref = tree_to_expr(ref->get_tree(&context));
+      ret = gogo->backend()->conditional_expression(NULL, bref, ret, NULL,
+                                                    end_loc);
+      stmts.push_back(gogo->backend()->expression_statement(ret));
+    }
+
+  go_assert(*fini == NULL);
+  *fini = gogo->backend()->statement_list(stmts);
+}
+
+// Return the statement that assigns values to this function's result struct.
+
+Bstatement*
+Function::return_value(Gogo* gogo, Named_object* named_function,
+		       Location location) const
+{
+  const Typed_identifier_list* results = this->type_->results();
+  if (results == NULL || results->empty())
+    return NULL;
+
+  go_assert(this->results_ != NULL);
+  if (this->results_->size() != results->size())
+    {
+      go_assert(saw_errors());
+      return gogo->backend()->error_statement();
+    }
+
+  std::vector<Bexpression*> vals(results->size());
+  for (size_t i = 0; i < vals.size(); ++i)
+    {
+      Named_object* no = (*this->results_)[i];
+      Bvariable* bvar = no->get_backend_variable(gogo, named_function);
+      Bexpression* val = gogo->backend()->var_expression(bvar, location);
+      if (no->result_var_value()->is_in_heap())
+        val = gogo->backend()->indirect_expression(val, true, location);
+      vals[i] = val;
+    }
+  return gogo->backend()->return_statement(this->fndecl_, vals, location);
+}
+
 // Class Block.
 
 Block::Block(Block* enclosing, Location location)
@@ -4857,6 +5171,74 @@ Variable::determine_type()
     }
 }
 
+// Get the initial value of a variable.  This does not
+// consider whether the variable is in the heap--it returns the
+// initial value as though it were always stored in the stack.
+
+Bexpression*
+Variable::get_init(Gogo* gogo, Named_object* function)
+{
+  go_assert(this->preinit_ == NULL);
+  Location loc = this->location();
+  if (this->init_ == NULL)
+    {
+      go_assert(!this->is_parameter_);
+      if (this->is_global_ || this->is_in_heap())
+	return NULL;
+      Btype* btype = this->type()->get_backend(gogo);
+      return gogo->backend()->zero_expression(btype);
+    }
+  else
+    {
+      Translate_context context(gogo, function, NULL, NULL);
+      Expression* init = Expression::make_cast(this->type(), this->init_, loc);
+      return tree_to_expr(init->get_tree(&context));
+    }
+}
+
+// Get the initial value of a variable when a block is required.
+// VAR_DECL is the decl to set; it may be NULL for a sink variable.
+
+Bstatement*
+Variable::get_init_block(Gogo* gogo, Named_object* function,
+                         Bvariable* var_decl)
+{
+  go_assert(this->preinit_ != NULL);
+
+  // We want to add the variable assignment to the end of the preinit
+  // block.
+
+  Translate_context context(gogo, function, NULL, NULL);
+  Bblock* bblock = this->preinit_->get_backend(&context);
+
+  // It's possible to have pre-init statements without an initializer
+  // if the pre-init statements set the variable.
+  Bstatement* decl_init = NULL;
+  if (this->init_ != NULL)
+    {
+      if (var_decl == NULL)
+        {
+          Bexpression* init_bexpr =
+              tree_to_expr(this->init_->get_tree(&context));
+          decl_init = gogo->backend()->expression_statement(init_bexpr);
+        }
+      else
+	{
+          Location loc = this->location();
+          Expression* val_expr =
+              Expression::convert_for_assignment(gogo, this->type(),
+                                                 this->init_, this->location());
+          Bexpression* val = tree_to_expr(val_expr->get_tree(&context));
+          Bexpression* var_ref = gogo->backend()->var_expression(var_decl, loc);
+          decl_init = gogo->backend()->assignment_statement(var_ref, val, loc);
+	}
+    }
+  Bstatement* block_stmt = gogo->backend()->block_statement(bblock);
+  if (decl_init != NULL)
+    block_stmt = gogo->backend()->compound_statement(block_stmt, decl_init);
+  return block_stmt;
+}
+
 // Export the variable
 
 void
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 3f2808781b7..3dc401d6955 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -612,34 +612,9 @@ class Gogo
   void
   build_interface_method_tables();
 
-  // Build an interface method table for a type: a list of function
-  // pointers, one for each interface method.  This returns a decl.
-  tree
-  interface_method_table_for_type(const Interface_type*, Type*,
-				  bool is_pointer);
-
-  // Return a tree which allocate SIZE bytes to hold values of type
-  // TYPE.
-  tree
-  allocate_memory(Type *type, tree size, Location);
-
-  // Return a type to use for pointer to const char.
-  static tree
-  const_char_pointer_type_tree();
-
-  // Build a string constant with the right type.
-  static tree
-  string_constant_tree(const std::string&);
-
-  // Build a Go string constant.  This returns a pointer to the
-  // constant.
-  tree
-  go_string_constant_tree(const std::string&);
-
-  // Receive a value from a channel.
-  static tree
-  receive_from_channel(tree type_tree, tree type_descriptor_tree, tree channel,
-		       Location);
+  // Return an expression which allocates memory to hold values of type TYPE.
+  Expression*
+  allocate_memory(Type *type, Location);
 
  private:
   // During parsing, we keep a stack of functions.  Each function on
@@ -687,11 +662,6 @@ class Gogo
   void
   register_gc_vars(const std::vector<Named_object*>&, tree*);
 
-  // Build a pointer to a Go string constant.  This returns a pointer
-  // to the pointer.
-  tree
-  ptr_go_string_constant_tree(const std::string&);
-
   // Type used to map import names to packages.
   typedef std::map<std::string, Package*> Imports;
 
@@ -1119,14 +1089,14 @@ class Function
   tree
   get_decl() const;
 
-  // Set the function decl to hold a tree of the function code.
+  // Set the function decl to hold a backend representation of the function
+  // code.
   void
-  build_tree(Gogo*, Named_object*);
+  build(Gogo*, Named_object*);
 
-  // Get the value to return when not explicitly specified.  May also
-  // add statements to execute first to STMT_LIST.
-  tree
-  return_value(Gogo*, Named_object*, Location, tree* stmt_list) const;
+  // Get the statement that assigns values to this function's result struct.
+  Bstatement*
+  return_value(Gogo*, Named_object*, Location) const;
 
   // Get a tree for the variable holding the defer stack.
   Expression*
@@ -1151,14 +1121,8 @@ class Function
   // Type for mapping from label names to Label objects.
   typedef Unordered_map(std::string, Label*) Labels;
 
-  tree
-  make_receiver_parm_decl(Gogo*, Named_object*, tree);
-
-  tree
-  copy_parm_to_heap(Gogo*, Named_object*, tree);
-
   void
-  build_defer_wrapper(Gogo*, Named_object*, tree*, tree*);
+  build_defer_wrapper(Gogo*, Named_object*, Bstatement**, Bstatement**);
 
   typedef std::vector<std::pair<Named_object*,
 				Location> > Closure_fields;
@@ -1531,16 +1495,16 @@ class Variable
   get_backend_variable(Gogo*, Named_object*, const Package*,
 		       const std::string&);
 
-  // Get the initial value of the variable as a tree.  This may only
+  // Get the initial value of the variable.  This may only
   // be called if has_pre_init() returns false.
-  tree
-  get_init_tree(Gogo*, Named_object* function);
+  Bexpression*
+  get_init(Gogo*, Named_object* function);
 
   // Return a series of statements which sets the value of the
   // variable in DECL.  This should only be called is has_pre_init()
   // returns true.  DECL may be NULL for a sink variable.
-  tree
-  get_init_block(Gogo*, Named_object* function, tree decl);
+  Bstatement*
+  get_init_block(Gogo*, Named_object* function, Bvariable* decl);
 
   // Export the variable.
   void
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index 7614e6fc795..3d60171dde2 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -2955,7 +2955,7 @@ Parse::create_closure(Named_object* function, Enclosing_vars* enclosing_vars,
   Struct_type* st = closure_var->var_value()->type()->deref()->struct_type();
   Expression* cv = Expression::make_struct_composite_literal(st, initializer,
 							     location);
-  return Expression::make_heap_composite(cv, location);
+  return Expression::make_heap_expression(cv, location);
 }
 
 // PrimaryExpr = Operand { Selector | Index | Slice | TypeGuard | Call } .
@@ -3538,7 +3538,7 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
 	expr = Expression::make_type(Type::make_pointer_type(expr->type()),
 				     location);
       else if (op == OPERATOR_AND && expr->is_composite_literal())
-	expr = Expression::make_heap_composite(expr, location);
+	expr = Expression::make_heap_expression(expr, location);
       else if (op != OPERATOR_CHANOP)
 	expr = Expression::make_unary(op, expr, location);
       else
@@ -3765,7 +3765,8 @@ Parse::labeled_stmt(const std::string& label_name, Location location)
     {
       // Mark the label as used to avoid a useless error about an
       // unused label.
-      label->set_is_used();
+      if (label != NULL)
+        label->set_is_used();
 
       error_at(location, "missing statement after label");
       this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON,
diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def
index a303a50410f..8c6e82b2267 100644
--- a/gcc/go/gofrontend/runtime.def
+++ b/gcc/go/gofrontend/runtime.def
@@ -142,11 +142,8 @@ DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(TYPE, CHAN, UINT64), R0())
 // Send a big value on a channel.
 DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(TYPE, CHAN, POINTER), R0())
 
-// Receive a small value from a channel.
-DEF_GO_RUNTIME(RECEIVE_SMALL, "__go_receive_small", P2(TYPE, CHAN), R1(UINT64))
-
-// Receive a big value from a channel.
-DEF_GO_RUNTIME(RECEIVE_BIG, "__go_receive_big", P3(TYPE, CHAN, POINTER), R0())
+// Receive a value from a channel.
+DEF_GO_RUNTIME(RECEIVE, "__go_receive", P3(TYPE, CHAN, POINTER), R0())
 
 // Receive a value from a channel returning whether it is closed.
 DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P3(TYPE, CHAN, POINTER),
@@ -208,7 +205,7 @@ DEF_GO_RUNTIME(RUNTIME_ERROR, "__go_runtime_error", P1(INT32), R0())
 
 
 // Close.
-DEF_GO_RUNTIME(CLOSE, "__go_close", P1(CHAN), R0())
+DEF_GO_RUNTIME(CLOSE, "__go_builtin_close", P1(CHAN), R0())
 
 
 // Copy.
@@ -233,6 +230,11 @@ DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P1(UINTPTR), R1(POINTER))
 // Start a new goroutine.
 DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0())
 
+// Get the function closure.
+DEF_GO_RUNTIME(GET_CLOSURE, "__go_get_closure", P0(), R1(POINTER))
+
+// Set the function closure.
+DEF_GO_RUNTIME(SET_CLOSURE, "__go_set_closure", P1(POINTER), R0())
 
 // Defer a function.
 DEF_GO_RUNTIME(DEFER, "__go_defer", P3(BOOLPTR, FUNC_PTR, POINTER), R0())
@@ -270,7 +272,7 @@ DEF_GO_RUNTIME(IFACEI2T2, "runtime.ifaceI2T2", P3(TYPE, IFACE, POINTER),
 
 // 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())
+DEF_GO_RUNTIME(ASSERT_INTERFACE, "__go_assert_interface", P2(TYPE, TYPE), R1(POINTER))
 
 // Convert one interface type to another.  This is used for an
 // assignment.
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index d195ab9845a..49a864faa44 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -264,8 +264,7 @@ Variable_declaration_statement::do_get_backend(Translate_context* context)
   Variable* var = this->var_->var_value();
   Bvariable* bvar = this->var_->get_backend_variable(context->gogo(),
 						     context->function());
-  tree init = var->get_init_tree(context->gogo(), context->function());
-  Bexpression* binit = init == NULL ? NULL : tree_to_expr(init);
+  Bexpression* binit = var->get_init(context->gogo(), context->function());
 
   if (!var->is_in_heap())
     {
@@ -638,13 +637,17 @@ Assignment_statement::do_check_types(Gogo*)
 Bstatement*
 Assignment_statement::do_get_backend(Translate_context* context)
 {
-  tree rhs_tree = this->rhs_->get_tree(context);
   if (this->lhs_->is_sink_expression())
-    return context->backend()->expression_statement(tree_to_expr(rhs_tree));
+    {
+      tree rhs_tree = this->rhs_->get_tree(context);
+      return context->backend()->expression_statement(tree_to_expr(rhs_tree));
+    }
+
   tree lhs_tree = this->lhs_->get_tree(context);
-  rhs_tree = Expression::convert_for_assignment(context, this->lhs_->type(),
-						this->rhs_->type(), rhs_tree,
-						this->location());
+  Expression* rhs =
+      Expression::convert_for_assignment(context->gogo(), this->lhs_->type(),
+                                         this->rhs_, this->location());
+  tree rhs_tree = rhs->get_tree(context);
   return context->backend()->assignment_statement(tree_to_expr(lhs_tree),
 						  tree_to_expr(rhs_tree),
 						  this->location());
@@ -2187,7 +2190,7 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
 					      location);
 
   // Allocate the initialized struct on the heap.
-  constructor = Expression::make_heap_composite(constructor, location);
+  constructor = Expression::make_heap_expression(constructor, location);
 
   // Look up the thunk.
   Named_object* named_thunk = gogo->lookup(thunk_name, NULL);
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 2148a1a43e6..91a535f01c8 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -3075,34 +3075,6 @@ String_type::do_get_backend(Gogo* gogo)
   return backend_string_type;
 }
 
-// Return a tree for the length of STRING.
-
-tree
-String_type::length_tree(Gogo*, tree string)
-{
-  tree string_type = TREE_TYPE(string);
-  go_assert(TREE_CODE(string_type) == RECORD_TYPE);
-  tree length_field = DECL_CHAIN(TYPE_FIELDS(string_type));
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(length_field)),
-		    "__length") == 0);
-  return fold_build3(COMPONENT_REF, TREE_TYPE(length_field), string,
-		     length_field, NULL_TREE);
-}
-
-// Return a tree for a pointer to the bytes of STRING.
-
-tree
-String_type::bytes_tree(Gogo*, tree string)
-{
-  tree string_type = TREE_TYPE(string);
-  go_assert(TREE_CODE(string_type) == RECORD_TYPE);
-  tree bytes_field = TYPE_FIELDS(string_type);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(bytes_field)),
-		    "__data") == 0);
-  return fold_build3(COMPONENT_REF, TREE_TYPE(bytes_field), string,
-		     bytes_field, NULL_TREE);
-}
-
 // The type descriptor for the string type.
 
 Expression*
@@ -4916,9 +4888,8 @@ Struct_type::method_function(const std::string& name, bool* is_ambiguous) const
 // the interface INTERFACE.  IS_POINTER is true if this is for a
 // pointer to THIS.
 
-tree
-Struct_type::interface_method_table(Gogo* gogo,
-				    const Interface_type* interface,
+Expression*
+Struct_type::interface_method_table(Interface_type* interface,
 				    bool is_pointer)
 {
   std::pair<Struct_type*, Struct_type::Struct_method_table_pair*>
@@ -4937,7 +4908,7 @@ Struct_type::interface_method_table(Gogo* gogo,
       ins.first->second = smtp;
     }
 
-  return Type::interface_method_table(gogo, this, interface, is_pointer,
+  return Type::interface_method_table(this, interface, is_pointer,
 				      &smtp->first, &smtp->second);
 }
 
@@ -8198,13 +8169,12 @@ Named_type::method_function(const std::string& name, bool* is_ambiguous) const
 // the interface INTERFACE.  IS_POINTER is true if this is for a
 // pointer to THIS.
 
-tree
-Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface,
-				   bool is_pointer)
+Expression*
+Named_type::interface_method_table(Interface_type* interface, bool is_pointer)
 {
-  return Type::interface_method_table(gogo, this, interface, is_pointer,
-				      &this->interface_method_tables_,
-				      &this->pointer_interface_method_tables_);
+  return Type::interface_method_table(this, interface, is_pointer,
+                                      &this->interface_method_tables_,
+                                      &this->pointer_interface_method_tables_);
 }
 
 // Return whether a named type has any hidden fields.
@@ -9385,9 +9355,9 @@ Type::method_function(const Methods* methods, const std::string& name,
 // Return a pointer to the interface method table for TYPE for the
 // interface INTERFACE.
 
-tree
-Type::interface_method_table(Gogo* gogo, Type* type,
-			     const Interface_type *interface,
+Expression*
+Type::interface_method_table(Type* type,
+			     Interface_type *interface,
 			     bool is_pointer,
 			     Interface_method_tables** method_tables,
 			     Interface_method_tables** pointer_tables)
@@ -9399,23 +9369,18 @@ Type::interface_method_table(Gogo* gogo, Type* type,
   if (*pimt == NULL)
     *pimt = new Interface_method_tables(5);
 
-  std::pair<const Interface_type*, tree> val(interface, NULL_TREE);
+  std::pair<Interface_type*, Expression*> val(interface, NULL);
   std::pair<Interface_method_tables::iterator, bool> ins = (*pimt)->insert(val);
 
+  Location loc = Linemap::predeclared_location();
   if (ins.second)
     {
       // This is a new entry in the hash table.
-      go_assert(ins.first->second == NULL_TREE);
-      ins.first->second = gogo->interface_method_table_for_type(interface,
-								type,
-								is_pointer);
+      go_assert(ins.first->second == NULL);
+      ins.first->second =
+	Expression::make_interface_mtable_ref(interface, type, is_pointer, loc);
     }
-
-  tree decl = ins.first->second;
-  if (decl == error_mark_node)
-    return error_mark_node;
-  go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL);
-  return build_fold_addr_expr(decl);
+  return Expression::make_unary(OPERATOR_AND, ins.first->second, loc);
 }
 
 // Look for field or method NAME for TYPE.  Return an Expression for
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index 5fda4e7285e..d2ca1bf27fb 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -1019,14 +1019,14 @@ class Type
 
   // A mapping from interfaces to the associated interface method
   // tables for this type.  This maps to a decl.
-  typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical,
+  typedef Unordered_map_hash(Interface_type*, Expression*, Type_hash_identical,
 			     Type_identical) Interface_method_tables;
 
   // Return a pointer to the interface method table for TYPE for the
   // interface INTERFACE.
-  static tree
-  interface_method_table(Gogo* gogo, Type* type,
-			 const Interface_type *interface, bool is_pointer,
+  static Expression*
+  interface_method_table(Type* type,
+			 Interface_type *interface, bool is_pointer,
 			 Interface_method_tables** method_tables,
 			 Interface_method_tables** pointer_tables);
 
@@ -1688,14 +1688,6 @@ class String_type : public Type
     : Type(TYPE_STRING)
   { }
 
-  // Return a tree for the length of STRING.
-  static tree
-  length_tree(Gogo*, tree string);
-
-  // Return a tree which points to the bytes of STRING.
-  static tree
-  bytes_tree(Gogo*, tree string);
-
  protected:
   bool
   do_has_pointer() const
@@ -2205,9 +2197,8 @@ class Struct_type : public Type
   // the interface INTERFACE.  If IS_POINTER is true, set the type
   // descriptor to a pointer to this type, otherwise set it to this
   // type.
-  tree
-  interface_method_table(Gogo*, const Interface_type* interface,
-			 bool is_pointer);
+  Expression*
+  interface_method_table(Interface_type* interface, bool is_pointer);
 
   // Traverse just the field types of a struct type.
   int
@@ -2946,9 +2937,8 @@ class Named_type : public Type
   // the interface INTERFACE.  If IS_POINTER is true, set the type
   // descriptor to a pointer to this type, otherwise set it to this
   // type.
-  tree
-  interface_method_table(Gogo*, const Interface_type* interface,
-			 bool is_pointer);
+  Expression*
+  interface_method_table(Interface_type* interface, bool is_pointer);
 
   // Whether this type has any hidden fields.
   bool
diff --git a/libgo/runtime/chan.c b/libgo/runtime/chan.c
index 1d9e6681d35..38a2aafc775 100644
--- a/libgo/runtime/chan.c
+++ b/libgo/runtime/chan.c
@@ -483,31 +483,10 @@ __go_send_big(ChanType *t, Hchan* c, byte* p)
 	runtime_chansend(t, c, p, nil, runtime_getcallerpc(&t));
 }
 
-// The compiler generates a call to __go_receive_small to receive a
-// value 8 bytes or smaller.
-uint64
-__go_receive_small(ChanType *t, Hchan* c)
-{
-	union {
-		byte b[sizeof(uint64)];
-		uint64 v;
-	} u;
-	byte *p;
-
-	u.v = 0;
-#ifndef WORDS_BIGENDIAN
-	p = u.b;
-#else
-	p = u.b + sizeof(uint64) - t->__element_type->__size;
-#endif
-	runtime_chanrecv(t, c, p, nil, nil);
-	return u.v;
-}
-
-// The compiler generates a call to __go_receive_big to receive a
-// value larger than 8 bytes.
+// The compiler generates a call to __go_receive to receive a
+// value from a channel.
 void
-__go_receive_big(ChanType *t, Hchan* c, byte* p)
+__go_receive(ChanType *t, Hchan* c, byte* p)
 {
 	runtime_chanrecv(t, c, p, nil, nil);
 }