From patchwork Wed Nov 10 22:45:12 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 70707 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 D1C69B710F for ; Thu, 11 Nov 2010 09:45:29 +1100 (EST) Received: (qmail 20810 invoked by alias); 10 Nov 2010 22:45:27 -0000 Received: (qmail 20801 invoked by uid 22791); 10 Nov 2010 22:45:26 -0000 X-SWARE-Spam-Status: No, hits=-2.2 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, SPF_HELO_PASS, TW_CC, 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) (216.239.44.51) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 10 Nov 2010 22:45:19 +0000 Received: from hpaq3.eem.corp.google.com (hpaq3.eem.corp.google.com [172.25.149.3]) by smtp-out.google.com with ESMTP id oAAMjHUv026375 for ; Wed, 10 Nov 2010 14:45:17 -0800 Received: from pxi8 (pxi8.prod.google.com [10.243.27.8]) by hpaq3.eem.corp.google.com with ESMTP id oAAMjEIu010192 for ; Wed, 10 Nov 2010 14:45:15 -0800 Received: by pxi8 with SMTP id 8so98689pxi.39 for ; Wed, 10 Nov 2010 14:45:14 -0800 (PST) Received: by 10.142.97.18 with SMTP id u18mr7446576wfb.235.1289429114637; Wed, 10 Nov 2010 14:45:14 -0800 (PST) Received: from coign.google.com (dhcp-172-22-127-239.mtv.corp.google.com [172.22.127.239]) by mx.google.com with ESMTPS id x35sm1440138wfd.1.2010.11.10.14.45.13 (version=TLSv1/SSLv3 cipher=RC4-MD5); Wed, 10 Nov 2010 14:45:13 -0800 (PST) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: [gccgo] Use the same GIMPLE type for all identical Go types Date: Wed, 10 Nov 2010 14:45:12 -0800 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 The rules for type identity in Go are not the same as in GIMPLE. In Go, for example, two unnamed structs with the same field names and types are identical. In GIMPLE they are not. This patch uses a hash table to ensure that we produce the same GIMPLE type (the same tree pointer) for each identical Go type, so that GIMPLE does not get confused by struct assignments which are valid in Go but not in GIMPLE. I previously did that for array types, but encountered a case where it happened with a struct type, so I moved the array code to the general Type class. Committed to gccgo branch. Ian diff -r f304a0c9339a go/types.cc --- a/go/types.cc Wed Nov 10 14:39:09 2010 -0800 +++ b/go/types.cc Wed Nov 10 14:41:03 2010 -0800 @@ -775,12 +775,61 @@ return false; } +// A hash table mapping unnamed types to trees. + +Type::Type_trees Type::type_trees; + // Return a tree representing this type. tree Type::get_tree(Gogo* gogo) { - if (this->tree_ == NULL) + if (this->tree_ != NULL) + return this->tree_; + + if (this->forward_declaration_type() != NULL + || this->named_type() != NULL) + return this->get_tree_without_hash(gogo); + + // To avoid confusing GIMPLE, we need to translate all identical Go + // types to the same GIMPLE type. We use a hash table to do that. + // There is no need to use the hash table for named types, as named + // types are only identical to themselves. + + std::pair val(this, NULL); + std::pair ins = + Type::type_trees.insert(val); + if (!ins.second && ins.first->second != NULL_TREE) + { + this->tree_ = ins.first->second; + return this->tree_; + } + + tree t = this->get_tree_without_hash(gogo); + + if (ins.first->second == NULL_TREE) + ins.first->second = t; + else + { + // We have already created a tree for this type. This can + // happen when an unnamed type is defined using a named type + // which in turns uses an identical unnamed type. Use the tree + // we created earlier and ignore the one we just built. + t = ins.first->second; + this->tree_ = t; + } + + return t; +} + +// Return a tree for a type without looking in the hash table for +// identical types. This is used for named types, since there is no +// point to looking in the hash table for them. + +tree +Type::get_tree_without_hash(Gogo* gogo) +{ + if (this->tree_ == NULL_TREE) { tree t = this->do_get_tree(gogo); @@ -4044,8 +4093,6 @@ // Class Array_type. -Array_type::Array_trees Array_type::array_trees; - // Whether two array types are identical. bool @@ -4320,22 +4367,6 @@ { gcc_assert(this->length_ == NULL); - // Two different slices of the same element type are really the same - // type. In order to make that valid at the tree level, we make - // sure to return the same struct. - std::pair val(this->element_type_, NULL); - std::pair ins = - Array_type::array_trees.insert(val); - if (!ins.second) - { - // We've already created a tree type for a slice with this - // element type. - gcc_assert(ins.first->second != NULL_TREE); - return ins.first->second; - } - - ins.first->second = struct_type; - tree element_type_tree = this->element_type_->get_tree(gogo); tree field = TYPE_FIELDS(struct_type); gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0); @@ -6753,7 +6784,7 @@ case TYPE_MAP: case TYPE_CHANNEL: // All maps and channels have the same type in GENERIC. - t = this->type_->get_tree(gogo); + t = Type::get_named_type_tree(gogo, this->type_); if (t == error_mark_node) return error_mark_node; // Build a copy to set TYPE_NAME. @@ -6771,7 +6802,7 @@ == this)) return ptr_type_node; this->seen_ = true; - t = this->type_->get_tree(gogo); + t = Type::get_named_type_tree(gogo, this->type_); this->seen_ = false; if (t == error_mark_node) return error_mark_node; @@ -6784,7 +6815,7 @@ if (this->seen_ && this->points_to()->forwarded() == this) return ptr_type_node; this->seen_ = true; - t = this->type_->get_tree(gogo); + t = Type::get_named_type_tree(gogo, this->type_); this->seen_ = false; if (t == error_mark_node) return error_mark_node; @@ -6801,7 +6832,7 @@ case TYPE_ARRAY: if (!this->is_open_array_type()) - t = this->type_->get_tree(gogo); + t = Type::get_named_type_tree(gogo, this->type_); else { if (this->named_tree_ != NULL_TREE) @@ -6818,7 +6849,7 @@ case TYPE_INTERFACE: if (this->type_->interface_type()->is_empty()) { - t = this->type_->get_tree(gogo); + t = Type::get_named_type_tree(gogo, this->type_); if (t == error_mark_node) return error_mark_node; t = build_variant_type_copy(t); @@ -6842,7 +6873,7 @@ // but it's as close as we can get with GENERIC. bool was_seen = this->seen_; this->seen_ = true; - t = this->type_->get_tree(gogo); + t = Type::get_named_type_tree(gogo, this->type_); this->seen_ = was_seen; if (was_seen) return t; @@ -7906,7 +7937,7 @@ Forward_declaration_type::do_get_tree(Gogo* gogo) { if (this->is_defined()) - return this->real_type()->get_tree(gogo); + return Type::get_named_type_tree(gogo, this->real_type()); if (this->warned_) return error_mark_node; diff -r f304a0c9339a go/types.h --- a/go/types.h Wed Nov 10 14:39:09 2010 -0800 +++ b/go/types.h Wed Nov 10 14:41:03 2010 -0800 @@ -945,6 +945,11 @@ static unsigned int hash_string(const std::string&, unsigned int); + // Return a tree for the underlying type of a named type. + static tree + get_named_type_tree(Gogo* gogo, Type* base_type) + { return base_type->get_tree_without_hash(gogo); } + private: // Convert to the desired type classification, or return NULL. This // is a controlled dynamic_cast. @@ -1057,6 +1062,18 @@ bool* found_pointer_method, std::string* ambig1, std::string* ambig2); + // Get a tree for a type without looking in the hash table for + // identical types. + tree + get_tree_without_hash(Gogo*); + + // A mapping from Type to tree, used to ensure that the GIMPLE + // representation of identical types is identical. + typedef std::tr1::unordered_map Type_trees; + + static Type_trees type_trees; + // The type classification. Type_classification classification_; // The tree representation of the type, once it has been determined. @@ -2067,13 +2084,6 @@ Expression* slice_type_descriptor(Gogo*, Named_type*); - // A mapping from Type to tree, used to ensure that arrays of - // identical types are identical. - typedef std::tr1::unordered_map Array_trees; - - static Array_trees array_trees; - // The type of elements of the array. Type* element_type_; // The number of elements. This may be NULL.