diff options
Diffstat (limited to 'gcc/go/gofrontend/gogo.cc')
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 89 |
1 files changed, 88 insertions, 1 deletions
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()), |