From patchwork Tue Jan 9 21:34:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 857789 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-470609-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="AAU9gphh"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zGQQ06X6dz9s9Y for ; Wed, 10 Jan 2018 08:34:16 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=G+mWDIrz4hyNrIOjbBKDKsjMvufh2odRAfE1Rpm2ZOWupl FPJsb6HqDTUTbYZ1uIpLuLRfiSbqWLrMegd7Tlju5xUFDh26cH70BVQ5+ugUFFb4 h4Xnj4kwc0dcP+RuEWJ1lm+PFVVySq9iMZCET7y6NAFuV0zIyCy9pVSd1Vzyo= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=Uz62vPxoMA18Vf70lTYXOPL5MkU=; b=AAU9gphhYKoz6VKEz8xW 7l4YPCdSn+xnbPSm27fT9/wM135m3QUEIolkAzf4ntFaw5+B/VykNUf1HIgPnhz0 SesgyRUeqI3J6eoCkn/ymO6G9yH1d9L7nCPKr1jO3tFhGoDEndqg2vs3OKS9HtyW y8CTKazE3tu38Kk4RIAbJf4= Received: (qmail 69021 invoked by alias); 9 Jan 2018 21:34:09 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 67745 invoked by uid 89); 9 Jan 2018 21:34:08 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-11.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=Statement, no X-HELO: mail-wm0-f67.google.com Received: from mail-wm0-f67.google.com (HELO mail-wm0-f67.google.com) (74.125.82.67) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 09 Jan 2018 21:34:06 +0000 Received: by mail-wm0-f67.google.com with SMTP id b141so23144059wme.1 for ; Tue, 09 Jan 2018 13:34:06 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=d1jZVLuOHSzgLUg6aV/owP7fCv0Bclu0uvbJPs26PkQ=; b=j/nrQy97ocoRNOGYYxdHPSuwNsTtIeUiCsHCtr+FNsxE0njtxIoa3XtJ1lGUv0NQMF pfXmCRYelfw0/lUbKPv4QffNzYcbcqiMLVriMvpXqBgfXr07cT+LO3j8ESZbPzpipdUM SgsBDpAxNNSSxATqDH3gfq9fskB7vp79gAh1zJ/uAdBjch9K7aKs+dTHfevRWfnZUinw KbAjQ5GvZLw8Zdo5h6YDRENDHy4jwEbIvkDiDO3BYys5hPkPcCUwdv0xcQMYRJureSFM oXxRqmHx7O5c9iubu59/B/X0wqCAculoYbGVSivtjh8WurtXAMyEzYJnuvYDdAuz/lm3 i+9A== X-Gm-Message-State: AKwxyteW4bi8RVLTQ54dZKpDVvm1Q8WrKkgT3QUWlOCrQHzgFEVf3zj7 iedLDXQdMdtdv4VLXys4UHj0HJ/XcXRvWzNJ5+m4l3Ki X-Google-Smtp-Source: ACJfBovXvibrpm5ZmFzJzmJocyAmfnvDOSFJg+U97JPaSpZptJNhoQYJQ0N9g6EFwnWw69dF9ayE2Y8qmJqwwGWX+HY= X-Received: by 10.80.168.164 with SMTP id k33mr174353edc.31.1515533644244; Tue, 09 Jan 2018 13:34:04 -0800 (PST) MIME-Version: 1.0 Received: by 10.80.179.221 with HTTP; Tue, 9 Jan 2018 13:34:03 -0800 (PST) From: Ian Lance Taylor Date: Tue, 9 Jan 2018 13:34:03 -0800 Message-ID: Subject: Go patch committed: Make top-level decl for address-taken non-escaping locals To: gcc-patches , gofrontend-dev@googlegroups.com In the Go frontend, if a local variable's address is taken and passed out of its lexical scope, the GCC middle-end may reuse the stack slot for the variable, not knowing it is still live through a pointer. This patch by Cherry Zhang creates 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. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian 2018-01-09 Cherry Zhang * go-gcc.cc (local_variable): Add decl_var parameter. Index: gcc/go/go-gcc.cc =================================================================== --- gcc/go/go-gcc.cc (revision 256366) +++ gcc/go/go-gcc.cc (working copy) @@ -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,7 +2584,7 @@ Gcc_backend::global_variable_set_init(Bv Bvariable* Gcc_backend::local_variable(Bfunction* function, const std::string& name, - Btype* btype, bool is_address_taken, + Btype* btype, Bvariable* decl_var, bool is_address_taken, Location location) { tree type_tree = btype->get_tree(); @@ -2597,6 +2597,11 @@ Gcc_backend::local_variable(Bfunction* f 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); } Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 256389) +++ gcc/go/gofrontend/MERGE (working copy) @@ -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. Index: gcc/go/gofrontend/backend.h =================================================================== --- gcc/go/gofrontend/backend.h (revision 256366) +++ gcc/go/gofrontend/backend.h (working copy) @@ -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 Index: gcc/go/gofrontend/gogo.cc =================================================================== --- gcc/go/gofrontend/gogo.cc (revision 256366) +++ gcc/go/gofrontend/gogo.cc (working copy) @@ -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, Expressio 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* gog 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(Go 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_); } } Index: gcc/go/gofrontend/gogo.h =================================================================== --- gcc/go/gofrontend/gogo.h (revision 256393) +++ gcc/go/gofrontend/gogo.h (working copy) @@ -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