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