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]

[gccgo] Lower tuple type assertion assignment statement


I committed this patch to the gccgo branch to lower a tuple type
assertion statement (r, ok = v.(type)).

Ian

Index: libgo/runtime/iface.cgo
===================================================================
--- libgo/runtime/iface.cgo	(revision 0)
+++ libgo/runtime/iface.cgo	(revision 0)
@@ -0,0 +1,36 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+#include "go-type.h"
+#include "interface.h"
+#define nil NULL
+
+typedef _Bool bool;
+typedef struct __go_type_descriptor descriptor;
+typedef struct __go_interface interface;
+
+func ifaceI2I2(inter *descriptor, i *interface) (ret *interface, ok bool) {
+	ret = __go_convert_interface(inter, i, &ok);
+}
+
+func ifaceI2T2P(inter *descriptor, i *interface) (ret *void, ok bool) {
+	if (i != nil && __go_type_descriptors_equal(inter, i->__type_descriptor)) {
+		ret = i->__object;
+		ok = 1;
+	} else {
+		ret = nil;
+		ok = 0;
+	}
+}
+
+func ifaceI2T2(inter *descriptor, i *interface, ret *void) (ok bool) {
+	if (i != nil && __go_type_descriptors_equal(inter, i->__type_descriptor)) {
+		__builtin_memcpy(ret, i->__object, inter->__size);
+		ok = 1;
+	} else {
+		__builtin_memset(ret, 0, inter->__size);
+		ok = 0;
+	}
+}
Index: libgo/Makefile.am
===================================================================
--- libgo/Makefile.am	(revision 155971)
+++ libgo/Makefile.am	(working copy)
@@ -311,6 +311,7 @@ runtime_files = \
 	runtime/proc.c \
 	malloc_go.c \
 	chan.c \
+	iface.c \
 	map.c \
 	sigqueue.c \
 	string.c
Index: gcc/go/types.h
===================================================================
--- gcc/go/types.h	(revision 155628)
+++ gcc/go/types.h	(working copy)
@@ -201,6 +201,9 @@ class Type
   static Interface_type*
   make_interface_type(Typed_identifier_list* methods, source_location);
 
+  static Type*
+  make_type_descriptor_ptr_type();
+
   static Named_type*
   make_named_type(Named_object*, Type*, source_location);
 
Index: gcc/go/expressions.h
===================================================================
--- gcc/go/expressions.h	(revision 155952)
+++ gcc/go/expressions.h	(working copy)
@@ -90,7 +90,8 @@ class Expression
     EXPRESSION_RECEIVE,
     EXPRESSION_SEND,
     EXPRESSION_REFCOUNT_ADJUST,
-    EXPRESSION_REFCOUNT_DECREMENT_LVALUE
+    EXPRESSION_REFCOUNT_DECREMENT_LVALUE,
+    EXPRESSION_TYPE_DESCRIPTOR
   };
 
   Expression(Expression_classification, source_location);
@@ -275,6 +276,11 @@ class Expression
   static Expression*
   make_refcount_decrement_lvalue(Refcounts*, Expression*);
 
+  // Make an expression which evaluates to the type descriptor of a
+  // type.
+  static Expression*
+  make_type_descriptor(Type* type, source_location);
+
   // Return the expression classification.
   Expression_classification
   classification() const
Index: gcc/go/statements.cc
===================================================================
--- gcc/go/statements.cc	(revision 155971)
+++ gcc/go/statements.cc	(working copy)
@@ -1350,7 +1350,7 @@ Statement::make_tuple_receive_assignment
 }
 
 // An assignment to a pair of values from a type guard.  This is a
-// conditional type guard.
+// conditional type guard.  v, ok = i.(type).
 
 class Tuple_type_guard_assignment_statement : public Statement
 {
@@ -1367,18 +1367,26 @@ class Tuple_type_guard_assignment_statem
   do_traverse(Traverse*);
 
   bool
-  do_traverse_assignments(Traverse_assignments*);
+  do_traverse_assignments(Traverse_assignments*)
+  { gcc_unreachable(); }
+
+  Statement*
+  do_lower(Gogo*, Block*);
+
+  tree
+  do_get_tree(Translate_context*)
+  { gcc_unreachable(); }
 
+ private:
   void
-  do_determine_types();
+  lower_to_interface(Block*);
 
   void
-  do_check_types(Gogo*);
+  lower_to_pointer_type(Block*);
 
-  tree
-  do_get_tree(Translate_context*);
+  void
+  lower_to_type(Block*);
 
- private:
   // The variable which recieves the converted value.
   Expression* val_;
   // The variable which receives the indication of success.
@@ -1401,225 +1409,161 @@ Tuple_type_guard_assignment_statement::d
   return this->traverse_expression(traverse, &this->expr_);
 }
 
-bool
-Tuple_type_guard_assignment_statement::do_traverse_assignments(
-    Traverse_assignments* tassign)
+// Lower to a function call.
+
+Statement*
+Tuple_type_guard_assignment_statement::do_lower(Gogo*, Block* enclosing)
 {
-  tassign->assignment(&this->val_, NULL);
-  tassign->assignment(&this->ok_, NULL);
-  tassign->value(&this->expr_, false, this->val_->is_local_variable());
-  return true;
-}
+  source_location loc = this->location();
 
-// Determine types of a type guard tuple assignment.
+  if (this->expr_->type()->interface_type() == NULL)
+    {
+      this->report_error(_("type assertion only valid for interface types"));
+      return Statement::make_error_statement(loc);
+    }
 
-void
-Tuple_type_guard_assignment_statement::do_determine_types()
-{
-  this->val_->determine_type_no_context();
-  Type_context subcontext(Type::lookup_bool_type(), false);
-  this->ok_->determine_type(&subcontext);
-  this->expr_->determine_type_no_context();
+  Block* b = new Block(enclosing, loc);
+
+  // Make sure that any subexpressions on the left hand side are
+  // evaluated in the right order.
+  Move_ordered_evals moe(b);
+  this->val_->traverse_subexpressions(&moe);
+  this->ok_->traverse_subexpressions(&moe);
+
+  if (this->type_->interface_type() != NULL)
+    this->lower_to_interface(b);
+  else if (this->type_->points_to() != NULL)
+    this->lower_to_pointer_type(b);
+  else
+    this->lower_to_type(b);
+
+  return Statement::make_block_statement(b, loc);
 }
 
-// Check types of a type guard tuple assignment.
+// Lower a conversion to an interface type.
 
 void
-Tuple_type_guard_assignment_statement::do_check_types(Gogo*)
+Tuple_type_guard_assignment_statement::lower_to_interface(Block* b)
 {
-  if (this->expr_->type()->interface_type() == NULL)
-    {
-      this->report_error(_("type guard only valid for interface types"));
-      return;
-    }
+  source_location loc = this->location();
 
-  if (!this->val_->is_lvalue() || !this->ok_->is_lvalue())
-    {
-      this->report_error(_("invalid left hand side of assignment"));
-      return;
-    }
+  // func ifaceI2I2(*descriptor, *interface) (*interface, bool)
+  source_location bloc = BUILTINS_LOCATION;
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("inter",
+					  Type::make_type_descriptor_ptr_type(),
+					  bloc));
+  param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc));
+  Typed_identifier_list* ret_types = new Typed_identifier_list();
+  ret_types->push_back(Typed_identifier("ret", this->type_, bloc));
+  ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
+  Function_type* fntype = Type::make_function_type(NULL, param_types,
+						   ret_types, bloc);
+  Named_object* ifaceI2I2 =
+    Named_object::make_function_declaration("ifaceI2I2", NULL, fntype, bloc);
+  ifaceI2I2->func_declaration_value()->set_asm_name("runtime.ifaceI2I2");
 
-  std::string reason;
-  if (!Type::are_compatible_for_assign(this->val_->type(), this->type_,
-				       &reason))
-    {
-      if (reason.empty())
-	error_at(this->val_->location(),
-		 "incompatible types for type guard value");
-      else
-	error_at(this->val_->location(),
-		 "incompatible types for type guard value (%s)",
-		 reason.c_str());
-      this->set_is_error();
-    }
+  // val, ok = ifaceI2I2(type_descriptor, expr)
+  Expression* func = Expression::make_func_reference(ifaceI2I2, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(Expression::make_type_descriptor(this->type_, loc));
+  params->push_back(this->expr_);
+  Call_expression* call = Expression::make_call(func, params, loc);
 
-  if (!Type::are_compatible_for_assign(this->ok_->type(),
-				       Type::lookup_bool_type(), &reason))
-    {
-      if (reason.empty())
-	error_at(this->ok_->location(), "incompatible type for type guard");
-      else
-	error_at(this->ok_->location(), "incompatible type for type guard (%s)",
-		 reason.c_str());
-      this->set_is_error();
-    }
+  Expression* res = Expression::make_call_result(call, 0);
+  Statement* s = Statement::make_assignment(OPERATOR_EQ, this->val_, res,
+					    loc);
+  b->add_statement(s);
+
+  res = Expression::make_call_result(call, 1);
+  s = Statement::make_assignment(OPERATOR_EQ, this->ok_, res, loc);
+  b->add_statement(s);
 }
 
-// Return the tree for a type guard tuple statement.  The right hand
-// side (THIS->EXPR_) is an interface type.  There are two cases to
-// consider: whether or not we are converting to an interface type.
+// Lower a conversion to a pointer type.
 
-tree
-Tuple_type_guard_assignment_statement::do_get_tree(Translate_context* context)
+void
+Tuple_type_guard_assignment_statement::lower_to_pointer_type(Block* b)
 {
-  Gogo* gogo = context->gogo();
+  source_location loc = this->location();
 
-  tree expr_tree = this->expr_->get_tree(context);
-  if (expr_tree == error_mark_node)
-    return error_mark_node;
+  // func ifaceI2T2P(*descriptor, *interface) (T, bool)
+  source_location bloc = BUILTINS_LOCATION;
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("inter",
+					  Type::make_type_descriptor_ptr_type(),
+					  bloc));
+  param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc));
+  Typed_identifier_list* ret_types = new Typed_identifier_list();
+  ret_types->push_back(Typed_identifier("ret", this->type_, bloc));
+  ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
+  Function_type* fntype = Type::make_function_type(NULL, param_types,
+						   ret_types, bloc);
+  Named_object* ifaceI2T2P =
+    Named_object::make_function_declaration("ifaceI2T2P", NULL, fntype, bloc);
+  ifaceI2T2P->func_declaration_value()->set_asm_name("runtime.ifaceI2T2P");
 
-  source_location location = this->location();
+  // val, ok = ifaceI2T2P(type_descriptor, expr)
+  Expression* func = Expression::make_func_reference(ifaceI2T2P, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(Expression::make_type_descriptor(this->type_, loc));
+  params->push_back(this->expr_);
+  Call_expression* call = Expression::make_call(func, params, loc);
 
-  gcc_assert(this->expr_->type()->interface_type() != NULL);
+  Expression* res = Expression::make_call_result(call, 0);
+  Statement* s = Statement::make_assignment(OPERATOR_EQ, this->val_, res,
+					    loc);
+  b->add_statement(s);
 
-  Interface_type* interface_type = this->type_->interface_type();
-  if (interface_type != NULL)
-    {
-      tree lhs_type_descriptor = interface_type->type_descriptor(gogo);
-      gcc_assert(POINTER_TYPE_P(TREE_TYPE(expr_tree)));
+  res = Expression::make_call_result(call, 1);
+  s = Statement::make_assignment(OPERATOR_EQ, this->ok_, res, loc);
+  b->add_statement(s);
+}
 
-      tree stmt_list = NULL_TREE;
+// Lower a conversion to a non-interface non-pointer type.
 
-      tree ok_tree = this->ok_->get_tree(context);
-      if (ok_tree == error_mark_node)
-	return error_mark_node;
-
-      tree tmp;
-      tree ok_addr;
-      if (TREE_CODE(ok_tree) == VAR_DECL)
-	{
-	  tmp = NULL_TREE;
-	  gcc_assert(TREE_CODE(TREE_TYPE(ok_tree)) == BOOLEAN_TYPE);
-	  ok_addr = build_fold_addr_expr(ok_tree);
-	  TREE_ADDRESSABLE(ok_tree) = 1;
-	}
-      else
-	{
-	  tmp = create_tmp_var(boolean_type_node, get_name(boolean_type_node));
-	  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);
-	  append_to_statement_list(make_tmp, &stmt_list);
-	  ok_addr = build_fold_addr_expr(tmp);
-	}
+void
+Tuple_type_guard_assignment_statement::lower_to_type(Block* b)
+{
+  source_location loc = this->location();
 
-      static tree convert_interface_decl;
-      tree call = Gogo::call_builtin(&convert_interface_decl,
-				     location,
-				     "__go_convert_interface",
-				     3,
-				     ptr_type_node,
-				     TREE_TYPE(lhs_type_descriptor),
-				     lhs_type_descriptor,
-				     ptr_type_node,
-				     fold_convert(ptr_type_node, expr_tree),
-				     build_pointer_type(boolean_type_node),
-				     ok_addr);
-      call = save_expr(call);
-      append_to_statement_list(call, &stmt_list);
-      if (tmp != NULL_TREE)
-	append_to_statement_list(build2(MODIFY_EXPR, void_type_node,
-					ok_tree, tmp),
-				 &stmt_list);
-      else
-	tmp = ok_tree;
+  // var val_temp TYPE
+  Temporary_statement* val_temp = Statement::make_temporary(this->type_, NULL,
+							    loc);
+  b->add_statement(val_temp);
 
-      call = fold_convert(interface_type->get_tree(gogo), call);
-      tree assign = Assignment_statement::get_assignment_tree(context,
-							      OPERATOR_EQ,
-							      this->val_,
-							      NULL_TREE,
-							      NULL,
-							      this->type_,
-							      call,
-							      location);
+  // func ifaceI2T2(*descriptor, *interface, *T) bool
+  source_location bloc = BUILTINS_LOCATION;
+  Typed_identifier_list* param_types = new Typed_identifier_list();
+  param_types->push_back(Typed_identifier("inter",
+					  Type::make_type_descriptor_ptr_type(),
+					  bloc));
+  param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc));
+  Type* ptype = Type::make_pointer_type(this->type_);
+  param_types->push_back(Typed_identifier("v", ptype, bloc));
+  Typed_identifier_list* ret_types = new Typed_identifier_list();
+  ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc));
+  Function_type* fntype = Type::make_function_type(NULL, param_types,
+						   ret_types, bloc);
+  Named_object* ifaceI2T2 =
+    Named_object::make_function_declaration("ifaceI2T2", NULL, fntype, bloc);
+  ifaceI2T2->func_declaration_value()->set_asm_name("runtime.ifaceI2T2");
 
-      append_to_statement_list(build3(COND_EXPR, void_type_node, tmp, assign,
-				      NULL_TREE),
-			       &stmt_list);
+  // ok = ifaceI2T2(type_descriptor, expr, &val_temp)
+  Expression* func = Expression::make_func_reference(ifaceI2T2, NULL, loc);
+  Expression_list* params = new Expression_list();
+  params->push_back(Expression::make_type_descriptor(this->type_, loc));
+  params->push_back(this->expr_);
+  Expression* ref = Expression::make_temporary_reference(val_temp, loc);
+  params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc));
+  Expression* call = Expression::make_call(func, params, loc);
+  Statement* s = Statement::make_assignment(OPERATOR_EQ, this->ok_, call, loc);
+  b->add_statement(s);
 
-      return stmt_list;
-    }
-  else
-    {
-      // We are converting from an interface to a plain type.  This is
-      // OK if the type descriptors are the same.
-      expr_tree = save_expr(expr_tree);
-      gcc_assert(POINTER_TYPE_P(TREE_TYPE(expr_tree)));
-      tree struct_type = TREE_TYPE(TREE_TYPE(expr_tree));
-      gcc_assert(TREE_CODE(struct_type) == RECORD_TYPE);
-      tree field = TYPE_FIELDS(struct_type);
-      gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),
-			"__type_descriptor") == 0);
-      tree rhs_td = build3(COMPONENT_REF, TREE_TYPE(field),
-			   build_fold_indirect_ref(expr_tree),
-			   field, NULL_TREE);
-
-      tree lhs_td = this->type_->type_descriptor(gogo);
-
-      tree ok_true =
-	Assignment_statement::get_assignment_tree(context,
-						  OPERATOR_EQ,
-						  this->ok_,
-						  NULL_TREE,
-						  NULL,
-						  Type::lookup_bool_type(),
-						  boolean_true_node,
-						  location);
-      tree ok_false =
-	Assignment_statement::get_assignment_tree(context,
-						  OPERATOR_EQ,
-						  this->ok_,
-						  NULL_TREE,
-						  NULL,
-						  Type::lookup_bool_type(),
-						  boolean_false_node,
-						  location);
-      tree val_true =
-	Assignment_statement::get_assignment_tree(context,
-						  OPERATOR_EQ,
-						  this->val_,
-						  NULL_TREE,
-						  this->expr_,
-						  NULL,
-						  expr_tree,
-						  location);
-
-      static tree type_descriptors_equal_fndecl;
-      tree compare = Gogo::call_builtin(&type_descriptors_equal_fndecl,
-					location,
-					"__go_type_descriptors_equal",
-					2,
-					boolean_type_node,
-					TREE_TYPE(lhs_td),
-					lhs_td,
-					TREE_TYPE(rhs_td),
-					rhs_td);
-
-      tree is_nil = fold_build2(EQ_EXPR, boolean_type_node, expr_tree,
-				fold_convert(TREE_TYPE(expr_tree),
-					     null_pointer_node));
-
-      return fold_build3(COND_EXPR, void_type_node,
-			 is_nil,
-			 ok_false,
-			 build3(COND_EXPR, void_type_node,
-				compare,
-				build2(COMPOUND_EXPR, void_type_node, ok_true,
-				       val_true),
-				ok_false));
-    }
+  // val = val_temp
+  ref = Expression::make_temporary_reference(val_temp, loc);
+  s = Statement::make_assignment(OPERATOR_EQ, this->val_, ref, loc);
+  b->add_statement(s);
 }
 
 // Make an assignment from a type guard to a pair of variables.
Index: gcc/go/statements.h
===================================================================
--- gcc/go/statements.h	(revision 155971)
+++ gcc/go/statements.h	(working copy)
@@ -91,7 +91,6 @@ class Statement
     STATEMENT_TEMPORARY,
     STATEMENT_DESTROY_TEMPORARY,
     STATEMENT_ASSIGNMENT,
-    STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT,
     STATEMENT_EXPRESSION,
     STATEMENT_BLOCK,
     STATEMENT_INCDEC,
@@ -115,6 +114,7 @@ class Statement
     STATEMENT_TUPLE_MAP_ASSIGNMENT,
     STATEMENT_MAP_ASSIGNMENT,
     STATEMENT_TUPLE_RECEIVE_ASSIGNMENT,
+    STATEMENT_TUPLE_TYPE_GUARD_ASSIGNMENT,
     STATEMENT_FOR,
     STATEMENT_FOR_RANGE
   };
Index: gcc/go/types.cc
===================================================================
--- gcc/go/types.cc	(revision 155628)
+++ gcc/go/types.cc	(working copy)
@@ -4632,6 +4632,39 @@ Type::make_interface_type(Typed_identifi
   return new Interface_type(methods, location);
 }
 
+// Make the type of a pointer to a type descriptor as represented in
+// Go.  We should really tie this to runtime.Type rather than copying
+// it.
+
+Type*
+Type::make_type_descriptor_ptr_type()
+{
+  static Type* ret;
+  if (ret == NULL)
+    {
+      source_location bloc = BUILTINS_LOCATION;
+      Struct_field_list* sfl = new Struct_field_list();
+      Type* uint8_type = Type::lookup_integer_type("uint8");
+      Type* uintptr_type = Type::lookup_integer_type("uintptr");
+      sfl->push_back(Struct_field(Typed_identifier("Code", uint8_type, bloc)));
+      sfl->push_back(Struct_field(Typed_identifier("align", uint8_type, bloc)));
+      sfl->push_back(Struct_field(Typed_identifier("fieldAlign", uint8_type,
+						   bloc)));
+      sfl->push_back(Struct_field(Typed_identifier("size", uintptr_type,
+						   bloc)));
+      // We don't try to represent the real function type.
+      Type* fntype = Type::make_function_type(NULL, NULL, NULL, bloc);
+      sfl->push_back(Struct_field(Typed_identifier("hash", fntype, bloc)));
+      sfl->push_back(Struct_field(Typed_identifier("equal", fntype, bloc)));
+      Type* stype = Type::make_pointer_type(Type::lookup_string_type());
+      sfl->push_back(Struct_field(Typed_identifier("string", stype, bloc)));
+      // We omit the pointer to uncommonType.
+      Type* t = Type::make_struct_type(sfl, bloc);
+      ret = Type::make_pointer_type(t);
+    }
+  return ret;
+}
+
 // Class Method.
 
 // Bind a method to an object.
Index: gcc/go/expressions.cc
===================================================================
--- gcc/go/expressions.cc	(revision 155952)
+++ gcc/go/expressions.cc	(working copy)
@@ -10562,6 +10562,47 @@ Refcount_decrement_lvalue_expression::se
   return fold_build2(COMPOUND_EXPR, void_type_node, save, set);
 }
 
+// An expression which evaluates to a pointer to the type descriptor
+// of a type.
+
+class Type_descriptor_expression : public Expression
+{
+ public:
+  Type_descriptor_expression(Type* type, source_location location)
+    : Expression(EXPRESSION_TYPE_DESCRIPTOR, location),
+      type_(type)
+  { }
+
+ protected:
+  Type*
+  do_type()
+  { return Type::make_type_descriptor_ptr_type(); }
+
+  void
+  do_determine_type(const Type_context*)
+  { }
+
+  Expression*
+  do_copy()
+  { return this; }
+
+  tree
+  do_get_tree(Translate_context* context)
+  { return this->type_->type_descriptor(context->gogo()); }
+
+ private:
+  // The type for which this is the descriptor.
+  Type* type_;
+};
+
+// Make a type descriptor expression.
+
+Expression*
+Expression::make_type_descriptor(Type* type, source_location location)
+{
+  return new Type_descriptor_expression(type, location);
+}
+
 // Make a reference count decrement of an lvalue.
 
 Expression*

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