From patchwork Fri Jan 24 22:49:08 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 314098 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 388CF2C009C for ; Sat, 25 Jan 2014 09:49:27 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:mime-version:content-type; q=dns; s= default; b=xL9KLCu52Fn9bJ/2rwlvLEYobkS1XI+a86QSVOOYCgKx0ci0AbCkK 4YQl5ykXsa5rtXLRXLdXgGzUJn/d/PO8NAdBST44Nq2oUc7ooJ74Pu9FZBqkJs0U his3Qj9/1jRf/6ESCN/iXarKuWEarPICFy6FTwzvJJMdIo5KgSYHdw= 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:from :to:subject:date:message-id:mime-version:content-type; s= default; bh=pg/nvcueoC7tmjf1Qr+Vy3S29wE=; b=LEcrICPTT3EpjIbFC4oD /7ioEvDZmdOLwVhkFXcKyVT0rMgVaDMUa6X0GJp61OhZm/z1gr6PsavjdwyEUytr mrrrS0PPzMNYICCpoOs2AV0ltDkw3yFCvk3lHrATMTWrX77g8SHaAY3kIHCpYK8K 3qiBpXZyYUdP1VZngZw0XAU= Received: (qmail 21276 invoked by alias); 24 Jan 2014 22:49:20 -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 21266 invoked by uid 89); 24 Jan 2014 22:49:19 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD, SPF_PASS, T_TVD_MIME_NO_HEADERS autolearn=ham version=3.3.2 X-HELO: mail-bk0-f41.google.com Received: from mail-bk0-f41.google.com (HELO mail-bk0-f41.google.com) (209.85.214.41) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Fri, 24 Jan 2014 22:49:17 +0000 Received: by mail-bk0-f41.google.com with SMTP id na10so1570307bkb.14 for ; Fri, 24 Jan 2014 14:49:13 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:user-agent :mime-version:content-type; bh=RYG06beYmA/JBfkGUmvk9c3cAlYZAvyorQcscIOqgEw=; b=WP8lOefCWnm9xwSggrHW7VhXiCt746C35ZpyVN9ECR03z+KJZWhkLtkbigjzfjZ6Pk oa/KrCsJjX/y4mEDfFzNmm61I7PxbbJLAWmOpCYhXrinrSBK+DJszPavb5KMeNxy52Sr Mwu0Ax4U+CxNsAJKwT86vlEIzSeo0Q5+ZHAWIrTxUSZo3KN96wKwFJ6IdVYlB4e4605N dYktj94SM92ast93WoTXSAZ9ESU18V4bstFz4drdCLv4oa1FAqDPT3nq0elv/Valvf5q AvtND9x9EZ8HsUA2pm1Y4guuxvccnk6LueEFvkiwuzfnrZtNxnysye/1R2aC0c1crGU1 rsWw== X-Gm-Message-State: ALoCoQkxwhSFGgyqEeb54mix66l9dWoZIdViicrOiAyB/PYeimcgV7gJfX4z5kcU72kiEIay8LRKEZ7MYqtzEakCXF2iFSFE6znd6uPRV9o+vAVIdHeIocybJDZbhXU2CsO11wHsZ5ECYS45cp8uhWT5SMhw7y8VDvQbsgVop167ErOsIqm+oSgQSv19u8FQWXiWDEE8KG+R8y253ae1exQMtwcinhSv/A== X-Received: by 10.204.122.1 with SMTP id j1mr7750567bkr.57.1390603753703; Fri, 24 Jan 2014 14:49:13 -0800 (PST) Received: from iant-glaptop.roam.corp.google.com.google.com ([2620:0:1000:3204:5d40:42b5:5c44:88d8]) by mx.google.com with ESMTPSA id dg4sm4155434bkc.10.2014.01.24.14.49.10 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 24 Jan 2014 14:49:12 -0800 (PST) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: Go patch committed: Use backend interface for unary expressions Date: Fri, 24 Jan 2014 14:49:08 -0800 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux) MIME-Version: 1.0 X-IsSubscribed: yes This patch from Chris Manghane changes the Go frontend to use the backend interface for unary expressions. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline. Ian 2014-01-24 Chris Manghane * go-gcc.cc (Gcc_backend::unary_expression): New function. Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 206904) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -1464,6 +1464,10 @@ class Func_code_reference_expression : p do_traverse(Traverse*) { return TRAVERSE_CONTINUE; } + bool + do_is_immutable() const + { return true; } + Type* do_type() { return Type::make_pointer_type(Type::make_void_type()); } @@ -2941,6 +2945,10 @@ class Nil_expression : public Expression do_is_constant() const { return true; } + bool + do_is_immutable() const + { return true; } + Type* do_type() { return Type::make_nil_type(); } @@ -3682,10 +3690,17 @@ class Unary_expression : public Expressi Expression* do_lower(Gogo*, Named_object*, Statement_inserter*, int); + Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*); + bool do_is_constant() const; bool + do_is_immutable() const + { return this->expr_->is_immutable(); } + + bool do_numeric_constant_value(Numeric_constant*) const; Type* @@ -3806,6 +3821,45 @@ Unary_expression::do_lower(Gogo*, Named_ return this; } +// Flatten expression if a nil check must be performed and create temporary +// variables if necessary. + +Expression* +Unary_expression::do_flatten(Gogo* gogo, Named_object*, + Statement_inserter* inserter) +{ + Location location = this->location(); + if (this->op_ == OPERATOR_MULT + && !this->expr_->is_variable()) + { + go_assert(this->expr_->type()->points_to() != NULL); + Type* ptype = this->expr_->type()->points_to(); + if (!ptype->is_void_type()) + { + Btype* pbtype = ptype->get_backend(gogo); + size_t s = gogo->backend()->type_size(pbtype); + if (s >= 4096 || this->issue_nil_check_) + { + Temporary_statement* temp = + Statement::make_temporary(NULL, this->expr_, location); + inserter->insert(temp); + this->expr_ = + Expression::make_temporary_reference(temp, location); + } + } + } + + if (this->create_temp_ && !this->expr_->is_variable()) + { + Temporary_statement* temp = + Statement::make_temporary(NULL, this->expr_, location); + inserter->insert(temp); + this->expr_ = Expression::make_temporary_reference(temp, location); + } + + return this; +} + // Return whether a unary expression is a constant. bool @@ -3821,8 +3875,8 @@ Unary_expression::do_is_constant() const else if (this->op_ == OPERATOR_AND) { // Taking the address of a variable is constant if it is a - // global variable, not constant otherwise. In other cases - // taking the address is probably not a constant. + // global variable, not constant otherwise. In other cases taking the + // address is probably not a constant. Var_expression* ve = this->expr_->var_expression(); if (ve != NULL) { @@ -4151,58 +4205,40 @@ Unary_expression::do_get_tree(Translate_ { Temporary_statement* temp = sut->temporary(); Bvariable* bvar = temp->get_backend_variable(context); - tree var_tree = var_to_tree(bvar); - Expression* val = sut->expression(); - tree val_tree = val->get_tree(context); - if (var_tree == error_mark_node || val_tree == error_mark_node) - return error_mark_node; - tree addr_tree = build_fold_addr_expr_loc(loc.gcc_location(), - var_tree); - return build2_loc(loc.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(addr_tree), - build2_loc(sut->location().gcc_location(), - MODIFY_EXPR, void_type_node, - var_tree, val_tree), - addr_tree); + Bexpression* bvar_expr = gogo->backend()->var_expression(bvar, loc); + + Expression* val = sut->expression(); + Bexpression* bval = tree_to_expr(val->get_tree(context)); + + Bstatement* bassign = + gogo->backend()->assignment_statement(bvar_expr, bval, loc); + Bexpression* bvar_addr = + gogo->backend()->address_expression(bvar_expr, loc); + Bexpression* ret = + gogo->backend()->compound_expression(bassign, bvar_addr, loc); + return expr_to_tree(ret); } } + Bexpression* ret; tree expr = this->expr_->get_tree(context); - if (expr == error_mark_node) - return error_mark_node; - + Bexpression* bexpr = tree_to_expr(expr); + Btype* btype = this->expr_->type()->get_backend(gogo); switch (this->op_) { case OPERATOR_PLUS: - return expr; + ret = bexpr; + break; case OPERATOR_MINUS: - { - tree type = TREE_TYPE(expr); - tree compute_type = excess_precision_type(type); - if (compute_type != NULL_TREE) - expr = ::convert(compute_type, expr); - tree ret = fold_build1_loc(loc.gcc_location(), NEGATE_EXPR, - (compute_type != NULL_TREE - ? compute_type - : type), - expr); - if (compute_type != NULL_TREE) - ret = ::convert(type, ret); - return ret; - } + ret = gogo->backend()->unary_expression(this->op_, bexpr, loc); + ret = gogo->backend()->convert_expression(btype, ret, loc); + break; case OPERATOR_NOT: - if (TREE_CODE(TREE_TYPE(expr)) == BOOLEAN_TYPE) - return fold_build1_loc(loc.gcc_location(), TRUTH_NOT_EXPR, - TREE_TYPE(expr), expr); - else - return fold_build2_loc(loc.gcc_location(), NE_EXPR, boolean_type_node, - expr, build_int_cst(TREE_TYPE(expr), 0)); - case OPERATOR_XOR: - return fold_build1_loc(loc.gcc_location(), BIT_NOT_EXPR, TREE_TYPE(expr), - expr); + ret = gogo->backend()->unary_expression(this->op_, bexpr, loc); + break; case OPERATOR_AND: if (!this->create_temp_) @@ -4211,127 +4247,91 @@ Unary_expression::do_get_tree(Translate_ // where we would see one should have been moved onto the // heap at parse time. Taking the address of a nonconstant // constructor will not do what the programmer expects. - go_assert(TREE_CODE(expr) != CONSTRUCTOR || TREE_CONSTANT(expr)); - go_assert(TREE_CODE(expr) != ADDR_EXPR); + + go_assert(!this->expr_->is_composite_literal() + || this->expr_->is_immutable()); + Unary_expression* ue = static_cast(this->expr_); + go_assert(ue == NULL || ue->op() != OPERATOR_AND); } // Build a decl for a constant constructor. - if (TREE_CODE(expr) == CONSTRUCTOR && TREE_CONSTANT(expr)) - { - tree decl = build_decl(this->location().gcc_location(), VAR_DECL, - create_tmp_var_name("C"), TREE_TYPE(expr)); - DECL_EXTERNAL(decl) = 0; - TREE_PUBLIC(decl) = 0; - TREE_READONLY(decl) = 1; - TREE_CONSTANT(decl) = 1; - TREE_STATIC(decl) = 1; - TREE_ADDRESSABLE(decl) = 1; - DECL_ARTIFICIAL(decl) = 1; - DECL_INITIAL(decl) = expr; - rest_of_decl_compilation(decl, 1, 0); - expr = decl; - } - - if (this->create_temp_ - && !TREE_ADDRESSABLE(TREE_TYPE(expr)) - && (TREE_CODE(expr) == CONST_DECL || !DECL_P(expr)) - && TREE_CODE(expr) != INDIRECT_REF - && TREE_CODE(expr) != COMPONENT_REF) - { - if (current_function_decl != NULL) - { - tree tmp = create_tmp_var(TREE_TYPE(expr), get_name(expr)); - DECL_IGNORED_P(tmp) = 1; - DECL_INITIAL(tmp) = expr; - TREE_ADDRESSABLE(tmp) = 1; - return build2_loc(loc.gcc_location(), COMPOUND_EXPR, - build_pointer_type(TREE_TYPE(expr)), - build1_loc(loc.gcc_location(), DECL_EXPR, - void_type_node, tmp), - build_fold_addr_expr_loc(loc.gcc_location(), - tmp)); - } - else - { - tree tmp = build_decl(loc.gcc_location(), VAR_DECL, - create_tmp_var_name("A"), TREE_TYPE(expr)); - DECL_EXTERNAL(tmp) = 0; - TREE_PUBLIC(tmp) = 0; - TREE_STATIC(tmp) = 1; - DECL_ARTIFICIAL(tmp) = 1; - TREE_ADDRESSABLE(tmp) = 1; - tree make_tmp; - if (!TREE_CONSTANT(expr)) - make_tmp = fold_build2_loc(loc.gcc_location(), INIT_EXPR, - void_type_node, tmp, expr); - else - { - TREE_READONLY(tmp) = 1; - TREE_CONSTANT(tmp) = 1; - DECL_INITIAL(tmp) = expr; - make_tmp = NULL_TREE; - } - rest_of_decl_compilation(tmp, 1, 0); - tree addr = build_fold_addr_expr_loc(loc.gcc_location(), tmp); - if (make_tmp == NULL_TREE) - return addr; - return build2_loc(loc.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(addr), make_tmp, addr); - } - } + if ((this->expr_->is_composite_literal() + || this->expr_->string_expression() != NULL) + && this->expr_->is_immutable()) + { + static unsigned int counter; + char buf[100]; + snprintf(buf, sizeof buf, "C%u", counter); + ++counter; + + Bvariable* decl = + gogo->backend()->immutable_struct(buf, true, false, btype, loc); + gogo->backend()->immutable_struct_set_init(decl, buf, true, false, + btype, loc, bexpr); + bexpr = gogo->backend()->var_expression(decl, loc); + } - return build_fold_addr_expr_loc(loc.gcc_location(), expr); + go_assert(!this->create_temp_ || this->expr_->is_variable()); + ret = gogo->backend()->address_expression(bexpr, loc); + break; case OPERATOR_MULT: { - go_assert(POINTER_TYPE_P(TREE_TYPE(expr))); + go_assert(this->expr_->type()->points_to() != NULL); // If we are dereferencing the pointer to a large struct, we // need to check for nil. We don't bother to check for small // structs because we expect the system to crash on a nil // pointer dereference. However, if we know the address of this // expression is being taken, we must always check for nil. - tree target_type_tree = TREE_TYPE(TREE_TYPE(expr)); - if (!VOID_TYPE_P(target_type_tree)) + + Type* ptype = this->expr_->type()->points_to(); + Btype* pbtype = ptype->get_backend(gogo); + if (!ptype->is_void_type()) { - HOST_WIDE_INT s = int_size_in_bytes(target_type_tree); - if (s == -1 || s >= 4096 || this->issue_nil_check_) + size_t s = gogo->backend()->type_size(pbtype); + if (s >= 4096 || this->issue_nil_check_) { - if (!DECL_P(expr)) - expr = save_expr(expr); - tree compare = fold_build2_loc(loc.gcc_location(), EQ_EXPR, - boolean_type_node, - expr, - fold_convert(TREE_TYPE(expr), - null_pointer_node)); + go_assert(this->expr_->is_variable()); + + Expression* nil_expr = Expression::make_nil(loc); + Bexpression* nil = tree_to_expr(nil_expr->get_tree(context)); + Bexpression* compare = + gogo->backend()->binary_expression(OPERATOR_EQEQ, bexpr, + nil, loc); + Expression* crash_expr = gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, loc); - tree crash = crash_expr->get_tree(context); - expr = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(expr), build3(COND_EXPR, - void_type_node, - compare, crash, - NULL_TREE), - expr); + Bexpression* crash = + tree_to_expr(crash_expr->get_tree(context)); + bexpr = gogo->backend()->conditional_expression(btype, compare, + crash, bexpr, + loc); + } } // If the type of EXPR is a recursive pointer type, then we // need to insert a cast before indirecting. - if (VOID_TYPE_P(target_type_tree)) - { - Type* pt = this->expr_->type()->points_to(); - tree ind = type_to_tree(pt->get_backend(gogo)); - expr = fold_convert_loc(loc.gcc_location(), + tree expr = expr_to_tree(bexpr); + tree target_type_tree = TREE_TYPE(TREE_TYPE(expr)); + if (VOID_TYPE_P(target_type_tree)) + { + tree ind = type_to_tree(pbtype); + expr = fold_convert_loc(loc.gcc_location(), build_pointer_type(ind), expr); - } + bexpr = tree_to_expr(expr); + } - return build_fold_indirect_ref_loc(loc.gcc_location(), expr); + ret = gogo->backend()->indirect_expression(bexpr, false, loc); } + break; default: go_unreachable(); } + + return expr_to_tree(ret); } // Export a unary expression. @@ -12232,6 +12232,9 @@ class Struct_construction_expression : p int do_traverse(Traverse* traverse); + bool + do_is_immutable() const; + Type* do_type() { return this->type_; } @@ -12334,6 +12337,23 @@ Struct_construction_expression::is_const return true; } +// Return whether this struct is immutable. + +bool +Struct_construction_expression::do_is_immutable() const +{ + if (this->vals_ == NULL) + return true; + for (Expression_list::const_iterator pv = this->vals_->begin(); + pv != this->vals_->end(); + ++pv) + { + if (*pv != NULL && !(*pv)->is_immutable()) + return false; + } + return true; +} + // Final type determination. void @@ -12546,6 +12566,9 @@ protected: int do_traverse(Traverse* traverse); + bool + do_is_immutable() const; + Type* do_type() { return this->type_; } @@ -12624,6 +12647,23 @@ Array_construction_expression::is_consta return true; } +// Return whether this is an immutable array initializer. + +bool +Array_construction_expression::do_is_immutable() const +{ + if (this->vals_ == NULL) + return true; + for (Expression_list::const_iterator pv = this->vals_->begin(); + pv != this->vals_->end(); + ++pv) + { + if (*pv != NULL && !(*pv)->is_immutable()) + return false; + } + return true; +} + // Final type determination. void @@ -14390,6 +14430,10 @@ class Type_descriptor_expression : publi do_type() { return Type::make_type_descriptor_ptr_type(); } + bool + do_is_immutable() const + { return true; } + void do_determine_type(const Type_context*) { } Index: gcc/go/gofrontend/expressions.h =================================================================== --- gcc/go/gofrontend/expressions.h (revision 206904) +++ gcc/go/gofrontend/expressions.h (working copy) @@ -403,6 +403,11 @@ class Expression is_constant() const { return this->do_is_constant(); } + // Return whether this is an immutable expression. + bool + is_immutable() const + { return this->do_is_immutable(); } + // If this is not a numeric constant, return false. If it is one, // return true, and set VAL to hold the value. bool @@ -758,6 +763,11 @@ class Expression do_is_constant() const { return false; } + // Return whether this is an immutable expression. + virtual bool + do_is_immutable() const + { return false; } + // Return whether this is a constant expression of numeric type, and // set the Numeric_constant to the value. virtual bool @@ -1196,6 +1206,10 @@ class String_expression : public Express { return true; } bool + do_is_immutable() const + { return true; } + + bool do_string_constant_value(std::string* val) const { *val = this->val_; Index: gcc/go/gofrontend/backend.h =================================================================== --- gcc/go/gofrontend/backend.h (revision 206904) +++ gcc/go/gofrontend/backend.h (working copy) @@ -298,6 +298,12 @@ class Backend Bexpression* then_expr, Bexpression* else_expr, Location) = 0; + // Return an expression for the unary operation OP EXPR. + // Supported values of OP are (from operators.h): + // MINUS, NOT, XOR. + virtual Bexpression* + unary_expression(Operator op, Bexpression* expr, Location) = 0; + // Return an expression for the binary operation LEFT OP RIGHT. // Supported values of OP are (from operators.h): // EQEQ, NOTEQ, LT, LE, GT, GE, PLUS, MINUS, OR, XOR, MULT, DIV, MOD, Index: gcc/go/go-gcc.cc =================================================================== --- gcc/go/go-gcc.cc (revision 206904) +++ gcc/go/go-gcc.cc (working copy) @@ -254,6 +254,9 @@ class Gcc_backend : public Backend Location); Bexpression* + unary_expression(Operator, Bexpression*, Location); + + Bexpression* binary_expression(Operator, Bexpression*, Bexpression*, Location); // Statements. @@ -1081,6 +1084,47 @@ Gcc_backend::conditional_expression(Btyp return this->make_expression(ret); } +// Return an expression for the unary operation OP EXPR. + +Bexpression* +Gcc_backend::unary_expression(Operator op, Bexpression* expr, Location location) +{ + tree expr_tree = expr->get_tree(); + if (expr_tree == error_mark_node + || TREE_TYPE(expr_tree) == error_mark_node) + return this->error_expression(); + + tree type_tree = TREE_TYPE(expr_tree); + enum tree_code code; + switch (op) + { + case OPERATOR_MINUS: + { + tree computed_type = excess_precision_type(type_tree); + if (computed_type != NULL_TREE) + { + expr_tree = convert(computed_type, expr_tree); + type_tree = computed_type; + } + code = NEGATE_EXPR; + break; + } + case OPERATOR_NOT: + code = TRUTH_NOT_EXPR; + break; + case OPERATOR_XOR: + code = BIT_NOT_EXPR; + break; + default: + gcc_unreachable(); + break; + } + + tree ret = fold_build1_loc(location.gcc_location(), code, type_tree, + expr_tree); + return this->make_expression(ret); +} + // Convert a gofrontend operator to an equivalent tree_code. static enum tree_code