From patchwork Tue Apr 19 21:52:44 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 92058 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 2F0F81007D9 for ; Wed, 20 Apr 2011 07:53:22 +1000 (EST) Received: (qmail 1992 invoked by alias); 19 Apr 2011 21:53:20 -0000 Received: (qmail 1982 invoked by uid 22791); 19 Apr 2011 21:53:19 -0000 X-SWARE-Spam-Status: No, hits=-2.6 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, SPF_HELO_PASS, T_RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (74.125.121.67) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 19 Apr 2011 21:52:50 +0000 Received: from hpaq14.eem.corp.google.com (hpaq14.eem.corp.google.com [172.25.149.14]) by smtp-out.google.com with ESMTP id p3JLqnKV012471 for ; Tue, 19 Apr 2011 14:52:49 -0700 Received: from pzk27 (pzk27.prod.google.com [10.243.19.155]) by hpaq14.eem.corp.google.com with ESMTP id p3JLqkkX018654 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=NOT) for ; Tue, 19 Apr 2011 14:52:47 -0700 Received: by pzk27 with SMTP id 27so92469pzk.13 for ; Tue, 19 Apr 2011 14:52:46 -0700 (PDT) Received: by 10.68.33.42 with SMTP id o10mr9334334pbi.90.1303249966079; Tue, 19 Apr 2011 14:52:46 -0700 (PDT) Received: from coign.google.com (dhcp-172-22-126-213.mtv.corp.google.com [172.22.126.213]) by mx.google.com with ESMTPS id u3sm188092pbh.8.2011.04.19.14.52.45 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 19 Apr 2011 14:52:45 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: Go patch committed: Use backend interface for temporary variables Date: Tue, 19 Apr 2011 14:52:44 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-System-Of-Record: true X-IsSubscribed: yes 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 This patch to the Go frontend uses the backend interface for temporary variables. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline. Ian 2011-04-19 Ian Lance Taylor * go-gcc.cc (Gcc_backend::temporary_variable): New function. Index: gcc/go/go-gcc.cc =================================================================== --- gcc/go/go-gcc.cc (revision 172731) +++ gcc/go/go-gcc.cc (working copy) @@ -255,6 +255,10 @@ class Gcc_backend : public Backend parameter_variable(Bfunction*, const std::string& name, Btype* type, source_location); + Bvariable* + temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool, + source_location, Bstatement**); + // Labels. Blabel* @@ -702,6 +706,68 @@ Gcc_backend::parameter_variable(Bfunctio return new Bvariable(decl); } +// Make a temporary variable. + +Bvariable* +Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, + Btype* btype, Bexpression* binit, + bool is_address_taken, + source_location location, + Bstatement** pstatement) +{ + tree type_tree = btype->get_tree(); + tree init_tree = binit == NULL ? NULL_TREE : binit->get_tree(); + if (type_tree == error_mark_node || init_tree == error_mark_node) + { + *pstatement = this->error_statement(); + return this->error_variable(); + } + + tree var; + // We can only use create_tmp_var if the type is not addressable. + if (!TREE_ADDRESSABLE(type_tree)) + var = create_tmp_var(type_tree, "GOTMP"); + else + { + gcc_assert(bblock != NULL); + var = build_decl(location, VAR_DECL, + create_tmp_var_name("GOTMP"), + type_tree); + DECL_ARTIFICIAL(var) = 1; + DECL_IGNORED_P(var) = 1; + TREE_USED(var) = 1; + // FIXME: Permitting function to be NULL here is a temporary + // measure until we have a proper representation of the init + // function. + if (function != NULL) + DECL_CONTEXT(var) = function->get_tree(); + else + { + gcc_assert(current_function_decl != NULL_TREE); + DECL_CONTEXT(var) = current_function_decl; + } + + // We have to add this variable to the BLOCK and the BIND_EXPR. + tree bind_tree = bblock->get_tree(); + gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR); + tree block_tree = BIND_EXPR_BLOCK(bind_tree); + gcc_assert(TREE_CODE(block_tree) == BLOCK); + DECL_CHAIN(var) = BLOCK_VARS(block_tree); + BLOCK_VARS(block_tree) = var; + BIND_EXPR_VARS(bind_tree) = BLOCK_VARS(block_tree); + } + + if (init_tree != NULL_TREE) + DECL_INITIAL(var) = fold_convert_loc(location, type_tree, init_tree); + + if (is_address_taken) + TREE_ADDRESSABLE(var) = 1; + + *pstatement = this->make_statement(build1_loc(location, DECL_EXPR, + void_type_node, var)); + return new Bvariable(var); +} + // Make a label. Blabel* Index: gcc/go/gofrontend/statements.cc =================================================================== --- gcc/go/gofrontend/statements.cc (revision 172731) +++ gcc/go/gofrontend/statements.cc (working copy) @@ -311,19 +311,6 @@ Temporary_statement::type() const return this->type_ != NULL ? this->type_ : this->init_->type(); } -// Return the tree for the temporary variable. - -tree -Temporary_statement::get_decl() const -{ - if (this->decl_ == NULL) - { - gcc_assert(saw_errors()); - return error_mark_node; - } - return this->decl_; -} - // Traversal. int @@ -400,53 +387,52 @@ Temporary_statement::do_check_types(Gogo tree Temporary_statement::do_get_tree(Translate_context* context) { - gcc_assert(this->decl_ == NULL_TREE); - tree type_tree = this->type()->get_tree(context->gogo()); - tree init_tree = (this->init_ == NULL - ? NULL_TREE - : this->init_->get_tree(context)); - if (type_tree == error_mark_node || init_tree == error_mark_node) + gcc_assert(this->bvariable_ == NULL); + + // FIXME: Permitting FUNCTION to be NULL here is a temporary measure + // until we have a better representation of the init function. + Named_object* function = context->function(); + Bfunction* bfunction; + if (function == NULL) + bfunction = NULL; + else + bfunction = tree_to_function(function->func_value()->get_decl()); + + Btype* btype = tree_to_type(this->type()->get_tree(context->gogo())); + + Bexpression* binit; + if (this->init_ == NULL) + binit = NULL; + else if (this->type_ == NULL) + binit = tree_to_expr(this->init_->get_tree(context)); + else { - this->decl_ = error_mark_node; - return error_mark_node; + Expression* init = Expression::make_cast(this->type_, this->init_, + this->location()); + context->gogo()->lower_expression(context->function(), &init); + binit = tree_to_expr(init->get_tree(context)); } - // We can only use create_tmp_var if the type is not addressable. - if (!TREE_ADDRESSABLE(type_tree)) + + Bstatement* statement; + this->bvariable_ = + context->backend()->temporary_variable(bfunction, context->bblock(), + btype, binit, + this->is_address_taken_, + this->location(), &statement); + return stat_to_tree(statement); +} + +// Return the backend variable. + +Bvariable* +Temporary_statement::get_backend_variable(Translate_context* context) const +{ + if (this->bvariable_ == NULL) { - this->decl_ = create_tmp_var(type_tree, "GOTMP"); - DECL_SOURCE_LOCATION(this->decl_) = this->location(); + gcc_assert(saw_errors()); + return context->backend()->error_variable(); } - else - { - gcc_assert(context->function() != NULL && context->block() != NULL); - tree decl = build_decl(this->location(), VAR_DECL, - create_tmp_var_name("GOTMP"), - type_tree); - DECL_ARTIFICIAL(decl) = 1; - DECL_IGNORED_P(decl) = 1; - TREE_USED(decl) = 1; - gcc_assert(current_function_decl != NULL_TREE); - DECL_CONTEXT(decl) = current_function_decl; - - // We have to add this variable to the BLOCK and the BIND_EXPR. - tree bind_tree = block_to_tree(context->bblock()); - gcc_assert(bind_tree != NULL_TREE && TREE_CODE(bind_tree) == BIND_EXPR); - tree block_tree = BIND_EXPR_BLOCK(bind_tree); - gcc_assert(TREE_CODE(block_tree) == BLOCK); - DECL_CHAIN(decl) = BLOCK_VARS(block_tree); - BLOCK_VARS(block_tree) = decl; - BIND_EXPR_VARS(bind_tree) = BLOCK_VARS(block_tree); - - this->decl_ = decl; - } - if (init_tree != NULL_TREE) - DECL_INITIAL(this->decl_) = - Expression::convert_for_assignment(context, this->type(), - this->init_->type(), init_tree, - this->location()); - if (this->is_address_taken_) - TREE_ADDRESSABLE(this->decl_) = 1; - return this->build_stmt_1(DECL_EXPR, this->decl_); + return this->bvariable_; } // Make and initialize a temporary variable in BLOCK. Index: gcc/go/gofrontend/statements.h =================================================================== --- gcc/go/gofrontend/statements.h (revision 172468) +++ gcc/go/gofrontend/statements.h (working copy) @@ -41,6 +41,7 @@ class Select_clauses; class Typed_identifier_list; class Bexpression; class Bstatement; +class Bvariable; // This class is used to traverse assignments made by a statement // which makes assignments. @@ -475,28 +476,23 @@ class Temporary_statement : public State public: Temporary_statement(Type* type, Expression* init, source_location location) : Statement(STATEMENT_TEMPORARY, location), - type_(type), init_(init), decl_(NULL), is_address_taken_(false) + type_(type), init_(init), bvariable_(NULL), is_address_taken_(false) { } // Return the type of the temporary variable. Type* type() const; - // Return the initialization expression. - Expression* - init() const - { return this->init_; } - // Record that something takes the address of this temporary // variable. void set_is_address_taken() { this->is_address_taken_ = true; } - // Return the tree for the temporary variable itself. This should - // not be called until after the statement itself has been expanded. - tree - get_decl() const; + // Return the temporary variable. This should not be called until + // after the statement itself has been converted. + Bvariable* + get_backend_variable(Translate_context*) const; protected: int @@ -519,8 +515,8 @@ class Temporary_statement : public State Type* type_; // The initial value of the temporary variable. This may be NULL. Expression* init_; - // The DECL for the temporary variable. - tree decl_; + // The backend representation of the temporary variable. + Bvariable* bvariable_; // True if something takes the address of this temporary variable. bool is_address_taken_; }; Index: gcc/go/gofrontend/backend.h =================================================================== --- gcc/go/gofrontend/backend.h (revision 172731) +++ gcc/go/gofrontend/backend.h (working copy) @@ -246,6 +246,22 @@ class Backend parameter_variable(Bfunction* function, const std::string& name, Btype* type, source_location location) = 0; + // Create a temporary variable. A temporary variable has no name, + // just a type. We pass in FUNCTION and BLOCK in case they are + // needed. If INIT is not NULL, the variable should be initialized + // to that value. Otherwise the initial value is irrelevant--the + // backend does not have to explicitly initialize it to zero. + // ADDRESS_IS_TAKEN is true if the programs needs to take the + // address of this temporary variable. LOCATION is the location of + // the statement or expression which requires creating the temporary + // variable, and may not be very useful. This function should + // return a variable which can be referenced later and should set + // *PSTATEMENT to a statement which initializes the variable. + virtual Bvariable* + temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression* init, + bool address_is_taken, source_location location, + Bstatement** pstatement) = 0; + // Labels. // Create a new label. NAME will be empty if this is a label Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 172693) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -1029,9 +1029,22 @@ Temporary_reference_expression::do_addre // Get a tree referring to the variable. tree -Temporary_reference_expression::do_get_tree(Translate_context*) +Temporary_reference_expression::do_get_tree(Translate_context* context) { - return this->statement_->get_decl(); + Bvariable* bvar = this->statement_->get_backend_variable(context); + + // The gcc backend can't represent the same set of recursive types + // that the Go frontend can. In some cases this means that a + // temporary variable won't have the right backend type. Correct + // that here by adding a type cast. We need to use base() to push + // the circularity down one level. + tree ret = var_to_tree(bvar); + if (POINTER_TYPE_P(TREE_TYPE(ret)) && VOID_TYPE_P(TREE_TYPE(TREE_TYPE(ret)))) + { + tree type_tree = this->type()->base()->get_tree(context->gogo()); + ret = fold_convert_loc(this->location(), type_tree, ret); + } + return ret; } // Make a reference to a temporary variable. @@ -8952,7 +8965,7 @@ Call_expression::do_get_tree(Translate_c // This is to support builtin math functions when using 80387 math. tree excess_type = NULL_TREE; - if (DECL_P(fndecl) + if (TREE_CODE(fndecl) == FUNCTION_DECL && DECL_IS_BUILTIN(fndecl) && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL && nargs > 0