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