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