Source file src/pkg/cmd/compile/internal/ssa/func.go
1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/types"
9 "cmd/internal/src"
10 "crypto/sha1"
11 "fmt"
12 "io"
13 "math"
14 "os"
15 "strings"
16 )
17
18 type writeSyncer interface {
19 io.Writer
20 Sync() error
21 }
22
23
24
25
26 type Func struct {
27 Config *Config
28 Cache *Cache
29 fe Frontend
30 pass *pass
31 Name string
32 Type *types.Type
33 Blocks []*Block
34 Entry *Block
35 bid idAlloc
36 vid idAlloc
37
38
39
40 logfiles map[string]writeSyncer
41 HTMLWriter *HTMLWriter
42 DebugTest bool
43 PrintOrHtmlSSA bool
44 ruleMatches map[string]int
45
46 scheduled bool
47 laidout bool
48 NoSplit bool
49
50
51 RegAlloc []Location
52
53
54 NamedValues map[LocalSlot][]*Value
55
56
57 Names []LocalSlot
58
59
60
61
62
63 WBLoads []*Block
64
65 freeValues *Value
66 freeBlocks *Block
67
68 cachedPostorder []*Block
69 cachedIdom []*Block
70 cachedSdom SparseTree
71 cachedLoopnest *loopnest
72 cachedLineStarts *xposmap
73
74 auxmap auxmap
75 constants map[int64][]*Value
76 }
77
78
79
80 func NewFunc(fe Frontend) *Func {
81 return &Func{fe: fe, NamedValues: make(map[LocalSlot][]*Value)}
82 }
83
84
85 func (f *Func) NumBlocks() int {
86 return f.bid.num()
87 }
88
89
90 func (f *Func) NumValues() int {
91 return f.vid.num()
92 }
93
94
95 func (f *Func) newSparseSet(n int) *sparseSet {
96 for i, scr := range f.Cache.scrSparseSet {
97 if scr != nil && scr.cap() >= n {
98 f.Cache.scrSparseSet[i] = nil
99 scr.clear()
100 return scr
101 }
102 }
103 return newSparseSet(n)
104 }
105
106
107
108 func (f *Func) retSparseSet(ss *sparseSet) {
109 for i, scr := range f.Cache.scrSparseSet {
110 if scr == nil {
111 f.Cache.scrSparseSet[i] = ss
112 return
113 }
114 }
115 f.Cache.scrSparseSet = append(f.Cache.scrSparseSet, ss)
116 }
117
118
119 func (f *Func) newSparseMap(n int) *sparseMap {
120 for i, scr := range f.Cache.scrSparseMap {
121 if scr != nil && scr.cap() >= n {
122 f.Cache.scrSparseMap[i] = nil
123 scr.clear()
124 return scr
125 }
126 }
127 return newSparseMap(n)
128 }
129
130
131
132 func (f *Func) retSparseMap(ss *sparseMap) {
133 for i, scr := range f.Cache.scrSparseMap {
134 if scr == nil {
135 f.Cache.scrSparseMap[i] = ss
136 return
137 }
138 }
139 f.Cache.scrSparseMap = append(f.Cache.scrSparseMap, ss)
140 }
141
142
143 func (f *Func) newPoset() *poset {
144 if len(f.Cache.scrPoset) > 0 {
145 po := f.Cache.scrPoset[len(f.Cache.scrPoset)-1]
146 f.Cache.scrPoset = f.Cache.scrPoset[:len(f.Cache.scrPoset)-1]
147 return po
148 }
149 return newPoset()
150 }
151
152
153 func (f *Func) retPoset(po *poset) {
154 f.Cache.scrPoset = append(f.Cache.scrPoset, po)
155 }
156
157
158
159 func (f *Func) newDeadcodeLive() []bool {
160 r := f.Cache.deadcode.live
161 f.Cache.deadcode.live = nil
162 return r
163 }
164
165
166 func (f *Func) retDeadcodeLive(live []bool) {
167 f.Cache.deadcode.live = live
168 }
169
170
171
172
173 func (f *Func) newDeadcodeLiveOrderStmts() []*Value {
174 r := f.Cache.deadcode.liveOrderStmts
175 f.Cache.deadcode.liveOrderStmts = nil
176 return r
177 }
178
179
180 func (f *Func) retDeadcodeLiveOrderStmts(liveOrderStmts []*Value) {
181 f.Cache.deadcode.liveOrderStmts = liveOrderStmts
182 }
183
184
185 func (f *Func) newValue(op Op, t *types.Type, b *Block, pos src.XPos) *Value {
186 var v *Value
187 if f.freeValues != nil {
188 v = f.freeValues
189 f.freeValues = v.argstorage[0]
190 v.argstorage[0] = nil
191 } else {
192 ID := f.vid.get()
193 if int(ID) < len(f.Cache.values) {
194 v = &f.Cache.values[ID]
195 v.ID = ID
196 } else {
197 v = &Value{ID: ID}
198 }
199 }
200 v.Op = op
201 v.Type = t
202 v.Block = b
203 if notStmtBoundary(op) {
204 pos = pos.WithNotStmt()
205 }
206 v.Pos = pos
207 b.Values = append(b.Values, v)
208 return v
209 }
210
211
212
213
214
215 func (f *Func) newValueNoBlock(op Op, t *types.Type, pos src.XPos) *Value {
216 var v *Value
217 if f.freeValues != nil {
218 v = f.freeValues
219 f.freeValues = v.argstorage[0]
220 v.argstorage[0] = nil
221 } else {
222 ID := f.vid.get()
223 if int(ID) < len(f.Cache.values) {
224 v = &f.Cache.values[ID]
225 v.ID = ID
226 } else {
227 v = &Value{ID: ID}
228 }
229 }
230 v.Op = op
231 v.Type = t
232 v.Block = nil
233 if notStmtBoundary(op) {
234 pos = pos.WithNotStmt()
235 }
236 v.Pos = pos
237 return v
238 }
239
240
241
242
243
244
245
246 func (f *Func) LogStat(key string, args ...interface{}) {
247 value := ""
248 for _, a := range args {
249 value += fmt.Sprintf("\t%v", a)
250 }
251 n := "missing_pass"
252 if f.pass != nil {
253 n = strings.Replace(f.pass.name, " ", "_", -1)
254 }
255 f.Warnl(f.Entry.Pos, "\t%s\t%s%s\t%s", n, key, value, f.Name)
256 }
257
258
259 func (f *Func) freeValue(v *Value) {
260 if v.Block == nil {
261 f.Fatalf("trying to free an already freed value")
262 }
263 if v.Uses != 0 {
264 f.Fatalf("value %s still has %d uses", v, v.Uses)
265 }
266 if len(v.Args) != 0 {
267 f.Fatalf("value %s still has %d args", v, len(v.Args))
268 }
269
270 id := v.ID
271
272
273 nArgs := opcodeTable[v.Op].argLen
274 if nArgs == 0 || v.Op == OpOffPtr {
275 vv := f.constants[v.AuxInt]
276 for i, cv := range vv {
277 if v == cv {
278 vv[i] = vv[len(vv)-1]
279 vv[len(vv)-1] = nil
280 f.constants[v.AuxInt] = vv[0 : len(vv)-1]
281 break
282 }
283 }
284 }
285 *v = Value{}
286 v.ID = id
287 v.argstorage[0] = f.freeValues
288 f.freeValues = v
289 }
290
291
292 func (f *Func) NewBlock(kind BlockKind) *Block {
293 var b *Block
294 if f.freeBlocks != nil {
295 b = f.freeBlocks
296 f.freeBlocks = b.succstorage[0].b
297 b.succstorage[0].b = nil
298 } else {
299 ID := f.bid.get()
300 if int(ID) < len(f.Cache.blocks) {
301 b = &f.Cache.blocks[ID]
302 b.ID = ID
303 } else {
304 b = &Block{ID: ID}
305 }
306 }
307 b.Kind = kind
308 b.Func = f
309 b.Preds = b.predstorage[:0]
310 b.Succs = b.succstorage[:0]
311 b.Values = b.valstorage[:0]
312 f.Blocks = append(f.Blocks, b)
313 f.invalidateCFG()
314 return b
315 }
316
317 func (f *Func) freeBlock(b *Block) {
318 if b.Func == nil {
319 f.Fatalf("trying to free an already freed block")
320 }
321
322 id := b.ID
323 *b = Block{}
324 b.ID = id
325 b.succstorage[0].b = f.freeBlocks
326 f.freeBlocks = b
327 }
328
329
330 func (b *Block) NewValue0(pos src.XPos, op Op, t *types.Type) *Value {
331 v := b.Func.newValue(op, t, b, pos)
332 v.AuxInt = 0
333 v.Args = v.argstorage[:0]
334 return v
335 }
336
337
338 func (b *Block) NewValue0I(pos src.XPos, op Op, t *types.Type, auxint int64) *Value {
339 v := b.Func.newValue(op, t, b, pos)
340 v.AuxInt = auxint
341 v.Args = v.argstorage[:0]
342 return v
343 }
344
345
346 func (b *Block) NewValue0A(pos src.XPos, op Op, t *types.Type, aux interface{}) *Value {
347 if _, ok := aux.(int64); ok {
348
349
350
351 b.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux)
352 }
353 v := b.Func.newValue(op, t, b, pos)
354 v.AuxInt = 0
355 v.Aux = aux
356 v.Args = v.argstorage[:0]
357 return v
358 }
359
360
361 func (b *Block) NewValue0IA(pos src.XPos, op Op, t *types.Type, auxint int64, aux interface{}) *Value {
362 v := b.Func.newValue(op, t, b, pos)
363 v.AuxInt = auxint
364 v.Aux = aux
365 v.Args = v.argstorage[:0]
366 return v
367 }
368
369
370 func (b *Block) NewValue1(pos src.XPos, op Op, t *types.Type, arg *Value) *Value {
371 v := b.Func.newValue(op, t, b, pos)
372 v.AuxInt = 0
373 v.Args = v.argstorage[:1]
374 v.argstorage[0] = arg
375 arg.Uses++
376 return v
377 }
378
379
380 func (b *Block) NewValue1I(pos src.XPos, op Op, t *types.Type, auxint int64, arg *Value) *Value {
381 v := b.Func.newValue(op, t, b, pos)
382 v.AuxInt = auxint
383 v.Args = v.argstorage[:1]
384 v.argstorage[0] = arg
385 arg.Uses++
386 return v
387 }
388
389
390 func (b *Block) NewValue1A(pos src.XPos, op Op, t *types.Type, aux interface{}, arg *Value) *Value {
391 v := b.Func.newValue(op, t, b, pos)
392 v.AuxInt = 0
393 v.Aux = aux
394 v.Args = v.argstorage[:1]
395 v.argstorage[0] = arg
396 arg.Uses++
397 return v
398 }
399
400
401 func (b *Block) NewValue1IA(pos src.XPos, op Op, t *types.Type, auxint int64, aux interface{}, arg *Value) *Value {
402 v := b.Func.newValue(op, t, b, pos)
403 v.AuxInt = auxint
404 v.Aux = aux
405 v.Args = v.argstorage[:1]
406 v.argstorage[0] = arg
407 arg.Uses++
408 return v
409 }
410
411
412 func (b *Block) NewValue2(pos src.XPos, op Op, t *types.Type, arg0, arg1 *Value) *Value {
413 v := b.Func.newValue(op, t, b, pos)
414 v.AuxInt = 0
415 v.Args = v.argstorage[:2]
416 v.argstorage[0] = arg0
417 v.argstorage[1] = arg1
418 arg0.Uses++
419 arg1.Uses++
420 return v
421 }
422
423
424 func (b *Block) NewValue2A(pos src.XPos, op Op, t *types.Type, aux interface{}, arg0, arg1 *Value) *Value {
425 v := b.Func.newValue(op, t, b, pos)
426 v.AuxInt = 0
427 v.Aux = aux
428 v.Args = v.argstorage[:2]
429 v.argstorage[0] = arg0
430 v.argstorage[1] = arg1
431 arg0.Uses++
432 arg1.Uses++
433 return v
434 }
435
436
437 func (b *Block) NewValue2I(pos src.XPos, op Op, t *types.Type, auxint int64, arg0, arg1 *Value) *Value {
438 v := b.Func.newValue(op, t, b, pos)
439 v.AuxInt = auxint
440 v.Args = v.argstorage[:2]
441 v.argstorage[0] = arg0
442 v.argstorage[1] = arg1
443 arg0.Uses++
444 arg1.Uses++
445 return v
446 }
447
448
449 func (b *Block) NewValue2IA(pos src.XPos, op Op, t *types.Type, auxint int64, aux interface{}, arg0, arg1 *Value) *Value {
450 v := b.Func.newValue(op, t, b, pos)
451 v.AuxInt = auxint
452 v.Aux = aux
453 v.Args = v.argstorage[:2]
454 v.argstorage[0] = arg0
455 v.argstorage[1] = arg1
456 arg0.Uses++
457 arg1.Uses++
458 return v
459 }
460
461
462 func (b *Block) NewValue3(pos src.XPos, op Op, t *types.Type, arg0, arg1, arg2 *Value) *Value {
463 v := b.Func.newValue(op, t, b, pos)
464 v.AuxInt = 0
465 v.Args = v.argstorage[:3]
466 v.argstorage[0] = arg0
467 v.argstorage[1] = arg1
468 v.argstorage[2] = arg2
469 arg0.Uses++
470 arg1.Uses++
471 arg2.Uses++
472 return v
473 }
474
475
476 func (b *Block) NewValue3I(pos src.XPos, op Op, t *types.Type, auxint int64, arg0, arg1, arg2 *Value) *Value {
477 v := b.Func.newValue(op, t, b, pos)
478 v.AuxInt = auxint
479 v.Args = v.argstorage[:3]
480 v.argstorage[0] = arg0
481 v.argstorage[1] = arg1
482 v.argstorage[2] = arg2
483 arg0.Uses++
484 arg1.Uses++
485 arg2.Uses++
486 return v
487 }
488
489
490 func (b *Block) NewValue3A(pos src.XPos, op Op, t *types.Type, aux interface{}, arg0, arg1, arg2 *Value) *Value {
491 v := b.Func.newValue(op, t, b, pos)
492 v.AuxInt = 0
493 v.Aux = aux
494 v.Args = v.argstorage[:3]
495 v.argstorage[0] = arg0
496 v.argstorage[1] = arg1
497 v.argstorage[2] = arg2
498 arg0.Uses++
499 arg1.Uses++
500 arg2.Uses++
501 return v
502 }
503
504
505 func (b *Block) NewValue4(pos src.XPos, op Op, t *types.Type, arg0, arg1, arg2, arg3 *Value) *Value {
506 v := b.Func.newValue(op, t, b, pos)
507 v.AuxInt = 0
508 v.Args = []*Value{arg0, arg1, arg2, arg3}
509 arg0.Uses++
510 arg1.Uses++
511 arg2.Uses++
512 arg3.Uses++
513 return v
514 }
515
516
517 func (b *Block) NewValue4I(pos src.XPos, op Op, t *types.Type, auxint int64, arg0, arg1, arg2, arg3 *Value) *Value {
518 v := b.Func.newValue(op, t, b, pos)
519 v.AuxInt = auxint
520 v.Args = []*Value{arg0, arg1, arg2, arg3}
521 arg0.Uses++
522 arg1.Uses++
523 arg2.Uses++
524 arg3.Uses++
525 return v
526 }
527
528
529 func (f *Func) constVal(op Op, t *types.Type, c int64, setAuxInt bool) *Value {
530 if f.constants == nil {
531 f.constants = make(map[int64][]*Value)
532 }
533 vv := f.constants[c]
534 for _, v := range vv {
535 if v.Op == op && v.Type.Compare(t) == types.CMPeq {
536 if setAuxInt && v.AuxInt != c {
537 panic(fmt.Sprintf("cached const %s should have AuxInt of %d", v.LongString(), c))
538 }
539 return v
540 }
541 }
542 var v *Value
543 if setAuxInt {
544 v = f.Entry.NewValue0I(src.NoXPos, op, t, c)
545 } else {
546 v = f.Entry.NewValue0(src.NoXPos, op, t)
547 }
548 f.constants[c] = append(vv, v)
549 return v
550 }
551
552
553
554
555
556 const (
557 constSliceMagic = 1122334455
558 constInterfaceMagic = 2233445566
559 constNilMagic = 3344556677
560 constEmptyStringMagic = 4455667788
561 )
562
563
564 func (f *Func) ConstBool(t *types.Type, c bool) *Value {
565 i := int64(0)
566 if c {
567 i = 1
568 }
569 return f.constVal(OpConstBool, t, i, true)
570 }
571 func (f *Func) ConstInt8(t *types.Type, c int8) *Value {
572 return f.constVal(OpConst8, t, int64(c), true)
573 }
574 func (f *Func) ConstInt16(t *types.Type, c int16) *Value {
575 return f.constVal(OpConst16, t, int64(c), true)
576 }
577 func (f *Func) ConstInt32(t *types.Type, c int32) *Value {
578 return f.constVal(OpConst32, t, int64(c), true)
579 }
580 func (f *Func) ConstInt64(t *types.Type, c int64) *Value {
581 return f.constVal(OpConst64, t, c, true)
582 }
583 func (f *Func) ConstFloat32(t *types.Type, c float64) *Value {
584 return f.constVal(OpConst32F, t, int64(math.Float64bits(float64(float32(c)))), true)
585 }
586 func (f *Func) ConstFloat64(t *types.Type, c float64) *Value {
587 return f.constVal(OpConst64F, t, int64(math.Float64bits(c)), true)
588 }
589
590 func (f *Func) ConstSlice(t *types.Type) *Value {
591 return f.constVal(OpConstSlice, t, constSliceMagic, false)
592 }
593 func (f *Func) ConstInterface(t *types.Type) *Value {
594 return f.constVal(OpConstInterface, t, constInterfaceMagic, false)
595 }
596 func (f *Func) ConstNil(t *types.Type) *Value {
597 return f.constVal(OpConstNil, t, constNilMagic, false)
598 }
599 func (f *Func) ConstEmptyString(t *types.Type) *Value {
600 v := f.constVal(OpConstString, t, constEmptyStringMagic, false)
601 v.Aux = ""
602 return v
603 }
604 func (f *Func) ConstOffPtrSP(t *types.Type, c int64, sp *Value) *Value {
605 v := f.constVal(OpOffPtr, t, c, true)
606 if len(v.Args) == 0 {
607 v.AddArg(sp)
608 }
609 return v
610
611 }
612
613 func (f *Func) Frontend() Frontend { return f.fe }
614 func (f *Func) Warnl(pos src.XPos, msg string, args ...interface{}) { f.fe.Warnl(pos, msg, args...) }
615 func (f *Func) Logf(msg string, args ...interface{}) { f.fe.Logf(msg, args...) }
616 func (f *Func) Log() bool { return f.fe.Log() }
617 func (f *Func) Fatalf(msg string, args ...interface{}) { f.fe.Fatalf(f.Entry.Pos, msg, args...) }
618
619
620 func (f *Func) postorder() []*Block {
621 if f.cachedPostorder == nil {
622 f.cachedPostorder = postorder(f)
623 }
624 return f.cachedPostorder
625 }
626
627 func (f *Func) Postorder() []*Block {
628 return f.postorder()
629 }
630
631
632
633 func (f *Func) Idom() []*Block {
634 if f.cachedIdom == nil {
635 f.cachedIdom = dominators(f)
636 }
637 return f.cachedIdom
638 }
639
640
641
642 func (f *Func) sdom() SparseTree {
643 if f.cachedSdom == nil {
644 f.cachedSdom = newSparseTree(f, f.Idom())
645 }
646 return f.cachedSdom
647 }
648
649
650 func (f *Func) loopnest() *loopnest {
651 if f.cachedLoopnest == nil {
652 f.cachedLoopnest = loopnestfor(f)
653 }
654 return f.cachedLoopnest
655 }
656
657
658 func (f *Func) invalidateCFG() {
659 f.cachedPostorder = nil
660 f.cachedIdom = nil
661 f.cachedSdom = nil
662 f.cachedLoopnest = nil
663 }
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679 func (f *Func) DebugHashMatch(evname, name string) bool {
680 evhash := os.Getenv(evname)
681 switch evhash {
682 case "":
683 return true
684 case "y", "Y":
685 f.logDebugHashMatch(evname, name)
686 return true
687 case "n", "N":
688 return false
689 }
690
691
692
693 hstr := ""
694 for _, b := range sha1.Sum([]byte(name)) {
695 hstr += fmt.Sprintf("%08b", b)
696 }
697
698 if strings.HasSuffix(hstr, evhash) {
699 f.logDebugHashMatch(evname, name)
700 return true
701 }
702
703
704
705 for i := 0; true; i++ {
706 ev := fmt.Sprintf("%s%d", evname, i)
707 evv := os.Getenv(ev)
708 if evv == "" {
709 break
710 }
711 if strings.HasSuffix(hstr, evv) {
712 f.logDebugHashMatch(ev, name)
713 return true
714 }
715 }
716 return false
717 }
718
719 func (f *Func) logDebugHashMatch(evname, name string) {
720 if f.logfiles == nil {
721 f.logfiles = make(map[string]writeSyncer)
722 }
723 file := f.logfiles[evname]
724 if file == nil {
725 file = os.Stdout
726 if tmpfile := os.Getenv("GSHS_LOGFILE"); tmpfile != "" {
727 var err error
728 file, err = os.Create(tmpfile)
729 if err != nil {
730 f.Fatalf("could not open hash-testing logfile %s", tmpfile)
731 }
732 }
733 f.logfiles[evname] = file
734 }
735 fmt.Fprintf(file, "%s triggered %s\n", evname, name)
736 file.Sync()
737 }
738
739 func DebugNameMatch(evname, name string) bool {
740 return os.Getenv(evname) == name
741 }
742
View as plain text