compiler: Use backend interface for type sizes and alignments.
authorIan Lance Taylor <iant@google.com>
Wed, 11 Jan 2012 04:48:22 +0000 (04:48 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 11 Jan 2012 04:48:22 +0000 (04:48 +0000)
* 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.

From-SVN: r183089

gcc/go/ChangeLog
gcc/go/go-backend.c
gcc/go/go-c.h
gcc/go/go-gcc.cc
gcc/go/gofrontend/backend.h
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h

index c3b03e9..2067558 100644 (file)
@@ -1,3 +1,12 @@
+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.
+
 2011-12-27  Ian Lance Taylor  <iant@google.com>
 
        * go-gcc.cc (Gcc_backend::set_placeholder_struct_type): Use
index 4d1ea82..5dab2f1 100644 (file)
@@ -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.  If not see
 /* 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 5e65dea..0bfed85 100644 (file)
@@ -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);
index 492787d..bfa0ec7 100644 (file)
@@ -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(Btype* btype)
   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 382f5a1..9777acc 100644 (file)
@@ -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 84c18a3..337b949 100644 (file)
@@ -7979,35 +7979,32 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant,
        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_constant_value(bool iota_is_constant,
        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 334dc33..d93b68b 100644 (file)
@@ -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, std::string* ret) const
   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* gogo)
     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* gogo)
        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 b00b007..200164c 100644 (file)
@@ -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.