Skip to content

Commit

Permalink
gc, runtime: handle floating point map keys
Browse files Browse the repository at this point in the history
Fixes #2609.

R=ken2
CC=golang-dev
https://golang.org/cl/5572069
  • Loading branch information
rsc committed Jan 26, 2012
1 parent 109a976 commit 408f0b1
Show file tree
Hide file tree
Showing 6 changed files with 332 additions and 8 deletions.
4 changes: 4 additions & 0 deletions src/cmd/gc/go.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ enum
AINTER,
ANILINTER,
ASLICE,
AFLOAT32,
AFLOAT64,
ACPLX64,
ACPLX128,

BADWIDTH = -1000000000,
};
Expand Down
43 changes: 37 additions & 6 deletions src/cmd/gc/subr.c
Original file line number Diff line number Diff line change
Expand Up @@ -515,23 +515,31 @@ algtype1(Type *t, Type **bad)
case TINT:
case TUINT:
case TUINTPTR:
case TCOMPLEX64:
case TCOMPLEX128:
case TFLOAT32:
case TFLOAT64:
case TBOOL:
case TPTR32:
case TPTR64:
case TCHAN:
case TUNSAFEPTR:
return AMEM;

case TFUNC:
case TMAP:
if(bad)
*bad = t;
return ANOEQ;

case TFLOAT32:
return AFLOAT32;

case TFLOAT64:
return AFLOAT64;

case TCOMPLEX64:
return ACPLX64;

case TCOMPLEX128:
return ACPLX128;

case TSTRING:
return ASTRING;

Expand Down Expand Up @@ -2511,6 +2519,18 @@ hashfor(Type *t)
case ASTRING:
sym = pkglookup("strhash", runtimepkg);
break;
case AFLOAT32:
sym = pkglookup("f32hash", runtimepkg);
break;
case AFLOAT64:
sym = pkglookup("f64hash", runtimepkg);
break;
case ACPLX64:
sym = pkglookup("c64hash", runtimepkg);
break;
case ACPLX128:
sym = pkglookup("c128hash", runtimepkg);
break;
default:
sym = typesymprefix(".hash", t);
break;
Expand All @@ -2537,7 +2557,7 @@ genhash(Sym *sym, Type *t)
Node *hashel;
Type *first, *t1;
int old_safemode;
int64 size;
int64 size, mul;

if(debug['r'])
print("genhash %S %T\n", sym, t);
Expand Down Expand Up @@ -2594,6 +2614,17 @@ genhash(Sym *sym, Type *t)
nod(OLSH, nod(OIND, nh, N), nodintconst(3)),
nod(ORSH, nod(OIND, nh, N), nodintconst(widthptr*8-3)))));

// *h *= mul
// Same multipliers as in runtime.memhash.
if(widthptr == 4)
mul = 3267000013LL;
else
mul = 23344194077549503LL;
n->nbody = list(n->nbody,
nod(OAS,
nod(OIND, nh, N),
nod(OMUL, nod(OIND, nh, N), nodintconst(mul))));

// hashel(h, sizeof(p[i]), &p[i])
call = nod(OCALL, hashel, N);
call->list = list(call->list, nh);
Expand Down
104 changes: 104 additions & 0 deletions src/pkg/runtime/alg.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,106 @@ runtime·memcopy128(uintptr s, void *a, void *b)
((uint64*)a)[1] = ((uint64*)b)[1];
}

void
runtime·f32equal(bool *eq, uintptr s, void *a, void *b)
{
USED(s);
*eq = *(float32*)a == *(float32*)b;
}

void
runtime·f64equal(bool *eq, uintptr s, void *a, void *b)
{
USED(s);
*eq = *(float64*)a == *(float64*)b;
}

void
runtime·c64equal(bool *eq, uintptr s, void *a, void *b)
{
Complex64 *ca, *cb;

USED(s);
ca = a;
cb = b;
*eq = ca->real == cb->real && ca->imag == cb->imag;
}

void
runtime·c128equal(bool *eq, uintptr s, void *a, void *b)
{
Complex128 *ca, *cb;

USED(s);
ca = a;
cb = b;
*eq = ca->real == cb->real && ca->imag == cb->imag;
}

// NOTE: Because NaN != NaN, a map can contain any
// number of (mostly useless) entries keyed with NaNs.
// To avoid long hash chains, we assign a random number
// as the hash value for a NaN.

void
runtime·f32hash(uintptr *h, uintptr s, void *a)
{
uintptr hash;
float32 f;

USED(s);
f = *(float32*)a;
if(f == 0)
hash = 0; // +0, -0
else if(f != f)
hash = runtime·fastrand1(); // any kind of NaN
else
hash = *(uint32*)a;
*h ^= (*h ^ hash ^ 2860486313U) * 3267000013U;
}

void
runtime·f64hash(uintptr *h, uintptr s, void *a)
{
uintptr hash;
float64 f;
uint64 u;

USED(s);
f = *(float32*)a;
if(f == 0)
hash = 0; // +0, -0
else if(f != f)
hash = runtime·fastrand1(); // any kind of NaN
else {
u = *(uint64*)a;
if(sizeof(uintptr) == 4)
hash = ((uint32)(u>>32) ^ 2860486313) * (uint32)u;
else
hash = u;
}
if(sizeof(uintptr) == 4)
*h = (*h ^ hash ^ 2860486313U) * 3267000013U;
else
*h = (*h ^ hash ^ 33054211828000289ULL) * 23344194077549503ULL;
}

void
runtime·c64hash(uintptr *h, uintptr s, void *a)
{
USED(s);
runtime·f32hash(h, 0, a);
runtime·f32hash(h, 0, (float32*)a+1);
}

void
runtime·c128hash(uintptr *h, uintptr s, void *a)
{
USED(s);
runtime·f64hash(h, 0, a);
runtime·f64hash(h, 0, (float64*)a+1);
}

void
runtime·slicecopy(uintptr s, void *a, void *b)
{
Expand Down Expand Up @@ -349,6 +449,10 @@ runtime·algarray[] =
[AINTER] { runtime·interhash, runtime·interequal, runtime·interprint, runtime·intercopy },
[ANILINTER] { runtime·nilinterhash, runtime·nilinterequal, runtime·nilinterprint, runtime·nilintercopy },
[ASLICE] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·slicecopy },
[AFLOAT32] { runtime·f32hash, runtime·f32equal, runtime·memprint, runtime·memcopy },
[AFLOAT64] { runtime·f64hash, runtime·f64equal, runtime·memprint, runtime·memcopy },
[ACPLX64] { runtime·c64hash, runtime·c64equal, runtime·memprint, runtime·memcopy },
[ACPLX128] { runtime·c128hash, runtime·c128equal, runtime·memprint, runtime·memcopy },
[AMEM0] { runtime·memhash, runtime·memequal0, runtime·memprint, runtime·memcopy0 },
[AMEM8] { runtime·memhash, runtime·memequal8, runtime·memprint, runtime·memcopy8 },
[AMEM16] { runtime·memhash, runtime·memequal16, runtime·memprint, runtime·memcopy16 },
Expand Down
28 changes: 26 additions & 2 deletions src/pkg/runtime/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,8 @@ runtime·check(void)
uint32 f;
int64 g;
uint64 h;
float32 i;
float64 j;
float32 i, i1;
float64 j, j1;
void* k;
uint16* l;
struct x1 {
Expand Down Expand Up @@ -319,6 +319,30 @@ runtime·check(void)
if(z != 4)
runtime·throw("cas4");

*(uint64*)&j = ~0ULL;
if(j == j)
runtime·throw("float64nan");
if(!(j != j))
runtime·throw("float64nan1");

*(uint64*)&j1 = ~1ULL;
if(j == j1)
runtime·throw("float64nan2");
if(!(j != j1))
runtime·throw("float64nan3");

*(uint32*)&i = ~0UL;
if(i == i)
runtime·throw("float32nan");
if(!(i != i))
runtime·throw("float32nan1");

*(uint32*)&i1 = ~1UL;
if(i == i1)
runtime·throw("float32nan2");
if(!(i != i1))
runtime·throw("float32nan3");

runtime·initsig(0);
}

Expand Down
4 changes: 4 additions & 0 deletions src/pkg/runtime/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,10 @@ enum
AINTER,
ANILINTER,
ASLICE,
AFLOAT32,
AFLOAT64,
ACPLX64,
ACPLX128,
Amax
};
typedef struct Alg Alg;
Expand Down
Loading

0 comments on commit 408f0b1

Please sign in to comment.