diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/go/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/go/go-gcc.cc | 27 | ||||
-rw-r--r-- | gcc/go/gofrontend/backend.h | 24 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 8 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 89 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 20 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 38 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 6 |
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 |