Source file src/pkg/cmd/compile/internal/gc/alg.go
1
2
3
4
5 package gc
6
7 import (
8 "cmd/compile/internal/types"
9 "fmt"
10 )
11
12
13
14 type AlgKind int
15
16 const (
17
18 ANOEQ AlgKind = iota
19 AMEM0
20 AMEM8
21 AMEM16
22 AMEM32
23 AMEM64
24 AMEM128
25 ASTRING
26 AINTER
27 ANILINTER
28 AFLOAT32
29 AFLOAT64
30 ACPLX64
31 ACPLX128
32
33
34 AMEM AlgKind = 100
35
36
37 ASPECIAL AlgKind = -1
38 )
39
40
41 func IsComparable(t *types.Type) bool {
42 a, _ := algtype1(t)
43 return a != ANOEQ
44 }
45
46
47 func IsRegularMemory(t *types.Type) bool {
48 a, _ := algtype1(t)
49 return a == AMEM
50 }
51
52
53 func IncomparableField(t *types.Type) *types.Field {
54 for _, f := range t.FieldSlice() {
55 if !IsComparable(f.Type) {
56 return f
57 }
58 }
59 return nil
60 }
61
62
63
64 func algtype(t *types.Type) AlgKind {
65 a, _ := algtype1(t)
66 if a == AMEM {
67 switch t.Width {
68 case 0:
69 return AMEM0
70 case 1:
71 return AMEM8
72 case 2:
73 return AMEM16
74 case 4:
75 return AMEM32
76 case 8:
77 return AMEM64
78 case 16:
79 return AMEM128
80 }
81 }
82
83 return a
84 }
85
86
87
88
89 func algtype1(t *types.Type) (AlgKind, *types.Type) {
90 if t.Broke() {
91 return AMEM, nil
92 }
93 if t.Noalg() {
94 return ANOEQ, t
95 }
96
97 switch t.Etype {
98 case TANY, TFORW:
99
100 return ANOEQ, t
101
102 case TINT8, TUINT8, TINT16, TUINT16,
103 TINT32, TUINT32, TINT64, TUINT64,
104 TINT, TUINT, TUINTPTR,
105 TBOOL, TPTR,
106 TCHAN, TUNSAFEPTR:
107 return AMEM, nil
108
109 case TFUNC, TMAP:
110 return ANOEQ, t
111
112 case TFLOAT32:
113 return AFLOAT32, nil
114
115 case TFLOAT64:
116 return AFLOAT64, nil
117
118 case TCOMPLEX64:
119 return ACPLX64, nil
120
121 case TCOMPLEX128:
122 return ACPLX128, nil
123
124 case TSTRING:
125 return ASTRING, nil
126
127 case TINTER:
128 if t.IsEmptyInterface() {
129 return ANILINTER, nil
130 }
131 return AINTER, nil
132
133 case TSLICE:
134 return ANOEQ, t
135
136 case TARRAY:
137 a, bad := algtype1(t.Elem())
138 switch a {
139 case AMEM:
140 return AMEM, nil
141 case ANOEQ:
142 return ANOEQ, bad
143 }
144
145 switch t.NumElem() {
146 case 0:
147
148 return AMEM, nil
149 case 1:
150
151 return a, nil
152 }
153
154 return ASPECIAL, nil
155
156 case TSTRUCT:
157 fields := t.FieldSlice()
158
159
160 if len(fields) == 1 && !fields[0].Sym.IsBlank() {
161 return algtype1(fields[0].Type)
162 }
163
164 ret := AMEM
165 for i, f := range fields {
166
167 a, bad := algtype1(f.Type)
168 if a == ANOEQ {
169 return ANOEQ, bad
170 }
171
172
173
174 if a != AMEM || f.Sym.IsBlank() || ispaddedfield(t, i) {
175 ret = ASPECIAL
176 }
177 }
178
179 return ret, nil
180 }
181
182 Fatalf("algtype1: unexpected type %v", t)
183 return 0, nil
184 }
185
186
187 func genhash(sym *types.Sym, t *types.Type) {
188 if Debug['r'] != 0 {
189 fmt.Printf("genhash %v %v\n", sym, t)
190 }
191
192 lineno = autogeneratedPos
193 dclcontext = PEXTERN
194
195
196 tfn := nod(OTFUNC, nil, nil)
197 tfn.List.Set2(
198 namedfield("p", types.NewPtr(t)),
199 namedfield("h", types.Types[TUINTPTR]),
200 )
201 tfn.Rlist.Set1(anonfield(types.Types[TUINTPTR]))
202
203 fn := dclfunc(sym, tfn)
204 np := asNode(tfn.Type.Params().Field(0).Nname)
205 nh := asNode(tfn.Type.Params().Field(1).Nname)
206
207
208
209
210 switch t.Etype {
211 default:
212 Fatalf("genhash %v", t)
213
214 case types.TARRAY:
215
216
217
218 hashel := hashfor(t.Elem())
219
220 n := nod(ORANGE, nil, nod(ODEREF, np, nil))
221 ni := newname(lookup("i"))
222 ni.Type = types.Types[TINT]
223 n.List.Set1(ni)
224 n.SetColas(true)
225 colasdefn(n.List.Slice(), n)
226 ni = n.List.First()
227
228
229 call := nod(OCALL, hashel, nil)
230
231 nx := nod(OINDEX, np, ni)
232 nx.SetBounded(true)
233 na := nod(OADDR, nx, nil)
234 call.List.Append(na)
235 call.List.Append(nh)
236 n.Nbody.Append(nod(OAS, nh, call))
237
238 fn.Nbody.Append(n)
239
240 case types.TSTRUCT:
241
242
243 for i, fields := 0, t.FieldSlice(); i < len(fields); {
244 f := fields[i]
245
246
247 if f.Sym.IsBlank() {
248 i++
249 continue
250 }
251
252
253 if !IsRegularMemory(f.Type) {
254 hashel := hashfor(f.Type)
255 call := nod(OCALL, hashel, nil)
256 nx := nodSym(OXDOT, np, f.Sym)
257 na := nod(OADDR, nx, nil)
258 call.List.Append(na)
259 call.List.Append(nh)
260 fn.Nbody.Append(nod(OAS, nh, call))
261 i++
262 continue
263 }
264
265
266 size, next := memrun(t, i)
267
268
269 hashel := hashmem(f.Type)
270 call := nod(OCALL, hashel, nil)
271 nx := nodSym(OXDOT, np, f.Sym)
272 na := nod(OADDR, nx, nil)
273 call.List.Append(na)
274 call.List.Append(nh)
275 call.List.Append(nodintconst(size))
276 fn.Nbody.Append(nod(OAS, nh, call))
277
278 i = next
279 }
280 }
281
282 r := nod(ORETURN, nil, nil)
283 r.List.Append(nh)
284 fn.Nbody.Append(r)
285
286 if Debug['r'] != 0 {
287 dumplist("genhash body", fn.Nbody)
288 }
289
290 funcbody()
291
292 fn.Func.SetDupok(true)
293 fn = typecheck(fn, ctxStmt)
294
295 Curfn = fn
296 typecheckslice(fn.Nbody.Slice(), ctxStmt)
297 Curfn = nil
298
299 if debug_dclstack != 0 {
300 testdclstack()
301 }
302
303 fn.Func.SetNilCheckDisabled(true)
304 funccompile(fn)
305 }
306
307 func hashfor(t *types.Type) *Node {
308 var sym *types.Sym
309
310 switch a, _ := algtype1(t); a {
311 case AMEM:
312 Fatalf("hashfor with AMEM type")
313 case AINTER:
314 sym = Runtimepkg.Lookup("interhash")
315 case ANILINTER:
316 sym = Runtimepkg.Lookup("nilinterhash")
317 case ASTRING:
318 sym = Runtimepkg.Lookup("strhash")
319 case AFLOAT32:
320 sym = Runtimepkg.Lookup("f32hash")
321 case AFLOAT64:
322 sym = Runtimepkg.Lookup("f64hash")
323 case ACPLX64:
324 sym = Runtimepkg.Lookup("c64hash")
325 case ACPLX128:
326 sym = Runtimepkg.Lookup("c128hash")
327 default:
328 sym = typesymprefix(".hash", t)
329 }
330
331 n := newname(sym)
332 n.SetClass(PFUNC)
333 n.Sym.SetFunc(true)
334 n.Type = functype(nil, []*Node{
335 anonfield(types.NewPtr(t)),
336 anonfield(types.Types[TUINTPTR]),
337 }, []*Node{
338 anonfield(types.Types[TUINTPTR]),
339 })
340 return n
341 }
342
343
344
345 func geneq(sym *types.Sym, t *types.Type) {
346 if Debug['r'] != 0 {
347 fmt.Printf("geneq %v %v\n", sym, t)
348 }
349
350 lineno = autogeneratedPos
351 dclcontext = PEXTERN
352
353
354 tfn := nod(OTFUNC, nil, nil)
355 tfn.List.Set2(
356 namedfield("p", types.NewPtr(t)),
357 namedfield("q", types.NewPtr(t)),
358 )
359 tfn.Rlist.Set1(anonfield(types.Types[TBOOL]))
360
361 fn := dclfunc(sym, tfn)
362 np := asNode(tfn.Type.Params().Field(0).Nname)
363 nq := asNode(tfn.Type.Params().Field(1).Nname)
364
365
366
367
368 switch t.Etype {
369 default:
370 Fatalf("geneq %v", t)
371
372 case TARRAY:
373
374
375
376
377
378 nrange := nod(ORANGE, nil, nod(ODEREF, np, nil))
379
380 ni := newname(lookup("i"))
381 ni.Type = types.Types[TINT]
382 nrange.List.Set1(ni)
383 nrange.SetColas(true)
384 colasdefn(nrange.List.Slice(), nrange)
385 ni = nrange.List.First()
386
387
388 nx := nod(OINDEX, np, ni)
389
390 nx.SetBounded(true)
391 ny := nod(OINDEX, nq, ni)
392 ny.SetBounded(true)
393
394 nif := nod(OIF, nil, nil)
395 nif.Left = nod(ONE, nx, ny)
396 r := nod(ORETURN, nil, nil)
397 r.List.Append(nodbool(false))
398 nif.Nbody.Append(r)
399 nrange.Nbody.Append(nif)
400 fn.Nbody.Append(nrange)
401
402
403 ret := nod(ORETURN, nil, nil)
404 ret.List.Append(nodbool(true))
405 fn.Nbody.Append(ret)
406
407 case TSTRUCT:
408 var cond *Node
409 and := func(n *Node) {
410 if cond == nil {
411 cond = n
412 return
413 }
414 cond = nod(OANDAND, cond, n)
415 }
416
417
418
419 for i, fields := 0, t.FieldSlice(); i < len(fields); {
420 f := fields[i]
421
422
423 if f.Sym.IsBlank() {
424 i++
425 continue
426 }
427
428
429 if !IsRegularMemory(f.Type) {
430 and(eqfield(np, nq, f.Sym))
431 i++
432 continue
433 }
434
435
436 size, next := memrun(t, i)
437
438
439
440 if s := fields[i:next]; len(s) <= 2 {
441
442 for _, f := range s {
443 and(eqfield(np, nq, f.Sym))
444 }
445 } else {
446
447 and(eqmem(np, nq, f.Sym, size))
448 }
449 i = next
450 }
451
452 if cond == nil {
453 cond = nodbool(true)
454 }
455
456 ret := nod(ORETURN, nil, nil)
457 ret.List.Append(cond)
458 fn.Nbody.Append(ret)
459 }
460
461 if Debug['r'] != 0 {
462 dumplist("geneq body", fn.Nbody)
463 }
464
465 funcbody()
466
467 fn.Func.SetDupok(true)
468 fn = typecheck(fn, ctxStmt)
469
470 Curfn = fn
471 typecheckslice(fn.Nbody.Slice(), ctxStmt)
472 Curfn = nil
473
474 if debug_dclstack != 0 {
475 testdclstack()
476 }
477
478
479
480
481
482 fn.Func.SetNilCheckDisabled(true)
483 funccompile(fn)
484 }
485
486
487
488 func eqfield(p *Node, q *Node, field *types.Sym) *Node {
489 nx := nodSym(OXDOT, p, field)
490 ny := nodSym(OXDOT, q, field)
491 ne := nod(OEQ, nx, ny)
492 return ne
493 }
494
495
496
497 func eqmem(p *Node, q *Node, field *types.Sym, size int64) *Node {
498 nx := nod(OADDR, nodSym(OXDOT, p, field), nil)
499 ny := nod(OADDR, nodSym(OXDOT, q, field), nil)
500 nx = typecheck(nx, ctxExpr)
501 ny = typecheck(ny, ctxExpr)
502
503 fn, needsize := eqmemfunc(size, nx.Type.Elem())
504 call := nod(OCALL, fn, nil)
505 call.List.Append(nx)
506 call.List.Append(ny)
507 if needsize {
508 call.List.Append(nodintconst(size))
509 }
510
511 return call
512 }
513
514 func eqmemfunc(size int64, t *types.Type) (fn *Node, needsize bool) {
515 switch size {
516 default:
517 fn = syslook("memequal")
518 needsize = true
519 case 1, 2, 4, 8, 16:
520 buf := fmt.Sprintf("memequal%d", int(size)*8)
521 fn = syslook(buf)
522 }
523
524 fn = substArgTypes(fn, t, t)
525 return fn, needsize
526 }
527
528
529
530
531
532 func memrun(t *types.Type, start int) (size int64, next int) {
533 next = start
534 for {
535 next++
536 if next == t.NumFields() {
537 break
538 }
539
540 if ispaddedfield(t, next-1) {
541 break
542 }
543
544 if f := t.Field(next); f.Sym.IsBlank() || !IsRegularMemory(f.Type) {
545 break
546 }
547 }
548 return t.Field(next-1).End() - t.Field(start).Offset, next
549 }
550
551
552
553 func ispaddedfield(t *types.Type, i int) bool {
554 if !t.IsStruct() {
555 Fatalf("ispaddedfield called non-struct %v", t)
556 }
557 end := t.Width
558 if i+1 < t.NumFields() {
559 end = t.Field(i + 1).Offset
560 }
561 return t.Field(i).End() != end
562 }
563
View as plain text