Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 206615)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -5536,6 +5536,61 @@ Binary_expression::lower_compare_to_memc
   return Expression::make_binary(this->op_, call, zero, loc);
 }
 
+Expression*
+Binary_expression::do_flatten(Gogo*, Named_object*,
+                              Statement_inserter* inserter)
+{
+  Location loc = this->location();
+  Temporary_statement* temp;
+  if (this->left_->type()->is_string_type()
+      && this->op_ == OPERATOR_PLUS)
+    {
+      if (!this->left_->is_variable())
+        {
+          temp = Statement::make_temporary(NULL, this->left_, loc);
+          inserter->insert(temp);
+          this->left_ = Expression::make_temporary_reference(temp, loc);
+        }
+      if (!this->right_->is_variable())
+        {
+          temp =
+              Statement::make_temporary(this->left_->type(), this->right_, loc);
+          this->right_ = Expression::make_temporary_reference(temp, loc);
+          inserter->insert(temp);
+        }
+    }
+
+  Type* left_type = this->left_->type();
+  bool is_shift_op = (this->op_ == OPERATOR_LSHIFT
+                      || this->op_ == OPERATOR_RSHIFT);
+  bool is_idiv_op = ((this->op_ == OPERATOR_DIV &&
+                      left_type->integer_type() != NULL)
+                     || this->op_ == OPERATOR_MOD);
+
+  // FIXME: go_check_divide_zero and go_check_divide_overflow are globals
+  // defined in gcc/go/lang.opt.  These should be defined in go_create_gogo
+  // and accessed from the Gogo* passed to do_flatten.
+  if (is_shift_op
+      || (is_idiv_op && (go_check_divide_zero || go_check_divide_overflow)))
+    {
+      if (!this->left_->is_variable())
+        {
+          temp = Statement::make_temporary(NULL, this->left_, loc);
+          inserter->insert(temp);
+          this->left_ = Expression::make_temporary_reference(temp, loc);
+        }
+      if (!this->right_->is_variable())
+        {
+          temp =
+              Statement::make_temporary(NULL, this->right_, loc);
+          this->right_ = Expression::make_temporary_reference(temp, loc);
+          inserter->insert(temp);
+        }
+    }
+  return this;
+}
+
+
 // Return the address of EXPR, cast to unsafe.Pointer.
 
 Expression*
@@ -5956,14 +6011,10 @@ tree
 Binary_expression::do_get_tree(Translate_context* context)
 {
   Gogo* gogo = context->gogo();
+  Location loc = this->location();
+  Type* left_type = this->left_->type();
+  Type* right_type = this->right_->type();
 
-  tree left = this->left_->get_tree(context);
-  tree right = this->right_->get_tree(context);
-
-  if (left == error_mark_node || right == error_mark_node)
-    return error_mark_node;
-
-  enum tree_code code;
   bool use_left_type = true;
   bool is_shift_op = false;
   bool is_idiv_op = false;
@@ -5975,198 +6026,126 @@ Binary_expression::do_get_tree(Translate
     case OPERATOR_LE:
     case OPERATOR_GT:
     case OPERATOR_GE:
-      return Expression::comparison_tree(context, this->type_, this->op_,
-					 this->left_, this->right_,
-					 this->location());
+      {
+        Bexpression* ret =
+            Expression::comparison(context, this->type_, this->op_,
+                                   this->left_, this->right_, loc);
+        return expr_to_tree(ret);
+      }
 
     case OPERATOR_OROR:
-      code = TRUTH_ORIF_EXPR;
-      use_left_type = false;
-      break;
     case OPERATOR_ANDAND:
-      code = TRUTH_ANDIF_EXPR;
       use_left_type = false;
       break;
     case OPERATOR_PLUS:
-      code = PLUS_EXPR;
-      break;
     case OPERATOR_MINUS:
-      code = MINUS_EXPR;
-      break;
     case OPERATOR_OR:
-      code = BIT_IOR_EXPR;
-      break;
     case OPERATOR_XOR:
-      code = BIT_XOR_EXPR;
-      break;
     case OPERATOR_MULT:
-      code = MULT_EXPR;
       break;
     case OPERATOR_DIV:
-      {
-	Type *t = this->left_->type();
-	if (t->float_type() != NULL || t->complex_type() != NULL)
-	  code = RDIV_EXPR;
-	else
-	  {
-	    code = TRUNC_DIV_EXPR;
-	    is_idiv_op = true;
-	  }
-      }
-      break;
+      if (left_type->float_type() != NULL || left_type->complex_type() != NULL)
+        break;
     case OPERATOR_MOD:
-      code = TRUNC_MOD_EXPR;
       is_idiv_op = true;
       break;
     case OPERATOR_LSHIFT:
-      code = LSHIFT_EXPR;
-      is_shift_op = true;
-      break;
     case OPERATOR_RSHIFT:
-      code = RSHIFT_EXPR;
       is_shift_op = true;
       break;
-    case OPERATOR_AND:
-      code = BIT_AND_EXPR;
-      break;
     case OPERATOR_BITCLEAR:
-      right = fold_build1(BIT_NOT_EXPR, TREE_TYPE(right), right);
-      code = BIT_AND_EXPR;
+      this->right_ = Expression::make_unary(OPERATOR_XOR, this->right_, loc);
+    case OPERATOR_AND:
       break;
     default:
       go_unreachable();
     }
 
-  location_t gccloc = this->location().gcc_location();
-  tree type = use_left_type ? TREE_TYPE(left) : TREE_TYPE(right);
-
-  if (this->left_->type()->is_string_type())
+  if (left_type->is_string_type())
     {
       go_assert(this->op_ == OPERATOR_PLUS);
-      Type* st = Type::make_string_type();
-      tree string_type = type_to_tree(st->get_backend(gogo));
-      static tree string_plus_decl;
-      return Gogo::call_builtin(&string_plus_decl,
-				this->location(),
-				"__go_string_plus",
-				2,
-				string_type,
-				string_type,
-				left,
-				string_type,
-				right);
+      Expression* string_plus =
+          Runtime::make_call(Runtime::STRING_PLUS, loc, 2,
+                             this->left_, this->right_);
+      return string_plus->get_tree(context);
     }
 
-  // For complex division Go wants slightly different results than the
-  // GCC library provides, so we have our own runtime routine.
+  // For complex division Go might want slightly different results than the
+  // backend implementation provides, so we have our own runtime routine.
   if (this->op_ == OPERATOR_DIV && this->left_->type()->complex_type() != NULL)
     {
-      const char *name;
-      tree *pdecl;
-      Type* ctype;
-      static tree complex64_div_decl;
-      static tree complex128_div_decl;
+      Runtime::Function complex_code;
       switch (this->left_->type()->complex_type()->bits())
 	{
 	case 64:
-	  name = "__go_complex64_div";
-	  pdecl = &complex64_div_decl;
-	  ctype = Type::lookup_complex_type("complex64");
+          complex_code = Runtime::COMPLEX64_DIV;
 	  break;
 	case 128:
-	  name = "__go_complex128_div";
-	  pdecl = &complex128_div_decl;
-	  ctype = Type::lookup_complex_type("complex128");
+          complex_code = Runtime::COMPLEX128_DIV;
 	  break;
 	default:
 	  go_unreachable();
 	}
-      Btype* cbtype = ctype->get_backend(gogo);
-      tree ctype_tree = type_to_tree(cbtype);
-      return Gogo::call_builtin(pdecl,
-				this->location(),
-				name,
-				2,
-				ctype_tree,
-				ctype_tree,
-				fold_convert_loc(gccloc, ctype_tree, left),
-				type,
-				fold_convert_loc(gccloc, ctype_tree, right));
+      Expression* complex_div =
+          Runtime::make_call(complex_code, loc, 2, this->left_, this->right_);
+      return complex_div->get_tree(context);
     }
 
-  tree compute_type = excess_precision_type(type);
-  if (compute_type != NULL_TREE)
-    {
-      left = ::convert(compute_type, left);
-      right = ::convert(compute_type, right);
-    }
+  Bexpression* left = tree_to_expr(this->left_->get_tree(context));
+  Bexpression* right = tree_to_expr(this->right_->get_tree(context));
 
-  tree eval_saved = NULL_TREE;
-  if (is_shift_op
-      || (is_idiv_op && (go_check_divide_zero || go_check_divide_overflow)))
-    {
-      // Make sure the values are evaluated.
-      if (!DECL_P(left))
-	{
-	  left = save_expr(left);
-	  eval_saved = left;
-	}
-      if (!DECL_P(right))
-	{
-	  right = save_expr(right);
-	  if (eval_saved == NULL_TREE)
-	    eval_saved = right;
-	  else
-	    eval_saved = fold_build2_loc(gccloc, COMPOUND_EXPR,
-					 void_type_node, eval_saved, right);
-	}
-    }
+  Type* type = use_left_type ? left_type : right_type;
+  Btype* btype = type->get_backend(gogo);
+
+  Bexpression* ret =
+      gogo->backend()->binary_expression(this->op_, left, right, loc);
+  ret = gogo->backend()->convert_expression(btype, ret, loc);
 
-  tree ret = fold_build2_loc(gccloc, code,
-			     compute_type != NULL_TREE ? compute_type : type,
-			     left, right);
+  // Initialize overflow constants.
+  Bexpression* overflow;
+  mpz_t zero;
+  mpz_init_set_ui(zero, 0UL);
+  mpz_t one;
+  mpz_init_set_ui(one, 1UL);
+  mpz_t neg_one;
+  mpz_init_set_si(neg_one, -1);
 
-  if (compute_type != NULL_TREE)
-    ret = ::convert(type, ret);
+  Btype* left_btype = left_type->get_backend(gogo);
+  Btype* right_btype = right_type->get_backend(gogo);
 
   // In Go, a shift larger than the size of the type is well-defined.
-  // This is not true in GENERIC, so we need to insert a conditional.
+  // This is not true in C, so we need to insert a conditional.
   if (is_shift_op)
     {
-      go_assert(INTEGRAL_TYPE_P(TREE_TYPE(left)));
-      go_assert(this->left_->type()->integer_type() != NULL);
-      int bits = TYPE_PRECISION(TREE_TYPE(left));
+      go_assert(left_type->integer_type() != NULL);
 
-      tree compare = fold_build2(LT_EXPR, boolean_type_node, right,
-				 build_int_cst_type(TREE_TYPE(right), bits));
-
-      tree overflow_result = fold_convert_loc(gccloc, TREE_TYPE(left),
-					      integer_zero_node);
+      mpz_t bitsval;
+      int bits = left_type->integer_type()->bits();
+      mpz_init_set_ui(bitsval, bits);
+      Bexpression* bits_expr =
+          gogo->backend()->integer_constant_expression(right_btype, bitsval);
+      Bexpression* compare =
+          gogo->backend()->binary_expression(OPERATOR_LT,
+                                             right, bits_expr, loc);
+
+      Bexpression* zero_expr =
+          gogo->backend()->integer_constant_expression(left_btype, zero);
+      overflow = zero_expr;
       if (this->op_ == OPERATOR_RSHIFT
-	  && !this->left_->type()->integer_type()->is_unsigned())
+	  && !left_type->integer_type()->is_unsigned())
 	{
-	  tree neg =
-            fold_build2_loc(gccloc, LT_EXPR, boolean_type_node,
-			    left,
-                            fold_convert_loc(gccloc, TREE_TYPE(left),
-                                             integer_zero_node));
-	  tree neg_one =
-            fold_build2_loc(gccloc, MINUS_EXPR, TREE_TYPE(left),
-                            fold_convert_loc(gccloc, TREE_TYPE(left),
-                                             integer_zero_node),
-                            fold_convert_loc(gccloc, TREE_TYPE(left),
-                                             integer_one_node));
-	  overflow_result =
-            fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left),
-			    neg, neg_one, overflow_result);
-	}
-
-      ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(left),
-			    compare, ret, overflow_result);
-
-      if (eval_saved != NULL_TREE)
-	ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
-			      eval_saved, ret);
+          Bexpression* neg_expr =
+              gogo->backend()->binary_expression(OPERATOR_LT, left,
+                                                 zero_expr, loc);
+          Bexpression* neg_one_expr =
+              gogo->backend()->integer_constant_expression(left_btype, neg_one);
+          overflow = gogo->backend()->conditional_expression(btype, neg_expr,
+                                                             neg_one_expr,
+                                                             zero_expr, loc);
+	}
+      ret = gogo->backend()->conditional_expression(btype, compare, ret,
+                                                    overflow, loc);
+      mpz_clear(bitsval);
     }
 
   // Add checks for division by zero and division overflow as needed.
@@ -6175,23 +6154,20 @@ Binary_expression::do_get_tree(Translate
       if (go_check_divide_zero)
 	{
 	  // right == 0
-	  tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
-				       right,
-				       fold_convert_loc(gccloc,
-							TREE_TYPE(right),
-							integer_zero_node));
+          Bexpression* zero_expr =
+              gogo->backend()->integer_constant_expression(right_btype, zero);
+          Bexpression* check =
+              gogo->backend()->binary_expression(OPERATOR_EQEQ,
+                                                 right, zero_expr, loc);
 
-	  // __go_runtime_error(RUNTIME_ERROR_DIVISION_BY_ZERO), 0
+	  // __go_runtime_error(RUNTIME_ERROR_DIVISION_BY_ZERO)
 	  int errcode = RUNTIME_ERROR_DIVISION_BY_ZERO;
-	  Expression* crash = gogo->runtime_error(errcode, this->location());
-	  tree panic = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
-				       crash->get_tree(context),
-				       fold_convert_loc(gccloc, TREE_TYPE(ret),
-							integer_zero_node));
+	  Expression* crash = gogo->runtime_error(errcode, loc);
+          Bexpression* crash_expr = tree_to_expr(crash->get_tree(context));
 
 	  // right == 0 ? (__go_runtime_error(...), 0) : ret
-	  ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
-				check, panic, ret);
+          ret = gogo->backend()->conditional_expression(btype, check,
+                                                        crash_expr, ret, loc);
 	}
 
       if (go_check_divide_overflow)
@@ -6199,60 +6175,62 @@ Binary_expression::do_get_tree(Translate
 	  // right == -1
 	  // FIXME: It would be nice to say that this test is expected
 	  // to return false.
-	  tree m1 = integer_minus_one_node;
-	  tree check = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
-				       right,
-				       fold_convert_loc(gccloc,
-							TREE_TYPE(right),
-							m1));
 
-	  tree overflow;
-	  if (TYPE_UNSIGNED(TREE_TYPE(ret)))
+          Bexpression* neg_one_expr =
+              gogo->backend()->integer_constant_expression(right_btype, neg_one);
+          Bexpression* check =
+              gogo->backend()->binary_expression(OPERATOR_EQEQ,
+                                                 right, neg_one_expr, loc);
+
+          Bexpression* zero_expr =
+              gogo->backend()->integer_constant_expression(btype, zero);
+          Bexpression* one_expr =
+              gogo->backend()->integer_constant_expression(btype, one);
+
+	  if (type->integer_type()->is_unsigned())
 	    {
 	      // An unsigned -1 is the largest possible number, so
 	      // dividing is always 1 or 0.
-	      tree cmp = fold_build2_loc(gccloc, EQ_EXPR, boolean_type_node,
-					 left, right);
+
+              Bexpression* cmp =
+                  gogo->backend()->binary_expression(OPERATOR_EQEQ,
+                                                     left, right, loc);
 	      if (this->op_ == OPERATOR_DIV)
-		overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
-					   cmp,
-					   fold_convert_loc(gccloc,
-							    TREE_TYPE(ret),
-							    integer_one_node),
-					   fold_convert_loc(gccloc,
-							    TREE_TYPE(ret),
-							    integer_zero_node));
+                overflow =
+                    gogo->backend()->conditional_expression(btype, cmp,
+                                                            one_expr, zero_expr,
+                                                            loc);
 	      else
-		overflow = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
-					   cmp,
-					   fold_convert_loc(gccloc,
-							    TREE_TYPE(ret),
-							    integer_zero_node),
-					   left);
+                overflow =
+                    gogo->backend()->conditional_expression(btype, cmp,
+                                                            zero_expr, left,
+                                                            loc);
 	    }
 	  else
 	    {
 	      // Computing left / -1 is the same as computing - left,
 	      // which does not overflow since Go sets -fwrapv.
 	      if (this->op_ == OPERATOR_DIV)
-		overflow = fold_build1_loc(gccloc, NEGATE_EXPR, TREE_TYPE(left),
-					   left);
+                {
+                  Expression* negate_expr =
+                      Expression::make_unary(OPERATOR_MINUS, this->left_, loc);
+                  overflow = tree_to_expr(negate_expr->get_tree(context));
+                }
 	      else
-		overflow = integer_zero_node;
+                overflow = zero_expr;
 	    }
-	  overflow = fold_convert_loc(gccloc, TREE_TYPE(ret), overflow);
+          overflow = gogo->backend()->convert_expression(btype, overflow, loc);
 
 	  // right == -1 ? - left : ret
-	  ret = fold_build3_loc(gccloc, COND_EXPR, TREE_TYPE(ret),
-				check, overflow, ret);
+          ret = gogo->backend()->conditional_expression(btype, check, overflow,
+                                                        ret, loc);
 	}
-
-      if (eval_saved != NULL_TREE)
-	ret = fold_build2_loc(gccloc, COMPOUND_EXPR, TREE_TYPE(ret),
-			      eval_saved, ret);
     }
 
-  return ret;
+  mpz_clear(zero);
+  mpz_clear(one);
+  mpz_clear(neg_one);
+  return expr_to_tree(ret);
 }
 
 // Export a binary expression.
@@ -6471,10 +6449,10 @@ Expression::make_binary(Operator op, Exp
 
 // Implement a comparison.
 
-tree
-Expression::comparison_tree(Translate_context* context, Type* result_type,
-			    Operator op, Expression* left, Expression* right,
-			    Location location)
+Bexpression*
+Expression::comparison(Translate_context* context, Type* result_type,
+		       Operator op, Expression* left, Expression* right,
+		       Location location)
 {
   Type* left_type = left->type();
   Type* right_type = right->type();
@@ -6484,31 +6462,6 @@ Expression::comparison_tree(Translate_co
   Expression* zexpr = Expression::make_integer(&zval, NULL, location);
   mpz_clear(zval);
 
-  enum tree_code code;
-  switch (op)
-    {
-    case OPERATOR_EQEQ:
-      code = EQ_EXPR;
-      break;
-    case OPERATOR_NOTEQ:
-      code = NE_EXPR;
-      break;
-    case OPERATOR_LT:
-      code = LT_EXPR;
-      break;
-    case OPERATOR_LE:
-      code = LE_EXPR;
-      break;
-    case OPERATOR_GT:
-      code = GT_EXPR;
-      break;
-    case OPERATOR_GE:
-      code = GE_EXPR;
-      break;
-    default:
-      go_unreachable();
-    }
-
   if (left_type->is_string_type() && right_type->is_string_type())
     {
       left = Runtime::make_call(Runtime::STRCMP, location, 2,
@@ -6601,20 +6554,15 @@ Expression::comparison_tree(Translate_co
 	}
     }
 
-  tree left_tree = left->get_tree(context);
-  tree right_tree = right->get_tree(context);
-  if (left_tree == error_mark_node || right_tree == error_mark_node)
-    return error_mark_node;
+  Bexpression* left_bexpr = tree_to_expr(left->get_tree(context));
+  Bexpression* right_bexpr = tree_to_expr(right->get_tree(context));
 
-  tree result_type_tree;
-  if (result_type == NULL)
-    result_type_tree = boolean_type_node;
-  else
-    result_type_tree = type_to_tree(result_type->get_backend(context->gogo()));
-
-  tree ret = fold_build2(code, result_type_tree, left_tree, right_tree);
-  if (CAN_HAVE_LOCATION_P(ret))
-    SET_EXPR_LOCATION(ret, location.gcc_location());
+  Gogo* gogo = context->gogo();
+  Bexpression* ret = gogo->backend()->binary_expression(op, left_bexpr,
+                                                        right_bexpr, location);
+  if (result_type != NULL)
+    ret = gogo->backend()->convert_expression(result_type->get_backend(gogo),
+                                              ret, location);
   return ret;
 }
 
@@ -6830,6 +6778,7 @@ Bound_method_expression::create_thunk(Go
   Block* b = gogo->finish_block(loc);
   gogo->add_block(b, loc);
   gogo->lower_block(new_no, b);
+  gogo->flatten_block(new_no, b);
   gogo->finish_function(loc);
 
   ins.first->second = new_no;
@@ -11827,6 +11776,7 @@ Interface_field_reference_expression::cr
   Block* b = gogo->finish_block(loc);
   gogo->add_block(b, loc);
   gogo->lower_block(new_no, b);
+  gogo->flatten_block(new_no, b);
   gogo->finish_function(loc);
 
   ins.first->second->push_back(std::make_pair(name, new_no));
@@ -11888,7 +11838,7 @@ Interface_field_reference_expression::do
   Bexpression* bcrash = tree_to_expr(crash->get_tree(context));
 
   Bexpression* bcond =
-      gogo->backend()->conditional_expression(bnil_check, bcrash, NULL, loc);
+      gogo->backend()->conditional_expression(NULL, bnil_check, bcrash, NULL, loc);
   Bstatement* cond_statement = gogo->backend()->expression_statement(bcond);
   Bexpression* ret =
       gogo->backend()->compound_expression(cond_statement, bclosure, loc);
@@ -12157,6 +12107,7 @@ Selector_expression::lower_method_expres
 
   // Lower the call in case there are multiple results.
   gogo->lower_block(no, b);
+  gogo->flatten_block(no, b);
 
   gogo->finish_function(location);
 
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h	(revision 206615)
+++ gcc/go/gofrontend/expressions.h	(working copy)
@@ -704,11 +704,11 @@ class Expression
 				 Type* rhs_type, tree rhs_tree,
 				 bool for_type_guard, Location);
 
-  // Return a tree implementing the comparison LHS_EXPR OP RHS_EXPR.
+  // Return a backend expression implementing the comparison LEFT OP RIGHT.
   // TYPE is the type of both sides.
-  static tree
-  comparison_tree(Translate_context*, Type* result_type, Operator op,
-		  Expression* left_expr, Expression* right_expr, Location);
+  static Bexpression*
+  comparison(Translate_context*, Type* result_type, Operator op,
+	     Expression* left, Expression* right, Location);
 
   // Return the backend expression for the numeric constant VAL.
   static Bexpression*
@@ -1289,6 +1289,9 @@ class Binary_expression : public Express
   Expression*
   do_lower(Gogo*, Named_object*, Statement_inserter*, int);
 
+  Expression*
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
   bool
   do_is_constant() const
   { return this->left_->is_constant() && this->right_->is_constant(); }
Index: gcc/go/gofrontend/backend.h
===================================================================
--- gcc/go/gofrontend/backend.h	(revision 206615)
+++ gcc/go/gofrontend/backend.h	(working copy)
@@ -10,6 +10,8 @@
 #include <gmp.h>
 #include <mpfr.h>
 
+#include "operator.h"
+
 // Pointers to these types are created by the backend, passed to the
 // frontend, and passed back to the backend.  The types must be
 // defined by the backend using these names.
@@ -289,10 +291,20 @@ class Backend
   compound_expression(Bstatement* bstat, Bexpression* bexpr, Location) = 0;
 
   // Return an expression that executes THEN_EXPR if CONDITION is true, or
-  // ELSE_EXPR otherwise.  ELSE_EXPR may be NULL.
+  // ELSE_EXPR otherwise and returns the result as type BTYPE.  ELSE_EXPR
+  // may be NULL.  BTYPE may be NULL.
+  virtual Bexpression*
+  conditional_expression(Btype* btype, Bexpression* condition,
+                         Bexpression* then_expr, Bexpression* else_expr,
+                         Location) = 0;
+
+  // Return an expression for the binary operation LEFT OP RIGHT.
+  // Supported values of OP are (from operators.h):
+  //    EQEQ, NOTEQ, LT, LE, GT, GE, PLUS, MINUS, OR, XOR, MULT, DIV, MOD,
+  //    LSHIFT, RSHIFT, AND, NOT.
   virtual Bexpression*
-  conditional_expression(Bexpression* condition, Bexpression* then_expr,
-                         Bexpression* else_expr, Location) = 0;
+  binary_expression(Operator op, Bexpression* left, Bexpression* right,
+                    Location) = 0;
 
   // Statements.
 
Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 206615)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -250,7 +250,11 @@ class Gcc_backend : public Backend
   compound_expression(Bstatement*, Bexpression*, Location);
 
   Bexpression*
-  conditional_expression(Bexpression*, Bexpression*, Bexpression*, Location);
+  conditional_expression(Btype*, Bexpression*, Bexpression*, Bexpression*,
+                         Location);
+
+  Bexpression*
+  binary_expression(Operator, Bexpression*, Bexpression*, Location);
 
   // Statements.
 
@@ -1059,22 +1063,142 @@ Gcc_backend::compound_expression(Bstatem
 // ELSE_EXPR otherwise.
 
 Bexpression*
-Gcc_backend::conditional_expression(Bexpression* condition,
+Gcc_backend::conditional_expression(Btype* btype, Bexpression* condition,
                                     Bexpression* then_expr,
                                     Bexpression* else_expr, Location location)
 {
+  tree type_tree = btype == NULL ? void_type_node : btype->get_tree();
   tree cond_tree = condition->get_tree();
   tree then_tree = then_expr->get_tree();
   tree else_tree = else_expr == NULL ? NULL_TREE : else_expr->get_tree();
-  if (cond_tree == error_mark_node
+  if (type_tree == error_mark_node
+      || cond_tree == error_mark_node
       || then_tree == error_mark_node
       || else_tree == error_mark_node)
     return this->error_expression();
-  tree ret = build3_loc(location.gcc_location(), COND_EXPR, void_type_node,
+  tree ret = build3_loc(location.gcc_location(), COND_EXPR, type_tree,
                         cond_tree, then_tree, else_tree);
   return this->make_expression(ret);
 }
 
+// Convert a gofrontend operator to an equivalent tree_code.
+
+enum tree_code
+operator_to_tree_code(Operator op, tree type)
+{
+  enum tree_code code;
+  switch (op)
+    {
+    case OPERATOR_EQEQ:
+      code = EQ_EXPR;
+      break;
+    case OPERATOR_NOTEQ:
+      code = NE_EXPR;
+      break;
+    case OPERATOR_LT:
+      code = LT_EXPR;
+      break;
+    case OPERATOR_LE:
+      code = LE_EXPR;
+      break;
+    case OPERATOR_GT:
+      code = GT_EXPR;
+      break;
+    case OPERATOR_GE:
+      code = GE_EXPR;
+      break;
+    case OPERATOR_OROR:
+      code = TRUTH_ORIF_EXPR;
+      break;
+    case OPERATOR_ANDAND:
+      code = TRUTH_ANDIF_EXPR;
+      break;
+    case OPERATOR_PLUS:
+      code = PLUS_EXPR;
+      break;
+    case OPERATOR_MINUS:
+      code = MINUS_EXPR;
+      break;
+    case OPERATOR_OR:
+      code = BIT_IOR_EXPR;
+      break;
+    case OPERATOR_XOR:
+      code = BIT_XOR_EXPR;
+      break;
+    case OPERATOR_MULT:
+      code = MULT_EXPR;
+      break;
+    case OPERATOR_DIV:
+      if (TREE_CODE(type) == REAL_TYPE || TREE_CODE(type) == COMPLEX_TYPE)
+	code = RDIV_EXPR;
+      else
+	code = TRUNC_DIV_EXPR;
+      break;
+    case OPERATOR_MOD:
+      code = TRUNC_MOD_EXPR;
+      break;
+    case OPERATOR_LSHIFT:
+      code = LSHIFT_EXPR;
+      break;
+    case OPERATOR_RSHIFT:
+      code = RSHIFT_EXPR;
+      break;
+    case OPERATOR_AND:
+      code = BIT_AND_EXPR;
+      break;
+    case OPERATOR_BITCLEAR:
+      code = BIT_AND_EXPR;
+      break;
+    default:
+      gcc_unreachable();
+    }
+
+  return code;
+}
+
+// Return an expression for the binary operation LEFT OP RIGHT.
+
+Bexpression*
+Gcc_backend::binary_expression(Operator op, Bexpression* left,
+                               Bexpression* right, Location location)
+{
+  tree left_tree = left->get_tree();
+  tree right_tree = right->get_tree();
+  if (left_tree == error_mark_node
+      || right_tree == error_mark_node)
+    return this->error_expression();
+  enum tree_code code = operator_to_tree_code(op, TREE_TYPE(left_tree));
+
+  bool use_left_type = op != OPERATOR_OROR && op != OPERATOR_ANDAND;
+  tree type_tree = use_left_type ? TREE_TYPE(left_tree) : TREE_TYPE(right_tree);
+  tree computed_type = excess_precision_type(type_tree);
+  if (computed_type != NULL_TREE)
+    {
+      left_tree = convert(computed_type, left_tree);
+      right_tree = convert(computed_type, right_tree);
+      type_tree = computed_type;
+    }
+
+  // For comparison operators, the resulting type should be boolean.
+  switch (op)
+    {
+    case OPERATOR_EQEQ:
+    case OPERATOR_NOTEQ:
+    case OPERATOR_LT:
+    case OPERATOR_LE:
+    case OPERATOR_GT:
+    case OPERATOR_GE:
+      type_tree = boolean_type_node;
+      break;
+    default:
+      break;
+    }
+
+  tree ret = fold_build2_loc(location.gcc_location(), code, type_tree,
+                             left_tree, right_tree);
+  return this->make_expression(ret);
+}
+
 // An expression as a statement.
 
 Bstatement*
