Skip to content

Commit 408f0b1

Browse files
committed
gc, runtime: handle floating point map keys
Fixes #2609. R=ken2 CC=golang-dev https://golang.org/cl/5572069
1 parent 109a976 commit 408f0b1

File tree

6 files changed

+332
-8
lines changed

6 files changed

+332
-8
lines changed

src/cmd/gc/go.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ enum
5757
AINTER,
5858
ANILINTER,
5959
ASLICE,
60+
AFLOAT32,
61+
AFLOAT64,
62+
ACPLX64,
63+
ACPLX128,
6064

6165
BADWIDTH = -1000000000,
6266
};

src/cmd/gc/subr.c

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -515,23 +515,31 @@ algtype1(Type *t, Type **bad)
515515
case TINT:
516516
case TUINT:
517517
case TUINTPTR:
518-
case TCOMPLEX64:
519-
case TCOMPLEX128:
520-
case TFLOAT32:
521-
case TFLOAT64:
522518
case TBOOL:
523519
case TPTR32:
524520
case TPTR64:
525521
case TCHAN:
526522
case TUNSAFEPTR:
527523
return AMEM;
528-
524+
529525
case TFUNC:
530526
case TMAP:
531527
if(bad)
532528
*bad = t;
533529
return ANOEQ;
534530

531+
case TFLOAT32:
532+
return AFLOAT32;
533+
534+
case TFLOAT64:
535+
return AFLOAT64;
536+
537+
case TCOMPLEX64:
538+
return ACPLX64;
539+
540+
case TCOMPLEX128:
541+
return ACPLX128;
542+
535543
case TSTRING:
536544
return ASTRING;
537545

@@ -2511,6 +2519,18 @@ hashfor(Type *t)
25112519
case ASTRING:
25122520
sym = pkglookup("strhash", runtimepkg);
25132521
break;
2522+
case AFLOAT32:
2523+
sym = pkglookup("f32hash", runtimepkg);
2524+
break;
2525+
case AFLOAT64:
2526+
sym = pkglookup("f64hash", runtimepkg);
2527+
break;
2528+
case ACPLX64:
2529+
sym = pkglookup("c64hash", runtimepkg);
2530+
break;
2531+
case ACPLX128:
2532+
sym = pkglookup("c128hash", runtimepkg);
2533+
break;
25142534
default:
25152535
sym = typesymprefix(".hash", t);
25162536
break;
@@ -2537,7 +2557,7 @@ genhash(Sym *sym, Type *t)
25372557
Node *hashel;
25382558
Type *first, *t1;
25392559
int old_safemode;
2540-
int64 size;
2560+
int64 size, mul;
25412561

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

2617+
// *h *= mul
2618+
// Same multipliers as in runtime.memhash.
2619+
if(widthptr == 4)
2620+
mul = 3267000013LL;
2621+
else
2622+
mul = 23344194077549503LL;
2623+
n->nbody = list(n->nbody,
2624+
nod(OAS,
2625+
nod(OIND, nh, N),
2626+
nod(OMUL, nod(OIND, nh, N), nodintconst(mul))));
2627+
25972628
// hashel(h, sizeof(p[i]), &p[i])
25982629
call = nod(OCALL, hashel, N);
25992630
call->list = list(call->list, nh);

src/pkg/runtime/alg.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,106 @@ runtime·memcopy128(uintptr s, void *a, void *b)
197197
((uint64*)a)[1] = ((uint64*)b)[1];
198198
}
199199

200+
void
201+
runtime·f32equal(bool *eq, uintptr s, void *a, void *b)
202+
{
203+
USED(s);
204+
*eq = *(float32*)a == *(float32*)b;
205+
}
206+
207+
void
208+
runtime·f64equal(bool *eq, uintptr s, void *a, void *b)
209+
{
210+
USED(s);
211+
*eq = *(float64*)a == *(float64*)b;
212+
}
213+
214+
void
215+
runtime·c64equal(bool *eq, uintptr s, void *a, void *b)
216+
{
217+
Complex64 *ca, *cb;
218+
219+
USED(s);
220+
ca = a;
221+
cb = b;
222+
*eq = ca->real == cb->real && ca->imag == cb->imag;
223+
}
224+
225+
void
226+
runtime·c128equal(bool *eq, uintptr s, void *a, void *b)
227+
{
228+
Complex128 *ca, *cb;
229+
230+
USED(s);
231+
ca = a;
232+
cb = b;
233+
*eq = ca->real == cb->real && ca->imag == cb->imag;
234+
}
235+
236+
// NOTE: Because NaN != NaN, a map can contain any
237+
// number of (mostly useless) entries keyed with NaNs.
238+
// To avoid long hash chains, we assign a random number
239+
// as the hash value for a NaN.
240+
241+
void
242+
runtime·f32hash(uintptr *h, uintptr s, void *a)
243+
{
244+
uintptr hash;
245+
float32 f;
246+
247+
USED(s);
248+
f = *(float32*)a;
249+
if(f == 0)
250+
hash = 0; // +0, -0
251+
else if(f != f)
252+
hash = runtime·fastrand1(); // any kind of NaN
253+
else
254+
hash = *(uint32*)a;
255+
*h ^= (*h ^ hash ^ 2860486313U) * 3267000013U;
256+
}
257+
258+
void
259+
runtime·f64hash(uintptr *h, uintptr s, void *a)
260+
{
261+
uintptr hash;
262+
float64 f;
263+
uint64 u;
264+
265+
USED(s);
266+
f = *(float32*)a;
267+
if(f == 0)
268+
hash = 0; // +0, -0
269+
else if(f != f)
270+
hash = runtime·fastrand1(); // any kind of NaN
271+
else {
272+
u = *(uint64*)a;
273+
if(sizeof(uintptr) == 4)
274+
hash = ((uint32)(u>>32) ^ 2860486313) * (uint32)u;
275+
else
276+
hash = u;
277+
}
278+
if(sizeof(uintptr) == 4)
279+
*h = (*h ^ hash ^ 2860486313U) * 3267000013U;
280+
else
281+
*h = (*h ^ hash ^ 33054211828000289ULL) * 23344194077549503ULL;
282+
}
283+
284+
void
285+
runtime·c64hash(uintptr *h, uintptr s, void *a)
286+
{
287+
USED(s);
288+
runtime·f32hash(h, 0, a);
289+
runtime·f32hash(h, 0, (float32*)a+1);
290+
}
291+
292+
void
293+
runtime·c128hash(uintptr *h, uintptr s, void *a)
294+
{
295+
USED(s);
296+
runtime·f64hash(h, 0, a);
297+
runtime·f64hash(h, 0, (float64*)a+1);
298+
}
299+
200300
void
201301
runtime·slicecopy(uintptr s, void *a, void *b)
202302
{
@@ -349,6 +449,10 @@ runtime·algarray[] =
349449
[AINTER] { runtime·interhash, runtime·interequal, runtime·interprint, runtime·intercopy },
350450
[ANILINTER] { runtime·nilinterhash, runtime·nilinterequal, runtime·nilinterprint, runtime·nilintercopy },
351451
[ASLICE] { runtime·nohash, runtime·noequal, runtime·memprint, runtime·slicecopy },
452+
[AFLOAT32] { runtime·f32hash, runtime·f32equal, runtime·memprint, runtime·memcopy },
453+
[AFLOAT64] { runtime·f64hash, runtime·f64equal, runtime·memprint, runtime·memcopy },
454+
[ACPLX64] { runtime·c64hash, runtime·c64equal, runtime·memprint, runtime·memcopy },
455+
[ACPLX128] { runtime·c128hash, runtime·c128equal, runtime·memprint, runtime·memcopy },
352456
[AMEM0] { runtime·memhash, runtime·memequal0, runtime·memprint, runtime·memcopy0 },
353457
[AMEM8] { runtime·memhash, runtime·memequal8, runtime·memprint, runtime·memcopy8 },
354458
[AMEM16] { runtime·memhash, runtime·memequal16, runtime·memprint, runtime·memcopy16 },

src/pkg/runtime/runtime.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,8 @@ runtime·check(void)
278278
uint32 f;
279279
int64 g;
280280
uint64 h;
281-
float32 i;
282-
float64 j;
281+
float32 i, i1;
282+
float64 j, j1;
283283
void* k;
284284
uint16* l;
285285
struct x1 {
@@ -319,6 +319,30 @@ runtime·check(void)
319319
if(z != 4)
320320
runtime·throw("cas4");
321321

322+
*(uint64*)&j = ~0ULL;
323+
if(j == j)
324+
runtime·throw("float64nan");
325+
if(!(j != j))
326+
runtime·throw("float64nan1");
327+
328+
*(uint64*)&j1 = ~1ULL;
329+
if(j == j1)
330+
runtime·throw("float64nan2");
331+
if(!(j != j1))
332+
runtime·throw("float64nan3");
333+
334+
*(uint32*)&i = ~0UL;
335+
if(i == i)
336+
runtime·throw("float32nan");
337+
if(!(i != i))
338+
runtime·throw("float32nan1");
339+
340+
*(uint32*)&i1 = ~1UL;
341+
if(i == i1)
342+
runtime·throw("float32nan2");
343+
if(!(i != i1))
344+
runtime·throw("float32nan3");
345+
322346
runtime·initsig(0);
323347
}
324348

src/pkg/runtime/runtime.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,10 @@ enum
375375
AINTER,
376376
ANILINTER,
377377
ASLICE,
378+
AFLOAT32,
379+
AFLOAT64,
380+
ACPLX64,
381+
ACPLX128,
378382
Amax
379383
};
380384
typedef struct Alg Alg;

0 commit comments

Comments
 (0)