diff mbox

Go patch committed: Use backend interface for type size and align

Message ID mcrwr8yyhcv.fsf@dhcp-172-18-216-180.mtv.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor Jan. 11, 2012, 4:48 a.m. UTC
This patch to the Go frontend changes it to use the backend interface to
determine type size and alignment information.  This is a preliminary to
a patch adjusting the handling of struct comparison, which will follow.
Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian


2012-01-10  Ian Lance Taylor  <iant@google.com>

	* go-gcc.cc (Gcc_backend::type_size): New function.
	(Gcc_backend::type_alignment): New function.
	(Gcc_backend::type_field_alignment): New function.
	(Gcc_backend::type_field_offset): New function.
	* go-backend.c (go_type_alignment): Remove.
	* go-c.h (go_type_alignment): Don't declare.
diff mbox

Patch

Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 182698)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -1,5 +1,5 @@ 
 // go-gcc.cc -- Go frontend to gcc IR.
-// Copyright (C) 2011 Free Software Foundation, Inc.
+// Copyright (C) 2011, 2012 Free Software Foundation, Inc.
 // Contributed by Ian Lance Taylor, Google.
 
 // This file is part of GCC.
@@ -195,6 +195,18 @@  class Gcc_backend : public Backend
   bool
   is_circular_pointer_type(Btype*);
 
+  size_t
+  type_size(Btype*);
+
+  size_t
+  type_alignment(Btype*);
+
+  size_t
+  type_field_alignment(Btype*);
+
+  size_t
+  type_field_offset(Btype*, size_t index);
+
   // Expressions.
 
   Bexpression*
@@ -755,6 +767,56 @@  Gcc_backend::is_circular_pointer_type(Bt
   return btype->get_tree() == ptr_type_node;
 }
 
+// Return the size of a type.
+
+size_t
+Gcc_backend::type_size(Btype* btype)
+{
+  tree t = TYPE_SIZE_UNIT(btype->get_tree());
+  gcc_assert(TREE_CODE(t) == INTEGER_CST);
+  gcc_assert(TREE_INT_CST_HIGH(t) == 0);
+  unsigned HOST_WIDE_INT val_wide = TREE_INT_CST_LOW(t);
+  size_t ret = static_cast<size_t>(val_wide);
+  gcc_assert(ret == val_wide);
+  return ret;
+}
+
+// Return the alignment of a type.
+
+size_t
+Gcc_backend::type_alignment(Btype* btype)
+{
+  return TYPE_ALIGN_UNIT(btype->get_tree());
+}
+
+// Return the alignment of a struct field of type BTYPE.
+
+size_t
+Gcc_backend::type_field_alignment(Btype* btype)
+{
+  return go_field_alignment(btype->get_tree());
+}
+
+// Return the offset of a field in a struct.
+
+size_t
+Gcc_backend::type_field_offset(Btype* btype, size_t index)
+{
+  tree struct_tree = btype->get_tree();
+  gcc_assert(TREE_CODE(struct_tree) == RECORD_TYPE);
+  tree field = TYPE_FIELDS(struct_tree);
+  for (; index > 0; --index)
+    {
+      field = DECL_CHAIN(field);
+      gcc_assert(field != NULL_TREE);
+    }
+  HOST_WIDE_INT offset_wide = int_byte_position(field);
+  gcc_assert(offset_wide >= 0);
+  size_t ret = static_cast<size_t>(offset_wide);
+  gcc_assert(ret == static_cast<unsigned HOST_WIDE_INT>(offset_wide));
+  return ret;
+}
+
 // Return the zero value for a type.
 
 Bexpression*
Index: gcc/go/gofrontend/types.h
===================================================================
--- gcc/go/gofrontend/types.h	(revision 182971)
+++ gcc/go/gofrontend/types.h	(working copy)
@@ -861,6 +861,27 @@  class Type
   std::string
   mangled_name(Gogo*) const;
 
+  // If the size of the type can be determined, set *PSIZE to the size
+  // in bytes and return true.  Otherwise, return false.  This queries
+  // the backend.
+  bool
+  backend_type_size(Gogo*, unsigned int* psize);
+
+  // If the alignment of the type can be determined, set *PALIGN to
+  // the alignment in bytes and return true.  Otherwise, return false.
+  bool
+  backend_type_align(Gogo*, unsigned int* palign);
+
+  // If the alignment of a struct field of this type can be
+  // determined, set *PALIGN to the alignment in bytes and return
+  // true.  Otherwise, return false.
+  bool
+  backend_type_field_align(Gogo*, unsigned int* palign);
+
+  // Whether the backend size is known.
+  bool
+  is_backend_type_size_known(Gogo*) const;
+
   // Get the hash and equality functions for a type.
   void
   type_functions(Gogo*, Named_type* name, Function_type* hash_fntype,
@@ -2013,6 +2034,12 @@  class Struct_type : public Type
   traverse_field_types(Traverse* traverse)
   { return this->do_traverse(traverse); }
 
+  // If the offset of field INDEX in the backend implementation can be
+  // determined, set *POFFSET to the offset in bytes and return true.
+  // Otherwise, return false.
+  bool
+  backend_field_offset(Gogo*, unsigned int index, unsigned int* poffset);
+
   // Import a struct type.
   static Struct_type*
   do_import(Import*);
@@ -2507,8 +2534,9 @@  class Named_type : public Type
       local_methods_(NULL), all_methods_(NULL),
       interface_method_tables_(NULL), pointer_interface_method_tables_(NULL),
       location_(location), named_btype_(NULL), dependencies_(),
-      is_visible_(true), is_error_(false), is_converted_(false),
-      is_circular_(false), seen_(false), seen_in_get_backend_(false)
+      is_visible_(true), is_error_(false), is_placeholder_(false),
+      is_converted_(false), is_circular_(false), seen_(false),
+      seen_in_get_backend_(false)
   { }
 
   // Return the associated Named_object.  This holds the actual name.
@@ -2672,6 +2700,13 @@  class Named_type : public Type
   add_dependency(Named_type* nt)
   { this->dependencies_.push_back(nt); }
 
+  // Return true if the size and alignment of the backend
+  // representation of this type is known.  This is always true after
+  // types have been converted, but may be false beforehand.
+  bool
+  is_named_backend_type_size_known() const
+  { return this->named_btype_ != NULL && !this->is_placeholder_; }
+
   // Export the type.
   void
   export_named_type(Export*, const std::string& name) const;
@@ -2766,8 +2801,11 @@  class Named_type : public Type
   bool is_visible_;
   // Whether this type is erroneous.
   bool is_error_;
+  // Whether the current value of named_btype_ is a placeholder for
+  // which the final size of the type is not known.
+  bool is_placeholder_;
   // Whether this type has been converted to the backend
-  // representation.
+  // representation.  Implies that is_placeholder_ is false.
   bool is_converted_;
   // Whether this is a pointer or function type which refers to the
   // type itself.
Index: gcc/go/gofrontend/backend.h
===================================================================
--- gcc/go/gofrontend/backend.h	(revision 182971)
+++ gcc/go/gofrontend/backend.h	(working copy)
@@ -198,6 +198,25 @@  class Backend
   virtual bool
   is_circular_pointer_type(Btype*) = 0;
 
+  // Return the size of a type.
+  virtual size_t
+  type_size(Btype*) = 0;
+
+  // Return the alignment of a type.
+  virtual size_t
+  type_alignment(Btype*) = 0;
+
+  // Return the alignment of a struct field of this type.  This is
+  // normally the same as type_alignment, but not always.
+  virtual size_t
+  type_field_alignment(Btype*) = 0;
+
+  // Return the offset of field INDEX in a struct type.  INDEX is the
+  // entry in the FIELDS std::vector parameter of struct_type or
+  // set_placeholder_struct_type.
+  virtual size_t
+  type_field_offset(Btype*, size_t index) = 0;
+
   // Expressions.
 
   // Return an expression for a zero value of the given type.  This is
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc	(revision 182971)
+++ gcc/go/gofrontend/types.cc	(working copy)
@@ -1950,6 +1950,126 @@  Type::mangled_name(Gogo* gogo) const
   return ret;
 }
 
+// Return whether the backend size of the type is known.
+
+bool
+Type::is_backend_type_size_known(Gogo* gogo) const
+{
+  switch (this->classification_)
+    {
+    case TYPE_ERROR:
+    case TYPE_VOID:
+    case TYPE_BOOLEAN:
+    case TYPE_INTEGER:
+    case TYPE_FLOAT:
+    case TYPE_COMPLEX:
+    case TYPE_STRING:
+    case TYPE_FUNCTION:
+    case TYPE_POINTER:
+    case TYPE_NIL:
+    case TYPE_MAP:
+    case TYPE_CHANNEL:
+    case TYPE_INTERFACE:
+      return true;
+
+    case TYPE_STRUCT:
+      {
+	const Struct_field_list* fields = this->struct_type()->fields();
+	for (Struct_field_list::const_iterator pf = fields->begin();
+	     pf != fields->end();
+	     ++pf)
+	  if (!pf->type()->is_backend_type_size_known(gogo))
+	    return false;
+	return true;
+      }
+
+    case TYPE_ARRAY:
+      {
+	const Array_type* at = this->array_type();
+	if (at->length() == NULL)
+	  return true;
+	else
+	  {
+	    mpz_t ival;
+	    mpz_init(ival);
+	    Type* dummy;
+	    bool length_known = at->length()->integer_constant_value(true,
+								     ival,
+								     &dummy);
+	    mpz_clear(ival);
+	    if (!length_known)
+	      return false;
+	    return at->element_type()->is_backend_type_size_known(gogo);
+	  }
+      }
+
+    case TYPE_NAMED:
+      return this->named_type()->is_named_backend_type_size_known();
+
+    case TYPE_FORWARD:
+      {
+	const Forward_declaration_type* fdt = this->forward_declaration_type();
+	return fdt->real_type()->is_backend_type_size_known(gogo);
+      }
+
+    case TYPE_SINK:
+    case TYPE_CALL_MULTIPLE_RESULT:
+      go_unreachable();
+
+    default:
+      go_unreachable();
+    }
+}
+
+// If the size of the type can be determined, set *PSIZE to the size
+// in bytes and return true.  Otherwise, return false.  This queries
+// the backend.
+
+bool
+Type::backend_type_size(Gogo* gogo, unsigned int *psize)
+{
+  Btype* btype = this->get_backend(gogo);
+  if (!this->is_backend_type_size_known(gogo))
+    return false;
+  size_t size = gogo->backend()->type_size(btype);
+  *psize = static_cast<unsigned int>(size);
+  if (*psize != size)
+    return false;
+  return true;
+}
+
+// If the alignment of the type can be determined, set *PALIGN to
+// the alignment in bytes and return true.  Otherwise, return false.
+
+bool
+Type::backend_type_align(Gogo* gogo, unsigned int *palign)
+{
+  Btype* btype = this->get_backend(gogo);
+  if (!this->is_backend_type_size_known(gogo))
+    return false;
+  size_t align = gogo->backend()->type_alignment(btype);
+  *palign = static_cast<unsigned int>(align);
+  if (*palign != align)
+    return false;
+  return true;
+}
+
+// Like backend_type_align, but return the alignment when used as a
+// field.
+
+bool
+Type::backend_type_field_align(Gogo* gogo, unsigned int *palign)
+{
+  Btype* btype = this->get_backend(gogo);
+  if (!this->is_backend_type_size_known(gogo))
+    return false;
+  size_t a = gogo->backend()->type_field_alignment(btype);
+  *palign = static_cast<unsigned int>(a);
+  if (*palign != a)
+    return false;
+  return true;
+}
+
 // Default function to export a type.
 
 void
@@ -4589,6 +4709,24 @@  Struct_type::do_mangled_name(Gogo* gogo,
   ret->push_back('e');
 }
 
+// If the offset of field INDEX in the backend implementation can be
+// determined, set *POFFSET to the offset in bytes and return true.
+// Otherwise, return false.
+
+bool
+Struct_type::backend_field_offset(Gogo* gogo, unsigned int index,
+				  unsigned int* poffset)
+{
+  Btype* btype = this->get_backend(gogo);
+  if (!this->is_backend_type_size_known(gogo))
+    return false;
+  size_t offset = gogo->backend()->type_field_offset(btype, index);
+  *poffset = static_cast<unsigned int>(offset);
+  if (*poffset != offset)
+    return false;
+  return true;
+}
+
 // Export.
 
 void
@@ -7518,6 +7656,7 @@  Named_type::convert(Gogo* gogo)
 
   this->named_btype_ = bt;
   this->is_converted_ = true;
+  this->is_placeholder_ = false;
 }
 
 // Create the placeholder for a named type.  This is the first step in
@@ -7578,6 +7717,7 @@  Named_type::create_placeholder(Gogo* gog
     case TYPE_STRUCT:
       bt = gogo->backend()->placeholder_struct_type(this->name(),
 						    this->location_);
+      this->is_placeholder_ = true;
       set_name = false;
       break;
 
@@ -7586,8 +7726,11 @@  Named_type::create_placeholder(Gogo* gog
 	bt = gogo->backend()->placeholder_struct_type(this->name(),
 						      this->location_);
       else
-	bt = gogo->backend()->placeholder_array_type(this->name(),
-						     this->location_);
+	{
+	  bt = gogo->backend()->placeholder_array_type(this->name(),
+						       this->location_);
+	  this->is_placeholder_ = true;
+	}
       set_name = false;
       break;
 
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 182971)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -7979,35 +7979,32 @@  Builtin_call_expression::do_integer_cons
 	return false;
       if (arg_type->named_type() != NULL)
 	arg_type->named_type()->convert(this->gogo_);
-      tree arg_type_tree = type_to_tree(arg_type->get_backend(this->gogo_));
-      if (arg_type_tree == error_mark_node)
-	return false;
-      unsigned long val_long;
+
+      unsigned int ret;
       if (this->code_ == BUILTIN_SIZEOF)
 	{
-	  tree type_size = TYPE_SIZE_UNIT(arg_type_tree);
-	  go_assert(TREE_CODE(type_size) == INTEGER_CST);
-	  if (TREE_INT_CST_HIGH(type_size) != 0)
-	    return false;
-	  unsigned HOST_WIDE_INT val_wide = TREE_INT_CST_LOW(type_size);
-	  val_long = static_cast<unsigned long>(val_wide);
-	  if (val_long != val_wide)
+	  if (!arg_type->backend_type_size(this->gogo_, &ret))
 	    return false;
 	}
       else if (this->code_ == BUILTIN_ALIGNOF)
 	{
 	  if (arg->field_reference_expression() == NULL)
-	    val_long = go_type_alignment(arg_type_tree);
+	    {
+	      if (!arg_type->backend_type_align(this->gogo_, &ret))
+		return false;
+	    }
 	  else
 	    {
 	      // Calling unsafe.Alignof(s.f) returns the alignment of
 	      // the type of f when it is used as a field in a struct.
-	      val_long = go_field_alignment(arg_type_tree);
+	      if (!arg_type->backend_type_field_align(this->gogo_, &ret))
+		return false;
 	    }
 	}
       else
 	go_unreachable();
-      mpz_set_ui(val, val_long);
+
+      mpz_set_ui(val, ret);
       *ptype = NULL;
       return true;
     }
@@ -8025,21 +8022,12 @@  Builtin_call_expression::do_integer_cons
 	return false;
       if (st->named_type() != NULL)
 	st->named_type()->convert(this->gogo_);
-      tree struct_tree = type_to_tree(st->get_backend(this->gogo_));
-      go_assert(TREE_CODE(struct_tree) == RECORD_TYPE);
-      tree field = TYPE_FIELDS(struct_tree);
-      for (unsigned int index = farg->field_index(); index > 0; --index)
-	{
-	  field = DECL_CHAIN(field);
-	  go_assert(field != NULL_TREE);
-	}
-      HOST_WIDE_INT offset_wide = int_byte_position (field);
-      if (offset_wide < 0)
+      unsigned int offset;
+      if (!st->struct_type()->backend_field_offset(this->gogo_,
+						   farg->field_index(),
+						   &offset))
 	return false;
-      unsigned long offset_long = static_cast<unsigned long>(offset_wide);
-      if (offset_long != static_cast<unsigned HOST_WIDE_INT>(offset_wide))
-	return false;
-      mpz_set_ui(val, offset_long);
+      mpz_set_ui(val, offset);
       return true;
     }
   return false;
@@ -13939,25 +13927,26 @@  Type_info_expression::do_type()
 tree
 Type_info_expression::do_get_tree(Translate_context* context)
 {
-  tree type_tree = type_to_tree(this->type_->get_backend(context->gogo()));
-  if (type_tree == error_mark_node)
-    return error_mark_node;
-
-  tree val_type_tree = type_to_tree(this->type()->get_backend(context->gogo()));
-  go_assert(val_type_tree != error_mark_node);
-
-  if (this->type_info_ == TYPE_INFO_SIZE)
-    return fold_convert_loc(BUILTINS_LOCATION, val_type_tree,
-			    TYPE_SIZE_UNIT(type_tree));
-  else
+  Btype* btype = this->type_->get_backend(context->gogo());
+  Gogo* gogo = context->gogo();
+  size_t val;
+  switch (this->type_info_)
     {
-      unsigned int val;
-      if (this->type_info_ == TYPE_INFO_ALIGNMENT)
-	val = go_type_alignment(type_tree);
-      else
-	val = go_field_alignment(type_tree);
-      return build_int_cstu(val_type_tree, val);
+    case TYPE_INFO_SIZE:
+      val = gogo->backend()->type_size(btype);
+      break;
+    case TYPE_INFO_ALIGNMENT:
+      val = gogo->backend()->type_alignment(btype);
+      break;
+    case TYPE_INFO_FIELD_ALIGNMENT:
+      val = gogo->backend()->type_field_alignment(btype);
+      break;
+    default:
+      go_unreachable();
     }
+  tree val_type_tree = type_to_tree(this->type()->get_backend(gogo));
+  go_assert(val_type_tree != error_mark_node);
+  return build_int_cstu(val_type_tree, val);
 }
 
 // Dump ast representation for a type info expression.
Index: gcc/go/go-backend.c
===================================================================
--- gcc/go/go-backend.c	(revision 182696)
+++ gcc/go/go-backend.c	(working copy)
@@ -1,5 +1,5 @@ 
 /* go-backend.c -- Go frontend interface to gcc backend.
-   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2010, 2011, 2012 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -48,14 +48,6 @@  along with GCC; see the file COPYING3.  
 /* This file holds all the cases where the Go frontend needs
    information from gcc's backend.  */
 
-/* Return the alignment in bytes of a value of type T.  */
-
-unsigned int
-go_type_alignment (tree t)
-{
-  return TYPE_ALIGN_UNIT (t);
-}
-
 /* Return the alignment in bytes of a struct field of type T.  */
 
 unsigned int
Index: gcc/go/go-c.h
===================================================================
--- gcc/go/go-c.h	(revision 182696)
+++ gcc/go/go-c.h	(working copy)
@@ -1,5 +1,5 @@ 
 /* go-c.h -- Header file for go frontend gcc C interface.
-   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -59,8 +59,6 @@  extern void go_preserve_from_gc (tree);
 
 extern const char *go_localize_identifier (const char*);
 
-extern unsigned int go_type_alignment (tree);
-
 extern unsigned int go_field_alignment (tree);
 
 extern void go_trampoline_info (unsigned int *size, unsigned int *alignment);