1
2
3
4
5 package ssa
6
7 import (
8 "fmt"
9 "internal/buildcfg"
10 "math"
11 "sort"
12 "strings"
13
14 "cmd/compile/internal/ir"
15 "cmd/compile/internal/ssa/ssabase"
16 "cmd/compile/internal/ssa/ssaop"
17 "cmd/compile/internal/types"
18 "cmd/internal/src"
19 )
20
21
22
23
24 type Value struct {
25
26
27 ID ID
28
29
30 Op ssaop.Op
31
32
33
34 Type *types.Type
35
36
37
38
39
40
41
42
43 AuxInt int64
44 Aux Aux
45
46
47 Args []*Value
48
49
50 Block *Block
51
52
53 Pos src.XPos
54
55
56 Uses int32
57
58
59
60 OnWasmStack bool
61
62
63 InCache bool
64
65
66 Argstorage [3]*Value
67 }
68
69
70 func CanSSA(t *types.Type) bool {
71 types.CalcSize(t)
72 if t.IsSIMD() {
73 return true
74 }
75 if t.Size() == 0 {
76 return true
77 }
78 sizeLimit := int64(MaxStruct * types.PtrSize)
79 if t.Size() > sizeLimit {
80
81
82
83 if !buildcfg.Experiment.SIMD {
84 return false
85 }
86 }
87 switch t.Kind() {
88 case types.TARRAY:
89
90
91
92 if t.NumElem() <= 1 {
93 return CanSSA(t.Elem())
94 }
95 return false
96 case types.TSTRUCT:
97 if types.IsDirectIface(t) {
98
99 return true
100 }
101 if t.NumFields() > MaxStruct {
102 return false
103 }
104 for _, t1 := range t.Fields() {
105 if !CanSSA(t1.Type) {
106 return false
107 }
108 }
109
110
111
112 if !buildcfg.Experiment.SIMD {
113 return true
114 }
115 if t.Size() <= sizeLimit {
116 return true
117 }
118 i, f := t.Registers()
119 return i+f <= MaxStruct
120 default:
121 return true
122 }
123 }
124
125
126
127 func AutoVar(v *Value) (*ir.Name, int64) {
128 if loc, ok := v.Block.Func.RegAlloc[v.ID].(LocalSlot); ok {
129 if v.Type.Size() > loc.Type.Size() {
130 v.Fatalf("v%d: spill/restore type %v doesn't fit in slot type %v", v.ID, v.Type, loc.Type)
131 }
132 return loc.N, loc.Off
133 }
134
135 nameOff := v.Aux.(*AuxNameOffset)
136 return nameOff.Name, nameOff.Offset
137 }
138
139
140
141
142
143
144
145
146
147 func (v *Value) String() string {
148 if v == nil {
149 return "nil"
150 }
151 return fmt.Sprintf("v%d", v.ID)
152 }
153
154 func (v *Value) AuxInt8() int8 {
155 if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeInt8 && ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeNameOffsetInt8 {
156 v.Fatalf("op %s doesn't have an int8 aux field", v.Op)
157 }
158 return int8(v.AuxInt)
159 }
160
161 func (v *Value) AuxUInt8() uint8 {
162 if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeUInt8 {
163 v.Fatalf("op %s doesn't have a uint8 aux field", v.Op)
164 }
165 return uint8(v.AuxInt)
166 }
167
168 func (v *Value) AuxInt16() int16 {
169 if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeInt16 {
170 v.Fatalf("op %s doesn't have an int16 aux field", v.Op)
171 }
172 return int16(v.AuxInt)
173 }
174
175 func (v *Value) AuxInt32() int32 {
176 if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeInt32 {
177 v.Fatalf("op %s doesn't have an int32 aux field", v.Op)
178 }
179 return int32(v.AuxInt)
180 }
181
182
183
184
185 func (v *Value) AuxUnsigned() uint64 {
186 c := v.AuxInt
187 switch v.Op {
188 case ssaop.OpConst64:
189 return uint64(c)
190 case ssaop.OpConst32:
191 return uint64(uint32(c))
192 case ssaop.OpConst16:
193 return uint64(uint16(c))
194 case ssaop.OpConst8:
195 return uint64(uint8(c))
196 }
197 v.Fatalf("op %s isn't OpConst*", v.Op)
198 return 0
199 }
200
201 func (v *Value) AuxFloat() float64 {
202 if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeFloat32 && ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeFloat64 {
203 v.Fatalf("op %s doesn't have a float aux field", v.Op)
204 }
205 return math.Float64frombits(uint64(v.AuxInt))
206 }
207
208 func (v *Value) AuxValAndOff() ValAndOff {
209 if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeSymValAndOff {
210 v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op)
211 }
212 return ValAndOff(v.AuxInt)
213 }
214
215 func (v *Value) AuxArm64BitField() Arm64BitField {
216 if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeARM64BitField {
217 v.Fatalf("op %s doesn't have a ARM64BitField aux field", v.Op)
218 }
219 return Arm64BitField(v.AuxInt)
220 }
221
222 func (v *Value) AuxArm64ConditionalParams() Arm64ConditionalParams {
223 if ssaop.OpcodeTable[v.Op].AuxType != ssaop.AuxTypeARM64ConditionalParams {
224 v.Fatalf("op %s doesn't have a ARM64ConditionalParams aux field", v.Op)
225 }
226 return AuxIntToArm64ConditionalParams(v.AuxInt)
227 }
228
229 func (v *Value) AuxSizeAndAlign() (int64, int64) {
230 return v.AuxInt, int64(v.Aux.(Int64Aux))
231 }
232
233
234 func (v *Value) LongString() string {
235 if v == nil {
236 return "<NIL VALUE>"
237 }
238 s := fmt.Sprintf("v%d = %s", v.ID, v.Op)
239 s += " <" + v.Type.String() + ">"
240 s += v.AuxString()
241 for _, a := range v.Args {
242 s += fmt.Sprintf(" %v", a)
243 }
244 if v.Block == nil {
245 return s
246 }
247 r := v.Block.Func.RegAlloc
248 if int(v.ID) < len(r) && r[v.ID] != nil {
249 s += " : " + r[v.ID].String()
250 }
251 if reg := v.Block.Func.TempRegs[v.ID]; reg != nil {
252 s += " tmp=" + reg.String()
253 }
254 var names []string
255 for name, values := range v.Block.Func.NamedValues {
256 for _, value := range values {
257 if value == v {
258 names = append(names, name.String())
259 break
260 }
261 }
262 }
263 if len(names) != 0 {
264 sort.Strings(names)
265 s += " (" + strings.Join(names, ", ") + ")"
266 }
267 return s
268 }
269
270 func (v *Value) AuxString() string {
271 switch ssaop.OpcodeTable[v.Op].AuxType {
272 case ssaop.AuxTypeBool:
273 if v.AuxInt == 0 {
274 return " [false]"
275 } else {
276 return " [true]"
277 }
278 case ssaop.AuxTypeInt8:
279 return fmt.Sprintf(" [%d]", v.AuxInt8())
280 case ssaop.AuxTypeInt16:
281 return fmt.Sprintf(" [%d]", v.AuxInt16())
282 case ssaop.AuxTypeInt32:
283 return fmt.Sprintf(" [%d]", v.AuxInt32())
284 case ssaop.AuxTypeInt64, ssaop.AuxTypeInt128:
285 return fmt.Sprintf(" [%d]", v.AuxInt)
286 case ssaop.AuxTypeUInt8:
287 return fmt.Sprintf(" [%d]", v.AuxUInt8())
288 case ssaop.AuxTypeARM64BitField:
289 lsb := v.AuxArm64BitField().Lsb()
290 width := v.AuxArm64BitField().Width()
291 return fmt.Sprintf(" [lsb=%d,width=%d]", lsb, width)
292 case ssaop.AuxTypeARM64ConditionalParams:
293 params := v.AuxArm64ConditionalParams()
294 cond := params.Cond
295 nzcv := params.Nzcv()
296 imm, ok := params.ConstValue()
297 if ok {
298 return fmt.Sprintf(" [cond=%s,nzcv=%d,imm=%d]", cond, nzcv, imm)
299 }
300 return fmt.Sprintf(" [cond=%s,nzcv=%d]", cond, nzcv)
301 case ssaop.AuxTypeFloat32, ssaop.AuxTypeFloat64:
302 return fmt.Sprintf(" [%g]", v.AuxFloat())
303 case ssaop.AuxTypeString:
304 return fmt.Sprintf(" {%q}", v.Aux)
305 case ssaop.AuxTypeSym, ssaop.AuxTypeCall, ssaop.AuxTypeTyp:
306 if v.Aux != nil {
307 return fmt.Sprintf(" {%v}", v.Aux)
308 }
309 return ""
310 case ssaop.AuxTypeSymOff, ssaop.AuxTypeCallOff, ssaop.AuxTypeTypSize, ssaop.AuxTypeNameOffsetInt8:
311 s := ""
312 if v.Aux != nil {
313 s = fmt.Sprintf(" {%v}", v.Aux)
314 }
315 if v.AuxInt != 0 || ssaop.OpcodeTable[v.Op].AuxType == ssaop.AuxTypeNameOffsetInt8 {
316 s += fmt.Sprintf(" [%v]", v.AuxInt)
317 }
318 return s
319 case ssaop.AuxTypeSymValAndOff:
320 s := ""
321 if v.Aux != nil {
322 s = fmt.Sprintf(" {%v}", v.Aux)
323 }
324 return s + fmt.Sprintf(" [%s]", v.AuxValAndOff())
325 case ssaop.AuxTypeCCop:
326 return fmt.Sprintf(" [%s]", ssaop.Op(v.AuxInt))
327 case ssaop.AuxTypeS390XCCMask, ssaop.AuxTypeS390XRotateParams:
328 return fmt.Sprintf(" {%v}", v.Aux)
329 case ssaop.AuxTypeFlagConstant:
330 return fmt.Sprintf("[%s]", FlagConstant(v.AuxInt))
331 case ssaop.AuxTypeSizeAndAlign:
332 return fmt.Sprintf(" [size=%d] {align=%d}", v.AuxInt, v.Aux)
333 case ssaop.AuxTypeNone:
334 return ""
335 default:
336
337 return fmt.Sprintf("[auxtype=%d AuxInt=%d Aux=%v]", ssaop.OpcodeTable[v.Op].AuxType, v.AuxInt, v.Aux)
338 }
339 }
340
341
342
343
344
345 func (v *Value) AddArg(w *Value) {
346 if v.Args == nil {
347 v.ResetArgs()
348 }
349 v.Args = append(v.Args, w)
350 w.Uses++
351 }
352
353
354 func (v *Value) AddArg2(w1, w2 *Value) {
355 if v.Args == nil {
356 v.ResetArgs()
357 }
358 v.Args = append(v.Args, w1, w2)
359 w1.Uses++
360 w2.Uses++
361 }
362
363
364 func (v *Value) AddArg3(w1, w2, w3 *Value) {
365 if v.Args == nil {
366 v.ResetArgs()
367 }
368 v.Args = append(v.Args, w1, w2, w3)
369 w1.Uses++
370 w2.Uses++
371 w3.Uses++
372 }
373
374
375 func (v *Value) AddArg4(w1, w2, w3, w4 *Value) {
376 v.Args = append(v.Args, w1, w2, w3, w4)
377 w1.Uses++
378 w2.Uses++
379 w3.Uses++
380 w4.Uses++
381 }
382
383
384 func (v *Value) AddArg5(w1, w2, w3, w4, w5 *Value) {
385 v.Args = append(v.Args, w1, w2, w3, w4, w5)
386 w1.Uses++
387 w2.Uses++
388 w3.Uses++
389 w4.Uses++
390 w5.Uses++
391 }
392
393
394 func (v *Value) AddArg6(w1, w2, w3, w4, w5, w6 *Value) {
395 v.Args = append(v.Args, w1, w2, w3, w4, w5, w6)
396 w1.Uses++
397 w2.Uses++
398 w3.Uses++
399 w4.Uses++
400 w5.Uses++
401 w6.Uses++
402 }
403
404 func (v *Value) AddArgs(a ...*Value) {
405 if v.Args == nil {
406 v.ResetArgs()
407 }
408 v.Args = append(v.Args, a...)
409 for _, x := range a {
410 x.Uses++
411 }
412 }
413
414 func (v *Value) SetArg(i int, w *Value) {
415 v.Args[i].Uses--
416 v.Args[i] = w
417 w.Uses++
418 }
419
420 func (v *Value) SetArgs1(a *Value) {
421 v.ResetArgs()
422 v.AddArg(a)
423 }
424
425 func (v *Value) SetArgs2(a, b *Value) {
426 v.ResetArgs()
427 v.AddArg(a)
428 v.AddArg(b)
429 }
430
431 func (v *Value) SetArgs3(a, b, c *Value) {
432 v.ResetArgs()
433 v.AddArg(a)
434 v.AddArg(b)
435 v.AddArg(c)
436 }
437
438 func (v *Value) SetArgs4(a, b, c, d *Value) {
439 v.ResetArgs()
440 v.AddArg(a)
441 v.AddArg(b)
442 v.AddArg(c)
443 v.AddArg(d)
444 }
445
446 func (v *Value) ResetArgs() {
447 for _, a := range v.Args {
448 a.Uses--
449 }
450 v.Argstorage[0] = nil
451 v.Argstorage[1] = nil
452 v.Argstorage[2] = nil
453 v.Args = v.Argstorage[:0]
454 }
455
456
457
458
459
460
461 func (v *Value) Reset(op ssaop.Op) {
462 if v.InCache {
463 v.Block.Func.UnCache(v)
464 }
465 v.Op = op
466 v.ResetArgs()
467 v.AuxInt = 0
468 v.Aux = nil
469 }
470
471
472
473
474
475
476
477
478
479 func (v *Value) InvalidateRecursively() bool {
480 lostStmt := v.Pos.IsStmt() == src.PosIsStmt
481 if v.InCache {
482 v.Block.Func.UnCache(v)
483 }
484 v.Op = ssaop.OpInvalid
485
486 for _, a := range v.Args {
487 a.Uses--
488 if a.Uses == 0 {
489 lost := a.InvalidateRecursively()
490 lostStmt = lost || lostStmt
491 }
492 }
493
494 v.Argstorage[0] = nil
495 v.Argstorage[1] = nil
496 v.Argstorage[2] = nil
497 v.Args = v.Argstorage[:0]
498
499 v.AuxInt = 0
500 v.Aux = nil
501 return lostStmt
502 }
503
504
505
506
507
508 func (v *Value) CopyOf(a *Value) {
509 if v == a {
510 return
511 }
512 if v.InCache {
513 v.Block.Func.UnCache(v)
514 }
515 v.Op = ssaop.OpCopy
516 v.ResetArgs()
517 v.AddArg(a)
518 v.AuxInt = 0
519 v.Aux = nil
520 v.Type = a.Type
521 }
522
523
524
525 func (v *Value) CopyInto(b *Block) *Value {
526 c := b.NewValue0(v.Pos.WithNotStmt(), v.Op, v.Type)
527 c.Aux = v.Aux
528 c.AuxInt = v.AuxInt
529 c.AddArgs(v.Args...)
530 for _, a := range v.Args {
531 if a.Type.IsMemory() {
532 v.Fatalf("can't move a value with a memory arg %s", v.LongString())
533 }
534 }
535 return c
536 }
537
538
539
540
541
542
543
544 func (v *Value) CopyIntoWithXPos(b *Block, pos src.XPos) *Value {
545 if v.Pos.IsStmt() == src.PosIsStmt && pos.IsStmt() != src.PosIsStmt && v.Pos.SameFileAndLine(pos) {
546 pos = pos.WithIsStmt()
547 }
548 c := b.NewValue0(pos, v.Op, v.Type)
549 c.Aux = v.Aux
550 c.AuxInt = v.AuxInt
551 c.AddArgs(v.Args...)
552 for _, a := range v.Args {
553 if a.Type.IsMemory() {
554 v.Fatalf("can't move a value with a memory arg %s", v.LongString())
555 }
556 }
557 return c
558 }
559
560 func (v *Value) Logf(msg string, args ...any) { v.Block.Logf(msg, args...) }
561
562 func (v *Value) Log() bool { return v.Block.Log() }
563
564 func (v *Value) Fatalf(msg string, args ...any) {
565 v.Block.Func.FatalfWithPos(v.Pos, msg, args...)
566 }
567
568
569 func (v *Value) IsGenericIntConst() bool {
570 return v != nil && (v.Op == ssaop.OpConst64 || v.Op == ssaop.OpConst32 || v.Op == ssaop.OpConst16 || v.Op == ssaop.OpConst8)
571 }
572
573
574
575
576 func (v *Value) ResultReg() int16 {
577 reg := v.Block.Func.RegAlloc[v.ID]
578 if reg == nil {
579 v.Fatalf("nil reg for value: %s\n%s\n", v.LongString(), v.Block.Func)
580 }
581 if pair, ok := reg.(LocPair); ok {
582 reg = pair[0]
583 }
584 if reg == nil {
585 v.Fatalf("nil reg0 for value: %s\n%s\n", v.LongString(), v.Block.Func)
586 }
587 return reg.(*ssabase.Register).ObjNum
588 }
589
590
591 func (v *Value) Reg() int16 {
592 reg := v.Block.Func.RegAlloc[v.ID]
593 if reg == nil {
594 v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
595 }
596 return reg.(*ssabase.Register).ObjNum
597 }
598
599
600 func (v *Value) Reg0() int16 {
601 reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[0]
602 if reg == nil {
603 v.Fatalf("nil first register for value: %s\n%s\n", v.LongString(), v.Block.Func)
604 }
605 return reg.(*ssabase.Register).ObjNum
606 }
607
608
609 func (v *Value) Reg1() int16 {
610 reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[1]
611 if reg == nil {
612 v.Fatalf("nil second register for value: %s\n%s\n", v.LongString(), v.Block.Func)
613 }
614 return reg.(*ssabase.Register).ObjNum
615 }
616
617
618 func (v *Value) RegTmp() int16 {
619 reg := v.Block.Func.TempRegs[v.ID]
620 if reg == nil {
621 v.Fatalf("nil tmp register for value: %s\n%s\n", v.LongString(), v.Block.Func)
622 }
623 return reg.ObjNum
624 }
625
626 func (v *Value) RegName() string {
627 reg := v.Block.Func.RegAlloc[v.ID]
628 if reg == nil {
629 v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
630 }
631 return reg.(*ssabase.Register).Name
632 }
633
634
635
636
637 func (v *Value) MemoryArg() *Value {
638 if v.Op == ssaop.OpPhi {
639 if v.Type.IsMemory() {
640 v.Fatalf("MemoryArg on Phi<mem> is ambiguous")
641 }
642
643
644
645
646 return nil
647 }
648
649 na := len(v.Args)
650 if na == 0 {
651 return nil
652 }
653 if m := v.Args[na-1]; m.Type.IsMemory() {
654 return m
655 }
656 return nil
657 }
658
659
660
661
662 func (v *Value) LackingPos() bool {
663
664
665
666 return v.Op == ssaop.OpVarDef || v.Op == ssaop.OpVarLive || v.Op == ssaop.OpPhi ||
667 (v.Op == ssaop.OpFwdRef || v.Op == ssaop.OpCopy) && v.Type == types.TypeMem
668 }
669
670
671
672 func (v *Value) Removeable() bool {
673 if v.Type.IsVoid() {
674
675 return false
676 }
677 if ssaop.OpcodeTable[v.Op].NilCheck {
678
679 return false
680 }
681 if v.Type.IsMemory() {
682
683
684
685 return false
686 }
687 if v.Op.HasSideEffects() {
688
689 return false
690 }
691 return true
692 }
693
694
695
696 func (v *Value) AddrSinkArg(idx int) bool {
697 if idx == 0 {
698 return ssaop.OpcodeTable[v.Op].AddrSinkArg0
699 }
700 if idx == 1 {
701 return ssaop.OpcodeTable[v.Op].AddrSinkArg1
702 }
703 return false
704 }
705
View as plain text