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