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