compiler: Use backend interface for comparisons.
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 14 Nov 2013 22:13:41 +0000 (22:13 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 14 Nov 2013 22:13:41 +0000 (22:13 +0000)
From-SVN: r204827

gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h

index f866bdc..4d2fbfd 100644 (file)
@@ -5321,7 +5321,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*,
        }
     }
 
-  // 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 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*,
       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 @@ Binary_expression::lower_array_comparison(Gogo* gogo,
   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 @@ Binary_expression::do_get_tree(Translate_context* context)
     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 @@ Expression::make_binary(Operator op, Expression* left, Expression* right,
 
 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)
+                           Operator op, Expression* left_expr,
+                           Expression* right_expr, Location location)
 {
-  Type* int_type = Type::lookup_integer_type("int");
-  tree int_type_tree = type_to_tree(int_type->get_backend(context->gogo()));
+  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 @@ Expression::comparison_tree(Translate_context* context, Type* result_type,
       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 @@ Expression::comparison_tree(Translate_context* context, Type* result_type,
       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;
-       }
-      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;
-       }
+        pointer_arg = right_expr;
       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;
+          go_assert(right_expr->is_addressable());
+          pointer_arg = Expression::make_unary(OPERATOR_AND, right_expr,
+                                               location);
        }
-      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);
+      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;
+         compare_function = Runtime::INTERFACE_EMPTY_COMPARE;
        }
 
-      right_tree = build_int_cst_type(int_type_tree, 0);
+      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 @@ Interface_field_reference_expression::do_get_tree(Translate_context* context)
   // 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);
index 47ce4c0..e447418 100644 (file)
@@ -655,12 +655,11 @@ class Expression
                                 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 @@ class Binary_expression : public Expression
   lower_array_comparison(Gogo*, Statement_inserter*);
 
   Expression*
+  lower_interface_value_comparison(Gogo*, Statement_inserter*);
+
+  Expression*
   lower_compare_to_memcmp(Gogo*, Statement_inserter*);
 
   Expression*