diff options
author | Chris Manghane <cmang@google.com> | 2014-05-06 00:11:29 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-05-06 00:11:29 +0000 |
commit | fb930306ba4cbb6fd54d1cbfa013cb6c8f92ad4f (patch) | |
tree | f3a9e000cbf0028296817998178ce156cf0715e6 | |
parent | 3e7b0938f13f937df971a1bc42f1dd32ca8a81bb (diff) | |
download | gcc-fb930306ba4cbb6fd54d1cbfa013cb6c8f92ad4f.tar.gz |
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
-rw-r--r-- | gcc/go/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/go/go-gcc.cc | 15 | ||||
-rw-r--r-- | gcc/go/gofrontend/backend.h | 13 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 158 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 16 |
5 files changed, 96 insertions, 111 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 4e4afdb64ba..8fe468f9b3d 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 343661ec9d2..3d9fc8e369a 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 e49cedf54cc..95f494accfc 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 b1d9bcc9839..9381764e143 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 0936e00bae0..6f03e02a8c6 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 |