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