diff mbox

Go patch committed: Use backend interface for comparisons

Message ID mcr8uwqiqcp.fsf@iant-glaptop.roam.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor Nov. 14, 2013, 10:13 p.m. UTC
This patch from Chris Manghane changes the Go frontend to use the
backend interface for comparisons.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

diff -r 8a3737dd11fd go/expressions.cc
--- a/go/expressions.cc	Thu Nov 14 12:18:10 2013 -0800
+++ b/go/expressions.cc	Thu Nov 14 14:12:04 2013 -0800
@@ -5321,7 +5321,7 @@ 
 	}
     }
 
-  // Lower struct and array comparisons.
+  // Lower struct, array, and some interface comparisons.
   if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ)
     {
       if (left->type()->struct_type() != NULL)
@@ -5329,6 +5329,11 @@ 
       else if (left->type()->array_type() != NULL
 	       && !left->type()->is_slice_type())
 	return this->lower_array_comparison(gogo, inserter);
+      else if ((left->type()->interface_type() != NULL
+                && right->type()->interface_type() == NULL)
+               || (left->type()->interface_type() == NULL
+                   && right->type()->interface_type() != NULL))
+	return this->lower_interface_value_comparison(gogo, inserter);
     }
 
   return this;
@@ -5457,6 +5462,57 @@ 
   return ret;
 }
 
+// Lower an interface to value comparison.
+
+Expression*
+Binary_expression::lower_interface_value_comparison(Gogo*,
+                                                    Statement_inserter* inserter)
+{
+  Type* left_type = this->left_->type();
+  Type* right_type = this->right_->type();
+  Interface_type* ift;
+  if (left_type->interface_type() != NULL)
+    {
+      ift = left_type->interface_type();
+      if (!ift->implements_interface(right_type, NULL))
+        return this;
+    }
+  else
+    {
+      ift = right_type->interface_type();
+      if (!ift->implements_interface(left_type, NULL))
+        return this;
+    }
+  if (!Type::are_compatible_for_comparison(true, left_type, right_type, NULL))
+    return this;
+
+  Location loc = this->location();
+
+  if (left_type->interface_type() == NULL
+      && left_type->points_to() == NULL
+      && !this->left_->is_addressable())
+    {
+      Temporary_statement* temp =
+          Statement::make_temporary(left_type, NULL, loc);
+      inserter->insert(temp);
+      this->left_ =
+          Expression::make_set_and_use_temporary(temp, this->left_, loc);
+    }
+
+  if (right_type->interface_type() == NULL
+      && right_type->points_to() == NULL
+      && !this->right_->is_addressable())
+    {
+      Temporary_statement* temp =
+          Statement::make_temporary(right_type, NULL, loc);
+      inserter->insert(temp);
+      this->right_ =
+          Expression::make_set_and_use_temporary(temp, this->right_, loc);
+    }
+
+  return this;
+}
+
 // Lower a struct or array comparison to a call to memcmp.
 
 Expression*
@@ -5919,8 +5975,7 @@ 
     case OPERATOR_GT:
     case OPERATOR_GE:
       return Expression::comparison_tree(context, this->type_, this->op_,
-					 this->left_->type(), left,
-					 this->right_->type(), right,
+					 this->left_, this->right_,
 					 this->location());
 
     case OPERATOR_OROR:
@@ -6417,12 +6472,16 @@ 
 
 tree
 Expression::comparison_tree(Translate_context* context, Type* result_type,
-			    Operator op, Type* left_type, tree left_tree,
-			    Type* right_type, tree right_tree,
-			    Location location)
-{
-  Type* int_type = Type::lookup_integer_type("int");
-  tree int_type_tree = type_to_tree(int_type->get_backend(context->gogo()));
+			    Operator op, Expression* left_expr,
+			    Expression* right_expr, Location location)
+{
+  Type* left_type = left_expr->type();
+  Type* right_type = right_expr->type();
+
+  mpz_t zval;
+  mpz_init_set_ui(zval, 0UL);
+  Expression* zexpr = Expression::make_integer(&zval, NULL, location);
+  mpz_clear(zval);
 
   enum tree_code code;
   switch (op)
@@ -6449,21 +6508,17 @@ 
       go_unreachable();
     }
 
+  // FIXME: Computing the tree here means it will be computed multiple times,
+  // which is wasteful.  This is a temporary modification until all tree code
+  // here can be replaced with frontend expressions.
+  tree left_tree = left_expr->get_tree(context);
+  tree right_tree = right_expr->get_tree(context);
   if (left_type->is_string_type() && right_type->is_string_type())
     {
-      Type* st = Type::make_string_type();
-      tree string_type = type_to_tree(st->get_backend(context->gogo()));
-      static tree string_compare_decl;
-      left_tree = Gogo::call_builtin(&string_compare_decl,
-				     location,
-				     "__go_strcmp",
-				     2,
-				     int_type_tree,
-				     string_type,
-				     left_tree,
-				     string_type,
-				     right_tree);
-      right_tree = build_int_cst_type(int_type_tree, 0);
+      Expression* strcmp_call = Runtime::make_call(Runtime::STRCMP, location, 2,
+                                                   left_expr, right_expr);
+      left_tree = strcmp_call->get_tree(context);
+      right_tree = zexpr->get_tree(context);
     }
   else if ((left_type->interface_type() != NULL
 	    && right_type->interface_type() == NULL
@@ -6476,154 +6531,61 @@ 
       if (left_type->interface_type() == NULL)
 	{
 	  std::swap(left_type, right_type);
-	  std::swap(left_tree, right_tree);
+	  std::swap(left_expr, right_expr);
 	}
 
       // The right operand is not an interface.  We need to take its
       // address if it is not a pointer.
-      tree make_tmp;
-      tree arg;
+      Expression* pointer_arg = NULL;
       if (right_type->points_to() != NULL)
-	{
-	  make_tmp = NULL_TREE;
-	  arg = right_tree;
-	}
-      else if (TREE_ADDRESSABLE(TREE_TYPE(right_tree))
-	       || (TREE_CODE(right_tree) != CONST_DECL
-		   && DECL_P(right_tree)))
-	{
-	  make_tmp = NULL_TREE;
-	  arg = build_fold_addr_expr_loc(location.gcc_location(), right_tree);
-	  if (DECL_P(right_tree))
-	    TREE_ADDRESSABLE(right_tree) = 1;
-	}
+        pointer_arg = right_expr;
       else
 	{
-	  tree tmp = create_tmp_var(TREE_TYPE(right_tree),
-				    get_name(right_tree));
-	  DECL_IGNORED_P(tmp) = 0;
-	  DECL_INITIAL(tmp) = right_tree;
-	  TREE_ADDRESSABLE(tmp) = 1;
-	  make_tmp = build1(DECL_EXPR, void_type_node, tmp);
-	  SET_EXPR_LOCATION(make_tmp, location.gcc_location());
-	  arg = build_fold_addr_expr_loc(location.gcc_location(), tmp);
-	}
-      arg = fold_convert_loc(location.gcc_location(), ptr_type_node, arg);
-
-      Bexpression* descriptor_bexpr =
-          right_type->type_descriptor_pointer(context->gogo(), location);
-      tree descriptor = expr_to_tree(descriptor_bexpr);
-
-      if (left_type->interface_type()->is_empty())
-	{
-	  static tree empty_interface_value_compare_decl;
-	  left_tree = Gogo::call_builtin(&empty_interface_value_compare_decl,
-					 location,
-					 "__go_empty_interface_value_compare",
-					 3,
-					 int_type_tree,
-					 TREE_TYPE(left_tree),
-					 left_tree,
-					 TREE_TYPE(descriptor),
-					 descriptor,
-					 ptr_type_node,
-					 arg);
-	  if (left_tree == error_mark_node)
-	    return error_mark_node;
-	  // This can panic if the type is not comparable.
-	  TREE_NOTHROW(empty_interface_value_compare_decl) = 0;
-	}
-      else
-	{
-	  static tree interface_value_compare_decl;
-	  left_tree = Gogo::call_builtin(&interface_value_compare_decl,
-					 location,
-					 "__go_interface_value_compare",
-					 3,
-					 int_type_tree,
-					 TREE_TYPE(left_tree),
-					 left_tree,
-					 TREE_TYPE(descriptor),
-					 descriptor,
-					 ptr_type_node,
-					 arg);
-	  if (left_tree == error_mark_node)
-	    return error_mark_node;
-	  // This can panic if the type is not comparable.
-	  TREE_NOTHROW(interface_value_compare_decl) = 0;
-	}
-      right_tree = build_int_cst_type(int_type_tree, 0);
-
-      if (make_tmp != NULL_TREE)
-	left_tree = build2(COMPOUND_EXPR, TREE_TYPE(left_tree), make_tmp,
-			   left_tree);
+          go_assert(right_expr->is_addressable());
+          pointer_arg = Expression::make_unary(OPERATOR_AND, right_expr,
+                                               location);
+	}
+
+      Expression* descriptor_expr = Expression::make_type_descriptor(right_type,
+                                                                     location);
+      Call_expression* iface_valcmp =
+          Runtime::make_call((left_type->interface_type()->is_empty()
+                              ? Runtime::EMPTY_INTERFACE_VALUE_COMPARE
+                              : Runtime::INTERFACE_VALUE_COMPARE),
+                             location, 3, left_expr, descriptor_expr,
+                             pointer_arg);
+      left_tree = iface_valcmp->get_tree(context);
+      right_tree = zexpr->get_tree(context);
     }
   else if (left_type->interface_type() != NULL
 	   && right_type->interface_type() != NULL)
     {
+      Runtime::Function compare_function;
       if (left_type->interface_type()->is_empty()
 	  && right_type->interface_type()->is_empty())
-	{
-	  static tree empty_interface_compare_decl;
-	  left_tree = Gogo::call_builtin(&empty_interface_compare_decl,
-					 location,
-					 "__go_empty_interface_compare",
-					 2,
-					 int_type_tree,
-					 TREE_TYPE(left_tree),
-					 left_tree,
-					 TREE_TYPE(right_tree),
-					 right_tree);
-	  if (left_tree == error_mark_node)
-	    return error_mark_node;
-	  // This can panic if the type is uncomparable.
-	  TREE_NOTHROW(empty_interface_compare_decl) = 0;
-	}
+	compare_function = Runtime::EMPTY_INTERFACE_COMPARE;
       else if (!left_type->interface_type()->is_empty()
 	       && !right_type->interface_type()->is_empty())
-	{
-	  static tree interface_compare_decl;
-	  left_tree = Gogo::call_builtin(&interface_compare_decl,
-					 location,
-					 "__go_interface_compare",
-					 2,
-					 int_type_tree,
-					 TREE_TYPE(left_tree),
-					 left_tree,
-					 TREE_TYPE(right_tree),
-					 right_tree);
-	  if (left_tree == error_mark_node)
-	    return error_mark_node;
-	  // This can panic if the type is uncomparable.
-	  TREE_NOTHROW(interface_compare_decl) = 0;
-	}
+	compare_function = Runtime::INTERFACE_COMPARE;
       else
 	{
 	  if (left_type->interface_type()->is_empty())
 	    {
 	      go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ);
 	      std::swap(left_type, right_type);
-	      std::swap(left_tree, right_tree);
+	      std::swap(left_expr, right_expr);
 	    }
 	  go_assert(!left_type->interface_type()->is_empty());
 	  go_assert(right_type->interface_type()->is_empty());
-	  static tree interface_empty_compare_decl;
-	  left_tree = Gogo::call_builtin(&interface_empty_compare_decl,
-					 location,
-					 "__go_interface_empty_compare",
-					 2,
-					 int_type_tree,
-					 TREE_TYPE(left_tree),
-					 left_tree,
-					 TREE_TYPE(right_tree),
-					 right_tree);
-	  if (left_tree == error_mark_node)
-	    return error_mark_node;
-	  // This can panic if the type is uncomparable.
-	  TREE_NOTHROW(interface_empty_compare_decl) = 0;
-	}
-
-      right_tree = build_int_cst_type(int_type_tree, 0);
+	  compare_function = Runtime::INTERFACE_EMPTY_COMPARE;
+	}
+
+      Call_expression* ifacecmp_call =
+          Runtime::make_call(compare_function, location, 2,
+                             left_expr, right_expr);
+
+      left_tree = ifacecmp_call->get_tree(context);
+      right_tree = zexpr->get_tree(context);
     }
 
   if (left_type->is_nil_type()
@@ -11908,14 +11870,11 @@ 
   // Note that we are evaluating this->expr_ twice, but that is OK
   // because in the lowering pass we forced it into a temporary
   // variable.
-  tree expr_tree = this->expr_->get_tree(context);
   tree nil_check_tree = Expression::comparison_tree(context,
 						    Type::lookup_bool_type(),
 						    OPERATOR_EQEQ,
-						    this->expr_->type(),
-						    expr_tree,
-						    Type::make_nil_type(),
-						    null_pointer_node,
+						    this->expr_,
+						    Expression::make_nil(loc),
 						    loc);
   tree crash = context->gogo()->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
 					      loc);
diff -r 8a3737dd11fd go/expressions.h
--- a/go/expressions.h	Thu Nov 14 12:18:10 2013 -0800
+++ b/go/expressions.h	Thu Nov 14 14:12:04 2013 -0800
@@ -655,12 +655,11 @@ 
 				 Type* rhs_type, tree rhs_tree,
 				 bool for_type_guard, Location);
 
-  // Return a tree implementing the comparison LHS_TREE OP RHS_TREE.
+  // Return a tree implementing the comparison LHS_EXPR OP RHS_EXPR.
   // TYPE is the type of both sides.
   static tree
   comparison_tree(Translate_context*, Type* result_type, Operator op,
-		  Type* left_type, tree left_tree, Type* right_type,
-		  tree right_tree, Location);
+		  Expression* left_expr, Expression* right_expr, Location);
 
   // Return the backend expression for the numeric constant VAL.
   static Bexpression*
@@ -1306,6 +1305,9 @@ 
   lower_array_comparison(Gogo*, Statement_inserter*);
 
   Expression*
+  lower_interface_value_comparison(Gogo*, Statement_inserter*);
+
+  Expression*
   lower_compare_to_memcmp(Gogo*, Statement_inserter*);
 
   Expression*