diff options
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/go/go-gcc.cc | 11 | ||||
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/backend.h | 17 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 44 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 17 |
6 files changed, 79 insertions, 16 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 4cd75f3..ae6d000 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,5 +1,9 @@ 2018-01-09 Cherry Zhang <cherryyz@google.com> + * go-gcc.cc (local_variable): Add decl_var parameter. + +2018-01-09 Cherry Zhang <cherryyz@google.com> + * lang.opt (fgo-debug-escape-hash): New option. * go-c.h (struct go_create_gogo_args): Add debug_escape_hash field. diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 7c78602..9bc049e 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -426,7 +426,7 @@ class Gcc_backend : public Backend global_variable_set_init(Bvariable*, Bexpression*); Bvariable* - local_variable(Bfunction*, const std::string&, Btype*, bool, + local_variable(Bfunction*, const std::string&, Btype*, Bvariable*, bool, Location); Bvariable* @@ -2584,8 +2584,8 @@ Gcc_backend::global_variable_set_init(Bvariable* var, Bexpression* expr) Bvariable* Gcc_backend::local_variable(Bfunction* function, const std::string& name, - Btype* btype, bool is_address_taken, - Location location) + Btype* btype, Bvariable* decl_var, + bool is_address_taken, Location location) { tree type_tree = btype->get_tree(); if (type_tree == error_mark_node) @@ -2597,6 +2597,11 @@ Gcc_backend::local_variable(Bfunction* function, const std::string& name, TREE_USED(decl) = 1; if (is_address_taken) TREE_ADDRESSABLE(decl) = 1; + if (decl_var != NULL) + { + DECL_HAS_VALUE_EXPR_P(decl) = 1; + SET_DECL_VALUE_EXPR(decl, decl_var->get_decl()); + } go_preserve_from_gc(decl); return new Bvariable(decl); } diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 9ed2078..870348d 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -0445dc01fd75325ff99f839cfaab29cb9f2a1f97 +29e821cf865aa6ee06cee9dae9823295202b1a61 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index 601e7c9..b601105 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -516,15 +516,18 @@ class Backend // Create a local variable. The frontend will create the local // variables first, and then create the block which contains them. // FUNCTION is the function in which the variable is defined. NAME - // is the name of the variable. TYPE is the type. IS_ADDRESS_TAKEN - // is true if the address of this variable is taken (this implies - // that the address does not escape the function, as otherwise the - // variable would be on the heap). LOCATION is where the variable - // is defined. For each local variable the frontend will call - // init_statement to set the initial value. + // is the name of the variable. TYPE is the type. DECL_VAR, if not + // null, gives the location at which the value of this variable may + // be found, typically used to create an inner-scope reference to an + // outer-scope variable, to extend the lifetime of the variable beyond + // the inner scope. IS_ADDRESS_TAKEN is true if the address of this + // variable is taken (this implies that the address does not escape + // the function, as otherwise the variable would be on the heap). + // LOCATION is where the variable is defined. For each local variable + // the frontend will call init_statement to set the initial value. virtual Bvariable* local_variable(Bfunction* function, const std::string& name, Btype* type, - bool is_address_taken, Location location) = 0; + Bvariable* decl_var, bool is_address_taken, Location location) = 0; // Create a function parameter. This is an incoming parameter, not // a result parameter (result parameters are treated as local diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index b1c7807..cdb8b18 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -3876,6 +3876,29 @@ Flatten::variable(Named_object* no) return TRAVERSE_CONTINUE; } + if (!no->var_value()->is_parameter() + && !no->var_value()->is_receiver() + && !no->var_value()->is_closure() + && no->var_value()->is_non_escaping_address_taken() + && !no->var_value()->is_in_heap() + && no->var_value()->toplevel_decl() == NULL) + { + // Local variable that has address taken but not escape. + // It needs to be live beyond its lexical scope. So we + // create a top-level declaration for it. + // No need to do it if it is already in the top level. + Block* top_block = function_->func_value()->block(); + if (top_block->bindings()->lookup_local(no->name()) != no) + { + Variable* var = no->var_value(); + Temporary_statement* ts = + Statement::make_temporary(var->type(), NULL, var->location()); + ts->set_is_address_taken(); + top_block->add_statement_at_front(ts); + var->set_toplevel_decl(ts); + } + } + go_assert(!no->var_value()->has_pre_init()); return TRAVERSE_SKIP_COMPONENTS; @@ -6174,7 +6197,8 @@ Variable::Variable(Type* type, Expression* init, bool is_global, type_from_init_tuple_(false), type_from_range_index_(false), type_from_range_value_(false), type_from_chan_element_(false), is_type_switch_var_(false), determined_type_(false), - in_unique_section_(false), escapes_(true) + in_unique_section_(false), escapes_(true), + toplevel_decl_(NULL) { go_assert(type != NULL || init != NULL); go_assert(!is_parameter || init == NULL); @@ -6751,9 +6775,19 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, is_address_taken, this->location_); else - bvar = backend->local_variable(bfunction, n, btype, - is_address_taken, - this->location_); + { + Bvariable* bvar_decl = NULL; + if (this->toplevel_decl_ != NULL) + { + Translate_context context(gogo, NULL, NULL, NULL); + bvar_decl = this->toplevel_decl_->temporary_statement() + ->get_backend_variable(&context); + } + bvar = backend->local_variable(bfunction, n, btype, + bvar_decl, + is_address_taken, + this->location_); + } } this->backend_ = bvar; } @@ -6785,7 +6819,7 @@ Result_variable::get_backend_variable(Gogo* gogo, Named_object* function, bool is_address_taken = (this->is_non_escaping_address_taken_ && !this->is_in_heap()); this->backend_ = backend->local_variable(bfunction, n, btype, - is_address_taken, + NULL, is_address_taken, this->location_); } } diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index ed044d4..6576272 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -1884,6 +1884,20 @@ class Variable this->in_unique_section_ = true; } + // Return the top-level declaration for this variable. + Statement* + toplevel_decl() + { return this->toplevel_decl_; } + + // Set the top-level declaration for this variable. Only used for local + // variables + void + set_toplevel_decl(Statement* s) + { + go_assert(!this->is_global_ && !this->is_parameter_ && !this->is_receiver_); + this->toplevel_decl_ = s; + } + // Traverse the initializer expression. int traverse_expression(Traverse*, unsigned int traverse_mask); @@ -1984,6 +1998,9 @@ class Variable // Whether this variable escapes the function it is created in. This is // true until shown otherwise. bool escapes_ : 1; + // The top-level declaration for this variable. Only used for local + // variables. Must be a Temporary_statement if not NULL. + Statement* toplevel_decl_; }; // A variable which is really the name for a function return value, or |