This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Go patch committed: Use backend interface for interface expressions


This Go frontend patch from Chris Manghane uses the backend interface
for interface info and field expressions.  Bootstrapped and ran Go
testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian


2014-01-14  Chris Manghane  <cmang@google.com>

	* go-gcc.cc (Gcc_backend::compound_expression): New function.
	(Gcc_backend::conditional_expression): New function.


Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 206509)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -6473,11 +6473,11 @@ Expression::make_binary(Operator op, Exp
 
 tree
 Expression::comparison_tree(Translate_context* context, Type* result_type,
-			    Operator op, Expression* left_expr,
-			    Expression* right_expr, Location location)
+			    Operator op, Expression* left, Expression* right,
+			    Location location)
 {
-  Type* left_type = left_expr->type();
-  Type* right_type = right_expr->type();
+  Type* left_type = left->type();
+  Type* right_type = right->type();
 
   mpz_t zval;
   mpz_init_set_ui(zval, 0UL);
@@ -6509,17 +6509,11 @@ Expression::comparison_tree(Translate_co
       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())
     {
-      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);
+      left = Runtime::make_call(Runtime::STRCMP, location, 2,
+                                left, right);
+      right = zexpr;
     }
   else if ((left_type->interface_type() != NULL
 	    && right_type->interface_type() == NULL
@@ -6532,31 +6526,30 @@ Expression::comparison_tree(Translate_co
       if (left_type->interface_type() == NULL)
 	{
 	  std::swap(left_type, right_type);
-	  std::swap(left_expr, right_expr);
+	  std::swap(left, right);
 	}
 
       // The right operand is not an interface.  We need to take its
       // address if it is not a pointer.
       Expression* pointer_arg = NULL;
       if (right_type->points_to() != NULL)
-        pointer_arg = right_expr;
+        pointer_arg = right;
       else
 	{
-          go_assert(right_expr->is_addressable());
-          pointer_arg = Expression::make_unary(OPERATOR_AND, right_expr,
+          go_assert(right->is_addressable());
+          pointer_arg = Expression::make_unary(OPERATOR_AND, right,
                                                location);
 	}
 
-      Expression* descriptor_expr = Expression::make_type_descriptor(right_type,
-                                                                     location);
-      Call_expression* iface_valcmp =
+      Expression* descriptor =
+          Expression::make_type_descriptor(right_type, location);
+      left =
           Runtime::make_call((left_type->interface_type()->is_empty()
                               ? Runtime::EMPTY_INTERFACE_VALUE_COMPARE
                               : Runtime::INTERFACE_VALUE_COMPARE),
-                             location, 3, left_expr, descriptor_expr,
+                             location, 3, left, descriptor,
                              pointer_arg);
-      left_tree = iface_valcmp->get_tree(context);
-      right_tree = zexpr->get_tree(context);
+      right = zexpr;
     }
   else if (left_type->interface_type() != NULL
 	   && right_type->interface_type() != NULL)
@@ -6574,56 +6567,42 @@ Expression::comparison_tree(Translate_co
 	    {
 	      go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ);
 	      std::swap(left_type, right_type);
-	      std::swap(left_expr, right_expr);
+	      std::swap(left, right);
 	    }
 	  go_assert(!left_type->interface_type()->is_empty());
 	  go_assert(right_type->interface_type()->is_empty());
 	  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);
+      left = Runtime::make_call(compare_function, location, 2, left, right);
+      right = zexpr;
     }
 
   if (left_type->is_nil_type()
       && (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ))
     {
       std::swap(left_type, right_type);
-      std::swap(left_tree, right_tree);
-      std::swap(left_expr, right_expr);
+      std::swap(left, right);
     }
 
   if (right_type->is_nil_type())
     {
+      right = Expression::make_nil(location);
       if (left_type->array_type() != NULL
 	  && left_type->array_type()->length() == NULL)
 	{
 	  Array_type* at = left_type->array_type();
-          left_expr = at->get_value_pointer(context->gogo(), left_expr);
-          left_tree = left_expr->get_tree(context);
-	  right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
+          left = at->get_value_pointer(context->gogo(), left);
 	}
       else if (left_type->interface_type() != NULL)
 	{
 	  // An interface is nil if the first field is nil.
-	  tree left_type_tree = TREE_TYPE(left_tree);
-	  go_assert(TREE_CODE(left_type_tree) == RECORD_TYPE);
-	  tree field = TYPE_FIELDS(left_type_tree);
-	  left_tree = build3(COMPONENT_REF, TREE_TYPE(field), left_tree,
-			     field, NULL_TREE);
-	  right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
-	}
-      else
-	{
-	  go_assert(POINTER_TYPE_P(TREE_TYPE(left_tree)));
-	  right_tree = fold_convert(TREE_TYPE(left_tree), null_pointer_node);
+          left = Expression::make_field_reference(left, 0, location);
 	}
     }
 
+  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;
 
@@ -9745,21 +9724,13 @@ Call_expression::do_must_eval_in_order()
 // Get the function and the first argument to use when calling an
 // interface method.
 
-tree
+Expression*
 Call_expression::interface_method_function(
-    Translate_context* context,
     Interface_field_reference_expression* interface_method,
-    tree* first_arg_ptr)
+    Expression** first_arg_ptr)
 {
-  tree expr = interface_method->expr()->get_tree(context);
-  if (expr == error_mark_node)
-    return error_mark_node;
-  expr = save_expr(expr);
-  tree first_arg = interface_method->get_underlying_object_tree(context, expr);
-  if (first_arg == error_mark_node)
-    return error_mark_node;
-  *first_arg_ptr = first_arg;
-  return interface_method->get_function_tree(context, expr);
+  *first_arg_ptr = interface_method->get_underlying_object();
+  return interface_method->get_function();
 }
 
 // Build the call expression.
@@ -9889,8 +9860,12 @@ Call_expression::do_get_tree(Translate_c
     }      
   else
     {
-      fn = this->interface_method_function(context, interface_method,
-					   &args[0]);
+      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;
@@ -11623,58 +11598,39 @@ Expression::make_field_reference(Express
 
 // Class Interface_field_reference_expression.
 
-// Return a tree for the pointer to the function to call.
+// Return an expression for the pointer to the function to call.
 
-tree
-Interface_field_reference_expression::get_function_tree(Translate_context*,
-							tree expr)
+Expression*
+Interface_field_reference_expression::get_function()
 {
-  if (this->expr_->type()->points_to() != NULL)
-    expr = build_fold_indirect_ref(expr);
-
-  tree expr_type = TREE_TYPE(expr);
-  go_assert(TREE_CODE(expr_type) == RECORD_TYPE);
-
-  tree field = TYPE_FIELDS(expr_type);
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") == 0);
-
-  tree table = build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE);
-  go_assert(POINTER_TYPE_P(TREE_TYPE(table)));
+  Expression* ref = this->expr_;
+  Location loc = this->location();
+  if (ref->type()->points_to() != NULL)
+    ref = Expression::make_unary(OPERATOR_MULT, ref, loc);
 
-  table = build_fold_indirect_ref(table);
-  go_assert(TREE_CODE(TREE_TYPE(table)) == RECORD_TYPE);
+  Expression* mtable =
+      Expression::make_interface_info(ref, INTERFACE_INFO_METHODS, loc);
+  Struct_type* mtable_type = mtable->type()->points_to()->struct_type();
 
   std::string name = Gogo::unpack_hidden_name(this->name_);
-  for (field = DECL_CHAIN(TYPE_FIELDS(TREE_TYPE(table)));
-       field != NULL_TREE;
-       field = DECL_CHAIN(field))
-    {
-      if (name == IDENTIFIER_POINTER(DECL_NAME(field)))
-	break;
-    }
-  go_assert(field != NULL_TREE);
-
-  return build3(COMPONENT_REF, TREE_TYPE(field), table, field, NULL_TREE);
+  unsigned int index;
+  const Struct_field* field = mtable_type->find_local_field(name, &index);
+  go_assert(field != NULL);
+  mtable = Expression::make_unary(OPERATOR_MULT, mtable, loc);
+  return Expression::make_field_reference(mtable, index, loc);
 }
 
-// Return a tree for the first argument to pass to the interface
+// Return an expression for the first argument to pass to the interface
 // function.
 
-tree
-Interface_field_reference_expression::get_underlying_object_tree(
-    Translate_context*,
-    tree expr)
+Expression*
+Interface_field_reference_expression::get_underlying_object()
 {
-  if (this->expr_->type()->points_to() != NULL)
-    expr = build_fold_indirect_ref(expr);
-
-  tree expr_type = TREE_TYPE(expr);
-  go_assert(TREE_CODE(expr_type) == RECORD_TYPE);
-
-  tree field = DECL_CHAIN(TYPE_FIELDS(expr_type));
-  go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0);
-
-  return build3(COMPONENT_REF, TREE_TYPE(field), expr, field, NULL_TREE);
+  Expression* expr = this->expr_;
+  if (expr->type()->points_to() != NULL)
+    expr = Expression::make_unary(OPERATOR_MULT, expr, this->location());
+  return Expression::make_interface_info(expr, INTERFACE_INFO_OBJECT,
+                                         this->location());
 }
 
 // Traversal.
@@ -11694,9 +11650,7 @@ Interface_field_reference_expression::do
 					       Statement_inserter* inserter,
 					       int)
 {
-  if (this->expr_->var_expression() == NULL
-      && this->expr_->temporary_reference_expression() == NULL
-      && this->expr_->set_and_use_temporary_expression() == NULL)
+  if (!this->expr_->is_variable())
     {
       Temporary_statement* temp =
 	Statement::make_temporary(this->expr_->type(), NULL, this->location());
@@ -11923,30 +11877,22 @@ Interface_field_reference_expression::do
   Expression* expr = Expression::make_struct_composite_literal(st, vals, loc);
   expr = Expression::make_heap_composite(expr, loc);
 
-  tree closure_tree = expr->get_tree(context);
+  Bexpression* bclosure = tree_to_expr(expr->get_tree(context));
+  Expression* nil_check =
+      Expression::make_binary(OPERATOR_EQEQ, this->expr_,
+                              Expression::make_nil(loc), loc);
+  Bexpression* bnil_check = tree_to_expr(nil_check->get_tree(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 nil_check_tree = Expression::comparison_tree(context,
-						    Type::lookup_bool_type(),
-						    OPERATOR_EQEQ,
-						    this->expr_,
-						    Expression::make_nil(loc),
-						    loc);
-  Expression* crash_expr =
-      context->gogo()->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, loc);
-  tree crash = crash_expr->get_tree(context);
-  if (closure_tree == error_mark_node
-      || nil_check_tree == error_mark_node
-      || crash == error_mark_node)
-    return error_mark_node;
-  return fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR,
-			 TREE_TYPE(closure_tree),
-			 build3_loc(loc.gcc_location(), COND_EXPR,
-				    void_type_node, nil_check_tree, crash,
-				    NULL_TREE),
-			 closure_tree);
+  Gogo* gogo = context->gogo();
+  Expression* crash = gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, loc);
+  Bexpression* bcrash = tree_to_expr(crash->get_tree(context));
+
+  Bexpression* bcond =
+      gogo->backend()->conditional_expression(bnil_check, bcrash, NULL, loc);
+  Bstatement* cond_statement = gogo->backend()->expression_statement(bcond);
+  Bexpression* ret =
+      gogo->backend()->compound_expression(cond_statement, bclosure, loc);
+  return expr_to_tree(ret);
 }
 
 // Dump ast representation for an interface field reference.
@@ -14754,6 +14700,155 @@ Expression::make_slice_info(Expression*
   return new Slice_info_expression(slice, slice_info, 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.
+
+class Interface_info_expression : public Expression
+{
+ public:
+  Interface_info_expression(Expression* iface, Interface_info iface_info,
+                        Location location)
+    : Expression(EXPRESSION_INTERFACE_INFO, location),
+      iface_(iface), iface_info_(iface_info)
+  { }
+
+ protected:
+  Type*
+  do_type();
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  {
+    return new Interface_info_expression(this->iface_->copy(),
+                                         this->iface_info_, this->location());
+  }
+
+  tree
+  do_get_tree(Translate_context* context);
+
+  void
+  do_dump_expression(Ast_dump_context*) const;
+
+  void
+  do_issue_nil_check()
+  { this->iface_->issue_nil_check(); }
+
+ private:
+  // The interface for which we are getting information.
+  Expression* iface_;
+  // What information we want.
+  Interface_info iface_info_;
+};
+
+// Return the type of the interface info.
+
+Type*
+Interface_info_expression::do_type()
+{
+  switch (this->iface_info_)
+    {
+    case INTERFACE_INFO_METHODS:
+      {
+        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)));
+
+        Interface_type* itype = this->iface_->type()->interface_type();
+        for (Typed_identifier_list::const_iterator p = itype->methods()->begin();
+             p != itype->methods()->end();
+             ++p)
+          {
+            Function_type* ft = p->type()->function_type();
+            go_assert(ft->receiver() == NULL);
+
+            const Typed_identifier_list* params = ft->parameters();
+            Typed_identifier_list* mparams = new Typed_identifier_list();
+            if (params != NULL)
+              mparams->reserve(params->size() + 1);
+            Type* vt = Type::make_pointer_type(Type::make_void_type());
+            mparams->push_back(Typed_identifier("", vt, ft->location()));
+            if (params != NULL)
+              {
+                for (Typed_identifier_list::const_iterator pp = params->begin();
+                     pp != params->end();
+                     ++pp)
+                  mparams->push_back(*pp);
+              }
+
+            Typed_identifier_list* mresults = (ft->results() == NULL
+                                               ? NULL
+                                               : ft->results()->copy());
+            Backend_function_type* mft =
+                Type::make_backend_function_type(NULL, mparams, mresults,
+                                                 ft->location());
+
+            std::string fname = Gogo::unpack_hidden_name(p->name());
+            sfl->push_back(Struct_field(Typed_identifier(fname, mft, loc)));
+          }
+
+        return Type::make_pointer_type(Type::make_struct_type(sfl, loc));
+      }
+    case INTERFACE_INFO_OBJECT:
+      return Type::make_pointer_type(Type::make_void_type());
+    default:
+      go_unreachable();
+    }
+}
+
+// Return interface information in GENERIC.
+
+tree
+Interface_info_expression::do_get_tree(Translate_context* context)
+{
+  Gogo* gogo = context->gogo();
+
+  Bexpression* biface = tree_to_expr(this->iface_->get_tree(context));
+  Bexpression* ret;
+  switch (this->iface_info_)
+    {
+    case INTERFACE_INFO_METHODS:
+    case INTERFACE_INFO_OBJECT:
+      ret = gogo->backend()->struct_field_expression(biface, this->iface_info_,
+                                                     this->location());
+      break;
+    default:
+      go_unreachable();
+    }
+  return expr_to_tree(ret);
+}
+
+// Dump ast representation for an interface info expression.
+
+void
+Interface_info_expression::do_dump_expression(
+    Ast_dump_context* ast_dump_context) const
+{
+  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_OBJECT ? "object"
+    : "unknown");
+  ast_dump_context->ostream() << ")";
+}
+
+// Make an interface info expression.
+
+Expression*
+Expression::make_interface_info(Expression* iface, Interface_info iface_info,
+                                Location location)
+{
+  return new Interface_info_expression(iface, iface_info, 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.
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h	(revision 206509)
+++ gcc/go/gofrontend/expressions.h	(working copy)
@@ -103,6 +103,7 @@ class Expression
     EXPRESSION_TYPE_DESCRIPTOR,
     EXPRESSION_TYPE_INFO,
     EXPRESSION_SLICE_INFO,
+    EXPRESSION_INTERFACE_INFO,
     EXPRESSION_STRUCT_FIELD_OFFSET,
     EXPRESSION_MAP_DESCRIPTOR,
     EXPRESSION_LABEL_ADDR
@@ -356,6 +357,21 @@ class Expression
   static Expression*
   make_slice_info(Expression* slice, Slice_info, Location);
 
+
+  // Make an expression that evaluates to some characteristic of a
+  // interface.  For simplicity, the enum values must match the field indexes
+  // of a non-empty interface in the underlying struct.
+  enum Interface_info
+    {
+      // The methods of an interface.
+      INTERFACE_INFO_METHODS,
+      // The first argument to pass to an interface method.
+      INTERFACE_INFO_OBJECT
+    };
+
+  static Expression*
+  make_interface_info(Expression* iface, Interface_info, 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.
@@ -1508,10 +1524,9 @@ class Call_expression : public Expressio
   bool
   check_argument_type(int, const Type*, const Type*, Location, bool);
 
-  tree
-  interface_method_function(Translate_context*,
-			    Interface_field_reference_expression*,
-			    tree*);
+  Expression*
+  interface_method_function(Interface_field_reference_expression*,
+			    Expression**);
 
   tree
   set_results(Translate_context*, tree);
@@ -2115,16 +2130,14 @@ class Interface_field_reference_expressi
   static Named_object*
   create_thunk(Gogo*, Interface_type* type, const std::string& name);
 
-  // Return a tree for the pointer to the function to call, given a
-  // tree for the expression.
-  tree
-  get_function_tree(Translate_context*, tree);
+  // Return an expression for the pointer to the function to call.
+  Expression*
+  get_function();
 
-  // Return a tree for the first argument to pass to the interface
-  // function, given a tree for the expression.  This is the real
-  // object associated with the interface object.
-  tree
-  get_underlying_object_tree(Translate_context*, tree);
+  // Return an expression for the first argument to pass to the interface
+  // function.  This is the real object associated with the interface object.
+  Expression*
+  get_underlying_object();
 
  protected:
   int
Index: gcc/go/gofrontend/backend.h
===================================================================
--- gcc/go/gofrontend/backend.h	(revision 206474)
+++ gcc/go/gofrontend/backend.h	(working copy)
@@ -284,6 +284,16 @@ class Backend
   virtual Bexpression*
   struct_field_expression(Bexpression* bstruct, size_t index, Location) = 0;
 
+  // Create an expression that executes BSTAT before BEXPR.
+  virtual Bexpression*
+  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.
+  virtual Bexpression*
+  conditional_expression(Bexpression* condition, Bexpression* then_expr,
+                         Bexpression* else_expr, Location) = 0;
+
   // Statements.
 
   // Create an error statement.  This is used for cases which should
Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 206474)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -246,6 +246,12 @@ class Gcc_backend : public Backend
   Bexpression*
   struct_field_expression(Bexpression*, size_t, Location);
 
+  Bexpression*
+  compound_expression(Bstatement*, Bexpression*, Location);
+
+  Bexpression*
+  conditional_expression(Bexpression*, Bexpression*, Bexpression*, Location);
+
   // Statements.
 
   Bstatement*
@@ -1034,6 +1040,41 @@ Gcc_backend::struct_field_expression(Bex
   return tree_to_expr(ret);
 }
 
+// Return an expression that executes BSTAT before BEXPR.
+
+Bexpression*
+Gcc_backend::compound_expression(Bstatement* bstat, Bexpression* bexpr,
+                                 Location location)
+{
+  tree stat = bstat->get_tree();
+  tree expr = bexpr->get_tree();
+  if (stat == error_mark_node || expr == error_mark_node)
+    return this->error_expression();
+  tree ret = fold_build2_loc(location.gcc_location(), COMPOUND_EXPR,
+                             TREE_TYPE(expr), stat, expr);
+  return this->make_expression(ret);
+}
+
+// Return an expression that executes THEN_EXPR if CONDITION is true, or
+// ELSE_EXPR otherwise.
+
+Bexpression*
+Gcc_backend::conditional_expression(Bexpression* condition,
+                                    Bexpression* then_expr,
+                                    Bexpression* else_expr, Location location)
+{
+  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
+      || 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,
+                        cond_tree, then_tree, else_tree);
+  return this->make_expression(ret);
+}
+
 // An expression as a statement.
 
 Bstatement*

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]