aboutsummaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend/gogo.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go/gofrontend/gogo.cc')
-rw-r--r--gcc/go/gofrontend/gogo.cc89
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()),