aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/ChangeLog5
-rw-r--r--gcc/go/go-gcc.cc27
-rw-r--r--gcc/go/gofrontend/backend.h24
-rw-r--r--gcc/go/gofrontend/expressions.cc8
-rw-r--r--gcc/go/gofrontend/gogo.cc89
-rw-r--r--gcc/go/gofrontend/gogo.h20
-rw-r--r--gcc/go/gofrontend/types.cc38
-rw-r--r--gcc/go/gofrontend/types.h6
8 files changed, 183 insertions, 34 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index d66b753..7cab856 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,8 @@
+2014-06-04 Ian Lance Taylor <iant@google.com>
+
+ * go-gcc.cc (Gcc_backend::implicit_variable): Add is_common and
+ alignment parameters. Permit init parameter to be NULL.
+
2014-06-02 Andrew MacLeod <amacleod@redhat.com>
* go-gcc.cc: Include builtins.h.
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 5b95e5d..df4b670 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -389,7 +389,8 @@ class Gcc_backend : public Backend
Location, Bstatement**);
Bvariable*
- implicit_variable(const std::string&, Btype*, Bexpression*, bool);
+ implicit_variable(const std::string&, Btype*, Bexpression*, bool, bool,
+ size_t);
Bvariable*
immutable_struct(const std::string&, bool, bool, Btype*, Location);
@@ -2497,10 +2498,15 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
Bvariable*
Gcc_backend::implicit_variable(const std::string& name, Btype* type,
- Bexpression* init, bool is_constant)
+ Bexpression* init, bool is_constant,
+ bool is_common, size_t alignment)
{
tree type_tree = type->get_tree();
- tree init_tree = init->get_tree();
+ tree init_tree;
+ if (init == NULL)
+ init_tree = NULL_TREE;
+ else
+ init_tree = init->get_tree();
if (type_tree == error_mark_node || init_tree == error_mark_node)
return this->error_variable();
@@ -2510,12 +2516,25 @@ Gcc_backend::implicit_variable(const std::string& name, Btype* type,
TREE_PUBLIC(decl) = 0;
TREE_STATIC(decl) = 1;
DECL_ARTIFICIAL(decl) = 1;
- if (is_constant)
+ if (is_common)
+ {
+ DECL_COMMON(decl) = 1;
+ TREE_PUBLIC(decl) = 1;
+ gcc_assert(init_tree == NULL_TREE);
+ }
+ else if (is_constant)
{
TREE_READONLY(decl) = 1;
TREE_CONSTANT(decl) = 1;
}
DECL_INITIAL(decl) = init_tree;
+
+ if (alignment != 0)
+ {
+ DECL_ALIGN(decl) = alignment * BITS_PER_UNIT;
+ DECL_USER_ALIGN(decl) = 1;
+ }
+
rest_of_decl_compilation(decl, 1, 0);
return new Bvariable(decl);
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index fdcfd28..323ac2e 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/gcc/go/gofrontend/backend.h
@@ -544,16 +544,24 @@ class Backend
bool address_is_taken, Location location,
Bstatement** pstatement) = 0;
- // Create an implicit variable that is compiler-defined. This is used when
- // generating GC root variables and storing the values of a slice constructor.
- // NAME is the name of the variable, either gc# for GC roots or C# for slice
- // initializers. TYPE is the type of the implicit variable with an initial
- // value INIT. IS_CONSTANT is true if the implicit variable should be treated
- // like it is immutable. For slice initializers, if the values must be copied
- // to the heap, the variable IS_CONSTANT.
+ // Create an implicit variable that is compiler-defined. This is
+ // used when generating GC root variables, when storing the values
+ // of a slice constructor, and for the zero value of types. NAME is
+ // the name of the variable, either gc# for GC roots or C# for slice
+ // initializers. TYPE is the type of the implicit variable with an
+ // initial value INIT. IS_CONSTANT is true if the implicit variable
+ // should be treated like it is immutable. For slice initializers,
+ // if the values must be copied to the heap, the variable
+ // IS_CONSTANT. IS_COMMON is true if the implicit variable should
+ // be treated as a common variable (multiple definitions with
+ // different sizes permitted in different object files, all merged
+ // into the largest definition at link time); this will be true for
+ // the zero value. If IS_COMMON is true, INIT will be NULL, and the
+ // variable should be initialized to all zeros. If ALIGNMENT is not
+ // zero, it is the desired alignment of the variable.
virtual Bvariable*
implicit_variable(const std::string& name, Btype* type, Bexpression* init,
- bool is_constant) = 0;
+ bool is_constant, bool is_common, size_t alignment) = 0;
// Create a named immutable initialized data structure. This is
// used for type descriptors, map descriptors, and function
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 6c9bdac..c481bc5 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -4105,7 +4105,8 @@ Unary_expression::do_get_backend(Translate_context* context)
&& !context->is_const());
}
Bvariable* implicit =
- gogo->backend()->implicit_variable(buf, btype, bexpr, copy_to_heap);
+ gogo->backend()->implicit_variable(buf, btype, bexpr, copy_to_heap,
+ false, 0);
bexpr = gogo->backend()->var_expression(implicit, loc);
}
else if ((this->expr_->is_composite_literal()
@@ -7598,7 +7599,7 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
if (this->seen_)
return false;
- unsigned int ret;
+ unsigned long ret;
if (this->code_ == BUILTIN_SIZEOF)
{
this->seen_ = true;
@@ -7626,8 +7627,7 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
else
go_unreachable();
- nc->set_unsigned_long(Type::lookup_integer_type("uintptr"),
- static_cast<unsigned long>(ret));
+ nc->set_unsigned_long(Type::lookup_integer_type("uintptr"), ret);
return true;
}
else if (this->code_ == BUILTIN_OFFSETOF)
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 0852186..b9c8fa9 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -41,6 +41,9 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
pkgpath_(),
pkgpath_symbol_(),
prefix_(),
+ zero_value_(NULL),
+ zero_value_size_(0),
+ zero_value_align_(0),
pkgpath_set_(false),
pkgpath_from_option_(false),
prefix_from_option_(false),
@@ -575,6 +578,88 @@ Gogo::current_bindings() const
return this->globals_;
}
+// Return the special variable used as the zero value of types.
+
+Named_object*
+Gogo::zero_value(Type *type)
+{
+ if (this->zero_value_ == NULL)
+ {
+ Location bloc = Linemap::predeclared_location();
+
+ // We will change the type later, when we know the size.
+ Type* byte_type = this->lookup_global("byte")->type_value();
+
+ mpz_t val;
+ mpz_init_set_ui(val, 0);
+ Expression* zero = Expression::make_integer(&val, NULL, bloc);
+ mpz_clear(val);
+
+ Type* array_type = Type::make_array_type(byte_type, zero);
+
+ Variable* var = new Variable(array_type, NULL, true, false, false, bloc);
+ this->zero_value_ = Named_object::make_variable("go$zerovalue", NULL,
+ var);
+ }
+
+ // The zero value will be the maximum required size.
+ unsigned long size;
+ bool ok = type->backend_type_size(this, &size);
+ if (!ok) {
+ go_assert(saw_errors());
+ size = 4;
+ }
+ if (size > this->zero_value_size_)
+ this->zero_value_size_ = size;
+
+ unsigned long align;
+ ok = type->backend_type_align(this, &align);
+ if (!ok) {
+ go_assert(saw_errors());
+ align = 4;
+ }
+ if (align > this->zero_value_align_)
+ this->zero_value_align_ = align;
+
+ return this->zero_value_;
+}
+
+// Return whether V is the zero value variable.
+
+bool
+Gogo::is_zero_value(Variable* v) const
+{
+ return this->zero_value_ != NULL && this->zero_value_->var_value() == v;
+}
+
+// Return the backend variable for the special zero value, or NULL if
+// it is not needed.
+
+Bvariable*
+Gogo::backend_zero_value()
+{
+ if (this->zero_value_ == NULL)
+ return NULL;
+
+ Type* byte_type = this->lookup_global("byte")->type_value();
+ Btype* bbtype_type = byte_type->get_backend(this);
+
+ Type* int_type = this->lookup_global("int")->type_value();
+ Btype* bint_type = int_type->get_backend(this);
+
+ mpz_t val;
+ mpz_init_set_ui(val, this->zero_value_size_);
+ Bexpression* blength =
+ this->backend()->integer_constant_expression(bint_type, val);
+ mpz_clear(val);
+
+ Btype* barray_type = this->backend()->array_type(bbtype_type, blength);
+
+ return this->backend()->implicit_variable(this->zero_value_->name(),
+ barray_type, NULL, true, true,
+ this->zero_value_align_);
+}
+
// Add statements to INIT_STMTS which run the initialization
// functions for imported packages. This is only used for the "main"
// package.
@@ -6078,7 +6163,9 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function,
Btype* btype = type->get_backend(gogo);
Bvariable* bvar;
- if (this->is_global_)
+ if (gogo->is_zero_value(this))
+ bvar = gogo->backend_zero_value();
+ else if (this->is_global_)
bvar = backend->global_variable((package == NULL
? gogo->package_name()
: package->package_name()),
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index b2076d7..700b092 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -591,6 +591,20 @@ class Gogo
named_types_are_converted() const
{ return this->named_types_are_converted_; }
+ // Return the variable to use for the zero value of TYPE. All types
+ // shared the same zero value, and we make sure that it is large
+ // enough.
+ Named_object*
+ zero_value(Type *type);
+
+ // Return whether a variable is the zero value variable.
+ bool
+ is_zero_value(Variable* v) const;
+
+ // Create the zero value variable.
+ Bvariable*
+ backend_zero_value();
+
// Write out the global values.
void
write_globals();
@@ -727,6 +741,12 @@ class Gogo
std::string pkgpath_symbol_;
// The prefix to use for symbols, from the -fgo-prefix option.
std::string prefix_;
+ // The special zero value variable.
+ Named_object* zero_value_;
+ // The size of the zero value variable.
+ unsigned long zero_value_size_;
+ // The alignment of the zero value variable, in bytes.
+ unsigned long zero_value_align_;
// Whether pkgpath_ has been set.
bool pkgpath_set_;
// Whether an explicit package path was set by -fgo-pkgpath.
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index c36979f..eba224b 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -1519,7 +1519,7 @@ Type::make_type_descriptor_type()
// The type descriptor type.
Struct_type* type_descriptor_type =
- Type::make_builtin_struct_type(10,
+ Type::make_builtin_struct_type(11,
"Kind", uint8_type,
"align", uint8_type,
"fieldAlign", uint8_type,
@@ -1530,7 +1530,8 @@ Type::make_type_descriptor_type()
"string", pointer_string_type,
"", pointer_uncommon_type,
"ptrToThis",
- pointer_type_descriptor_type);
+ pointer_type_descriptor_type,
+ "zero", unsafe_pointer_type);
Named_type* named = Type::make_builtin_named_type("commonType",
type_descriptor_type);
@@ -2050,6 +2051,15 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
}
++p;
+ go_assert(p->is_field_name("zero"));
+ Expression* z = Expression::make_var_reference(gogo->zero_value(this), bloc);
+ z = Expression::make_unary(OPERATOR_AND, z, bloc);
+ Type* void_type = Type::make_void_type();
+ Type* unsafe_pointer_type = Type::make_pointer_type(void_type);
+ z = Expression::make_cast(unsafe_pointer_type, z, bloc);
+ vals->push_back(z);
+
+ ++p;
go_assert(p == fields->end());
mpz_clear(iv);
@@ -2382,13 +2392,13 @@ Type::is_backend_type_size_known(Gogo* gogo)
// the backend.
bool
-Type::backend_type_size(Gogo* gogo, unsigned int *psize)
+Type::backend_type_size(Gogo* gogo, unsigned long *psize)
{
if (!this->is_backend_type_size_known(gogo))
return false;
Btype* bt = this->get_backend_placeholder(gogo);
size_t size = gogo->backend()->type_size(bt);
- *psize = static_cast<unsigned int>(size);
+ *psize = static_cast<unsigned long>(size);
if (*psize != size)
return false;
return true;
@@ -2398,13 +2408,13 @@ Type::backend_type_size(Gogo* gogo, unsigned int *psize)
// the alignment in bytes and return true. Otherwise, return false.
bool
-Type::backend_type_align(Gogo* gogo, unsigned int *palign)
+Type::backend_type_align(Gogo* gogo, unsigned long *palign)
{
if (!this->is_backend_type_size_known(gogo))
return false;
Btype* bt = this->get_backend_placeholder(gogo);
size_t align = gogo->backend()->type_alignment(bt);
- *palign = static_cast<unsigned int>(align);
+ *palign = static_cast<unsigned long>(align);
if (*palign != align)
return false;
return true;
@@ -2414,13 +2424,13 @@ Type::backend_type_align(Gogo* gogo, unsigned int *palign)
// field.
bool
-Type::backend_type_field_align(Gogo* gogo, unsigned int *palign)
+Type::backend_type_field_align(Gogo* gogo, unsigned long *palign)
{
if (!this->is_backend_type_size_known(gogo))
return false;
Btype* bt = this->get_backend_placeholder(gogo);
size_t a = gogo->backend()->type_field_alignment(bt);
- *palign = static_cast<unsigned int>(a);
+ *palign = static_cast<unsigned long>(a);
if (*palign != a)
return false;
return true;
@@ -4595,7 +4605,7 @@ Struct_type::do_compare_is_identity(Gogo* gogo)
const Struct_field_list* fields = this->fields_;
if (fields == NULL)
return true;
- unsigned int offset = 0;
+ unsigned long offset = 0;
for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end();
++pf)
@@ -4606,7 +4616,7 @@ Struct_type::do_compare_is_identity(Gogo* gogo)
if (!pf->type()->compare_is_identity(gogo))
return false;
- unsigned int field_align;
+ unsigned long field_align;
if (!pf->type()->backend_type_align(gogo, &field_align))
return false;
if ((offset & (field_align - 1)) != 0)
@@ -4617,13 +4627,13 @@ Struct_type::do_compare_is_identity(Gogo* gogo)
return false;
}
- unsigned int field_size;
+ unsigned long field_size;
if (!pf->type()->backend_type_size(gogo, &field_size))
return false;
offset += field_size;
}
- unsigned int struct_size;
+ unsigned long struct_size;
if (!this->backend_type_size(gogo, &struct_size))
return false;
if (offset != struct_size)
@@ -5620,8 +5630,8 @@ Array_type::do_compare_is_identity(Gogo* gogo)
return false;
// If there is any padding, then we can't use memcmp.
- unsigned int size;
- unsigned int align;
+ unsigned long size;
+ unsigned long align;
if (!this->element_type_->backend_type_size(gogo, &size)
|| !this->element_type_->backend_type_align(gogo, &align))
return false;
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index 09e2155..6fa6513 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -925,18 +925,18 @@ class Type
// in bytes and return true. Otherwise, return false. This queries
// the backend.
bool
- backend_type_size(Gogo*, unsigned int* psize);
+ backend_type_size(Gogo*, unsigned long* 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);
+ backend_type_align(Gogo*, unsigned long* 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);
+ backend_type_field_align(Gogo*, unsigned long* palign);
// Whether the backend size is known.
bool