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