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