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