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