compiler, runtime: Implement struct and array comparisons.

From-SVN: r182971
This commit is contained in:
Ian Lance Taylor 2012-01-06 21:47:49 +00:00
parent 4b6aaa996e
commit f9f9698753
23 changed files with 1868 additions and 248 deletions

View File

@ -379,9 +379,9 @@ class Backend
// must be a pointer to this struct type.
//
// We must create the named structure before we know its
// initializer, because the initializer refer to its own address.
// After calling this the frontend will call
// set_immutable_struct_initializer.
// initializer, because the initializer may refer to its own
// address. After calling this the frontend will call
// immutable_struct_set_init.
virtual Bvariable*
immutable_struct(const std::string& name, bool is_common, Btype* type,
Location) = 0;
@ -400,8 +400,8 @@ class Backend
// Create a reference to a named immutable initialized data
// structure defined in some other package. This will be a
// structure created by a call to immutable_struct_expression with
// the same NAME and TYPE and with IS_COMMON passed as false. This
// structure created by a call to immutable_struct with the same
// NAME and TYPE and with IS_COMMON passed as false. This
// corresponds to an extern const global variable in C.
virtual Bvariable*
immutable_struct_reference(const std::string& name, Btype* type,

View File

@ -1135,6 +1135,63 @@ Expression::make_temporary_reference(Temporary_statement* statement,
return new Temporary_reference_expression(statement, location);
}
// Class Set_and_use_temporary_expression.
// Return the type.
Type*
Set_and_use_temporary_expression::do_type()
{
return this->statement_->type();
}
// Take the address.
void
Set_and_use_temporary_expression::do_address_taken(bool)
{
this->statement_->set_is_address_taken();
}
// Return the backend representation.
tree
Set_and_use_temporary_expression::do_get_tree(Translate_context* context)
{
Bvariable* bvar = this->statement_->get_backend_variable(context);
tree var_tree = var_to_tree(bvar);
tree expr_tree = this->expr_->get_tree(context);
if (var_tree == error_mark_node || expr_tree == error_mark_node)
return error_mark_node;
Location loc = this->location();
return build2_loc(loc.gcc_location(), COMPOUND_EXPR, TREE_TYPE(var_tree),
build2_loc(loc.gcc_location(), MODIFY_EXPR, void_type_node,
var_tree, expr_tree),
var_tree);
}
// Dump.
void
Set_and_use_temporary_expression::do_dump_expression(
Ast_dump_context* ast_dump_context) const
{
ast_dump_context->ostream() << '(';
ast_dump_context->dump_temp_variable_name(this->statement_);
ast_dump_context->ostream() << " = ";
this->expr_->dump_expression(ast_dump_context);
ast_dump_context->ostream() << ')';
}
// Make a set-and-use temporary.
Set_and_use_temporary_expression*
Expression::make_set_and_use_temporary(Temporary_statement* statement,
Expression* expr, Location location)
{
return new Set_and_use_temporary_expression(statement, expr, location);
}
// A sink expression--a use of the blank identifier _.
class Sink_expression : public Expression
@ -4468,11 +4525,38 @@ Unary_expression::do_check_types(Gogo*)
tree
Unary_expression::do_get_tree(Translate_context* context)
{
Location loc = this->location();
// Taking the address of a set-and-use-temporary expression requires
// setting the temporary and then taking the address.
if (this->op_ == OPERATOR_AND)
{
Set_and_use_temporary_expression* sut =
this->expr_->set_and_use_temporary_expression();
if (sut != NULL)
{
Temporary_statement* temp = sut->temporary();
Bvariable* bvar = temp->get_backend_variable(context);
tree var_tree = var_to_tree(bvar);
Expression* val = sut->expression();
tree val_tree = val->get_tree(context);
if (var_tree == error_mark_node || val_tree == error_mark_node)
return error_mark_node;
tree addr_tree = build_fold_addr_expr_loc(loc.gcc_location(),
var_tree);
return build2_loc(loc.gcc_location(), COMPOUND_EXPR,
TREE_TYPE(addr_tree),
build2_loc(sut->location().gcc_location(),
MODIFY_EXPR, void_type_node,
var_tree, val_tree),
addr_tree);
}
}
tree expr = this->expr_->get_tree(context);
if (expr == error_mark_node)
return error_mark_node;
Location loc = this->location();
switch (this->op_)
{
case OPERATOR_PLUS:
@ -5398,7 +5482,8 @@ Binary_expression::eval_complex(Operator op, Type* left_type,
// constants.
Expression*
Binary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
Binary_expression::do_lower(Gogo* gogo, Named_object*,
Statement_inserter* inserter, int)
{
Location location = this->location();
Operator op = this->op_;
@ -5727,9 +5812,183 @@ Binary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
mpz_clear(right_val);
}
// Lower struct and array comparisons.
if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ)
{
if (left->type()->struct_type() != NULL)
return this->lower_struct_comparison(gogo, inserter);
else if (left->type()->array_type() != NULL
&& !left->type()->is_slice_type())
return this->lower_array_comparison(gogo, inserter);
}
return this;
}
// Lower a struct comparison.
Expression*
Binary_expression::lower_struct_comparison(Gogo* gogo,
Statement_inserter* inserter)
{
Struct_type* st = this->left_->type()->struct_type();
Struct_type* st2 = this->right_->type()->struct_type();
if (st2 == NULL)
return this;
if (st != st2 && !Type::are_identical(st, st2, false, NULL))
return this;
if (!Type::are_compatible_for_comparison(true, this->left_->type(),
this->right_->type(), NULL))
return this;
// See if we can compare using memcmp. As a heuristic, we use
// memcmp rather than field references and comparisons if there are
// more than two fields.
if (st->compare_is_identity() && st->total_field_count() > 2)
return this->lower_compare_to_memcmp(gogo, inserter);
Location loc = this->location();
Expression* left = this->left_;
Temporary_statement* left_temp = NULL;
if (left->var_expression() == NULL
&& left->temporary_reference_expression() == NULL)
{
left_temp = Statement::make_temporary(left->type(), NULL, loc);
inserter->insert(left_temp);
left = Expression::make_set_and_use_temporary(left_temp, left, loc);
}
Expression* right = this->right_;
Temporary_statement* right_temp = NULL;
if (right->var_expression() == NULL
&& right->temporary_reference_expression() == NULL)
{
right_temp = Statement::make_temporary(right->type(), NULL, loc);
inserter->insert(right_temp);
right = Expression::make_set_and_use_temporary(right_temp, right, loc);
}
Expression* ret = Expression::make_boolean(true, loc);
const Struct_field_list* fields = st->fields();
unsigned int field_index = 0;
for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end();
++pf, ++field_index)
{
if (field_index > 0)
{
if (left_temp == NULL)
left = left->copy();
else
left = Expression::make_temporary_reference(left_temp, loc);
if (right_temp == NULL)
right = right->copy();
else
right = Expression::make_temporary_reference(right_temp, loc);
}
Expression* f1 = Expression::make_field_reference(left, field_index,
loc);
Expression* f2 = Expression::make_field_reference(right, field_index,
loc);
Expression* cond = Expression::make_binary(OPERATOR_EQEQ, f1, f2, loc);
ret = Expression::make_binary(OPERATOR_ANDAND, ret, cond, loc);
}
if (this->op_ == OPERATOR_NOTEQ)
ret = Expression::make_unary(OPERATOR_NOT, ret, loc);
return ret;
}
// Lower an array comparison.
Expression*
Binary_expression::lower_array_comparison(Gogo* gogo,
Statement_inserter* inserter)
{
Array_type* at = this->left_->type()->array_type();
Array_type* at2 = this->right_->type()->array_type();
if (at2 == NULL)
return this;
if (at != at2 && !Type::are_identical(at, at2, false, NULL))
return this;
if (!Type::are_compatible_for_comparison(true, this->left_->type(),
this->right_->type(), NULL))
return this;
// Call memcmp directly if possible. This may let the middle-end
// optimize the call.
if (at->compare_is_identity())
return this->lower_compare_to_memcmp(gogo, inserter);
// Call the array comparison function.
Named_object* hash_fn;
Named_object* equal_fn;
at->type_functions(gogo, this->left_->type()->named_type(), NULL, NULL,
&hash_fn, &equal_fn);
Location loc = this->location();
Expression* func = Expression::make_func_reference(equal_fn, NULL, loc);
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);
if (this->op_ == OPERATOR_NOTEQ)
ret = Expression::make_unary(OPERATOR_NOT, ret, loc);
return ret;
}
// Lower a struct or array comparison to a call to memcmp.
Expression*
Binary_expression::lower_compare_to_memcmp(Gogo*, Statement_inserter* inserter)
{
Location loc = this->location();
Expression* a1 = this->operand_address(inserter, this->left_);
Expression* a2 = this->operand_address(inserter, this->right_);
Expression* len = Expression::make_type_info(this->left_->type(),
TYPE_INFO_SIZE);
Expression* call = Runtime::make_call(Runtime::MEMCMP, loc, 3, a1, a2, len);
mpz_t zval;
mpz_init_set_ui(zval, 0);
Expression* zero = Expression::make_integer(&zval, NULL, loc);
mpz_clear(zval);
return Expression::make_binary(this->op_, call, zero, loc);
}
// Return the address of EXPR, cast to unsafe.Pointer.
Expression*
Binary_expression::operand_address(Statement_inserter* inserter,
Expression* expr)
{
Location loc = this->location();
if (!expr->is_addressable())
{
Temporary_statement* temp = Statement::make_temporary(expr->type(), NULL,
loc);
inserter->insert(temp);
expr = Expression::make_set_and_use_temporary(temp, expr, loc);
}
expr = Expression::make_unary(OPERATOR_AND, expr, loc);
static_cast<Unary_expression*>(expr)->set_does_not_escape();
Type* void_type = Type::make_void_type();
Type* unsafe_pointer_type = Type::make_pointer_type(void_type);
return Expression::make_cast(unsafe_pointer_type, expr, loc);
}
// Return the integer constant value, if it has one.
bool
@ -6072,49 +6331,28 @@ Binary_expression::check_operator_type(Operator op, Type* type, Type* otype,
case OPERATOR_EQEQ:
case OPERATOR_NOTEQ:
if (type->integer_type() == NULL
&& type->float_type() == NULL
&& type->complex_type() == NULL
&& !type->is_string_type()
&& type->points_to() == NULL
&& !type->is_nil_type()
&& !type->is_boolean_type()
&& type->interface_type() == NULL
&& (type->array_type() == NULL
|| type->array_type()->length() != NULL)
&& type->map_type() == NULL
&& type->channel_type() == NULL
&& type->function_type() == NULL)
{
error_at(location,
("expected integer, floating, complex, string, pointer, "
"boolean, interface, slice, map, channel, "
"or function type"));
return false;
}
if ((type->is_slice_type()
|| type->map_type() != NULL
|| type->function_type() != NULL)
&& !otype->is_nil_type())
{
error_at(location,
("slice, map, and function types may only "
"be compared to nil"));
return false;
}
{
std::string reason;
if (!Type::are_compatible_for_comparison(true, type, otype, &reason))
{
error_at(location, "%s", reason.c_str());
return false;
}
}
break;
case OPERATOR_LT:
case OPERATOR_LE:
case OPERATOR_GT:
case OPERATOR_GE:
if (type->integer_type() == NULL
&& type->float_type() == NULL
&& !type->is_string_type())
{
error_at(location, "expected integer, floating, or string type");
return false;
}
{
std::string reason;
if (!Type::are_compatible_for_comparison(false, type, otype, &reason))
{
error_at(location, "%s", reason.c_str());
return false;
}
}
break;
case OPERATOR_PLUS:
@ -12740,10 +12978,10 @@ class Composite_literal_expression : public Parser_expression
lower_struct(Gogo*, Type*);
Expression*
lower_array(Type*);
lower_array(Gogo*, Type*);
Expression*
make_array(Type*, Expression_list*);
make_array(Gogo*, Type*, Expression_list*);
Expression*
lower_map(Gogo*, Named_object*, Statement_inserter*, Type*);
@ -12810,7 +13048,7 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function,
else if (type->struct_type() != NULL)
ret = this->lower_struct(gogo, type);
else if (type->array_type() != NULL)
ret = this->lower_array(type);
ret = this->lower_array(gogo, type);
else if (type->map_type() != NULL)
ret = this->lower_map(gogo, function, inserter, type);
else
@ -13023,11 +13261,11 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
// Lower an array composite literal.
Expression*
Composite_literal_expression::lower_array(Type* type)
Composite_literal_expression::lower_array(Gogo* gogo, Type* type)
{
Location location = this->location();
if (this->vals_ == NULL || !this->has_keys_)
return this->make_array(type, this->vals_);
return this->make_array(gogo, type, this->vals_);
std::vector<Expression*> vals;
vals.reserve(this->vals_->size());
@ -13127,14 +13365,15 @@ Composite_literal_expression::lower_array(Type* type)
for (size_t i = 0; i < size; ++i)
list->push_back(vals[i]);
return this->make_array(type, list);
return this->make_array(gogo, type, list);
}
// Actually build the array composite literal. This handles
// [...]{...}.
Expression*
Composite_literal_expression::make_array(Type* type, Expression_list* vals)
Composite_literal_expression::make_array(Gogo* gogo, Type* type,
Expression_list* vals)
{
Location location = this->location();
Array_type* at = type->array_type();
@ -13146,6 +13385,10 @@ Composite_literal_expression::make_array(Type* type, Expression_list* vals)
Expression* elen = Expression::make_integer(&vlen, NULL, location);
mpz_clear(vlen);
at = Type::make_array_type(at->element_type(), elen);
// This is after the finalize_methods pass, so run that now.
at->finalize_methods(gogo);
type = at;
}
if (at->length() != NULL)

View File

@ -25,6 +25,7 @@ class Struct_field;
class Expression_list;
class Var_expression;
class Temporary_reference_expression;
class Set_and_use_temporary_expression;
class String_expression;
class Binary_expression;
class Call_expression;
@ -60,6 +61,7 @@ class Expression
EXPRESSION_CONST_REFERENCE,
EXPRESSION_VAR_REFERENCE,
EXPRESSION_TEMPORARY_REFERENCE,
EXPRESSION_SET_AND_USE_TEMPORARY,
EXPRESSION_SINK,
EXPRESSION_FUNC_REFERENCE,
EXPRESSION_UNKNOWN_REFERENCE,
@ -134,6 +136,13 @@ class Expression
static Temporary_reference_expression*
make_temporary_reference(Temporary_statement*, Location);
// Make an expressions which sets a temporary variable and then
// evaluates to a reference to that temporary variable. This is
// used to set a temporary variable while retaining the order of
// evaluation.
static Set_and_use_temporary_expression*
make_set_and_use_temporary(Temporary_statement*, Expression*, Location);
// Make a sink expression--a reference to the blank identifier _.
static Expression*
make_sink(Location);
@ -396,6 +405,15 @@ class Expression
EXPRESSION_TEMPORARY_REFERENCE>();
}
// If this is a set-and-use-temporary, return the
// Set_and_use_temporary_expression. Otherwise, return NULL.
Set_and_use_temporary_expression*
set_and_use_temporary_expression()
{
return this->convert<Set_and_use_temporary_expression,
EXPRESSION_SET_AND_USE_TEMPORARY>();
}
// Return whether this is a sink expression.
bool
is_sink_expression() const
@ -1021,6 +1039,62 @@ class Temporary_reference_expression : public Expression
bool is_lvalue_;
};
// Set and use a temporary variable.
class Set_and_use_temporary_expression : public Expression
{
public:
Set_and_use_temporary_expression(Temporary_statement* statement,
Expression* expr, Location location)
: Expression(EXPRESSION_SET_AND_USE_TEMPORARY, location),
statement_(statement), expr_(expr)
{ }
// Return the temporary.
Temporary_statement*
temporary() const
{ return this->statement_; }
// Return the expression.
Expression*
expression() const
{ return this->expr_; }
protected:
Type*
do_type();
void
do_determine_type(const Type_context*)
{ }
Expression*
do_copy()
{
return make_set_and_use_temporary(this->statement_, this->expr_,
this->location());
}
bool
do_is_addressable() const
{ return true; }
void
do_address_taken(bool);
tree
do_get_tree(Translate_context*);
void
do_dump_expression(Ast_dump_context*) const;
private:
// The statement where the temporary variable is defined.
Temporary_statement* statement_;
// The expression to assign to the temporary.
Expression* expr_;
};
// A string expression.
class String_expression : public Expression
@ -1200,6 +1274,18 @@ class Binary_expression : public Expression
do_dump_expression(Ast_dump_context*) const;
private:
Expression*
lower_struct_comparison(Gogo*, Statement_inserter*);
Expression*
lower_array_comparison(Gogo*, Statement_inserter*);
Expression*
lower_compare_to_memcmp(Gogo*, Statement_inserter*);
Expression*
operand_address(Statement_inserter*, Expression*);
// The binary operator to apply.
Operator op_;
// The left hand side operand.

View File

@ -106,6 +106,9 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
// form which is easier to use.
::gogo->lower_parse_tree();
// Write out queued up functions for hash and comparison of types.
::gogo->write_specific_type_functions();
// Now that we have seen all the names, verify that types are
// correct.
::gogo->verify_types();

View File

@ -116,10 +116,10 @@ Gogo::define_builtin_function_trees()
NULL_TREE),
true);
// We use __builtin_memmove for the predeclared copy function.
define_builtin(BUILT_IN_MEMMOVE, "__builtin_memmove", "memmove",
build_function_type_list(ptr_type_node,
ptr_type_node,
// We use __builtin_memcmp for struct comparisons.
define_builtin(BUILT_IN_MEMCMP, "__builtin_memcmp", "memcmp",
build_function_type_list(integer_type_node,
const_ptr_type_node,
const_ptr_type_node,
size_type_node,
NULL_TREE),
@ -647,7 +647,8 @@ Gogo::write_globals()
this->build_interface_method_tables();
Bindings* bindings = this->current_bindings();
size_t count = bindings->size_definitions();
size_t count_definitions = bindings->size_definitions();
size_t count = count_definitions;
tree* vec = new tree[count];
@ -822,6 +823,10 @@ Gogo::write_globals()
|| this->is_main_package())
this->write_initialization_function(init_fndecl, init_stmt_list);
// We should not have seen any new bindings created during the
// conversion.
go_assert(count_definitions == this->current_bindings()->size_definitions());
// Pass everything back to the middle-end.
wrapup_global_declarations(vec, count);

View File

@ -38,6 +38,8 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int int_type_size,
unique_prefix_(),
unique_prefix_specified_(false),
interface_types_(),
specific_type_functions_(),
specific_type_functions_are_written_(false),
named_types_are_converted_(false)
{
const Location loc = Linemap::predeclared_location();
@ -978,6 +980,16 @@ Gogo::declare_package_type(const std::string& name, Location location)
return this->package_->bindings()->add_type_declaration(name, NULL, location);
}
// Declare a function at the package level.
Named_object*
Gogo::declare_package_function(const std::string& name, Function_type* type,
Location location)
{
return this->package_->bindings()->add_function_declaration(name, NULL, type,
location);
}
// Define a type which was already declared.
void
@ -1116,6 +1128,46 @@ Gogo::clear_file_scope()
}
}
// Queue up a type specific function for later writing. These are
// written out in write_specific_type_functions, called after the
// parse tree is lowered.
void
Gogo::queue_specific_type_function(Type* type, Named_type* name,
const std::string& hash_name,
Function_type* hash_fntype,
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* tsf = new Specific_type_function(type, name,
hash_name,
hash_fntype,
equal_name,
equal_fntype);
this->specific_type_functions_.push_back(tsf);
}
// Write out type specific functions.
void
Gogo::write_specific_type_functions()
{
while (!this->specific_type_functions_.empty())
{
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->hash_name,
tsf->hash_fntype,
tsf->equal_name,
tsf->equal_fntype);
delete tsf;
}
this->specific_type_functions_are_written_ = true;
}
// Traverse the tree.
void
@ -1468,6 +1520,10 @@ Finalize_methods::type(Type* t)
t->struct_type()->finalize_methods(this->gogo_);
break;
case Type::TYPE_ARRAY:
t->array_type()->finalize_methods(this->gogo_);
break;
default:
break;
}

View File

@ -277,6 +277,11 @@ class Gogo
Named_object*
declare_function(const std::string&, Function_type*, Location);
// Declare a function at the package level. This is used for
// functions generated for a type.
Named_object*
declare_package_function(const std::string&, Function_type*, Location);
// Add a label.
Label*
add_label_definition(const std::string&, Location);
@ -364,6 +369,20 @@ class Gogo
void
clear_file_scope();
// Queue up a type-specific function to be written out. This is
// used when a type-specific function is needed when not at the top
// level.
void
queue_specific_type_function(Type* type, Named_type* name,
const std::string& hash_name,
Function_type* hash_fntype,
const std::string& equal_name,
Function_type* equal_fntype);
// Write out queued specific type functions.
void
write_specific_type_functions();
// Traverse the tree. See the Traverse class.
void
traverse(Traverse*);
@ -603,6 +622,27 @@ class Gogo
// Type used to map special names in the sys package.
typedef std::map<std::string, std::string> Sys_names;
// Type used to queue writing a type specific function.
struct Specific_type_function
{
Type* type;
Named_type* name;
std::string hash_name;
Function_type* hash_fntype;
std::string equal_name;
Function_type* equal_fntype;
Specific_type_function(Type* atype, Named_type* aname,
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),
hash_fntype(ahash_fntype), equal_name(aequal_name),
equal_fntype(aequal_fntype)
{ }
};
// The backend generator.
Backend* backend_;
// The object used to keep track of file names and line numbers.
@ -635,6 +675,10 @@ class Gogo
bool unique_prefix_specified_;
// A list of interface types defined while parsing.
std::vector<Interface_type*> interface_types_;
// Type specific functions to write out.
std::vector<Specific_type_function*> specific_type_functions_;
// Whether we are done writing out specific type functions.
bool specific_type_functions_are_written_;
// Whether named types have been converted.
bool named_types_are_converted_;
};

View File

@ -28,6 +28,9 @@
// the name. The third is the parameter types and the fourth is the
// result types.
// The standard C memcmp function, used for struct comparisons.
DEF_GO_RUNTIME(MEMCMP, "memcmp", P3(POINTER, POINTER, UINTPTR), R1(INT))
// Range over a string, returning the next index.
DEF_GO_RUNTIME(STRINGITER, "runtime.stringiter", P2(STRING, INT), R1(INT))

File diff suppressed because it is too large Load Diff

View File

@ -522,6 +522,21 @@ class Type
static bool
are_compatible_for_binop(const Type* t1, const Type* t2);
// Return true if two types are compatible for use with the
// comparison operator. IS_EQUALITY_OP is true if this is an
// equality comparison, false if it is an ordered comparison. This
// is an equivalence relation. If this returns false, and REASON is
// not NULL, it sets *REASON.
static bool
are_compatible_for_comparison(bool is_equality_op, const Type *t1,
const Type *t2, std::string* reason);
// Return true if a type is comparable with itself. This is true of
// most types, but false for, e.g., function types.
bool
is_comparable() const
{ return Type::are_compatible_for_comparison(true, this, this, NULL); }
// Return true if a value with type RHS is assignable to a variable
// with type LHS. This is not an equivalence relation. If this
// returns false, and REASON is not NULL, it sets *REASON.
@ -549,6 +564,13 @@ class Type
bool
has_hidden_fields(const Named_type* within, std::string* reason) const;
// Return true if values of this type can be compared using an
// identity function which gets nothing but a pointer to the value
// and a size.
bool
compare_is_identity() const
{ return this->do_compare_is_identity(); }
// Return a hash code for this type for the method hash table.
// Types which are equivalent according to are_identical will have
// the same hash code.
@ -839,6 +861,20 @@ class Type
std::string
mangled_name(Gogo*) const;
// Get the hash and equality functions for a type.
void
type_functions(Gogo*, Named_type* name, Function_type* hash_fntype,
Function_type* equal_fntype, Named_object** hash_fn,
Named_object** equal_fn);
// Write the hash and equality type functions.
void
write_specific_type_functions(Gogo*, Named_type*,
const std::string& hash_name,
Function_type* hash_fntype,
const std::string& equal_name,
Function_type* equal_fntype);
// Export the type.
void
export_type(Export* exp) const
@ -866,6 +902,9 @@ class Type
do_has_pointer() const
{ return false; }
virtual bool
do_compare_is_identity() const = 0;
virtual unsigned int
do_hash_for_method(Gogo*) const;
@ -878,7 +917,6 @@ class Type
virtual void
do_reflection(Gogo*, std::string*) const = 0;
virtual void
do_mangled_name(Gogo*, std::string*) const = 0;
@ -1002,18 +1040,24 @@ class Type
void
make_type_descriptor_var(Gogo*);
// Return the name of the type descriptor variable for an unnamed
// type.
// Return the name of the type descriptor variable. If NAME is not
// NULL, it is the name to use.
std::string
unnamed_type_descriptor_var_name(Gogo*);
type_descriptor_var_name(Gogo*, Named_type* name);
// Return the name of the type descriptor variable for a named type.
std::string
type_descriptor_var_name(Gogo*);
// Return true if the type descriptor for this type should be
// defined in some other package. If NAME is not NULL, it is the
// name of this type. If this returns true it sets *PACKAGE to the
// package where the type descriptor is defined.
bool
type_descriptor_defined_elsewhere(Named_type* name, const Package** package);
// Get the hash and equality functions for a type.
// Build the hash and equality type functions for a type which needs
// specific functions.
void
type_functions(const char** hash_fn, const char** equal_fn) const;
specific_type_functions(Gogo*, Named_type*, Function_type* hash_fntype,
Function_type* equal_fntype, Named_object** hash_fn,
Named_object** equal_fn);
// Build a composite literal for the uncommon type information.
Expression*
@ -1097,6 +1141,14 @@ class Type
// A list of builtin named types.
static std::vector<Named_type*> named_builtin_types;
// A map from types which need specific type functions to the type
// functions themselves.
typedef std::pair<Named_object*, Named_object*> Hash_equal_fn;
typedef Unordered_map_hash(const Type*, Hash_equal_fn, Type_hash_identical,
Type_identical) Type_functions;
static Type_functions type_functions_table;
// The type classification.
Type_classification classification_;
// The backend representation of the type, once it has been
@ -1314,6 +1366,10 @@ class Integer_type : public Type
is_identical(const Integer_type* t) const;
protected:
bool
do_compare_is_identity() const
{ return true; }
unsigned int
do_hash_for_method(Gogo*) const;
@ -1383,6 +1439,10 @@ class Float_type : public Type
is_identical(const Float_type* t) const;
protected:
bool
do_compare_is_identity() const
{ return false; }
unsigned int
do_hash_for_method(Gogo*) const;
@ -1448,6 +1508,10 @@ class Complex_type : public Type
is_identical(const Complex_type* t) const;
protected:
bool
do_compare_is_identity() const
{ return false; }
unsigned int
do_hash_for_method(Gogo*) const;
@ -1504,6 +1568,10 @@ class String_type : public Type
do_has_pointer() const
{ return true; }
bool
do_compare_is_identity() const
{ return false; }
Btype*
do_get_backend(Gogo*);
@ -1618,6 +1686,10 @@ class Function_type : public Type
do_has_pointer() const
{ return true; }
bool
do_compare_is_identity() const
{ return false; }
unsigned int
do_hash_for_method(Gogo*) const;
@ -1699,6 +1771,10 @@ class Pointer_type : public Type
do_has_pointer() const
{ return true; }
bool
do_compare_is_identity() const
{ return true; }
unsigned int
do_hash_for_method(Gogo*) const;
@ -1944,6 +2020,14 @@ class Struct_type : public Type
static Type*
make_struct_type_descriptor_type();
// Write the hash function for this type.
void
write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*);
// Write the equality function for this type.
void
write_equal_function(Gogo*, Named_type*);
protected:
int
do_traverse(Traverse*);
@ -1954,6 +2038,9 @@ class Struct_type : public Type
bool
do_has_pointer() const;
bool
do_compare_is_identity() const;
unsigned int
do_hash_for_method(Gogo*) const;
@ -2022,6 +2109,10 @@ class Array_type : public Type
array_has_hidden_fields(const Named_type* within, std::string* reason) const
{ return this->element_type_->has_hidden_fields(within, reason); }
// Build the hash and equality functions if necessary.
void
finalize_methods(Gogo*);
// Return a tree for the pointer to the values in an array.
tree
value_pointer_tree(Gogo*, tree array) const;
@ -2052,6 +2143,14 @@ class Array_type : public Type
static Type*
make_slice_type_descriptor_type();
// Write the hash function for this type.
void
write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*);
// Write the equality function for this type.
void
write_equal_function(Gogo*, Named_type*);
protected:
int
do_traverse(Traverse* traverse);
@ -2065,6 +2164,13 @@ class Array_type : public Type
return this->length_ == NULL || this->element_type_->has_pointer();
}
bool
do_compare_is_identity() const
{
return (this->length_ != NULL
&& this->element_type_->compare_is_identity());
}
unsigned int
do_hash_for_method(Gogo*) const;
@ -2155,6 +2261,10 @@ class Map_type : public Type
do_has_pointer() const
{ return true; }
bool
do_compare_is_identity() const
{ return false; }
unsigned int
do_hash_for_method(Gogo*) const;
@ -2237,6 +2347,10 @@ class Channel_type : public Type
do_has_pointer() const
{ return true; }
bool
do_compare_is_identity() const
{ return true; }
unsigned int
do_hash_for_method(Gogo*) const;
@ -2348,6 +2462,10 @@ class Interface_type : public Type
do_has_pointer() const
{ return true; }
bool
do_compare_is_identity() const
{ return false; }
unsigned int
do_hash_for_method(Gogo*) const;
@ -2480,6 +2598,11 @@ class Named_type : public Type
bool
is_named_error_type() const;
// Return whether this type is comparable. If REASON is not NULL,
// set *REASON when returning false.
bool
named_type_is_comparable(std::string* reason) const;
// Add a method to this type.
Named_object*
add_method(const std::string& name, Function*);
@ -2572,6 +2695,9 @@ class Named_type : public Type
bool
do_has_pointer() const;
bool
do_compare_is_identity() const;
unsigned int
do_hash_for_method(Gogo*) const;
@ -2704,6 +2830,10 @@ class Forward_declaration_type : public Type
do_has_pointer() const
{ return this->real_type()->has_pointer(); }
bool
do_compare_is_identity() const
{ return this->real_type()->compare_is_identity(); }
unsigned int
do_hash_for_method(Gogo* gogo) const
{ return this->real_type()->hash_for_method(gogo); }

View File

@ -11,7 +11,7 @@ func use(bool) {}
type T1 *int
type T2 *int
type T3 struct {}
type T3 struct{ z []int }
var t3 T3
@ -21,12 +21,12 @@ func main() {
// so chan int can be compared against
// directional channels but channel of different
// direction cannot be compared against each other.
var c1 chan <-int
var c1 chan<- int
var c2 <-chan int
var c3 chan int
use(c1 == c2) // ERROR "invalid operation|incompatible"
use(c2 == c1) // ERROR "invalid operation|incompatible"
use(c1 == c2) // ERROR "invalid operation|incompatible"
use(c2 == c1) // ERROR "invalid operation|incompatible"
use(c1 == c3)
use(c2 == c2)
use(c3 == c1)
@ -36,14 +36,32 @@ func main() {
var p1 T1
var p2 T2
var p3 *int
use(p1 == p2) // ERROR "invalid operation|incompatible"
use(p2 == p1) // ERROR "invalid operation|incompatible"
use(p1 == p2) // ERROR "invalid operation|incompatible"
use(p2 == p1) // ERROR "invalid operation|incompatible"
use(p1 == p3)
use(p2 == p2)
use(p3 == p1)
use(p3 == p2)
// Comparison of structs should have a good message
use(t3 == t3) // ERROR "struct|expected"
use(t3 == t3) // ERROR "struct|expected"
// Slices, functions, and maps too.
var x []int
var f func()
var m map[int]int
use(x == x) // ERROR "slice can only be compared to nil"
use(f == f) // ERROR "func can only be compared to nil"
use(m == m) // ERROR "map can only be compared to nil"
// Comparison with interface that cannot return true
// (would panic).
var i interface{}
use(i == x) // ERROR "invalid operation"
use(x == i) // ERROR "invalid operation"
use(i == f) // ERROR "invalid operation"
use(f == i) // ERROR "invalid operation"
use(i == m) // ERROR "invalid operation"
use(m == i) // ERROR "invalid operation"
}

View File

@ -60,6 +60,7 @@ func test4() {
type T struct {
a, b int
c []int
}
func test5() {

View File

@ -460,8 +460,10 @@ runtime_files = \
runtime/go-strplus.c \
runtime/go-strslice.c \
runtime/go-trampoline.c \
runtime/go-type-complex.c \
runtime/go-type-eface.c \
runtime/go-type-error.c \
runtime/go-type-float.c \
runtime/go-type-identity.c \
runtime/go-type-interface.c \
runtime/go-type-string.c \

View File

@ -208,7 +208,8 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \
runtime/go-string-to-byte-array.c \
runtime/go-string-to-int-array.c runtime/go-strplus.c \
runtime/go-strslice.c runtime/go-trampoline.c \
runtime/go-type-eface.c runtime/go-type-error.c \
runtime/go-type-complex.c runtime/go-type-eface.c \
runtime/go-type-error.c runtime/go-type-float.c \
runtime/go-type-identity.c runtime/go-type-interface.c \
runtime/go-type-string.c runtime/go-typedesc-equal.c \
runtime/go-typestring.c runtime/go-unreflect.c \
@ -242,13 +243,14 @@ am__objects_4 = go-append.lo go-assert.lo go-assert-interface.lo \
go-reflect-map.lo go-rune.lo go-runtime-error.lo go-setenv.lo \
go-signal.lo go-strcmp.lo go-string-to-byte-array.lo \
go-string-to-int-array.lo go-strplus.lo go-strslice.lo \
go-trampoline.lo go-type-eface.lo go-type-error.lo \
go-type-identity.lo go-type-interface.lo go-type-string.lo \
go-typedesc-equal.lo go-typestring.lo go-unreflect.lo \
go-unsafe-new.lo go-unsafe-newarray.lo go-unsafe-pointer.lo \
go-unwind.lo chan.lo cpuprof.lo $(am__objects_1) mcache.lo \
mcentral.lo $(am__objects_2) mfinal.lo mfixalloc.lo mgc0.lo \
mheap.lo msize.lo proc.lo runtime.lo thread.lo yield.lo \
go-trampoline.lo go-type-complex.lo go-type-eface.lo \
go-type-error.lo go-type-float.lo go-type-identity.lo \
go-type-interface.lo go-type-string.lo go-typedesc-equal.lo \
go-typestring.lo go-unreflect.lo go-unsafe-new.lo \
go-unsafe-newarray.lo go-unsafe-pointer.lo go-unwind.lo \
chan.lo cpuprof.lo $(am__objects_1) mcache.lo mcentral.lo \
$(am__objects_2) mfinal.lo mfixalloc.lo mgc0.lo mheap.lo \
msize.lo proc.lo runtime.lo thread.lo yield.lo \
$(am__objects_3) iface.lo malloc.lo map.lo mprof.lo reflect.lo \
runtime1.lo sema.lo sigqueue.lo string.lo time.lo
am_libgo_la_OBJECTS = $(am__objects_4)
@ -881,8 +883,10 @@ runtime_files = \
runtime/go-strplus.c \
runtime/go-strslice.c \
runtime/go-trampoline.c \
runtime/go-type-complex.c \
runtime/go-type-eface.c \
runtime/go-type-error.c \
runtime/go-type-float.c \
runtime/go-type-identity.c \
runtime/go-type-interface.c \
runtime/go-type-string.c \
@ -2523,8 +2527,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strplus.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strslice.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-trampoline.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-complex.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-eface.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-error.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-float.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-identity.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-interface.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-string.Plo@am__quote@
@ -2928,6 +2934,13 @@ go-trampoline.lo: runtime/go-trampoline.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-trampoline.lo `test -f 'runtime/go-trampoline.c' || echo '$(srcdir)/'`runtime/go-trampoline.c
go-type-complex.lo: runtime/go-type-complex.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-complex.lo -MD -MP -MF $(DEPDIR)/go-type-complex.Tpo -c -o go-type-complex.lo `test -f 'runtime/go-type-complex.c' || echo '$(srcdir)/'`runtime/go-type-complex.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-complex.Tpo $(DEPDIR)/go-type-complex.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-complex.c' object='go-type-complex.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-complex.lo `test -f 'runtime/go-type-complex.c' || echo '$(srcdir)/'`runtime/go-type-complex.c
go-type-eface.lo: runtime/go-type-eface.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-eface.lo -MD -MP -MF $(DEPDIR)/go-type-eface.Tpo -c -o go-type-eface.lo `test -f 'runtime/go-type-eface.c' || echo '$(srcdir)/'`runtime/go-type-eface.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-eface.Tpo $(DEPDIR)/go-type-eface.Plo
@ -2942,6 +2955,13 @@ go-type-error.lo: runtime/go-type-error.c
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-error.lo `test -f 'runtime/go-type-error.c' || echo '$(srcdir)/'`runtime/go-type-error.c
go-type-float.lo: runtime/go-type-float.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-float.lo -MD -MP -MF $(DEPDIR)/go-type-float.Tpo -c -o go-type-float.lo `test -f 'runtime/go-type-float.c' || echo '$(srcdir)/'`runtime/go-type-float.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-float.Tpo $(DEPDIR)/go-type-float.Plo
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-float.c' object='go-type-float.lo' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-float.lo `test -f 'runtime/go-type-float.c' || echo '$(srcdir)/'`runtime/go-type-float.c
go-type-identity.lo: runtime/go-type-identity.c
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-identity.lo -MD -MP -MF $(DEPDIR)/go-type-identity.Tpo -c -o go-type-identity.lo `test -f 'runtime/go-type-identity.c' || echo '$(srcdir)/'`runtime/go-type-identity.c
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-identity.Tpo $(DEPDIR)/go-type-identity.Plo

View File

@ -0,0 +1,122 @@
/* 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 "runtime.h"
#include "go-type.h"
/* The 64-bit type. */
typedef unsigned int DItype __attribute__ ((mode (DI)));
/* Hash function for float types. */
uintptr_t
__go_type_hash_complex (const void *vkey, uintptr_t key_size)
{
if (key_size == 8)
{
union
{
unsigned char a[8];
__complex float cf;
DItype di;
} ucf;
__complex float cf;
float cfr;
float cfi;
__builtin_memcpy (ucf.a, vkey, 8);
cf = ucf.cf;
cfr = __builtin_crealf (cf);
cfi = __builtin_cimagf (cf);
if (__builtin_isinff (cfr) || __builtin_isinff (cfi)
|| __builtin_isnanf (cfr) || __builtin_isnanf (cfi))
return 0;
/* Avoid negative zero. */
if (cfr == 0 && cfi == 0)
return 0;
else if (cfr == 0)
ucf.cf = cfi * 1.0iF;
else if (cfi == 0)
ucf.cf = cfr;
return ucf.di;
}
else if (key_size == 16)
{
union
{
unsigned char a[16];
__complex double cd;
DItype adi[2];
} ucd;
__complex double cd;
double cdr;
double cdi;
__builtin_memcpy (ucd.a, vkey, 16);
cd = ucd.cd;
cdr = __builtin_crealf (cd);
cdi = __builtin_cimagf (cd);
if (__builtin_isinf (cdr) || __builtin_isinf (cdi)
|| __builtin_isnan (cdr) || __builtin_isnan (cdi))
return 0;
/* Avoid negative zero. */
if (cdr == 0 && cdi == 0)
return 0;
else if (cdr == 0)
ucd.cd = cdi * 1.0i;
else if (cdi == 0)
ucd.cd = cdr;
return ucd.adi[0] ^ ucd.adi[1];
}
else
runtime_throw ("__go_type_hash_complex: invalid complex size");
}
/* Equality function for complex types. */
_Bool
__go_type_equal_complex (const void *vk1, const void *vk2, uintptr_t key_size)
{
if (key_size == 8)
{
union
{
unsigned char a[8];
__complex float cf;
} ucf;
__complex float cf1;
__complex float cf2;
__builtin_memcpy (ucf.a, vk1, 8);
cf1 = ucf.cf;
__builtin_memcpy (ucf.a, vk2, 8);
cf2 = ucf.cf;
return cf1 == cf2;
}
else if (key_size == 16)
{
union
{
unsigned char a[16];
__complex double cd;
} ucd;
__complex double cd1;
__complex double cd2;
__builtin_memcpy (ucd.a, vk1, 16);
cd1 = ucd.cd;
__builtin_memcpy (ucd.a, vk2, 16);
cd2 = ucd.cd;
return cd1 == cd2;
}
else
runtime_throw ("__go_type_equal_complex: invalid complex size");
}

View File

@ -10,13 +10,13 @@
/* A hash function for an empty interface. */
size_t
uintptr_t
__go_type_hash_empty_interface (const void *vval,
size_t key_size __attribute__ ((unused)))
uintptr_t key_size __attribute__ ((unused)))
{
const struct __go_empty_interface *val;
const struct __go_type_descriptor *descriptor;
size_t size;
uintptr_t size;
val = (const struct __go_empty_interface *) vval;
descriptor = val->__type_descriptor;
@ -33,7 +33,7 @@ __go_type_hash_empty_interface (const void *vval,
_Bool
__go_type_equal_empty_interface (const void *vv1, const void *vv2,
size_t key_size __attribute__ ((unused)))
uintptr_t key_size __attribute__ ((unused)))
{
const struct __go_empty_interface *v1;
const struct __go_empty_interface *v2;

View File

@ -10,9 +10,9 @@
/* A hash function used for a type which does not support hash
functions. */
size_t
uintptr_t
__go_type_hash_error (const void *val __attribute__ ((unused)),
size_t key_size __attribute__ ((unused)))
uintptr_t key_size __attribute__ ((unused)))
{
runtime_panicstring ("hash of unhashable type");
}
@ -22,7 +22,7 @@ __go_type_hash_error (const void *val __attribute__ ((unused)),
_Bool
__go_type_equal_error (const void *v1 __attribute__ ((unused)),
const void *v2 __attribute__ ((unused)),
size_t key_size __attribute__ ((unused)))
uintptr_t key_size __attribute__ ((unused)))
{
runtime_panicstring ("comparing uncomparable types");
}

View File

@ -0,0 +1,96 @@
/* 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 "runtime.h"
#include "go-type.h"
/* The 32-bit and 64-bit types. */
typedef unsigned int SItype __attribute__ ((mode (SI)));
typedef unsigned int DItype __attribute__ ((mode (DI)));
/* Hash function for float types. */
uintptr_t
__go_type_hash_float (const void *vkey, uintptr_t key_size)
{
if (key_size == 4)
{
union
{
unsigned char a[4];
float f;
SItype si;
} uf;
float f;
__builtin_memcpy (uf.a, vkey, 4);
f = uf.f;
if (__builtin_isinff (f) || __builtin_isnanf (f) || f == 0)
return 0;
return (uintptr_t) uf.si;
}
else if (key_size == 8)
{
union
{
unsigned char a[8];
double d;
DItype di;
} ud;
double d;
__builtin_memcpy (ud.a, vkey, 8);
d = ud.d;
if (__builtin_isinf (d) || __builtin_isnan (d) || d == 0)
return 0;
return (uintptr_t) ud.di;
}
else
runtime_throw ("__go_type_hash_float: invalid float size");
}
/* Equality function for float types. */
_Bool
__go_type_equal_float (const void *vk1, const void *vk2, uintptr_t key_size)
{
if (key_size == 4)
{
union
{
unsigned char a[4];
float f;
} uf;
float f1;
float f2;
__builtin_memcpy (uf.a, vk1, 4);
f1 = uf.f;
__builtin_memcpy (uf.a, vk2, 4);
f2 = uf.f;
return f1 == f2;
}
else if (key_size == 8)
{
union
{
unsigned char a[8];
double d;
DItype di;
} ud;
double d1;
double d2;
__builtin_memcpy (ud.a, vk1, 8);
d1 = ud.d;
__builtin_memcpy (ud.a, vk2, 8);
d2 = ud.d;
return d1 == d2;
}
else
runtime_throw ("__go_type_equal_float: invalid float size");
}

View File

@ -8,35 +8,37 @@
#include "go-type.h"
/* Typedefs for accesses of different sizes. */
/* The 64-bit type. */
typedef int QItype __attribute__ ((mode (QI)));
typedef int HItype __attribute__ ((mode (HI)));
typedef int SItype __attribute__ ((mode (SI)));
typedef int DItype __attribute__ ((mode (DI)));
typedef unsigned int DItype __attribute__ ((mode (DI)));
/* An identity hash function for a type. This is used for types where
we can simply use the type value itself as a hash code. This is
true of, e.g., integers and pointers. */
size_t
__go_type_hash_identity (const void *key, size_t key_size)
uintptr_t
__go_type_hash_identity (const void *key, uintptr_t key_size)
{
switch (key_size)
uintptr_t ret;
uintptr_t i;
const unsigned char *p;
if (key_size <= 8)
{
case 1:
return *(const QItype *) key;
case 2:
return *(const HItype *) key;
case 3:
case 4:
case 5:
case 6:
case 7:
return *(const SItype *) key;
default:
return *(const DItype *) key;
union
{
DItype v;
unsigned char a[8];
} u;
u.v = 0;
__builtin_memcpy (&u.a, key, key_size);
return (uintptr_t) u.v;
}
ret = 5381;
for (i = 0, p = (const unsigned char *) key; i < key_size; i++, p++)
ret = ret * 33 + *p;
return ret;
}
/* An identity equality function for a type. This is used for types
@ -44,7 +46,7 @@ __go_type_hash_identity (const void *key, size_t key_size)
the same bits. */
_Bool
__go_type_equal_identity (const void *k1, const void *k2, size_t key_size)
__go_type_equal_identity (const void *k1, const void *k2, uintptr_t key_size)
{
return __builtin_memcmp (k1, k2, key_size) == 0;
}

View File

@ -9,13 +9,13 @@
/* A hash function for an interface. */
size_t
uintptr_t
__go_type_hash_interface (const void *vval,
size_t key_size __attribute__ ((unused)))
uintptr_t key_size __attribute__ ((unused)))
{
const struct __go_interface *val;
const struct __go_type_descriptor *descriptor;
size_t size;
uintptr_t size;
val = (const struct __go_interface *) vval;
if (val->__methods == NULL)
@ -32,7 +32,7 @@ __go_type_hash_interface (const void *vval,
_Bool
__go_type_equal_interface (const void *vv1, const void *vv2,
size_t key_size __attribute__ ((unused)))
uintptr_t key_size __attribute__ ((unused)))
{
const struct __go_interface *v1;
const struct __go_interface *v2;

View File

@ -11,14 +11,14 @@
/* A string hash function for a map. */
size_t
uintptr_t
__go_type_hash_string (const void *vkey,
size_t key_size __attribute__ ((unused)))
uintptr_t key_size __attribute__ ((unused)))
{
size_t ret;
uintptr_t ret;
const struct __go_string *key;
size_t len;
size_t i;
int len;
int i;
const unsigned char *p;
ret = 5381;
@ -33,7 +33,7 @@ __go_type_hash_string (const void *vkey,
_Bool
__go_type_equal_string (const void *vk1, const void *vk2,
size_t key_size __attribute__ ((unused)))
uintptr_t key_size __attribute__ ((unused)))
{
const struct __go_string *k1;
const struct __go_string *k2;

View File

@ -86,11 +86,11 @@ struct __go_type_descriptor
size of this type, and returns a hash code. We pass the size
explicitly becaues it means that we can share a single instance
of this function for various different types. */
size_t (*__hashfn) (const void *, size_t);
uintptr_t (*__hashfn) (const void *, uintptr_t);
/* This function takes two pointers to values of this type, and the
size of this type, and returns whether the values are equal. */
_Bool (*__equalfn) (const void *, const void *, size_t);
_Bool (*__equalfn) (const void *, const void *, uintptr_t);
/* A string describing this type. This is only used for
debugging. */
@ -317,13 +317,17 @@ extern _Bool
__go_type_descriptors_equal(const struct __go_type_descriptor*,
const struct __go_type_descriptor*);
extern size_t __go_type_hash_identity (const void *, size_t);
extern _Bool __go_type_equal_identity (const void *, const void *, size_t);
extern size_t __go_type_hash_string (const void *, size_t);
extern _Bool __go_type_equal_string (const void *, const void *, size_t);
extern size_t __go_type_hash_interface (const void *, size_t);
extern _Bool __go_type_equal_interface (const void *, const void *, size_t);
extern size_t __go_type_hash_error (const void *, size_t);
extern _Bool __go_type_equal_error (const void *, const void *, size_t);
extern uintptr_t __go_type_hash_identity (const void *, uintptr_t);
extern _Bool __go_type_equal_identity (const void *, const void *, uintptr_t);
extern uintptr_t __go_type_hash_string (const void *, uintptr_t);
extern _Bool __go_type_equal_string (const void *, const void *, uintptr_t);
extern uintptr_t __go_type_hash_float (const void *, uintptr_t);
extern _Bool __go_type_equal_float (const void *, const void *, uintptr_t);
extern uintptr_t __go_type_hash_complex (const void *, uintptr_t);
extern _Bool __go_type_equal_complex (const void *, const void *, uintptr_t);
extern uintptr_t __go_type_hash_interface (const void *, uintptr_t);
extern _Bool __go_type_equal_interface (const void *, const void *, uintptr_t);
extern uintptr_t __go_type_hash_error (const void *, uintptr_t);
extern _Bool __go_type_equal_error (const void *, const void *, uintptr_t);
#endif /* !defined(LIBGO_GO_TYPE_H) */

View File

@ -322,18 +322,18 @@ localname() {
pattern='Test([^a-z].*)?'
# The -p option tells GNU nm not to sort.
# The -v option tells Solaris nm to sort by value.
tests=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
tests=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
if [ "x$tests" = x ]; then
echo 'gotest: warning: no tests matching '$pattern in _gotest_.o $xofile 1>&2
exit 2
fi
# benchmarks are named BenchmarkFoo.
pattern='Benchmark([^a-z].*)?'
benchmarks=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
benchmarks=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
# examples are named ExampleFoo
pattern='Example([^a-z].*)?'
examples=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
examples=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
# package spec
echo 'package main'