Commit f9f96987 by Ian Lance Taylor

compiler, runtime: Implement struct and array comparisons.

From-SVN: r182971
parent 4b6aaa99
......@@ -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,
......
......@@ -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.
......
......@@ -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();
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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_;
};
......
......@@ -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))
......
......@@ -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); }
......
......@@ -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"
}
......@@ -60,6 +60,7 @@ func test4() {
type T struct {
a, b int
c []int
}
func test5() {
......
......@@ -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 \
......
......@@ -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
......
/* 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");
}
......@@ -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;
......
......@@ -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");
}
/* 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");
}
......@@ -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;
}
......@@ -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;
......
......@@ -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;
......
......@@ -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) */
......@@ -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'
......
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