public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Go patch committed: drop size arguments to hash/equal functions
@ 2017-01-10  3:59 Ian Lance Taylor
  2017-01-10 19:45 ` Rainer Orth
  0 siblings, 1 reply; 3+ messages in thread
From: Ian Lance Taylor @ 2017-01-10  3:59 UTC (permalink / raw)
  To: gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 649 bytes --]

Drop the size arguments for the hash/equal functions stored in type
descriptors.  Types know what size they are.  To make this work,
generate hash/equal functions for types that can use an identity
comparison but are not a standard size and alignment.

Drop the multiplications by 33 in the generated hash code and the
reflect package hash code.  They are not necessary since we started
passing a seed value around, as the seed includes the hash of the
earlier values.

Copy the algorithms for standard types from the Go 1.7 runtime,
replacing the C functions.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 55518 bytes --]

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 244236)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@
-189ea81cc758e000325fd6cca7882c252d33f8f0
+f439989e483b7c2eada6ddcf6e730a791cce603f
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 244166)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -5335,7 +5335,6 @@ Binary_expression::lower_array_compariso
   Expression_list* args = new Expression_list();
   args->push_back(this->operand_address(inserter, this->left_));
   args->push_back(this->operand_address(inserter, this->right_));
-  args->push_back(Expression::make_type_info(at, TYPE_INFO_SIZE));
 
   Expression* ret = Expression::make_call(func, args, false, loc);
 
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc	(revision 244166)
+++ gcc/go/gofrontend/gogo.cc	(working copy)
@@ -2343,7 +2343,7 @@ Gogo::clear_file_scope()
 // parse tree is lowered.
 
 void
-Gogo::queue_specific_type_function(Type* type, Named_type* name,
+Gogo::queue_specific_type_function(Type* type, Named_type* name, int64_t size,
 				   const std::string& hash_name,
 				   Function_type* hash_fntype,
 				   const std::string& equal_name,
@@ -2351,7 +2351,7 @@ Gogo::queue_specific_type_function(Type*
 {
   go_assert(!this->specific_type_functions_are_written_);
   go_assert(!this->in_global_scope());
-  Specific_type_function* tsf = new Specific_type_function(type, name,
+  Specific_type_function* tsf = new Specific_type_function(type, name, size,
 							   hash_name,
 							   hash_fntype,
 							   equal_name,
@@ -2386,7 +2386,7 @@ Specific_type_functions::type(Type* t)
     case Type::TYPE_NAMED:
       {
 	Named_type* nt = t->named_type();
-	if (!t->compare_is_identity(this->gogo_) && t->is_comparable())
+	if (t->needs_specific_type_functions(this->gogo_))
 	  t->type_functions(this->gogo_, nt, NULL, NULL, &hash_fn, &equal_fn);
 
 	// If this is a struct type, we don't want to make functions
@@ -2420,7 +2420,7 @@ Specific_type_functions::type(Type* t)
 
     case Type::TYPE_STRUCT:
     case Type::TYPE_ARRAY:
-      if (!t->compare_is_identity(this->gogo_) && t->is_comparable())
+      if (t->needs_specific_type_functions(this->gogo_))
 	t->type_functions(this->gogo_, NULL, NULL, NULL, &hash_fn, &equal_fn);
       break;
 
@@ -2443,7 +2443,7 @@ Gogo::write_specific_type_functions()
     {
       Specific_type_function* tsf = this->specific_type_functions_.back();
       this->specific_type_functions_.pop_back();
-      tsf->type->write_specific_type_functions(this, tsf->name,
+      tsf->type->write_specific_type_functions(this, tsf->name, tsf->size,
 					       tsf->hash_name,
 					       tsf->hash_fntype,
 					       tsf->equal_name,
Index: gcc/go/gofrontend/gogo.h
===================================================================
--- gcc/go/gofrontend/gogo.h	(revision 244166)
+++ gcc/go/gofrontend/gogo.h	(working copy)
@@ -563,7 +563,7 @@ class Gogo
   // used when a type-specific function is needed when not at the top
   // level.
   void
-  queue_specific_type_function(Type* type, Named_type* name,
+  queue_specific_type_function(Type* type, Named_type* name, int64_t size,
 			       const std::string& hash_name,
 			       Function_type* hash_fntype,
 			       const std::string& equal_name,
@@ -824,17 +824,18 @@ class Gogo
   {
     Type* type;
     Named_type* name;
+    int64_t size;
     std::string hash_name;
     Function_type* hash_fntype;
     std::string equal_name;
     Function_type* equal_fntype;
 
-    Specific_type_function(Type* atype, Named_type* aname,
+    Specific_type_function(Type* atype, Named_type* aname, int64_t asize,
 			   const std::string& ahash_name,
 			   Function_type* ahash_fntype,
 			   const std::string& aequal_name,
 			   Function_type* aequal_fntype)
-      : type(atype), name(aname), hash_name(ahash_name),
+      : type(atype), name(aname), size(asize), hash_name(ahash_name),
 	hash_fntype(ahash_fntype), equal_name(aequal_name),
 	equal_fntype(aequal_fntype)
     { }
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc	(revision 244166)
+++ gcc/go/gofrontend/types.cc	(working copy)
@@ -1425,7 +1425,9 @@ Type::make_builtin_struct_type(int nfiel
 
   va_end(ap);
 
-  return Type::make_struct_type(sfl, bloc);
+  Struct_type* ret = Type::make_struct_type(sfl, bloc);
+  ret->set_is_struct_incomparable();
+  return ret;
 }
 
 // A list of builtin named types.
@@ -1488,7 +1490,6 @@ Type::make_type_descriptor_type()
       Typed_identifier_list *params = new Typed_identifier_list();
       params->push_back(Typed_identifier("key", unsafe_pointer_type, bloc));
       params->push_back(Typed_identifier("seed", uintptr_type, bloc));
-      params->push_back(Typed_identifier("key_size", uintptr_type, bloc));
 
       Typed_identifier_list* results = new Typed_identifier_list();
       results->push_back(Typed_identifier("", uintptr_type, bloc));
@@ -1499,7 +1500,6 @@ Type::make_type_descriptor_type()
       params = new Typed_identifier_list();
       params->push_back(Typed_identifier("key1", unsafe_pointer_type, bloc));
       params->push_back(Typed_identifier("key2", unsafe_pointer_type, bloc));
-      params->push_back(Typed_identifier("key_size", uintptr_type, bloc));
 
       results = new Typed_identifier_list();
       results->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc));
@@ -1578,6 +1578,51 @@ Type::make_type_descriptor_ptr_type()
   return ret;
 }
 
+// Return whether this type needs specially built type functions.
+// This returns true for types that are comparable and either can not
+// use an identity comparison, or are a non-standard size.
+
+bool
+Type::needs_specific_type_functions(Gogo* gogo)
+{
+  if (!this->is_comparable())
+    return false;
+  if (!this->compare_is_identity(gogo))
+    return true;
+
+  // We create a few predeclared types for type descriptors; they are
+  // really just for the backend and don't need hash or equality
+  // functions.
+  Named_type* nt = this->named_type();
+  if (nt != NULL && Linemap::is_predeclared_location(nt->location()))
+    return false;
+
+  int64_t size, align;
+  if (!this->backend_type_size(gogo, &size)
+      || !this->backend_type_align(gogo, &align))
+    {
+      go_assert(saw_errors());
+      return false;
+    }
+  // This switch matches the one in Type::type_functions.
+  switch (size)
+    {
+    case 0:
+    case 1:
+    case 2:
+      return align < 2;
+    case 4:
+      return align < 4;
+    case 8:
+      return align < 8;
+    case 16:
+      // 8, not 16, because of how runtime.memequal128 is written.
+      return align < 8;
+    default:
+      return true;
+    }
+}
+
 // Set *HASH_FN and *EQUAL_FN to the runtime functions which compute a
 // hash code for this type and which compare whether two values of
 // this type are equal.  If NAME is not NULL it is the name of this
@@ -1610,7 +1655,6 @@ Type::type_functions(Gogo* gogo, Named_t
 	  params->push_back(Typed_identifier("key", unsafe_pointer_type,
 					     bloc));
 	  params->push_back(Typed_identifier("seed", uintptr_type, bloc));
-	  params->push_back(Typed_identifier("key_size", uintptr_type, bloc));
 
 	  Typed_identifier_list* results = new Typed_identifier_list();
 	  results->push_back(Typed_identifier("", uintptr_type, bloc));
@@ -1624,7 +1668,6 @@ Type::type_functions(Gogo* gogo, Named_t
 					     bloc));
 	  params->push_back(Typed_identifier("key2", unsafe_pointer_type,
 					     bloc));
-	  params->push_back(Typed_identifier("key_size", uintptr_type, bloc));
 
 	  Typed_identifier_list* results = new Typed_identifier_list();
 	  results->push_back(Typed_identifier("", Type::lookup_bool_type(),
@@ -1638,8 +1681,78 @@ Type::type_functions(Gogo* gogo, Named_t
   const char* equal_fnname;
   if (this->compare_is_identity(gogo))
     {
-      hash_fnname = "runtime.memhash";
-      equal_fnname = "__go_type_equal_identity";
+      int64_t size, align;
+      if (!this->backend_type_size(gogo, &size)
+	  || !this->backend_type_align(gogo, &align))
+	{
+	  go_assert(saw_errors());
+	  return;
+	}
+      bool build_functions = false;
+      // This switch matches the one in Type::needs_specific_type_functions.
+      // The alignment tests are because of the memequal functions,
+      // which assume that the values are aligned as required for an
+      // integer of that size.
+      switch (size)
+	{
+	case 0:
+	  hash_fnname = "runtime.memhash0";
+	  equal_fnname = "runtime.memequal0";
+	  break;
+	case 1:
+	  hash_fnname = "runtime.memhash8";
+	  equal_fnname = "runtime.memequal8";
+	  break;
+	case 2:
+	  if (align < 2)
+	    build_functions = true;
+	  else
+	    {
+	      hash_fnname = "runtime.memhash16";
+	      equal_fnname = "runtime.memequal16";
+	    }
+	  break;
+	case 4:
+	  if (align < 4)
+	    build_functions = true;
+	  else
+	    {
+	      hash_fnname = "runtime.memhash32";
+	      equal_fnname = "runtime.memequal32";
+	    }
+	  break;
+	case 8:
+	  if (align < 8)
+	    build_functions = true;
+	  else
+	    {
+	      hash_fnname = "runtime.memhash64";
+	      equal_fnname = "runtime.memequal64";
+	    }
+	  break;
+	case 16:
+	  // 8, not 16, because of how runtime.memequal128 is written.
+	  if (align < 8)
+	    build_functions = true;
+	  else
+	    {
+	      hash_fnname = "runtime.memhash128";
+	      equal_fnname = "runtime.memequal128";
+	    }
+	  break;
+	default:
+	  build_functions = true;
+	  break;
+	}
+      if (build_functions)
+	{
+	  // We don't have a built-in function for a type of this size
+	  // and alignment.  Build a function to use that calls the
+	  // generic hash/equality functions for identity, passing the size.
+	  this->specific_type_functions(gogo, name, size, hash_fntype,
+					equal_fntype, hash_fn, equal_fn);
+	  return;
+	}
     }
   else
     {
@@ -1661,18 +1774,40 @@ Type::type_functions(Gogo* gogo, Named_t
 	  go_unreachable();
 
 	case Type::TYPE_FLOAT:
-	  hash_fnname = "__go_type_hash_float";
-	  equal_fnname = "__go_type_equal_float";
+	  switch (this->float_type()->bits())
+	    {
+	    case 32:
+	      hash_fnname = "runtime.f32hash";
+	      equal_fnname = "runtime.f32equal";
+	      break;
+	    case 64:
+	      hash_fnname = "runtime.f64hash";
+	      equal_fnname = "runtime.f64equal";
+	      break;
+	    default:
+	      go_unreachable();
+	    }
 	  break;
 
 	case Type::TYPE_COMPLEX:
-	  hash_fnname = "__go_type_hash_complex";
-	  equal_fnname = "__go_type_equal_complex";
+	  switch (this->complex_type()->bits())
+	    {
+	    case 64:
+	      hash_fnname = "runtime.c64hash";
+	      equal_fnname = "runtime.c64equal";
+	      break;
+	    case 128:
+	      hash_fnname = "runtime.c128hash";
+	      equal_fnname = "runtime.c128equal";
+	      break;
+	    default:
+	      go_unreachable();
+	    }
 	  break;
 
 	case Type::TYPE_STRING:
-	  hash_fnname = "__go_type_hash_string";
-	  equal_fnname = "__go_type_equal_string";
+	  hash_fnname = "runtime.strhash";
+	  equal_fnname = "runtime.strequal";
 	  break;
 
 	case Type::TYPE_STRUCT:
@@ -1680,7 +1815,7 @@ Type::type_functions(Gogo* gogo, Named_t
 	    // This is a struct which can not be compared using a
 	    // simple identity function.  We need to build a function
 	    // for comparison.
-	    this->specific_type_functions(gogo, name, hash_fntype,
+	    this->specific_type_functions(gogo, name, -1, hash_fntype,
 					  equal_fntype, hash_fn, equal_fn);
 	    return;
 	  }
@@ -1697,7 +1832,7 @@ Type::type_functions(Gogo* gogo, Named_t
 	      // This is an array which can not be compared using a
 	      // simple identity function.  We need to build a
 	      // function for comparison.
-	      this->specific_type_functions(gogo, name, hash_fntype,
+	      this->specific_type_functions(gogo, name, -1, hash_fntype,
 					    equal_fntype, hash_fn, equal_fn);
 	      return;
 	    }
@@ -1739,11 +1874,13 @@ Type::type_functions(Gogo* gogo, Named_t
 
 Type::Type_functions Type::type_functions_table;
 
-// Handle a type function which is specific to a type: a struct or
-// array which can not use an identity comparison.
+// Handle a type function which is specific to a type: if SIZE == -1,
+// this is a struct or array that can not use an identity comparison.
+// Otherwise, it is a type that uses an identity comparison but is not
+// one of the standard supported sizes.
 
 void
-Type::specific_type_functions(Gogo* gogo, Named_type* name,
+Type::specific_type_functions(Gogo* gogo, Named_type* name, int64_t size,
 			      Function_type* hash_fntype,
 			      Function_type* equal_fntype,
 			      Named_object** hash_fn,
@@ -1829,11 +1966,13 @@ Type::specific_type_functions(Gogo* gogo
   if (!is_defined_elsewhere)
     {
       if (gogo->in_global_scope())
-	this->write_specific_type_functions(gogo, name, hash_name, hash_fntype,
-					    equal_name, equal_fntype);
+	this->write_specific_type_functions(gogo, name, size, hash_name,
+					    hash_fntype, equal_name,
+					    equal_fntype);
       else
-	gogo->queue_specific_type_function(this, name, hash_name, hash_fntype,
-					   equal_name, equal_fntype);
+	gogo->queue_specific_type_function(this, name, size, hash_name,
+					   hash_fntype, equal_name,
+					   equal_fntype);
     }
 }
 
@@ -1841,7 +1980,7 @@ Type::specific_type_functions(Gogo* gogo
 // written specially.
 
 void
-Type::write_specific_type_functions(Gogo* gogo, Named_type* name,
+Type::write_specific_type_functions(Gogo* gogo, Named_type* name, int64_t size,
 				    const std::string& hash_name,
 				    Function_type* hash_fntype,
 				    const std::string& equal_name,
@@ -1862,7 +2001,9 @@ Type::write_specific_type_functions(Gogo
   hash_fn->func_value()->set_is_type_specific_function();
   gogo->start_block(bloc);
 
-  if (name != NULL && name->real_type()->named_type() != NULL)
+  if (size != -1)
+    this->write_identity_hash(gogo, size);
+  else if (name != NULL && name->real_type()->named_type() != NULL)
     this->write_named_hash(gogo, name, hash_fntype, equal_fntype);
   else if (this->struct_type() != NULL)
     this->struct_type()->write_hash_function(gogo, name, hash_fntype,
@@ -1883,7 +2024,9 @@ Type::write_specific_type_functions(Gogo
   equal_fn->func_value()->set_is_type_specific_function();
   gogo->start_block(bloc);
 
-  if (name != NULL && name->real_type()->named_type() != NULL)
+  if (size != -1)
+    this->write_identity_equal(gogo, size);
+  else if (name != NULL && name->real_type()->named_type() != NULL)
     this->write_named_equal(gogo, name);
   else if (this->struct_type() != NULL)
     this->struct_type()->write_equal_function(gogo, name);
@@ -1902,6 +2045,112 @@ Type::write_specific_type_functions(Gogo
   equal_fn->func_value()->descriptor(gogo, equal_fn);
 }
 
+// Write a hash function for a type that can use an identity hash but
+// is not one of the standard supported sizes.  For example, this
+// would be used for the type [3]byte.  This builds a return statement
+// that returns a call to the memhash function, passing the key and
+// seed from the function arguments (already constructed before this
+// is called), and the constant size.
+
+void
+Type::write_identity_hash(Gogo* gogo, int64_t size)
+{
+  Location bloc = Linemap::predeclared_location();
+
+  Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+  Typed_identifier_list* params = new Typed_identifier_list();
+  params->push_back(Typed_identifier("key", unsafe_pointer_type, bloc));
+  params->push_back(Typed_identifier("seed", uintptr_type, bloc));
+  params->push_back(Typed_identifier("size", uintptr_type, bloc));
+
+  Typed_identifier_list* results = new Typed_identifier_list();
+  results->push_back(Typed_identifier("", uintptr_type, bloc));
+
+  Function_type* memhash_fntype = Type::make_function_type(NULL, params,
+							   results, bloc);
+
+  Named_object* memhash =
+    Named_object::make_function_declaration("runtime.memhash", NULL,
+					    memhash_fntype, bloc);
+  memhash->func_declaration_value()->set_asm_name("runtime.memhash");
+
+  Named_object* key_arg = gogo->lookup("key", NULL);
+  go_assert(key_arg != NULL);
+  Named_object* seed_arg = gogo->lookup("seed", NULL);
+  go_assert(seed_arg != NULL);
+
+  Expression* key_ref = Expression::make_var_reference(key_arg, bloc);
+  Expression* seed_ref = Expression::make_var_reference(seed_arg, bloc);
+  Expression* size_arg = Expression::make_integer_int64(size, uintptr_type,
+							bloc);
+  Expression_list* args = new Expression_list();
+  args->push_back(key_ref);
+  args->push_back(seed_ref);
+  args->push_back(size_arg);
+  Expression* func = Expression::make_func_reference(memhash, NULL, bloc);
+  Expression* call = Expression::make_call(func, args, false, bloc);
+
+  Expression_list* vals = new Expression_list();
+  vals->push_back(call);
+  Statement* s = Statement::make_return_statement(vals, bloc);
+  gogo->add_statement(s);
+}
+
+// Write an equality function for a type that can use an identity
+// equality comparison but is not one of the standard supported sizes.
+// For example, this would be used for the type [3]byte.  This builds
+// a return statement that returns a call to the memequal function,
+// passing the two keys from the function arguments (already
+// constructed before this is called), and the constant size.
+
+void
+Type::write_identity_equal(Gogo* gogo, int64_t size)
+{
+  Location bloc = Linemap::predeclared_location();
+
+  Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type());
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+
+  Typed_identifier_list* params = new Typed_identifier_list();
+  params->push_back(Typed_identifier("key1", unsafe_pointer_type, bloc));
+  params->push_back(Typed_identifier("key2", unsafe_pointer_type, bloc));
+  params->push_back(Typed_identifier("size", uintptr_type, bloc));
+
+  Typed_identifier_list* results = new Typed_identifier_list();
+  results->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc));
+
+  Function_type* memequal_fntype = Type::make_function_type(NULL, params,
+							    results, bloc);
+
+  Named_object* memequal =
+    Named_object::make_function_declaration("runtime.memequal", NULL,
+					    memequal_fntype, bloc);
+  memequal->func_declaration_value()->set_asm_name("runtime.memequal");
+
+  Named_object* key1_arg = gogo->lookup("key1", NULL);
+  go_assert(key1_arg != NULL);
+  Named_object* key2_arg = gogo->lookup("key2", NULL);
+  go_assert(key2_arg != NULL);
+
+  Expression* key1_ref = Expression::make_var_reference(key1_arg, bloc);
+  Expression* key2_ref = Expression::make_var_reference(key2_arg, bloc);
+  Expression* size_arg = Expression::make_integer_int64(size, uintptr_type,
+							bloc);
+  Expression_list* args = new Expression_list();
+  args->push_back(key1_ref);
+  args->push_back(key2_ref);
+  args->push_back(size_arg);
+  Expression* func = Expression::make_func_reference(memequal, NULL, bloc);
+  Expression* call = Expression::make_call(func, args, false, bloc);
+
+  Expression_list* vals = new Expression_list();
+  vals->push_back(call);
+  Statement* s = Statement::make_return_statement(vals, bloc);
+  gogo->add_statement(s);
+}
+
 // Write a hash function that simply calls the hash function for a
 // named type.  This is used when one named type is defined as
 // another.  This ensures that this case works when the other named
@@ -1926,10 +2175,6 @@ Type::write_named_hash(Gogo* gogo, Named
   Named_object* seed_arg = gogo->lookup("seed", NULL);
   go_assert(seed_arg != NULL);
 
-  // The size of the type we are going to hash.
-  Named_object* keysz_arg = gogo->lookup("key_size", NULL);
-  go_assert(keysz_arg != NULL);
-
   Named_object* hash_fn;
   Named_object* equal_fn;
   name->real_type()->type_functions(gogo, base_type, hash_fntype, equal_fntype,
@@ -1938,11 +2183,9 @@ Type::write_named_hash(Gogo* gogo, Named
   // Call the hash function for the base type.
   Expression* key_ref = Expression::make_var_reference(key_arg, bloc);
   Expression* seed_ref = Expression::make_var_reference(seed_arg, bloc);
-  Expression* keysz_ref = Expression::make_var_reference(keysz_arg, bloc);
   Expression_list* args = new Expression_list();
   args->push_back(key_ref);
   args->push_back(seed_ref);
-  args->push_back(keysz_ref);
   Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc);
   Expression* call = Expression::make_call(func, args, false, bloc);
 
@@ -5410,7 +5653,6 @@ Struct_type::write_hash_function(Gogo* g
   gogo->add_statement(key);
 
   // Loop over the struct fields.
-  bool first = true;
   const Struct_field_list* fields = this->fields_;
   for (Struct_field_list::const_iterator pf = fields->begin();
        pf != fields->end();
@@ -5419,19 +5661,6 @@ Struct_type::write_hash_function(Gogo* g
       if (Gogo::is_sink_name(pf->field_name()))
 	continue;
 
-      if (first)
-	first = false;
-      else
-	{
-	  // Multiply retval by 33.
-	  Expression* i33 = Expression::make_integer_ul(33, uintptr_type,
-							bloc);
-	  ref = Expression::make_temporary_reference(retval, bloc);
-	  Statement* s = Statement::make_assignment_operation(OPERATOR_MULTEQ,
-							      ref, i33, bloc);
-	  gogo->add_statement(s);
-	}
-
       // Get a pointer to the value of this field.
       Expression* offset = Expression::make_struct_field_offset(this, &*pf);
       ref = Expression::make_temporary_reference(key, bloc);
@@ -5439,10 +5668,6 @@ Struct_type::write_hash_function(Gogo* g
 						   bloc);
       subkey = Expression::make_cast(key_arg_type, subkey, bloc);
 
-      // Get the size of this field.
-      Expression* size = Expression::make_type_info(pf->type(),
-						    Expression::TYPE_INFO_SIZE);
-
       // Get the hash function to use for the type of this field.
       Named_object* hash_fn;
       Named_object* equal_fn;
@@ -5454,7 +5679,6 @@ Struct_type::write_hash_function(Gogo* g
       Expression_list* args = new Expression_list();
       args->push_back(subkey);
       args->push_back(ref);
-      args->push_back(size);
       Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc);
       Expression* call = Expression::make_call(func, args, false, bloc);
 
@@ -6295,14 +6519,6 @@ Array_type::write_hash_function(Gogo* go
 
   gogo->start_block(bloc);
 
-  // Multiply retval by 33.
-  Expression* i33 = Expression::make_integer_ul(33, uintptr_type, bloc);
-
-  ref = Expression::make_temporary_reference(retval, bloc);
-  Statement* s = Statement::make_assignment_operation(OPERATOR_MULTEQ, ref,
-						      i33, bloc);
-  gogo->add_statement(s);
-
   // Get the hash function for the element type.
   Named_object* hash_fn;
   Named_object* equal_fn;
@@ -6323,7 +6539,6 @@ Array_type::write_hash_function(Gogo* go
   Expression_list* args = new Expression_list();
   args->push_back(subkey);
   args->push_back(ref);
-  args->push_back(ele_size);
   Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc);
   Expression* call = Expression::make_call(func, args, false, bloc);
 
@@ -6331,7 +6546,7 @@ Array_type::write_hash_function(Gogo* go
   Temporary_reference_expression* tref =
     Expression::make_temporary_reference(retval, bloc);
   tref->set_is_lvalue();
-  s = Statement::make_assignment(tref, call, bloc);
+  Statement* s = Statement::make_assignment(tref, call, bloc);
   gogo->add_statement(s);
 
   // Increase the element pointer.
Index: gcc/go/gofrontend/types.h
===================================================================
--- gcc/go/gofrontend/types.h	(revision 244166)
+++ gcc/go/gofrontend/types.h	(working copy)
@@ -975,6 +975,10 @@ class Type
   bool
   is_backend_type_size_known(Gogo*);
 
+  // Return whether the type needs specially built type functions.
+  bool
+  needs_specific_type_functions(Gogo*);
+
   // Get the hash and equality functions for a type.
   void
   type_functions(Gogo*, Named_type* name, Function_type* hash_fntype,
@@ -983,7 +987,7 @@ class Type
 
   // Write the hash and equality type functions.
   void
-  write_specific_type_functions(Gogo*, Named_type*,
+  write_specific_type_functions(Gogo*, Named_type*, int64_t size,
 				const std::string& hash_name,
 				Function_type* hash_fntype,
 				const std::string& equal_name,
@@ -1206,11 +1210,18 @@ class Type
   // Build the hash and equality type functions for a type which needs
   // specific functions.
   void
-  specific_type_functions(Gogo*, Named_type*, Function_type* hash_fntype,
+  specific_type_functions(Gogo*, Named_type*, int64_t size,
+			  Function_type* hash_fntype,
 			  Function_type* equal_fntype, Named_object** hash_fn,
 			  Named_object** equal_fn);
 
   void
+  write_identity_hash(Gogo*, int64_t size);
+
+  void
+  write_identity_equal(Gogo*, int64_t size);
+
+  void
   write_named_hash(Gogo*, Named_type*, Function_type* hash_fntype,
 		   Function_type* equal_fntype);
 
Index: libgo/Makefile.am
===================================================================
--- libgo/Makefile.am	(revision 244166)
+++ libgo/Makefile.am	(working copy)
@@ -446,10 +446,6 @@ runtime_files = \
 	runtime/go-setenv.c \
 	runtime/go-signal.c \
 	runtime/go-strslice.c \
-	runtime/go-type-complex.c \
-	runtime/go-type-float.c \
-	runtime/go-type-identity.c \
-	runtime/go-type-string.c \
 	runtime/go-typedesc-equal.c \
 	runtime/go-unsafe-new.c \
 	runtime/go-unsafe-newarray.c \
Index: libgo/go/reflect/type.go
===================================================================
--- libgo/go/reflect/type.go	(revision 244166)
+++ libgo/go/reflect/type.go	(working copy)
@@ -254,8 +254,8 @@ type rtype struct {
 	size       uintptr
 	hash       uint32 // hash of type; avoids computation in hash tables
 
-	hashfn  func(unsafe.Pointer, uintptr, uintptr) uintptr     // hash function
-	equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool // equality function
+	hashfn  func(unsafe.Pointer, uintptr) uintptr     // hash function
+	equalfn func(unsafe.Pointer, unsafe.Pointer) bool // equality function
 
 	gc            unsafe.Pointer // garbage collection data
 	string        *string        // string form; unnecessary  but undeniably useful
@@ -2203,23 +2203,20 @@ func StructOf(fields []StructField) Type
 		typ.gc = unsafe.Pointer(&gc[0])
 	}
 
-	typ.hashfn = func(p unsafe.Pointer, seed, size uintptr) uintptr {
+	typ.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
 		ret := seed
-		for i, ft := range typ.fields {
-			if i > 0 {
-				ret *= 33
-			}
+		for _, ft := range typ.fields {
 			o := unsafe.Pointer(uintptr(p) + ft.offset)
-			ret = ft.typ.hashfn(o, ret, ft.typ.size)
+			ret = ft.typ.hashfn(o, ret)
 		}
 		return ret
 	}
 
-	typ.equalfn = func(p, q unsafe.Pointer, size uintptr) bool {
+	typ.equalfn = func(p, q unsafe.Pointer) bool {
 		for _, ft := range typ.fields {
 			pi := unsafe.Pointer(uintptr(p) + ft.offset)
 			qi := unsafe.Pointer(uintptr(q) + ft.offset)
-			if !ft.typ.equalfn(pi, qi, ft.typ.size) {
+			if !ft.typ.equalfn(pi, qi) {
 				return false
 			}
 		}
@@ -2348,19 +2345,18 @@ func ArrayOf(count int, elem Type) Type
 
 	array.kind &^= kindDirectIface
 
-	array.hashfn = func(p unsafe.Pointer, seed, size uintptr) uintptr {
+	array.hashfn = func(p unsafe.Pointer, seed uintptr) uintptr {
 		ret := seed
 		for i := 0; i < count; i++ {
-			ret *= 33
-			ret = typ.hashfn(p, ret, typ.size)
+			ret = typ.hashfn(p, ret)
 			p = unsafe.Pointer(uintptr(p) + typ.size)
 		}
 		return ret
 	}
 
-	array.equalfn = func(p1, p2 unsafe.Pointer, size uintptr) bool {
+	array.equalfn = func(p1, p2 unsafe.Pointer) bool {
 		for i := 0; i < count; i++ {
-			if !typ.equalfn(p1, p2, typ.size) {
+			if !typ.equalfn(p1, p2) {
 				return false
 			}
 			p1 = unsafe.Pointer(uintptr(p1) + typ.size)
Index: libgo/go/runtime/alg.go
===================================================================
--- libgo/go/runtime/alg.go	(revision 244166)
+++ libgo/go/runtime/alg.go	(working copy)
@@ -12,8 +12,30 @@ import (
 // For gccgo, use go:linkname to rename compiler-called functions to
 // themselves, so that the compiler will export them.
 //
+//go:linkname memhash0 runtime.memhash0
+//go:linkname memhash8 runtime.memhash8
+//go:linkname memhash16 runtime.memhash16
+//go:linkname memhash32 runtime.memhash32
+//go:linkname memhash64 runtime.memhash64
+//go:linkname memhash128 runtime.memhash128
+//go:linkname strhash runtime.strhash
+//go:linkname f32hash runtime.f32hash
+//go:linkname f64hash runtime.f64hash
+//go:linkname c64hash runtime.c64hash
+//go:linkname c128hash runtime.c128hash
 //go:linkname interhash runtime.interhash
 //go:linkname nilinterhash runtime.nilinterhash
+//go:linkname memequal0 runtime.memequal0
+//go:linkname memequal8 runtime.memequal8
+//go:linkname memequal16 runtime.memequal16
+//go:linkname memequal32 runtime.memequal32
+//go:linkname memequal64 runtime.memequal64
+//go:linkname memequal128 runtime.memequal128
+//go:linkname strequal runtime.strequal
+//go:linkname f32equal runtime.f32equal
+//go:linkname f64equal runtime.f64equal
+//go:linkname c64equal runtime.c64equal
+//go:linkname c128equal runtime.c128equal
 //go:linkname interequal runtime.interequal
 //go:linkname nilinterequal runtime.nilinterequal
 //go:linkname efaceeq runtime.efaceeq
@@ -32,6 +54,25 @@ const (
 	c1 = uintptr((8-sys.PtrSize)/4*3267000013 + (sys.PtrSize-4)/4*23344194077549503)
 )
 
+func memhash0(p unsafe.Pointer, h uintptr) uintptr {
+	return h
+}
+func memhash8(p unsafe.Pointer, h uintptr) uintptr {
+	return memhash(p, h, 1)
+}
+func memhash16(p unsafe.Pointer, h uintptr) uintptr {
+	return memhash(p, h, 2)
+}
+func memhash32(p unsafe.Pointer, h uintptr) uintptr {
+	return memhash(p, h, 4)
+}
+func memhash64(p unsafe.Pointer, h uintptr) uintptr {
+	return memhash(p, h, 8)
+}
+func memhash128(p unsafe.Pointer, h uintptr) uintptr {
+	return memhash(p, h, 16)
+}
+
 var useAeshash bool
 
 // in C code
@@ -46,6 +87,50 @@ func aeshashstr(p unsafe.Pointer, h uint
 	return aeshashbody(unsafe.Pointer(ps.str), h, uintptr(ps.len), aeskeysched[:])
 }
 
+func strhash(a unsafe.Pointer, h uintptr) uintptr {
+	x := (*stringStruct)(a)
+	return memhash(x.str, h, uintptr(x.len))
+}
+
+// NOTE: Because NaN != NaN, a map can contain any
+// number of (mostly useless) entries keyed with NaNs.
+// To avoid long hash chains, we assign a random number
+// as the hash value for a NaN.
+
+func f32hash(p unsafe.Pointer, h uintptr) uintptr {
+	f := *(*float32)(p)
+	switch {
+	case f == 0:
+		return c1 * (c0 ^ h) // +0, -0
+	case f != f:
+		return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
+	default:
+		return memhash(p, h, 4)
+	}
+}
+
+func f64hash(p unsafe.Pointer, h uintptr) uintptr {
+	f := *(*float64)(p)
+	switch {
+	case f == 0:
+		return c1 * (c0 ^ h) // +0, -0
+	case f != f:
+		return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
+	default:
+		return memhash(p, h, 8)
+	}
+}
+
+func c64hash(p unsafe.Pointer, h uintptr) uintptr {
+	x := (*[2]float32)(p)
+	return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h))
+}
+
+func c128hash(p unsafe.Pointer, h uintptr) uintptr {
+	x := (*[2]float64)(p)
+	return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h))
+}
+
 func interhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr {
 	a := (*iface)(p)
 	tab := a.tab
@@ -58,13 +143,13 @@ func interhash(p unsafe.Pointer, h uintp
 		panic(errorString("hash of unhashable type " + *t.string))
 	}
 	if isDirectIface(t) {
-		return c1 * fn(unsafe.Pointer(&a.data), h^c0, t.size)
+		return c1 * fn(unsafe.Pointer(&a.data), h^c0)
 	} else {
-		return c1 * fn(a.data, h^c0, t.size)
+		return c1 * fn(a.data, h^c0)
 	}
 }
 
-func nilinterhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr {
+func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
 	a := (*eface)(p)
 	t := a._type
 	if t == nil {
@@ -75,20 +160,51 @@ func nilinterhash(p unsafe.Pointer, h ui
 		panic(errorString("hash of unhashable type " + *t.string))
 	}
 	if isDirectIface(t) {
-		return c1 * fn(unsafe.Pointer(&a.data), h^c0, t.size)
+		return c1 * fn(unsafe.Pointer(&a.data), h^c0)
 	} else {
-		return c1 * fn(a.data, h^c0, t.size)
+		return c1 * fn(a.data, h^c0)
 	}
 }
 
+func memequal0(p, q unsafe.Pointer) bool {
+	return true
+}
+func memequal8(p, q unsafe.Pointer) bool {
+	return *(*int8)(p) == *(*int8)(q)
+}
+func memequal16(p, q unsafe.Pointer) bool {
+	return *(*int16)(p) == *(*int16)(q)
+}
+func memequal32(p, q unsafe.Pointer) bool {
+	return *(*int32)(p) == *(*int32)(q)
+}
+func memequal64(p, q unsafe.Pointer) bool {
+	return *(*int64)(p) == *(*int64)(q)
+}
+func memequal128(p, q unsafe.Pointer) bool {
+	return *(*[2]int64)(p) == *(*[2]int64)(q)
+}
+func f32equal(p, q unsafe.Pointer) bool {
+	return *(*float32)(p) == *(*float32)(q)
+}
+func f64equal(p, q unsafe.Pointer) bool {
+	return *(*float64)(p) == *(*float64)(q)
+}
+func c64equal(p, q unsafe.Pointer) bool {
+	return *(*complex64)(p) == *(*complex64)(q)
+}
+func c128equal(p, q unsafe.Pointer) bool {
+	return *(*complex128)(p) == *(*complex128)(q)
+}
+func strequal(p, q unsafe.Pointer) bool {
+	return *(*string)(p) == *(*string)(q)
+}
 func interequal(p, q unsafe.Pointer, size uintptr) bool {
 	return ifaceeq(*(*iface)(p), *(*iface)(q))
 }
-
 func nilinterequal(p, q unsafe.Pointer, size uintptr) bool {
 	return efaceeq(*(*eface)(p), *(*eface)(q))
 }
-
 func efaceeq(x, y eface) bool {
 	t := x._type
 	if !eqtype(t, y._type) {
@@ -104,9 +220,8 @@ func efaceeq(x, y eface) bool {
 	if isDirectIface(t) {
 		return x.data == y.data
 	}
-	return eq(x.data, y.data, t.size)
+	return eq(x.data, y.data)
 }
-
 func ifaceeq(x, y iface) bool {
 	xtab := x.tab
 	if xtab == nil && y.tab == nil {
@@ -126,7 +241,7 @@ func ifaceeq(x, y iface) bool {
 	if isDirectIface(t) {
 		return x.data == y.data
 	}
-	return eq(x.data, y.data, t.size)
+	return eq(x.data, y.data)
 }
 
 func ifacevaleq(x iface, t *_type, p unsafe.Pointer) bool {
@@ -144,7 +259,7 @@ func ifacevaleq(x iface, t *_type, p uns
 	if isDirectIface(t) {
 		return x.data == p
 	}
-	return eq(x.data, p, t.size)
+	return eq(x.data, p)
 }
 
 func ifaceefaceeq(x iface, y eface) bool {
@@ -165,7 +280,7 @@ func ifaceefaceeq(x iface, y eface) bool
 	if isDirectIface(xt) {
 		return x.data == y.data
 	}
-	return eq(x.data, y.data, xt.size)
+	return eq(x.data, y.data)
 }
 
 func efacevaleq(x eface, t *_type, p unsafe.Pointer) bool {
@@ -182,7 +297,7 @@ func efacevaleq(x eface, t *_type, p uns
 	if isDirectIface(t) {
 		return x.data == p
 	}
-	return eq(x.data, p, t.size)
+	return eq(x.data, p)
 }
 
 func eqstring(x, y string) bool {
@@ -213,13 +328,47 @@ func cmpstring(x, y string) int {
 	return 0
 }
 
+// For the unsafe.Pointer type descriptor in libgo/runtime/go-unsafe-pointer.c.
+
+func pointerhash(p unsafe.Pointer, h uintptr) uintptr {
+	return memhash(p, h, unsafe.Sizeof(unsafe.Pointer))
+}
+
+func pointerequal(p, q unsafe.Pointer) bool {
+	return *(*unsafe.Pointer)(p) == *(*unsafe.Pointer)(q)
+}
+
 // Force the creation of function descriptors for equality and hash
 // functions.  These will be referenced directly by the compiler.
 var _ = memhash
+var _ = memhash0
+var _ = memhash8
+var _ = memhash16
+var _ = memhash32
+var _ = memhash64
+var _ = memhash128
+var _ = strhash
+var _ = f32hash
+var _ = f64hash
+var _ = c64hash
+var _ = c128hash
 var _ = interhash
-var _ = interequal
 var _ = nilinterhash
+var _ = memequal0
+var _ = memequal8
+var _ = memequal16
+var _ = memequal32
+var _ = memequal64
+var _ = memequal128
+var _ = f32equal
+var _ = f64equal
+var _ = c64equal
+var _ = c128equal
+var _ = strequal
+var _ = interequal
 var _ = nilinterequal
+var _ = pointerhash
+var _ = pointerequal
 
 const hashRandomBytes = sys.PtrSize / 4 * 64
 
Index: libgo/go/runtime/hashmap.go
===================================================================
--- libgo/go/runtime/hashmap.go	(revision 244166)
+++ libgo/go/runtime/hashmap.go	(working copy)
@@ -300,7 +300,7 @@ func mapaccess1(t *maptype, h *hmap, key
 	}
 	hashfn := t.key.hashfn
 	equalfn := t.key.equalfn
-	hash := hashfn(key, uintptr(h.hash0), uintptr(t.keysize))
+	hash := hashfn(key, uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
@@ -322,7 +322,7 @@ func mapaccess1(t *maptype, h *hmap, key
 			if t.indirectkey {
 				k = *((*unsafe.Pointer)(k))
 			}
-			if equalfn(key, k, uintptr(t.keysize)) {
+			if equalfn(key, k) {
 				v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
 				if t.indirectvalue {
 					v = *((*unsafe.Pointer)(v))
@@ -355,7 +355,7 @@ func mapaccess2(t *maptype, h *hmap, key
 	}
 	hashfn := t.key.hashfn
 	equalfn := t.key.equalfn
-	hash := hashfn(key, uintptr(h.hash0), uintptr(t.keysize))
+	hash := hashfn(key, uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
@@ -377,7 +377,7 @@ func mapaccess2(t *maptype, h *hmap, key
 			if t.indirectkey {
 				k = *((*unsafe.Pointer)(k))
 			}
-			if equalfn(key, k, uintptr(t.keysize)) {
+			if equalfn(key, k) {
 				v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
 				if t.indirectvalue {
 					v = *((*unsafe.Pointer)(v))
@@ -402,7 +402,7 @@ func mapaccessK(t *maptype, h *hmap, key
 	}
 	hashfn := t.key.hashfn
 	equalfn := t.key.equalfn
-	hash := hashfn(key, uintptr(h.hash0), uintptr(t.keysize))
+	hash := hashfn(key, uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
@@ -424,7 +424,7 @@ func mapaccessK(t *maptype, h *hmap, key
 			if t.indirectkey {
 				k = *((*unsafe.Pointer)(k))
 			}
-			if equalfn(key, k, uintptr(t.keysize)) {
+			if equalfn(key, k) {
 				v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
 				if t.indirectvalue {
 					v = *((*unsafe.Pointer)(v))
@@ -477,7 +477,7 @@ func mapassign1(t *maptype, h *hmap, key
 
 	hashfn := t.key.hashfn
 	equalfn := t.key.equalfn
-	hash := hashfn(key, uintptr(h.hash0), uintptr(t.keysize))
+	hash := hashfn(key, uintptr(h.hash0))
 
 	if h.buckets == nil {
 		h.buckets = newarray(t.bucket, 1)
@@ -512,7 +512,7 @@ again:
 			if t.indirectkey {
 				k2 = *((*unsafe.Pointer)(k2))
 			}
-			if !equalfn(key, k2, uintptr(t.keysize)) {
+			if !equalfn(key, k2) {
 				continue
 			}
 			// already have a mapping for key. Update it.
@@ -592,7 +592,7 @@ func mapdelete(t *maptype, h *hmap, key
 
 	hashfn := t.key.hashfn
 	equalfn := t.key.equalfn
-	hash := hashfn(key, uintptr(h.hash0), uintptr(t.keysize))
+	hash := hashfn(key, uintptr(h.hash0))
 	bucket := hash & (uintptr(1)<<h.B - 1)
 	if h.oldbuckets != nil {
 		growWork(t, h, bucket)
@@ -612,7 +612,7 @@ func mapdelete(t *maptype, h *hmap, key
 			if t.indirectkey {
 				k2 = *((*unsafe.Pointer)(k2))
 			}
-			if !equalfn(key, k2, uintptr(t.keysize)) {
+			if !equalfn(key, k2) {
 				continue
 			}
 			memclr(k, uintptr(t.keysize))
@@ -760,10 +760,10 @@ next:
 				if t.indirectkey {
 					k2 = *((*unsafe.Pointer)(k2))
 				}
-				if t.reflexivekey || equalfn(k2, k2, uintptr(t.keysize)) {
+				if t.reflexivekey || equalfn(k2, k2) {
 					// If the item in the oldbucket is not destined for
 					// the current new bucket in the iteration, skip it.
-					hash := hashfn(k2, uintptr(h.hash0), uintptr(t.keysize))
+					hash := hashfn(k2, uintptr(h.hash0))
 					if hash&(uintptr(1)<<it.B-1) != checkBucket {
 						continue
 					}
@@ -797,7 +797,7 @@ next:
 				if t.indirectkey {
 					k2 = *((*unsafe.Pointer)(k2))
 				}
-				if t.reflexivekey || equalfn(k2, k2, uintptr(t.keysize)) {
+				if t.reflexivekey || equalfn(k2, k2) {
 					// Check the current hash table for the data.
 					// This code handles the case where the key
 					// has been deleted, updated, or deleted and reinserted.
@@ -913,9 +913,9 @@ func evacuate(t *maptype, h *hmap, oldbu
 				}
 				// Compute hash to make our evacuation decision (whether we need
 				// to send this key/value to bucket x or bucket y).
-				hash := hashfn(k2, uintptr(h.hash0), uintptr(t.keysize))
+				hash := hashfn(k2, uintptr(h.hash0))
 				if h.flags&iterator != 0 {
-					if !t.reflexivekey && !equalfn(k2, k2, uintptr(t.keysize)) {
+					if !t.reflexivekey && !equalfn(k2, k2) {
 						// If key != key (NaNs), then the hash could be (and probably
 						// will be) entirely different from the old hash. Moreover,
 						// it isn't reproducible. Reproducibility is required in the
Index: libgo/go/runtime/hashmap_fast.go
===================================================================
--- libgo/go/runtime/hashmap_fast.go	(revision 244166)
+++ libgo/go/runtime/hashmap_fast.go	(working copy)
@@ -25,7 +25,7 @@ func mapaccess1_fast32(t *maptype, h *hm
 		// One-bucket table. No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
-		hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0), uintptr(t.keysize))
+		hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
 		m := uintptr(1)<<h.B - 1
 		b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 		if c := h.oldbuckets; c != nil {
@@ -70,7 +70,7 @@ func mapaccess2_fast32(t *maptype, h *hm
 		// One-bucket table. No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
-		hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0), uintptr(t.keysize))
+		hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
 		m := uintptr(1)<<h.B - 1
 		b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 		if c := h.oldbuckets; c != nil {
@@ -115,7 +115,7 @@ func mapaccess1_fast64(t *maptype, h *hm
 		// One-bucket table. No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
-		hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0), uintptr(t.keysize))
+		hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
 		m := uintptr(1)<<h.B - 1
 		b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 		if c := h.oldbuckets; c != nil {
@@ -160,7 +160,7 @@ func mapaccess2_fast64(t *maptype, h *hm
 		// One-bucket table. No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
-		hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0), uintptr(t.keysize))
+		hash := t.key.hashfn(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
 		m := uintptr(1)<<h.B - 1
 		b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 		if c := h.oldbuckets; c != nil {
@@ -260,7 +260,7 @@ func mapaccess1_faststr(t *maptype, h *h
 		return unsafe.Pointer(&zeroVal[0])
 	}
 dohash:
-	hash := t.key.hashfn(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0), uintptr(t.keysize))
+	hash := t.key.hashfn(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
@@ -363,7 +363,7 @@ func mapaccess2_faststr(t *maptype, h *h
 		return unsafe.Pointer(&zeroVal[0]), false
 	}
 dohash:
-	hash := t.key.hashfn(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0), uintptr(t.keysize))
+	hash := t.key.hashfn(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
Index: libgo/go/runtime/type.go
===================================================================
--- libgo/go/runtime/type.go	(revision 244166)
+++ libgo/go/runtime/type.go	(working copy)
@@ -16,8 +16,8 @@ type _type struct {
 	size       uintptr
 	hash       uint32
 
-	hashfn  func(unsafe.Pointer, uintptr, uintptr) uintptr
-	equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
+	hashfn  func(unsafe.Pointer, uintptr) uintptr
+	equalfn func(unsafe.Pointer, unsafe.Pointer) bool
 
 	gc     unsafe.Pointer
 	string *string
Index: libgo/runtime/go-type-complex.c
===================================================================
--- libgo/runtime/go-type-complex.c	(revision 244166)
+++ libgo/runtime/go-type-complex.c	(working copy)
@@ -1,120 +0,0 @@
-/* go-type-complex.c -- hash and equality complex functions.
-
-   Copyright 2012 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.  */
-
-#include <complex.h>
-#include <math.h>
-#include <stdint.h>
-#include <string.h>
-#include "runtime.h"
-#include "go-type.h"
-
-/* Hash function for float types.  */
-
-uintptr_t
-__go_type_hash_complex (const void *vkey, uintptr_t seed, uintptr_t key_size)
-{
-  if (key_size == 8)
-    {
-      const complex float *cfp;
-      complex float cf;
-      float cfr;
-      float cfi;
-      uint64_t fi;
-
-      cfp = (const complex float *) vkey;
-      cf = *cfp;
-
-      cfr = crealf (cf);
-      cfi = cimagf (cf);
-
-      if (isinf (cfr) || isinf (cfi))
-	return seed;
-
-      /* NaN != NaN, so the hash code of a NaN is irrelevant.  Make it
-	 random so that not all NaNs wind up in the same place.  */
-      if (isnan (cfr) || isnan (cfi))
-	return runtime_fastrand1 ();
-
-      /* Avoid negative zero.  */
-      if (cfr == 0 && cfi == 0)
-	return seed;
-      else if (cfr == 0)
-	cf = cfi * I;
-      else if (cfi == 0)
-	cf = cfr;
-
-      memcpy (&fi, &cf, 8);
-      return (uintptr_t) cfi ^ seed;
-    }
-  else if (key_size == 16)
-    {
-      const complex double *cdp;
-      complex double cd;
-      double cdr;
-      double cdi;
-      uint64_t di[2];
-
-      cdp = (const complex double *) vkey;
-      cd = *cdp;
-
-      cdr = creal (cd);
-      cdi = cimag (cd);
-
-      if (isinf (cdr) || isinf (cdi))
-	return seed;
-
-      if (isnan (cdr) || isnan (cdi))
-	return runtime_fastrand1 ();
-
-      /* Avoid negative zero.  */
-      if (cdr == 0 && cdi == 0)
-	return seed;
-      else if (cdr == 0)
-	cd = cdi * I;
-      else if (cdi == 0)
-	cd = cdr;
-
-      memcpy (&di, &cd, 16);
-      return di[0] ^ di[1] ^ seed;
-    }
-  else
-    runtime_throw ("__go_type_hash_complex: invalid complex size");
-}
-
-const FuncVal __go_type_hash_complex_descriptor =
-  { (void *) __go_type_hash_complex };
-
-/* Equality function for complex types.  */
-
-_Bool
-__go_type_equal_complex (const void *vk1, const void *vk2, uintptr_t key_size)
-{
-  if (key_size == 8)
-    {
-      const complex float *cfp1;
-      const complex float *cfp2;
-      
-      cfp1 = (const complex float *) vk1;
-      cfp2 = (const complex float *) vk2;
-
-      return *cfp1 == *cfp2;
-    }
-  else if (key_size == 16)
-    {
-      const complex double *cdp1;
-      const complex double *cdp2;
-      
-      cdp1 = (const complex double *) vk1;
-      cdp2 = (const complex double *) vk2;
-
-      return *cdp1 == *cdp2;
-    }
-  else
-    runtime_throw ("__go_type_equal_complex: invalid complex size");
-}
-
-const FuncVal __go_type_equal_complex_descriptor =
-  { (void *) __go_type_equal_complex };
Index: libgo/runtime/go-type-float.c
===================================================================
--- libgo/runtime/go-type-float.c	(revision 244166)
+++ libgo/runtime/go-type-float.c	(working copy)
@@ -1,92 +0,0 @@
-/* go-type-float.c -- hash and equality float functions.
-
-   Copyright 2012 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.  */
-
-#include <math.h>
-#include <stdint.h>
-#include "runtime.h"
-#include "go-type.h"
-
-/* Hash function for float types.  */
-
-uintptr_t
-__go_type_hash_float (const void *vkey, uintptr_t seed, uintptr_t key_size)
-{
-  if (key_size == 4)
-    {
-      const float *fp;
-      float f;
-      uint32_t si;
-
-      fp = (const float *) vkey;
-      f = *fp;
-
-      if (isinf (f) || f == 0)
-	return seed;
-
-      /* NaN != NaN, so the hash code of a NaN is irrelevant.  Make it
-	 random so that not all NaNs wind up in the same place.  */
-      if (isnan (f))
-	return runtime_fastrand1 ();
-
-      memcpy (&si, vkey, 4);
-      return (uintptr_t) si ^ seed;
-    }
-  else if (key_size == 8)
-    {
-      const double *dp;
-      double d;
-      uint64_t di;
-
-      dp = (const double *) vkey;
-      d = *dp;
-
-      if (isinf (d) || d == 0)
-	return seed;
-
-      if (isnan (d))
-	return runtime_fastrand1 ();
-
-      memcpy (&di, vkey, 8);
-      return (uintptr_t) di ^ seed;
-    }
-  else
-    runtime_throw ("__go_type_hash_float: invalid float size");
-}
-
-const FuncVal __go_type_hash_float_descriptor =
-  { (void *) __go_type_hash_float };
-
-/* Equality function for float types.  */
-
-_Bool
-__go_type_equal_float (const void *vk1, const void *vk2, uintptr_t key_size)
-{
-  if (key_size == 4)
-    {
-      const float *fp1;
-      const float *fp2;
-
-      fp1 = (const float *) vk1;
-      fp2 = (const float *) vk2;
-
-      return *fp1 == *fp2;
-    }
-  else if (key_size == 8)
-    {
-      const double *dp1;
-      const double *dp2;
-
-      dp1 = (const double *) vk1;
-      dp2 = (const double *) vk2;
-
-      return *dp1 == *dp2;
-    }
-  else
-    runtime_throw ("__go_type_equal_float: invalid float size");
-}
-
-const FuncVal __go_type_equal_float_descriptor =
-  { (void *) __go_type_equal_float };
Index: libgo/runtime/go-type-identity.c
===================================================================
--- libgo/runtime/go-type-identity.c	(revision 244166)
+++ libgo/runtime/go-type-identity.c	(working copy)
@@ -1,32 +0,0 @@
-/* go-type-identity.c -- hash and equality identity functions.
-
-   Copyright 2009 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.  */
-
-#include <stddef.h>
-
-#include "runtime.h"
-#include "go-type.h"
-
-/* The hash functions for types that can compare as identity is
-   written in Go.  */
-
-extern uintptr runtime_memhash(void *, uintptr, uintptr)
-  __asm__ (GOSYM_PREFIX "runtime.memhash");
-
-const FuncVal __go_type_hash_identity_descriptor =
-  { (void *) runtime_memhash };
-
-/* An identity equality function for a type.  This is used for types
-   where we can check for equality by checking that the values have
-   the same bits.  */
-
-_Bool
-__go_type_equal_identity (const void *k1, const void *k2, uintptr_t key_size)
-{
-  return __builtin_memcmp (k1, k2, key_size) == 0;
-}
-
-const FuncVal __go_type_equal_identity_descriptor =
-  { (void *) __go_type_equal_identity };
Index: libgo/runtime/go-type-string.c
===================================================================
--- libgo/runtime/go-type-string.c	(revision 244166)
+++ libgo/runtime/go-type-string.c	(working copy)
@@ -1,49 +0,0 @@
-/* go-type-string.c -- hash and equality string functions.
-
-   Copyright 2009 The Go Authors. All rights reserved.
-   Use of this source code is governed by a BSD-style
-   license that can be found in the LICENSE file.  */
-
-#include "runtime.h"
-#include "go-type.h"
-#include "go-string.h"
-
-/* A string hash function for a map.  */
-
-uintptr_t
-__go_type_hash_string (const void *vkey, uintptr_t seed,
-		       uintptr_t key_size __attribute__ ((unused)))
-{
-  uintptr_t ret;
-  const String *key;
-  intgo len;
-  intgo i;
-  const byte *p;
-
-  ret = seed;
-  key = (const String *) vkey;
-  len = key->len;
-  for (i = 0, p = key->str; i < len; i++, p++)
-    ret = ret * 33 + *p;
-  return ret;
-}
-
-const FuncVal __go_type_hash_string_descriptor =
-  { (void *) __go_type_hash_string };
-
-/* A string equality function for a map.  */
-
-_Bool
-__go_type_equal_string (const void *vk1, const void *vk2,
-			uintptr_t key_size __attribute__ ((unused)))
-{
-  const String *k1;
-  const String *k2;
-
-  k1 = (const String *) vk1;
-  k2 = (const String *) vk2;
-  return __go_ptr_strings_equal (k1, k2);
-}
-
-const FuncVal __go_type_equal_string_descriptor =
-  { (void *) __go_type_equal_string };
Index: libgo/runtime/go-type.h
===================================================================
--- libgo/runtime/go-type.h	(revision 244166)
+++ libgo/runtime/go-type.h	(working copy)
@@ -362,24 +362,4 @@ extern _Bool
 __go_type_descriptors_equal(const struct __go_type_descriptor*,
 			    const struct __go_type_descriptor*);
 
-extern const FuncVal __go_type_hash_identity_descriptor;
-extern _Bool __go_type_equal_identity (const void *, const void *, uintptr_t);
-extern const FuncVal __go_type_equal_identity_descriptor;
-extern uintptr_t __go_type_hash_string (const void *, uintptr_t, uintptr_t);
-extern const FuncVal __go_type_hash_string_descriptor;
-extern _Bool __go_type_equal_string (const void *, const void *, uintptr_t);
-extern const FuncVal __go_type_equal_string_descriptor;
-extern uintptr_t __go_type_hash_float (const void *, uintptr_t, uintptr_t);
-extern const FuncVal __go_type_hash_float_descriptor;
-extern _Bool __go_type_equal_float (const void *, const void *, uintptr_t);
-extern const FuncVal __go_type_equal_float_descriptor;
-extern uintptr_t __go_type_hash_complex (const void *, uintptr_t, uintptr_t);
-extern const FuncVal __go_type_hash_complex_descriptor;
-extern _Bool __go_type_equal_complex (const void *, const void *, uintptr_t);
-extern const FuncVal __go_type_equal_complex_descriptor;
-extern uintptr_t __go_type_hash_interface (const void *, uintptr_t, uintptr_t);
-extern const FuncVal __go_type_hash_interface_descriptor;
-extern _Bool __go_type_equal_interface (const void *, const void *, uintptr_t);
-extern const FuncVal __go_type_equal_interface_descriptor;
-
 #endif /* !defined(LIBGO_GO_TYPE_H) */
Index: libgo/runtime/go-unsafe-pointer.c
===================================================================
--- libgo/runtime/go-unsafe-pointer.c	(revision 244166)
+++ libgo/runtime/go-unsafe-pointer.c	(working copy)
@@ -38,6 +38,11 @@ static const String reflection_string =
 
 const uintptr unsafe_Pointer_gc[] = {sizeof(void*), GC_APTR, 0, GC_END};
 
+extern const FuncVal runtime_pointerhash_descriptor
+  __asm__ (GOSYM_PREFIX "runtime.pointerhash$descriptor");
+extern const FuncVal runtime_pointerequal_descriptor
+  __asm__ (GOSYM_PREFIX "runtime.pointerequal$descriptor");
+
 const struct __go_type_descriptor unsafe_Pointer =
 {
   /* __code */
@@ -51,9 +56,9 @@ const struct __go_type_descriptor unsafe
   /* __hash */
   78501163U,
   /* __hashfn */
-  &__go_type_hash_identity_descriptor,
+  &runtime_pointerhash_descriptor,
   /* __equalfn */
-  &__go_type_equal_identity_descriptor,
+  &runtime_pointerequal_descriptor,
   /* __gc */
   unsafe_Pointer_gc,
   /* __reflection */
@@ -94,9 +99,9 @@ const struct __go_ptr_type pointer_unsaf
     /* __hash */
     1256018616U,
     /* __hashfn */
-    &__go_type_hash_identity_descriptor,
+    &runtime_pointerhash_descriptor,
     /* __equalfn */
-    &__go_type_equal_identity_descriptor,
+    &runtime_pointerequal_descriptor,
     /* __gc */
     unsafe_Pointer_gc,
     /* __reflection */

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Go patch committed: drop size arguments to hash/equal functions
  2017-01-10  3:59 Go patch committed: drop size arguments to hash/equal functions Ian Lance Taylor
@ 2017-01-10 19:45 ` Rainer Orth
  2017-01-11 17:42   ` Ian Lance Taylor
  0 siblings, 1 reply; 3+ messages in thread
From: Rainer Orth @ 2017-01-10 19:45 UTC (permalink / raw)
  To: Ian Lance Taylor; +Cc: gcc-patches, gofrontend-dev

Hi Ian,

> Drop the size arguments for the hash/equal functions stored in type
> descriptors.  Types know what size they are.  To make this work,
> generate hash/equal functions for types that can use an identity
> comparison but are not a standard size and alignment.
>
> Drop the multiplications by 33 in the generated hash code and the
> reflect package hash code.  They are not necessary since we started
> passing a seed value around, as the seed includes the hash of the
> earlier values.
>
> Copy the algorithms for standard types from the Go 1.7 runtime,
> replacing the C functions.
>
> Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
> to mainline.

this patch broke Solaris/SPARC bootstrap, it seems: building
debug/dwarf.lo ICEs like this:

go1: internal compiler error: in write_specific_type_functions, at go/gofrontend/types.cc:1993
0x4bc50b Type::write_specific_type_functions(Gogo*, Named_type*, long long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Function_type*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Function_type*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/types.cc:1993
0x4bc8ff Type::specific_type_functions(Gogo*, Named_type*, long long, Function_type*, Function_type*, Named_object**, Named_object**)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/types.cc:1971
0x4bb2a3 Type::type_functions(Gogo*, Named_type*, Function_type*, Function_type*, Named_object**, Named_object**)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/types.cc:1753
0x4bf06f Type::type_descriptor_constructor(Gogo*, int, Named_type*, Methods const*, bool)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/types.cc:2308
0x4c0893 Array_type::array_type_descriptor(Gogo*, Named_type*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/types.cc:6932
0x4b43c7 Type::make_type_descriptor_var(Gogo*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/types.cc:1237
0x4b47c3 Type::type_descriptor_pointer(Gogo*, Location)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/types.cc:1172
0x1232d63 Type_descriptor_expression::do_get_backend(Translate_context*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:14344
0x4251df Expression::get_backend(Translate_context*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:402
0x43faaf Struct_construction_expression::do_get_backend(Translate_context*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:12572
0x4251df Expression::get_backend(Translate_context*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:402
0x4408d3 Array_construction_expression::get_constructor(Translate_context*, Btype*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:12795
0x4251df Expression::get_backend(Translate_context*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:402
0x43cb93 Unary_expression::do_get_backend(Translate_context*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:4249
0x4251df Expression::get_backend(Translate_context*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:402
0x4260ef Slice_value_expression::do_get_backend(Translate_context*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:14729
0x4251df Expression::get_backend(Translate_context*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:402
0x4251df Expression::get_backend(Translate_context*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:402
0x43faaf Struct_construction_expression::do_get_backend(Translate_context*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:12572
0x4251df Expression::get_backend(Translate_context*)
        /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/expressions.cc:402

Solaris/x86 is fine.

	Rainer

-- 
-----------------------------------------------------------------------------
Rainer Orth, Center for Biotechnology, Bielefeld University

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: Go patch committed: drop size arguments to hash/equal functions
  2017-01-10 19:45 ` Rainer Orth
@ 2017-01-11 17:42   ` Ian Lance Taylor
  0 siblings, 0 replies; 3+ messages in thread
From: Ian Lance Taylor @ 2017-01-11 17:42 UTC (permalink / raw)
  To: Rainer Orth; +Cc: gcc-patches, gofrontend-dev

[-- Attachment #1: Type: text/plain, Size: 2044 bytes --]

On Tue, Jan 10, 2017 at 11:45 AM, Rainer Orth
<ro@cebitec.uni-bielefeld.de> wrote:
>
>> Drop the size arguments for the hash/equal functions stored in type
>> descriptors.  Types know what size they are.  To make this work,
>> generate hash/equal functions for types that can use an identity
>> comparison but are not a standard size and alignment.
>>
>> Drop the multiplications by 33 in the generated hash code and the
>> reflect package hash code.  They are not necessary since we started
>> passing a seed value around, as the seed includes the hash of the
>> earlier values.
>>
>> Copy the algorithms for standard types from the Go 1.7 runtime,
>> replacing the C functions.
>>
>> Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
>> to mainline.
>
> this patch broke Solaris/SPARC bootstrap, it seems: building
> debug/dwarf.lo ICEs like this:
>
> go1: internal compiler error: in write_specific_type_functions, at go/gofrontend/types.cc:1993
> 0x4bc50b Type::write_specific_type_functions(Gogo*, Named_type*, long long, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Function_type*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Function_type*)
>         /vol/gcc/src/hg/trunk/local/gcc/go/gofrontend/types.cc:1993

Thanks.  Looks like 32-bit SPARC requires a padding field in the
bucket struct created for some map type.  The compiler then tries to
generate type functions for the type descriptor, and fails due to a
phase ordering problem--at that point all type functions are expected
to have been created.  It worked previously because it used the
standard functions for types that can use an identity comparison, but
that is no longer the case for types with unusual sizes.  Fixed by
this patch, which marks compiler-created arrays and structs
non-comparable, meaning that no type functions are created.
Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian

[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 9590 bytes --]

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 244291)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@
-d3725d876496f2cca3d6ce538e98b58c85d90bfb
+6be46149636c3533389e62c6dc76f0a7ff461080
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 244256)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -6741,8 +6741,9 @@ Bound_method_expression::create_thunk(Go
   sfl->push_back(Struct_field(Typed_identifier("val.1",
 					       orig_fntype->receiver()->type(),
 					       loc)));
-  Type* closure_type = Type::make_struct_type(sfl, loc);
-  closure_type = Type::make_pointer_type(closure_type);
+  Struct_type* st = Type::make_struct_type(sfl, loc);
+  st->set_is_struct_incomparable();
+  Type* closure_type = Type::make_pointer_type(st);
 
   Function_type* new_fntype = orig_fntype->copy_with_names();
 
@@ -6896,6 +6897,7 @@ Bound_method_expression::do_flatten(Gogo
 						  loc)));
   fields->push_back(Struct_field(Typed_identifier("val.1", val->type(), loc)));
   Struct_type* st = Type::make_struct_type(fields, loc);
+  st->set_is_struct_incomparable();
 
   Expression_list* vals = new Expression_list();
   vals->push_back(Expression::make_func_code_reference(thunk, loc));
@@ -9683,6 +9685,7 @@ Call_expression::do_flatten(Gogo* gogo,
         }
 
       Struct_type* st = Type::make_struct_type(sfl, loc);
+      st->set_is_struct_incomparable();
       this->call_temp_ = Statement::make_temporary(st, NULL, loc);
       inserter->insert(this->call_temp_);
     }
@@ -11565,7 +11568,8 @@ Field_reference_expression::do_lower(Gog
   Expression* length_expr = Expression::make_integer_ul(s.length(), NULL, loc);
 
   Type* byte_type = gogo->lookup_global("byte")->type_value();
-  Type* array_type = Type::make_array_type(byte_type, length_expr);
+  Array_type* array_type = Type::make_array_type(byte_type, length_expr);
+  array_type->set_is_array_incomparable();
 
   Expression_list* bytes = new Expression_list();
   for (std::string::const_iterator p = s.begin(); p != s.end(); p++)
@@ -11843,8 +11847,9 @@ Interface_field_reference_expression::cr
   Type* vt = Type::make_pointer_type(Type::make_void_type());
   sfl->push_back(Struct_field(Typed_identifier("fn.0", vt, loc)));
   sfl->push_back(Struct_field(Typed_identifier("val.1", type, loc)));
-  Type* closure_type = Type::make_struct_type(sfl, loc);
-  closure_type = Type::make_pointer_type(closure_type);
+  Struct_type* st = Type::make_struct_type(sfl, loc);
+  st->set_is_struct_incomparable();
+  Type* closure_type = Type::make_pointer_type(st);
 
   Function_type* new_fntype = orig_fntype->copy_with_names();
 
@@ -11943,6 +11948,7 @@ Interface_field_reference_expression::do
 						  this->expr_->type(),
 						  loc)));
   Struct_type* st = Type::make_struct_type(fields, loc);
+  st->set_is_struct_incomparable();
 
   Expression_list* vals = new Expression_list();
   vals->push_back(Expression::make_func_code_reference(thunk, loc));
@@ -12930,7 +12936,9 @@ Slice_construction_expression::Slice_con
   Type* int_type = Type::lookup_integer_type("int");
   length = Expression::make_integer_ul(lenval, int_type, location);
   Type* element_type = type->array_type()->element_type();
-  this->valtype_ = Type::make_array_type(element_type, length);
+  Array_type* array_type = Type::make_array_type(element_type, length);
+  array_type->set_is_array_incomparable();
+  this->valtype_ = array_type;
 }
 
 // Traversal.
@@ -13161,8 +13169,9 @@ Map_construction_expression::do_flatten(
         }
 
       Expression* element_count = Expression::make_integer_ul(i, NULL, loc);
-      Type* ctor_type =
+      Array_type* ctor_type =
           Type::make_array_type(this->element_type_, element_count);
+      ctor_type->set_is_array_incomparable();
       Expression* constructor =
           new Fixed_array_construction_expression(ctor_type, NULL,
                                                   value_pairs, loc);
@@ -14863,7 +14872,9 @@ Interface_info_expression::do_type()
             sfl->push_back(Struct_field(Typed_identifier(fname, mft, loc)));
           }
 
-        Pointer_type *pt = Type::make_pointer_type(Type::make_struct_type(sfl, loc));
+	Struct_type* st = Type::make_struct_type(sfl, loc);
+	st->set_is_struct_incomparable();
+	Pointer_type *pt = Type::make_pointer_type(st);
         result_types[itype] = pt;
         return pt;
       }
@@ -15097,7 +15108,9 @@ Interface_mtable_expression::do_type()
        p != interface_methods->end();
        ++p)
     sfl->push_back(Struct_field(*p));
-  this->method_table_type_ = Type::make_struct_type(sfl, this->location());
+  Struct_type* st = Type::make_struct_type(sfl, this->location());
+  st->set_is_struct_incomparable();
+  this->method_table_type_ = st;
   return this->method_table_type_;
 }
 
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc	(revision 244256)
+++ gcc/go/gofrontend/gogo.cc	(working copy)
@@ -744,6 +744,7 @@ Gogo::register_gc_vars(const std::vector
   Expression* length = Expression::make_integer_ul(roots_len, NULL,
                                                    builtin_loc);
   Array_type* root_array_type = Type::make_array_type(root_type, length);
+  root_array_type->set_is_array_incomparable();
   Type* ptdt = Type::make_type_descriptor_ptr_type();
   Struct_type* root_list_type =
       Type::make_builtin_struct_type(2,
@@ -4833,7 +4834,8 @@ Function::closure_var()
       // we find them.
       Location loc = this->type_->location();
       Struct_field_list* sfl = new Struct_field_list;
-      Type* struct_type = Type::make_struct_type(sfl, loc);
+      Struct_type* struct_type = Type::make_struct_type(sfl, loc);
+      struct_type->set_is_struct_incomparable();
       Variable* var = new Variable(Type::make_pointer_type(struct_type),
 				   NULL, false, false, false, loc);
       var->set_is_used();
Index: gcc/go/gofrontend/runtime.cc
===================================================================
--- gcc/go/gofrontend/runtime.cc	(revision 244166)
+++ gcc/go/gofrontend/runtime.cc	(working copy)
@@ -190,27 +190,47 @@ runtime_function_type(Runtime_function_t
 	  break;
 
 	case RFT_ARRAY2STRING:
-	  t = Type::make_array_type(Type::make_string_type(),
+	  {
+	    Array_type* at =
+	      Type::make_array_type(Type::make_string_type(),
 				    Expression::make_integer_ul(2, NULL,
 								bloc));
+	    at->set_is_array_incomparable();
+	    t = at;
+	  }
 	  break;
 
 	case RFT_ARRAY3STRING:
-	  t = Type::make_array_type(Type::make_string_type(),
+	  {
+	    Array_type* at =
+	      Type::make_array_type(Type::make_string_type(),
 				    Expression::make_integer_ul(3, NULL,
 								bloc));
+	    at->set_is_array_incomparable();
+	    t = at;
+	  }
 	  break;
 
 	case RFT_ARRAY4STRING:
-	  t = Type::make_array_type(Type::make_string_type(),
+	  {
+	    Array_type* at =
+	      Type::make_array_type(Type::make_string_type(),
 				    Expression::make_integer_ul(4, NULL,
 								bloc));
+	    at->set_is_array_incomparable();
+	    t = at;
+	  }
 	  break;
 
 	case RFT_ARRAY5STRING:
-	  t = Type::make_array_type(Type::make_string_type(),
+	  {
+	    Array_type* at =
+	      Type::make_array_type(Type::make_string_type(),
 				    Expression::make_integer_ul(5, NULL,
 								bloc));
+	    at->set_is_array_incomparable();
+	    t = at;
+	  }
 	  break;
 	}
 
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc	(revision 244256)
+++ gcc/go/gofrontend/types.cc	(working copy)
@@ -2500,6 +2500,7 @@ Type::gc_symbol_constructor(Gogo* gogo)
   Expression* len = Expression::make_integer_ul(vals->size(), NULL,
 						bloc);
   Array_type* gc_symbol_type = Type::make_array_type(uintptr_t, len);
+  gc_symbol_type->set_is_array_incomparable();
   return Expression::make_array_composite_literal(gc_symbol_type, vals, bloc);
 }
 
@@ -4037,6 +4038,7 @@ Function_type::get_backend_fntype(Gogo*
 		    }
 		  Struct_type* st = Type::make_struct_type(sfl,
 							   this->location());
+		  st->set_is_struct_incomparable();
 		  ins.first->second = st->get_backend(gogo);
 		}
 	      bresult_struct = ins.first->second;
@@ -7209,7 +7211,8 @@ Map_type::fat_zero_value(Gogo* gogo)
       // The final type will be set in backend_zero_value.
       Type* uint8_type = Type::lookup_integer_type("uint8");
       Expression* size = Expression::make_integer_ul(0, NULL, bloc);
-      Type* array_type = Type::make_array_type(uint8_type, size);
+      Array_type* array_type = Type::make_array_type(uint8_type, size);
+      array_type->set_is_array_incomparable();
       Variable* var = new Variable(array_type, NULL, true, false, false, bloc);
       Map_type::zero_value = Named_object::make_variable("go$zerovalue", NULL,
 							 var);
@@ -7619,7 +7622,8 @@ Map_type::bucket_type(Gogo* gogo, int64_
 
       Expression* pad_expr = Expression::make_integer_ul(pad, NULL,
 							 this->location_);
-      Type* pad_type = Type::make_array_type(uint8_type, pad_expr);
+      Array_type* pad_type = Type::make_array_type(uint8_type, pad_expr);
+      pad_type->set_is_array_incomparable();
 
       ret = make_builtin_struct_type(5,
 				     "topbits", topbits_type,

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-01-11 17:42 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-01-10  3:59 Go patch committed: drop size arguments to hash/equal functions Ian Lance Taylor
2017-01-10 19:45 ` Rainer Orth
2017-01-11 17:42   ` Ian Lance Taylor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).