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