aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorChris Manghane <cmang@google.com>2014-05-06 00:11:29 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2014-05-06 00:11:29 +0000
commitfb930306ba4cbb6fd54d1cbfa013cb6c8f92ad4f (patch)
treef3a9e000cbf0028296817998178ce156cf0715e6 /gcc
parent3e7b0938f13f937df971a1bc42f1dd32ca8a81bb (diff)
downloadgcc-fb930306ba4cbb6fd54d1cbfa013cb6c8f92ad4f.zip
gcc-fb930306ba4cbb6fd54d1cbfa013cb6c8f92ad4f.tar.gz
gcc-fb930306ba4cbb6fd54d1cbfa013cb6c8f92ad4f.tar.bz2
compiler: Use backend interface for slice construction.
* go-gcc.cc (Gcc_backend::implicit_variable): Rename from gc_root_variable. Add name and is_constant parameters. From-SVN: r210088
Diffstat (limited to 'gcc')
-rw-r--r--gcc/go/ChangeLog5
-rw-r--r--gcc/go/go-gcc.cc15
-rw-r--r--gcc/go/gofrontend/backend.h13
-rw-r--r--gcc/go/gofrontend/expressions.cc158
-rw-r--r--gcc/go/gofrontend/expressions.h16
5 files changed, 96 insertions, 111 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index 4e4afdb..8fe468f 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,5 +1,10 @@
2014-05-05 Chris Manghane <cmang@google.com>
+ * go-gcc.cc (Gcc_backend::implicit_variable): Rename from
+ gc_root_variable. Add name and is_constant parameters.
+
+2014-05-05 Chris Manghane <cmang@google.com>
+
* go-gcc.cc (Gcc_backend::indirect_expression): Add btype
parameter.
(Gcc_backend::temporary_variable): Check for erroneous function.
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index 343661e..3d9fc8e 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -381,7 +381,7 @@ class Gcc_backend : public Backend
Location, Bstatement**);
Bvariable*
- gc_root_variable(Btype*, Bexpression*);
+ implicit_variable(const std::string&, Btype*, Bexpression*, bool);
Bvariable*
immutable_struct(const std::string&, bool, bool, Btype*, Location);
@@ -2476,10 +2476,12 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
return new Bvariable(var);
}
-// Make a GC root variable.
+// Create an implicit variable that is compiler-defined. This is used when
+// generating GC root variables and storing the values of a slice initializer.
Bvariable*
-Gcc_backend::gc_root_variable(Btype* type, Bexpression* init)
+Gcc_backend::implicit_variable(const std::string& name, Btype* type,
+ Bexpression* init, bool is_constant)
{
tree type_tree = type->get_tree();
tree init_tree = init->get_tree();
@@ -2487,11 +2489,16 @@ Gcc_backend::gc_root_variable(Btype* type, Bexpression* init)
return this->error_variable();
tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
- create_tmp_var_name("gc"), type_tree);
+ get_identifier_from_string(name), type_tree);
DECL_EXTERNAL(decl) = 0;
TREE_PUBLIC(decl) = 0;
TREE_STATIC(decl) = 1;
DECL_ARTIFICIAL(decl) = 1;
+ if (is_constant)
+ {
+ TREE_READONLY(decl) = 1;
+ TREE_CONSTANT(decl) = 1;
+ }
DECL_INITIAL(decl) = init_tree;
rest_of_decl_compilation(decl, 1, 0);
diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h
index e49cedf..95f494a 100644
--- a/gcc/go/gofrontend/backend.h
+++ b/gcc/go/gofrontend/backend.h
@@ -536,11 +536,16 @@ class Backend
bool address_is_taken, Location location,
Bstatement** pstatement) = 0;
- // Create a GC root variable. TYPE is the __go_gc_root_list struct described
- // in Gogo::register_gc_vars. INIT is the composite literal consisting of a
- // pointer to the next GC root and the global variables registered.
+ // 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.
virtual Bvariable*
- gc_root_variable(Btype* type, Bexpression* init) = 0;
+ implicit_variable(const std::string& name, Btype* type, Bexpression* init,
+ bool is_constant) = 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 b1d9bcc..9381764 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -4113,20 +4113,47 @@ Unary_expression::do_get_tree(Translate_context* context)
}
}
- if (this->is_gc_root_)
+ static unsigned int counter;
+ char buf[100];
+ if (this->is_gc_root_ || this->is_slice_init_)
{
- // Build a decl for a GC root variable. GC roots are mutable, so they
- // cannot be represented as an immutable_struct in the backend.
- Bvariable* gc_root = gogo->backend()->gc_root_variable(btype, bexpr);
- bexpr = gogo->backend()->var_expression(gc_root, loc);
+ bool copy_to_heap = false;
+ if (this->is_gc_root_)
+ {
+ // Build a decl for a GC root variable. GC roots are mutable, so
+ // they cannot be represented as an immutable_struct in the
+ // backend.
+ static unsigned int root_counter;
+ snprintf(buf, sizeof buf, "gc%u", root_counter);
+ ++root_counter;
+ }
+ else
+ {
+ // Build a decl for a slice value initializer. An immutable slice
+ // value initializer may have to be copied to the heap if it
+ // contains pointers in a non-constant context.
+ snprintf(buf, sizeof buf, "C%u", counter);
+ ++counter;
+
+ Array_type* at = this->expr_->type()->array_type();
+ go_assert(at != NULL);
+
+ // If we are not copying the value to the heap, we will only
+ // initialize the value once, so we can use this directly
+ // rather than copying it. In that case we can't make it
+ // read-only, because the program is permitted to change it.
+ copy_to_heap = (at->element_type()->has_pointer()
+ && !context->is_const());
+ }
+ Bvariable* implicit =
+ gogo->backend()->implicit_variable(buf, btype, bexpr, copy_to_heap);
+ bexpr = gogo->backend()->var_expression(implicit, loc);
}
else if ((this->expr_->is_composite_literal()
|| this->expr_->string_expression() != NULL)
&& this->expr_->is_immutable())
{
// Build a decl for a constant constructor.
- static unsigned int counter;
- char buf[100];
snprintf(buf, sizeof buf, "C%u", counter);
++counter;
@@ -12450,6 +12477,7 @@ Slice_construction_expression::do_get_tree(Translate_context* context)
return error_mark_node;
}
+ Location loc = this->location();
Type* element_type = array_type->element_type();
if (this->valtype_ == NULL)
{
@@ -12464,35 +12492,24 @@ Slice_construction_expression::do_get_tree(Translate_context* context)
else
mpz_init_set_ui(lenval, this->indexes()->back() + 1);
}
- Location loc = this->location();
Type* int_type = Type::lookup_integer_type("int");
length = Expression::make_integer(&lenval, int_type, loc);
mpz_clear(lenval);
this->valtype_ = Type::make_array_type(element_type, length);
}
- tree values;
- Gogo* gogo = context->gogo();
- Btype* val_btype = this->valtype_->get_backend(gogo);
+ Expression_list* vals = this->vals();
if (this->vals() == NULL || this->vals()->empty())
{
- // We need to create a unique value.
- Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo);
- Bexpression* zero = gogo->backend()->zero_expression(int_btype);
- std::vector<unsigned long> index(1, 0);
- std::vector<Bexpression*> val(1, zero);
- Bexpression* ctor =
- gogo->backend()->array_constructor_expression(val_btype, index, val,
- this->location());
- values = expr_to_tree(ctor);
+ // We need to create a unique value for the empty array literal.
+ vals = new Expression_list;
+ vals->push_back(NULL);
}
- else
- values = expr_to_tree(this->get_constructor(context, val_btype));
-
- if (values == error_mark_node)
- return error_mark_node;
+ Expression* array_val =
+ new Fixed_array_construction_expression(this->valtype_, this->indexes(),
+ vals, loc);
- bool is_constant_initializer = TREE_CONSTANT(values);
+ bool is_constant_initializer = array_val->is_immutable();
// We have to copy the initial values into heap memory if we are in
// a function or if the values are not constants. We also have to
@@ -12503,89 +12520,22 @@ Slice_construction_expression::do_get_tree(Translate_context* context)
|| (element_type->has_pointer()
&& !context->is_const()));
- if (is_constant_initializer)
- {
- tree tmp = build_decl(this->location().gcc_location(), VAR_DECL,
- create_tmp_var_name("C"), TREE_TYPE(values));
- DECL_EXTERNAL(tmp) = 0;
- TREE_PUBLIC(tmp) = 0;
- TREE_STATIC(tmp) = 1;
- DECL_ARTIFICIAL(tmp) = 1;
- if (copy_to_heap)
- {
- // If we are not copying the value to the heap, we will only
- // initialize the value once, so we can use this directly
- // rather than copying it. In that case we can't make it
- // read-only, because the program is permitted to change it.
- TREE_READONLY(tmp) = 1;
- TREE_CONSTANT(tmp) = 1;
- }
- DECL_INITIAL(tmp) = values;
- rest_of_decl_compilation(tmp, 1, 0);
- values = tmp;
- }
-
- tree space;
- tree set;
+ Expression* space;
if (!copy_to_heap)
{
- // the initializer will only run once.
- space = build_fold_addr_expr(values);
- set = NULL_TREE;
+ // The initializer will only run once.
+ space = Expression::make_unary(OPERATOR_AND, array_val, loc);
+ space->unary_expression()->set_is_slice_init();
}
else
- {
- Expression* alloc =
- context->gogo()->allocate_memory(this->valtype_, this->location());
- space = save_expr(alloc->get_tree(context));
-
- tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space);
- tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(),
- s);
- TREE_THIS_NOTRAP(ref) = 1;
- set = build2(MODIFY_EXPR, void_type_node, ref, values);
- }
+ space = Expression::make_heap_expression(array_val, loc);
// Build a constructor for the slice.
- tree type_tree = type_to_tree(this->type()->get_backend(context->gogo()));
- if (type_tree == error_mark_node)
- return error_mark_node;
- go_assert(TREE_CODE(type_tree) == RECORD_TYPE);
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 3);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(type_tree);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), space);
-
- tree length_tree = this->valtype_->array_type()->length()->get_tree(context);
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), length_tree);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)),"__capacity") == 0);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), length_tree);
-
- tree constructor = build_constructor(type_tree, init);
- if (constructor == error_mark_node)
- return error_mark_node;
- if (!copy_to_heap)
- TREE_CONSTANT(constructor) = 1;
-
- if (set == NULL_TREE)
- return constructor;
- else
- return build2(COMPOUND_EXPR, type_tree, set, constructor);
+ Expression* len = this->valtype_->array_type()->length();
+ Expression* slice_val =
+ Expression::make_slice_value(this->type(), space, len, len, loc);
+ return slice_val->get_tree(context);
}
// Make a slice composite literal. This is used by the type
@@ -14802,6 +14752,10 @@ class Struct_field_offset_expression : public Expression
{ }
protected:
+ bool
+ do_is_immutable() const
+ { return true; }
+
Type*
do_type()
{ return Type::lookup_integer_type("uintptr"); }
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 0936e00..6f03e02 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -1305,7 +1305,7 @@ class Unary_expression : public Expression
Unary_expression(Operator op, Expression* expr, Location location)
: Expression(EXPRESSION_UNARY, location),
op_(op), escapes_(true), create_temp_(false), is_gc_root_(false),
- expr_(expr), issue_nil_check_(false)
+ is_slice_init_(false), expr_(expr), issue_nil_check_(false)
{ }
// Return the operator.
@@ -1344,6 +1344,15 @@ class Unary_expression : public Expression
this->is_gc_root_ = true;
}
+ // Record that this is an address expression of a slice value initializer,
+ // which is mutable if the values are not copied to the heap.
+ void
+ set_is_slice_init()
+ {
+ go_assert(this->op_ == OPERATOR_AND);
+ this->is_slice_init_ = true;
+ }
+
// Apply unary opcode OP to UNC, setting NC. Return true if this
// could be done, false if not. Issue errors for overflow.
static bool
@@ -1427,6 +1436,11 @@ class Unary_expression : public Expression
// special struct composite literal that is mutable when addressed, meaning
// it cannot be represented as an immutable_struct in the backend.
bool is_gc_root_;
+ // True if this is an address expression for a slice value with an immutable
+ // initializer. The initializer for a slice's value pointer has an array
+ // type, meaning it cannot be represented as an immutable_struct in the
+ // backend.
+ bool is_slice_init_;
// The operand.
Expression* expr_;
// Whether or not to issue a nil check for this expression if its address