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
This commit is contained in:
Chris Manghane 2014-05-06 00:11:29 +00:00 committed by Ian Lance Taylor
parent 3e7b0938f1
commit fb930306ba
5 changed files with 96 additions and 111 deletions

View File

@ -1,3 +1,8 @@
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

View File

@ -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);

View File

@ -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

View File

@ -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));
Expression* array_val =
new Fixed_array_construction_expression(this->valtype_, this->indexes(),
vals, loc);
if (values == error_mark_node)
return error_mark_node;
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"); }

View File

@ -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