* 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
+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
/* 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.
/* 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
/* 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.
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);
// 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.
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*
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*
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
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;
}
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;
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.
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
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
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
case TYPE_STRUCT:
bt = gogo->backend()->placeholder_struct_type(this->name(),
this->location_);
+ this->is_placeholder_ = true;
set_name = false;
break;
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;
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,
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*);
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.
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;
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.