diff options
author | Cherry Zhang <cherryyz@google.com> | 2018-01-09 21:33:59 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2018-01-09 21:33:59 +0000 |
commit | 81e0f09288052014c5fb3136e6abc9dfcc7629db (patch) | |
tree | d85e4d07a55f301cdce0f9af88f503c2cc802899 /gcc/go/gofrontend/gogo.cc | |
parent | 6ef72c3661318d0b5d7e3fc8821d136bbba37194 (diff) | |
download | gcc-81e0f09288052014c5fb3136e6abc9dfcc7629db.zip gcc-81e0f09288052014c5fb3136e6abc9dfcc7629db.tar.gz gcc-81e0f09288052014c5fb3136e6abc9dfcc7629db.tar.bz2 |
compiler: make top-level decl for address-taken non-escaping locals
If a local variable's address is taken and passed out of its
lexical scope, GCC backend may reuse the stack slot for the
variable, not knowing it is still live through a pointer. In
this case, we create a top-level temporary variable and let the
user-defined variable refer to the temporary variable as its
storage location. As the temporary variable is declared at the
top level, its stack slot will remain live throughout the
function.
Reviewed-on: https://go-review.googlesource.com/84675
* go-gcc.cc (local_variable): Add decl_var parameter.
From-SVN: r256398
Diffstat (limited to 'gcc/go/gofrontend/gogo.cc')
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 44 |
1 files changed, 39 insertions, 5 deletions
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_); } } |