Commit 9279b5ba by Ian Lance Taylor

compiler: split writing of equal and hash functions for types

    
    Separate the generation of type equality and hash functions, rather
    than doing them in a single operation.
    
    This is almost entirely a pure refactoring in preparation for
    generating hash functions only for types that are map keys.  The only
    change in generated code is that for types that are the size of
    numeric types, but not aligned like numeric types, such as [8]byte,
    now use standard hash functions.  They previously used special-purpose
    hash functions because they required special-purpose equal functions.
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/212842

From-SVN: r279847
parent 45b6395b
393957c8b68e370504209eb901aa0c3874e256d4 b5c950fb98042fe434edca0c2403234692f25cd4
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -6238,10 +6238,8 @@ Binary_expression::lower_array_comparison(Gogo* gogo, ...@@ -6238,10 +6238,8 @@ Binary_expression::lower_array_comparison(Gogo* gogo,
return this->lower_compare_to_memcmp(gogo, inserter); return this->lower_compare_to_memcmp(gogo, inserter);
// Call the array comparison function. // Call the array comparison function.
Named_object* hash_fn; Named_object* equal_fn =
Named_object* equal_fn; at->equal_function(gogo, this->left_->type()->named_type(), NULL);
at->type_functions(gogo, this->left_->type()->named_type(), NULL, NULL,
&hash_fn, &equal_fn);
Location loc = this->location(); Location loc = this->location();
......
...@@ -2717,23 +2717,40 @@ Gogo::clear_file_scope() ...@@ -2717,23 +2717,40 @@ Gogo::clear_file_scope()
this->current_file_imported_unsafe_ = false; this->current_file_imported_unsafe_ = false;
} }
// Queue up a type specific function for later writing. These are // Queue up a type-specific hash function for later writing. These
// written out in write_specific_type_functions, called after the // are written out in write_specific_type_functions, called after the
// parse tree is lowered. // parse tree is lowered.
void void
Gogo::queue_specific_type_function(Type* type, Named_type* name, int64_t size, Gogo::queue_hash_function(Type* type, Named_type* name, int64_t size,
const std::string& hash_name, const std::string& hash_name,
Function_type* hash_fntype, Function_type* hash_fntype)
const std::string& equal_name,
Function_type* equal_fntype)
{ {
go_assert(!this->specific_type_functions_are_written_); go_assert(!this->specific_type_functions_are_written_);
go_assert(!this->in_global_scope()); go_assert(!this->in_global_scope());
Specific_type_function::Specific_type_function_kind kind =
Specific_type_function::SPECIFIC_HASH;
Specific_type_function* tsf = new Specific_type_function(type, name, size, Specific_type_function* tsf = new Specific_type_function(type, name, size,
hash_name, kind, hash_name,
hash_fntype, hash_fntype);
equal_name, this->specific_type_functions_.push_back(tsf);
}
// Queue up a type-specific equal function for later writing. These
// are written out in write_specific_type_functions, called after the
// parse tree is lowered.
void
Gogo::queue_equal_function(Type* type, Named_type* name, int64_t size,
const std::string& equal_name,
Function_type* equal_fntype)
{
go_assert(!this->specific_type_functions_are_written_);
go_assert(!this->in_global_scope());
Specific_type_function::Specific_type_function_kind kind =
Specific_type_function::SPECIFIC_EQUAL;
Specific_type_function* tsf = new Specific_type_function(type, name, size,
kind, equal_name,
equal_fntype); equal_fntype);
this->specific_type_functions_.push_back(tsf); this->specific_type_functions_.push_back(tsf);
} }
...@@ -2758,8 +2775,6 @@ class Specific_type_functions : public Traverse ...@@ -2758,8 +2775,6 @@ class Specific_type_functions : public Traverse
int int
Specific_type_functions::type(Type* t) Specific_type_functions::type(Type* t)
{ {
Named_object* hash_fn;
Named_object* equal_fn;
switch (t->classification()) switch (t->classification())
{ {
case Type::TYPE_NAMED: case Type::TYPE_NAMED:
...@@ -2768,7 +2783,10 @@ Specific_type_functions::type(Type* t) ...@@ -2768,7 +2783,10 @@ Specific_type_functions::type(Type* t)
if (nt->is_alias()) if (nt->is_alias())
return TRAVERSE_CONTINUE; return TRAVERSE_CONTINUE;
if (t->needs_specific_type_functions(this->gogo_)) if (t->needs_specific_type_functions(this->gogo_))
t->type_functions(this->gogo_, nt, NULL, NULL, &hash_fn, &equal_fn); {
t->equal_function(this->gogo_, nt, NULL);
t->hash_function(this->gogo_, nt, NULL);
}
// If this is a struct type, we don't want to make functions // If this is a struct type, we don't want to make functions
// for the unnamed struct. // for the unnamed struct.
...@@ -2802,7 +2820,10 @@ Specific_type_functions::type(Type* t) ...@@ -2802,7 +2820,10 @@ Specific_type_functions::type(Type* t)
case Type::TYPE_STRUCT: case Type::TYPE_STRUCT:
case Type::TYPE_ARRAY: case Type::TYPE_ARRAY:
if (t->needs_specific_type_functions(this->gogo_)) if (t->needs_specific_type_functions(this->gogo_))
t->type_functions(this->gogo_, NULL, NULL, NULL, &hash_fn, &equal_fn); {
t->equal_function(this->gogo_, NULL, NULL);
t->hash_function(this->gogo_, NULL, NULL);
}
break; break;
default: default:
...@@ -2824,11 +2845,12 @@ Gogo::write_specific_type_functions() ...@@ -2824,11 +2845,12 @@ Gogo::write_specific_type_functions()
{ {
Specific_type_function* tsf = this->specific_type_functions_.back(); Specific_type_function* tsf = this->specific_type_functions_.back();
this->specific_type_functions_.pop_back(); this->specific_type_functions_.pop_back();
tsf->type->write_specific_type_functions(this, tsf->name, tsf->size, if (tsf->kind == Specific_type_function::SPECIFIC_HASH)
tsf->hash_name, tsf->type->write_hash_function(this, tsf->name, tsf->size,
tsf->hash_fntype, tsf->fnname, tsf->fntype);
tsf->equal_name, else
tsf->equal_fntype); tsf->type->write_equal_function(this, tsf->name, tsf->size,
tsf->fnname, tsf->fntype);
delete tsf; delete tsf;
} }
this->specific_type_functions_are_written_ = true; this->specific_type_functions_are_written_ = true;
......
...@@ -598,15 +598,21 @@ class Gogo ...@@ -598,15 +598,21 @@ class Gogo
return p != this->var_deps_.end() ? p->second : NULL; return p != this->var_deps_.end() ? p->second : NULL;
} }
// Queue up a type-specific function to be written out. This is // Queue up a type-specific hash function to be written out. This
// used when a type-specific function is needed when not at the top // is used when a type-specific hash function is needed when not at
// level. // top level.
void void
queue_specific_type_function(Type* type, Named_type* name, int64_t size, queue_hash_function(Type* type, Named_type* name, int64_t size,
const std::string& hash_name, const std::string& hash_name,
Function_type* hash_fntype, Function_type* hash_fntype);
const std::string& equal_name,
Function_type* equal_fntype); // Queue up a type-specific equal function to be written out. This
// is used when a type-specific equal function is needed when not at
// top level.
void
queue_equal_function(Type* type, Named_type* name, int64_t size,
const std::string& equal_name,
Function_type* equal_fntype);
// Write out queued specific type functions. // Write out queued specific type functions.
void void
...@@ -871,11 +877,13 @@ class Gogo ...@@ -871,11 +877,13 @@ class Gogo
std::string std::string
stub_method_name(const Package*, const std::string& method_name); stub_method_name(const Package*, const std::string& method_name);
// Return the names of the hash and equality functions for TYPE. // Return the name of the hash function for TYPE.
void std::string
specific_type_function_names(const Type*, const Named_type*, hash_function_name(const Type*, const Named_type*);
std::string* hash_name,
std::string* equal_name); // Return the name of the equal function for TYPE.
std::string
equal_function_name(const Type*, const Named_type*);
// Return the assembler name to use for a global variable. // Return the assembler name to use for a global variable.
std::string std::string
...@@ -1059,22 +1067,21 @@ class Gogo ...@@ -1059,22 +1067,21 @@ class Gogo
// Type used to queue writing a type specific function. // Type used to queue writing a type specific function.
struct Specific_type_function struct Specific_type_function
{ {
enum Specific_type_function_kind { SPECIFIC_HASH, SPECIFIC_EQUAL };
Type* type; Type* type;
Named_type* name; Named_type* name;
int64_t size; int64_t size;
std::string hash_name; Specific_type_function_kind kind;
Function_type* hash_fntype; std::string fnname;
std::string equal_name; Function_type* fntype;
Function_type* equal_fntype;
Specific_type_function(Type* atype, Named_type* aname, int64_t asize, Specific_type_function(Type* atype, Named_type* aname, int64_t asize,
const std::string& ahash_name, Specific_type_function_kind akind,
Function_type* ahash_fntype, const std::string afnname,
const std::string& aequal_name, Function_type* afntype)
Function_type* aequal_fntype) : type(atype), name(aname), size(asize), kind(akind),
: type(atype), name(aname), size(asize), hash_name(ahash_name), fnname(afnname), fntype(afntype)
hash_fntype(ahash_fntype), equal_name(aequal_name),
equal_fntype(aequal_fntype)
{ } { }
}; };
......
...@@ -287,21 +287,30 @@ Gogo::stub_method_name(const Package* package, const std::string& mname) ...@@ -287,21 +287,30 @@ Gogo::stub_method_name(const Package* package, const std::string& mname)
return ret; return ret;
} }
// Return the names of the hash and equality functions for TYPE. If // Return the name of the hash function for TYPE. If NAME is not NULL
// NAME is not NULL it is the name of the type. Set *HASH_NAME and // it is the name of the type.
// *EQUAL_NAME.
void std::string
Gogo::specific_type_function_names(const Type* type, const Named_type* name, Gogo::hash_function_name(const Type* type, const Named_type* name)
std::string *hash_name, {
std::string *equal_name) const Type* rtype = type;
if (name != NULL)
rtype = name;
std::string tname = rtype->mangled_name(this);
return tname + "..hash";
}
// Return the name of the equal function for TYPE. If NAME is not
// NULL it is the name of the type.
std::string
Gogo::equal_function_name(const Type* type, const Named_type* name)
{ {
const Type* rtype = type; const Type* rtype = type;
if (name != NULL) if (name != NULL)
rtype = name; rtype = name;
std::string tname = rtype->mangled_name(this); std::string tname = rtype->mangled_name(this);
*hash_name = tname + "..hash"; return tname + "..eq";
*equal_name = tname + "..eq";
} }
// Return the assembler name to use for a global variable. GO_NAME is // Return the assembler name to use for a global variable. GO_NAME is
......
...@@ -1053,19 +1053,27 @@ class Type ...@@ -1053,19 +1053,27 @@ class Type
bool bool
needs_specific_type_functions(Gogo*); needs_specific_type_functions(Gogo*);
// Get the hash and equality functions for a type. // Get the equality function for a type. Returns NULL if the type
// is not comparable.
Named_object*
equal_function(Gogo*, Named_type* name, Function_type* equal_fntype);
// Get the hash function for a type. Returns NULL if the type is
// not comparable.
Named_object*
hash_function(Gogo*, Named_type* name, Function_type* hash_fntype);
// Write the equal function for a type.
void void
type_functions(Gogo*, Named_type* name, Function_type* hash_fntype, write_equal_function(Gogo*, Named_type*, int64_t size,
Function_type* equal_fntype, Named_object** hash_fn, const std::string& equal_name,
Named_object** equal_fn); Function_type* equal_fntype);
// Write the hash and equality type functions. // Write the hash function for a type.
void void
write_specific_type_functions(Gogo*, Named_type*, int64_t size, write_hash_function(Gogo*, Named_type*, int64_t size,
const std::string& hash_name, const std::string& hash_name,
Function_type* hash_fntype, Function_type* hash_fntype);
const std::string& equal_name,
Function_type* equal_fntype);
// Return the alignment required by the memequalN function. // Return the alignment required by the memequalN function.
static int64_t memequal_align(Gogo*, int size); static int64_t memequal_align(Gogo*, int size);
...@@ -1274,13 +1282,15 @@ class Type ...@@ -1274,13 +1282,15 @@ class Type
Expression* Expression*
gcprog_constructor(Gogo*, int64_t ptrsize, int64_t ptrdata); gcprog_constructor(Gogo*, int64_t ptrsize, int64_t ptrdata);
// Build the hash and equality type functions for a type which needs // Build the hash function for a type that needs specific functions.
// specific functions. Named_object*
void build_hash_function(Gogo*, Named_type*, int64_t size,
specific_type_functions(Gogo*, Named_type*, int64_t size, Function_type* hash_fntype);
Function_type* hash_fntype,
Function_type* equal_fntype, Named_object** hash_fn, // Build the equal function for a type that needs specific functions.
Named_object** equal_fn); Named_object*
build_equal_function(Gogo*, Named_type*, int64_t size,
Function_type* equal_fntype);
void void
write_identity_hash(Gogo*, int64_t size); write_identity_hash(Gogo*, int64_t size);
...@@ -1289,8 +1299,7 @@ class Type ...@@ -1289,8 +1299,7 @@ class Type
write_identity_equal(Gogo*, int64_t size); write_identity_equal(Gogo*, int64_t size);
void void
write_named_hash(Gogo*, Named_type*, Function_type* hash_fntype, write_named_hash(Gogo*, Named_type*, Function_type* hash_fntype);
Function_type* equal_fntype);
void void
write_named_equal(Gogo*, Named_type*); write_named_equal(Gogo*, Named_type*);
...@@ -1394,13 +1403,13 @@ class Type ...@@ -1394,13 +1403,13 @@ class Type
// A list of builtin named types. // A list of builtin named types.
static std::vector<Named_type*> named_builtin_types; static std::vector<Named_type*> named_builtin_types;
// A map from types which need specific type functions to the type // A map from types that need a specific hash or equality function
// functions themselves. // to the hash or equality function.
typedef std::pair<Named_object*, Named_object*> Hash_equal_fn; typedef Unordered_map_hash(const Type*, Named_object*, Type_hash_identical,
typedef Unordered_map_hash(const Type*, Hash_equal_fn, Type_hash_identical, Type_identical) Type_function;
Type_identical) Type_functions;
static Type_functions type_functions_table; static Type_function type_hash_functions_table;
static Type_function type_equal_functions_table;
// Cache for reusing existing pointer types; maps from pointed-to-type // Cache for reusing existing pointer types; maps from pointed-to-type
// to pointer type. // to pointer type.
...@@ -2619,7 +2628,7 @@ class Struct_type : public Type ...@@ -2619,7 +2628,7 @@ class Struct_type : public Type
// Write the hash function for this type. // Write the hash function for this type.
void void
write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*); write_hash_function(Gogo*, Named_type*, Function_type*);
// Write the equality function for this type. // Write the equality function for this type.
void void
...@@ -2806,7 +2815,7 @@ class Array_type : public Type ...@@ -2806,7 +2815,7 @@ class Array_type : public Type
// Write the hash function for this type. // Write the hash function for this type.
void void
write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*); write_hash_function(Gogo*, Named_type*, Function_type*);
// Write the equality function for this type. // Write the equality function for this type.
void void
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment