Commit ef1ed13d by Ian Lance Taylor Committed by Ian Lance Taylor

compiler: Use backend interface for type sizes and alignments.

	* 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
parent 5313d330
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> 2011-12-27 Ian Lance Taylor <iant@google.com>
* go-gcc.cc (Gcc_backend::set_placeholder_struct_type): Use * go-gcc.cc (Gcc_backend::set_placeholder_struct_type): Use
......
/* go-backend.c -- Go frontend interface to gcc backend. /* 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 is part of GCC.
...@@ -48,14 +48,6 @@ along with GCC; see the file COPYING3. If not see ...@@ -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 /* This file holds all the cases where the Go frontend needs
information from gcc's backend. */ 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. */ /* Return the alignment in bytes of a struct field of type T. */
unsigned int unsigned int
......
/* go-c.h -- Header file for go frontend gcc C interface. /* 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. This file is part of GCC.
...@@ -59,8 +59,6 @@ extern void go_preserve_from_gc (tree); ...@@ -59,8 +59,6 @@ extern void go_preserve_from_gc (tree);
extern const char *go_localize_identifier (const char*); extern const char *go_localize_identifier (const char*);
extern unsigned int go_type_alignment (tree);
extern unsigned int go_field_alignment (tree); extern unsigned int go_field_alignment (tree);
extern void go_trampoline_info (unsigned int *size, unsigned int *alignment); extern void go_trampoline_info (unsigned int *size, unsigned int *alignment);
......
// go-gcc.cc -- Go frontend to gcc IR. // 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. // Contributed by Ian Lance Taylor, Google.
// This file is part of GCC. // This file is part of GCC.
...@@ -195,6 +195,18 @@ class Gcc_backend : public Backend ...@@ -195,6 +195,18 @@ class Gcc_backend : public Backend
bool bool
is_circular_pointer_type(Btype*); 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. // Expressions.
Bexpression* Bexpression*
...@@ -755,6 +767,56 @@ Gcc_backend::is_circular_pointer_type(Btype* btype) ...@@ -755,6 +767,56 @@ Gcc_backend::is_circular_pointer_type(Btype* btype)
return btype->get_tree() == ptr_type_node; 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. // Return the zero value for a type.
Bexpression* Bexpression*
......
...@@ -198,6 +198,25 @@ class Backend ...@@ -198,6 +198,25 @@ class Backend
virtual bool virtual bool
is_circular_pointer_type(Btype*) = 0; 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. // Expressions.
// Return an expression for a zero value of the given type. This is // Return an expression for a zero value of the given type. This is
......
...@@ -7979,35 +7979,32 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant, ...@@ -7979,35 +7979,32 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant,
return false; return false;
if (arg_type->named_type() != NULL) if (arg_type->named_type() != NULL)
arg_type->named_type()->convert(this->gogo_); 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) unsigned int ret;
return false;
unsigned long val_long;
if (this->code_ == BUILTIN_SIZEOF) if (this->code_ == BUILTIN_SIZEOF)
{ {
tree type_size = TYPE_SIZE_UNIT(arg_type_tree); if (!arg_type->backend_type_size(this->gogo_, &ret))
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)
return false; return false;
} }
else if (this->code_ == BUILTIN_ALIGNOF) else if (this->code_ == BUILTIN_ALIGNOF)
{ {
if (arg->field_reference_expression() == NULL) 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 else
{ {
// Calling unsafe.Alignof(s.f) returns the alignment of // Calling unsafe.Alignof(s.f) returns the alignment of
// the type of f when it is used as a field in a struct. // 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 else
go_unreachable(); go_unreachable();
mpz_set_ui(val, val_long);
mpz_set_ui(val, ret);
*ptype = NULL; *ptype = NULL;
return true; return true;
} }
...@@ -8025,21 +8022,12 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant, ...@@ -8025,21 +8022,12 @@ Builtin_call_expression::do_integer_constant_value(bool iota_is_constant,
return false; return false;
if (st->named_type() != NULL) if (st->named_type() != NULL)
st->named_type()->convert(this->gogo_); st->named_type()->convert(this->gogo_);
tree struct_tree = type_to_tree(st->get_backend(this->gogo_)); unsigned int offset;
go_assert(TREE_CODE(struct_tree) == RECORD_TYPE); if (!st->struct_type()->backend_field_offset(this->gogo_,
tree field = TYPE_FIELDS(struct_tree); farg->field_index(),
for (unsigned int index = farg->field_index(); index > 0; --index) &offset))
{
field = DECL_CHAIN(field);
go_assert(field != NULL_TREE);
}
HOST_WIDE_INT offset_wide = int_byte_position (field);
if (offset_wide < 0)
return false; return false;
unsigned long offset_long = static_cast<unsigned long>(offset_wide); mpz_set_ui(val, offset);
if (offset_long != static_cast<unsigned HOST_WIDE_INT>(offset_wide))
return false;
mpz_set_ui(val, offset_long);
return true; return true;
} }
return false; return false;
...@@ -13939,25 +13927,26 @@ Type_info_expression::do_type() ...@@ -13939,25 +13927,26 @@ Type_info_expression::do_type()
tree tree
Type_info_expression::do_get_tree(Translate_context* context) Type_info_expression::do_get_tree(Translate_context* context)
{ {
tree type_tree = type_to_tree(this->type_->get_backend(context->gogo())); Btype* btype = this->type_->get_backend(context->gogo());
if (type_tree == error_mark_node) Gogo* gogo = context->gogo();
return error_mark_node; size_t val;
switch (this->type_info_)
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
{ {
unsigned int val; case TYPE_INFO_SIZE:
if (this->type_info_ == TYPE_INFO_ALIGNMENT) val = gogo->backend()->type_size(btype);
val = go_type_alignment(type_tree); break;
else case TYPE_INFO_ALIGNMENT:
val = go_field_alignment(type_tree); val = gogo->backend()->type_alignment(btype);
return build_int_cstu(val_type_tree, val); 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. // Dump ast representation for a type info expression.
......
...@@ -1950,6 +1950,126 @@ Type::mangled_name(Gogo* gogo) const ...@@ -1950,6 +1950,126 @@ Type::mangled_name(Gogo* gogo) const
return ret; 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. // Default function to export a type.
void void
...@@ -4589,6 +4709,24 @@ Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const ...@@ -4589,6 +4709,24 @@ Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const
ret->push_back('e'); 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. // Export.
void void
...@@ -7518,6 +7656,7 @@ Named_type::convert(Gogo* gogo) ...@@ -7518,6 +7656,7 @@ Named_type::convert(Gogo* gogo)
this->named_btype_ = bt; this->named_btype_ = bt;
this->is_converted_ = true; this->is_converted_ = true;
this->is_placeholder_ = false;
} }
// Create the placeholder for a named type. This is the first step in // Create the placeholder for a named type. This is the first step in
...@@ -7578,6 +7717,7 @@ Named_type::create_placeholder(Gogo* gogo) ...@@ -7578,6 +7717,7 @@ Named_type::create_placeholder(Gogo* gogo)
case TYPE_STRUCT: case TYPE_STRUCT:
bt = gogo->backend()->placeholder_struct_type(this->name(), bt = gogo->backend()->placeholder_struct_type(this->name(),
this->location_); this->location_);
this->is_placeholder_ = true;
set_name = false; set_name = false;
break; break;
...@@ -7586,8 +7726,11 @@ Named_type::create_placeholder(Gogo* gogo) ...@@ -7586,8 +7726,11 @@ Named_type::create_placeholder(Gogo* gogo)
bt = gogo->backend()->placeholder_struct_type(this->name(), bt = gogo->backend()->placeholder_struct_type(this->name(),
this->location_); this->location_);
else 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; set_name = false;
break; break;
......
...@@ -861,6 +861,27 @@ class Type ...@@ -861,6 +861,27 @@ class Type
std::string std::string
mangled_name(Gogo*) const; 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. // Get the hash and equality functions for a type.
void void
type_functions(Gogo*, Named_type* name, Function_type* hash_fntype, type_functions(Gogo*, Named_type* name, Function_type* hash_fntype,
...@@ -2013,6 +2034,12 @@ class Struct_type : public Type ...@@ -2013,6 +2034,12 @@ class Struct_type : public Type
traverse_field_types(Traverse* traverse) traverse_field_types(Traverse* traverse)
{ return this->do_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. // Import a struct type.
static Struct_type* static Struct_type*
do_import(Import*); do_import(Import*);
...@@ -2507,8 +2534,9 @@ class Named_type : public Type ...@@ -2507,8 +2534,9 @@ class Named_type : public Type
local_methods_(NULL), all_methods_(NULL), local_methods_(NULL), all_methods_(NULL),
interface_method_tables_(NULL), pointer_interface_method_tables_(NULL), interface_method_tables_(NULL), pointer_interface_method_tables_(NULL),
location_(location), named_btype_(NULL), dependencies_(), location_(location), named_btype_(NULL), dependencies_(),
is_visible_(true), is_error_(false), is_converted_(false), is_visible_(true), is_error_(false), is_placeholder_(false),
is_circular_(false), seen_(false), seen_in_get_backend_(false) is_converted_(false), is_circular_(false), seen_(false),
seen_in_get_backend_(false)
{ } { }
// Return the associated Named_object. This holds the actual name. // Return the associated Named_object. This holds the actual name.
...@@ -2672,6 +2700,13 @@ class Named_type : public Type ...@@ -2672,6 +2700,13 @@ class Named_type : public Type
add_dependency(Named_type* nt) add_dependency(Named_type* nt)
{ this->dependencies_.push_back(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. // Export the type.
void void
export_named_type(Export*, const std::string& name) const; export_named_type(Export*, const std::string& name) const;
...@@ -2766,8 +2801,11 @@ class Named_type : public Type ...@@ -2766,8 +2801,11 @@ class Named_type : public Type
bool is_visible_; bool is_visible_;
// Whether this type is erroneous. // Whether this type is erroneous.
bool is_error_; 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 // Whether this type has been converted to the backend
// representation. // representation. Implies that is_placeholder_ is false.
bool is_converted_; bool is_converted_;
// Whether this is a pointer or function type which refers to the // Whether this is a pointer or function type which refers to the
// type itself. // type itself.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment