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
156 func (v *Value) LongString() string {
157 if v == nil {
158 return "<NIL VALUE>"
159 }
160 s := fmt.Sprintf("v%d = %s", v.ID, v.Op)
161 s += " <" + v.Type.String() + ">"
162 s += v.auxString()
163 for _, a := range v.Args {
164 s += fmt.Sprintf(" %v", a)
165 }
166 if v.Block == nil {
167 return s
168 }
169 r := v.Block.Func.RegAlloc
170 if int(v.ID) < len(r) && r[v.ID] != nil {
171 s += " : " + r[v.ID].String()
172 }
173 if reg := v.Block.Func.tempRegs[v.ID]; reg != nil {
174 s += " tmp=" + reg.String()
175 }
176 var names []string
177 for name, values := range v.Block.Func.NamedValues {
178 for _, value := range values {
179 if value == v {
180 names = append(names, name.String())
181 break
182 }
183 }
184 }
185 if len(names) != 0 {
186 sort.Strings(names)
187 s += " (" + strings.Join(names, ", ") + ")"
188 }
189 return s
190 }
191
192 func (v *Value) auxString() string {
193 switch opcodeTable[v.Op].auxType {
194 case auxBool:
195 if v.AuxInt == 0 {
196 return " [false]"
197 } else {
198 return " [true]"
199 }
200 case auxInt8:
201 return fmt.Sprintf(" [%d]", v.AuxInt8())
202 case auxInt16:
203 return fmt.Sprintf(" [%d]", v.AuxInt16())
204 case auxInt32:
205 return fmt.Sprintf(" [%d]", v.AuxInt32())
206 case auxInt64, auxInt128:
207 return fmt.Sprintf(" [%d]", v.AuxInt)
208 case auxUInt8:
209 return fmt.Sprintf(" [%d]", v.AuxUInt8())
210 case auxARM64BitField:
211 lsb := v.AuxArm64BitField().lsb()
212 width := v.AuxArm64BitField().width()
213 return fmt.Sprintf(" [lsb=%d,width=%d]", lsb, width)
214 case auxARM64ConditionalParams:
215 params := v.AuxArm64ConditionalParams()
216 cond := params.Cond()
217 nzcv := params.Nzcv()
218 imm, ok := params.ConstValue()
219 if ok {
220 return fmt.Sprintf(" [cond=%s,nzcv=%d,imm=%d]", cond, nzcv, imm)
221 }
222 return fmt.Sprintf(" [cond=%s,nzcv=%d]", cond, nzcv)
223 case auxFloat32, auxFloat64:
224 return fmt.Sprintf(" [%g]", v.AuxFloat())
225 case auxString:
226 return fmt.Sprintf(" {%q}", v.Aux)
227 case auxSym, auxCall, auxTyp:
228 if v.Aux != nil {
229 return fmt.Sprintf(" {%v}", v.Aux)
230 }
231 return ""
232 case auxSymOff, auxCallOff, auxTypSize, auxNameOffsetInt8:
233 s := ""
234 if v.Aux != nil {
235 s = fmt.Sprintf(" {%v}", v.Aux)
236 }
237 if v.AuxInt != 0 || opcodeTable[v.Op].auxType == auxNameOffsetInt8 {
238 s += fmt.Sprintf(" [%v]", v.AuxInt)
239 }
240 return s
241 case auxSymValAndOff:
242 s := ""
243 if v.Aux != nil {
244 s = fmt.Sprintf(" {%v}", v.Aux)
245 }
246 return s + fmt.Sprintf(" [%s]", v.AuxValAndOff())
247 case auxCCop:
248 return fmt.Sprintf(" [%s]", Op(v.AuxInt))
249 case auxS390XCCMask, auxS390XRotateParams:
250 return fmt.Sprintf(" {%v}", v.Aux)
251 case auxFlagConstant:
252 return fmt.Sprintf("[%s]", flagConstant(v.AuxInt))
253 case auxNone:
254 return ""
255 default:
256
257 return fmt.Sprintf("[auxtype=%d AuxInt=%d Aux=%v]", opcodeTable[v.Op].auxType, v.AuxInt, v.Aux)
258 }
259 }
260
261
262
263
264
265 func (v *Value) AddArg(w *Value) {
266 if v.Args == nil {
267 v.resetArgs()
268 }
269 v.Args = append(v.Args, w)
270 w.Uses++
271 }
272
273
274 func (v *Value) AddArg2(w1, w2 *Value) {
275 if v.Args == nil {
276 v.resetArgs()
277 }
278 v.Args = append(v.Args, w1, w2)
279 w1.Uses++
280 w2.Uses++
281 }
282
283
284 func (v *Value) AddArg3(w1, w2, w3 *Value) {
285 if v.Args == nil {
286 v.resetArgs()
287 }
288 v.Args = append(v.Args, w1, w2, w3)
289 w1.Uses++
290 w2.Uses++
291 w3.Uses++
292 }
293
294
295 func (v *Value) AddArg4(w1, w2, w3, w4 *Value) {
296 v.Args = append(v.Args, w1, w2, w3, w4)
297 w1.Uses++
298 w2.Uses++
299 w3.Uses++
300 w4.Uses++
301 }
302
303
304 func (v *Value) AddArg5(w1, w2, w3, w4, w5 *Value) {
305 v.Args = append(v.Args, w1, w2, w3, w4, w5)
306 w1.Uses++
307 w2.Uses++
308 w3.Uses++
309 w4.Uses++
310 w5.Uses++
311 }
312
313
314 func (v *Value) AddArg6(w1, w2, w3, w4, w5, w6 *Value) {
315 v.Args = append(v.Args, w1, w2, w3, w4, w5, w6)
316 w1.Uses++
317 w2.Uses++
318 w3.Uses++
319 w4.Uses++
320 w5.Uses++
321 w6.Uses++
322 }
323
324 func (v *Value) AddArgs(a ...*Value) {
325 if v.Args == nil {
326 v.resetArgs()
327 }
328 v.Args = append(v.Args, a...)
329 for _, x := range a {
330 x.Uses++
331 }
332 }
333 func (v *Value) SetArg(i int, w *Value) {
334 v.Args[i].Uses--
335 v.Args[i] = w
336 w.Uses++
337 }
338 func (v *Value) SetArgs1(a *Value) {
339 v.resetArgs()
340 v.AddArg(a)
341 }
342 func (v *Value) SetArgs2(a, b *Value) {
343 v.resetArgs()
344 v.AddArg(a)
345 v.AddArg(b)
346 }
347 func (v *Value) SetArgs3(a, b, c *Value) {
348 v.resetArgs()
349 v.AddArg(a)
350 v.AddArg(b)
351 v.AddArg(c)
352 }
353 func (v *Value) SetArgs4(a, b, c, d *Value) {
354 v.resetArgs()
355 v.AddArg(a)
356 v.AddArg(b)
357 v.AddArg(c)
358 v.AddArg(d)
359 }
360
361 func (v *Value) resetArgs() {
362 for _, a := range v.Args {
363 a.Uses--
364 }
365 v.argstorage[0] = nil
366 v.argstorage[1] = nil
367 v.argstorage[2] = nil
368 v.Args = v.argstorage[:0]
369 }
370
371
372
373
374
375
376 func (v *Value) reset(op Op) {
377 if v.InCache {
378 v.Block.Func.unCache(v)
379 }
380 v.Op = op
381 v.resetArgs()
382 v.AuxInt = 0
383 v.Aux = nil
384 }
385
386
387
388
389
390
391
392
393
394 func (v *Value) invalidateRecursively() bool {
395 lostStmt := v.Pos.IsStmt() == src.PosIsStmt
396 if v.InCache {
397 v.Block.Func.unCache(v)
398 }
399 v.Op = OpInvalid
400
401 for _, a := range v.Args {
402 a.Uses--
403 if a.Uses == 0 {
404 lost := a.invalidateRecursively()
405 lostStmt = lost || lostStmt
406 }
407 }
408
409 v.argstorage[0] = nil
410 v.argstorage[1] = nil
411 v.argstorage[2] = nil
412 v.Args = v.argstorage[:0]
413
414 v.AuxInt = 0
415 v.Aux = nil
416 return lostStmt
417 }
418
419
420
421
422
423 func (v *Value) copyOf(a *Value) {
424 if v == a {
425 return
426 }
427 if v.InCache {
428 v.Block.Func.unCache(v)
429 }
430 v.Op = OpCopy
431 v.resetArgs()
432 v.AddArg(a)
433 v.AuxInt = 0
434 v.Aux = nil
435 v.Type = a.Type
436 }
437
438
439
440 func (v *Value) copyInto(b *Block) *Value {
441 c := b.NewValue0(v.Pos.WithNotStmt(), v.Op, v.Type)
442 c.Aux = v.Aux
443 c.AuxInt = v.AuxInt
444 c.AddArgs(v.Args...)
445 for _, a := range v.Args {
446 if a.Type.IsMemory() {
447 v.Fatalf("can't move a value with a memory arg %s", v.LongString())
448 }
449 }
450 return c
451 }
452
453
454
455
456
457
458
459 func (v *Value) copyIntoWithXPos(b *Block, pos src.XPos) *Value {
460 if v.Pos.IsStmt() == src.PosIsStmt && pos.IsStmt() != src.PosIsStmt && v.Pos.SameFileAndLine(pos) {
461 pos = pos.WithIsStmt()
462 }
463 c := b.NewValue0(pos, v.Op, v.Type)
464 c.Aux = v.Aux
465 c.AuxInt = v.AuxInt
466 c.AddArgs(v.Args...)
467 for _, a := range v.Args {
468 if a.Type.IsMemory() {
469 v.Fatalf("can't move a value with a memory arg %s", v.LongString())
470 }
471 }
472 return c
473 }
474
475 func (v *Value) Logf(msg string, args ...any) { v.Block.Logf(msg, args...) }
476 func (v *Value) Log() bool { return v.Block.Log() }
477 func (v *Value) Fatalf(msg string, args ...any) {
478 v.Block.Func.fe.Fatalf(v.Pos, msg, args...)
479 }
480
481
482 func (v *Value) isGenericIntConst() bool {
483 return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8)
484 }
485
486
487
488
489 func (v *Value) ResultReg() int16 {
490 reg := v.Block.Func.RegAlloc[v.ID]
491 if reg == nil {
492 v.Fatalf("nil reg for value: %s\n%s\n", v.LongString(), v.Block.Func)
493 }
494 if pair, ok := reg.(LocPair); ok {
495 reg = pair[0]
496 }
497 if reg == nil {
498 v.Fatalf("nil reg0 for value: %s\n%s\n", v.LongString(), v.Block.Func)
499 }
500 return reg.(*Register).objNum
501 }
502
503
504 func (v *Value) Reg() int16 {
505 reg := v.Block.Func.RegAlloc[v.ID]
506 if reg == nil {
507 v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
508 }
509 return reg.(*Register).objNum
510 }
511
512
513 func (v *Value) Reg0() int16 {
514 reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[0]
515 if reg == nil {
516 v.Fatalf("nil first register for value: %s\n%s\n", v.LongString(), v.Block.Func)
517 }
518 return reg.(*Register).objNum
519 }
520
521
522 func (v *Value) Reg1() int16 {
523 reg := v.Block.Func.RegAlloc[v.ID].(LocPair)[1]
524 if reg == nil {
525 v.Fatalf("nil second register for value: %s\n%s\n", v.LongString(), v.Block.Func)
526 }
527 return reg.(*Register).objNum
528 }
529
530
531 func (v *Value) RegTmp() int16 {
532 reg := v.Block.Func.tempRegs[v.ID]
533 if reg == nil {
534 v.Fatalf("nil tmp register for value: %s\n%s\n", v.LongString(), v.Block.Func)
535 }
536 return reg.objNum
537 }
538
539 func (v *Value) RegName() string {
540 reg := v.Block.Func.RegAlloc[v.ID]
541 if reg == nil {
542 v.Fatalf("nil register for value: %s\n%s\n", v.LongString(), v.Block.Func)
543 }
544 return reg.(*Register).name
545 }
546
547
548
549
550 func (v *Value) MemoryArg() *Value {
551 if v.Op == OpPhi {
552 v.Fatalf("MemoryArg on Phi")
553 }
554 na := len(v.Args)
555 if na == 0 {
556 return nil
557 }
558 if m := v.Args[na-1]; m.Type.IsMemory() {
559 return m
560 }
561 return nil
562 }
563
564
565
566
567 func (v *Value) LackingPos() bool {
568
569
570
571 return v.Op == OpVarDef || v.Op == OpVarLive || v.Op == OpPhi ||
572 (v.Op == OpFwdRef || v.Op == OpCopy) && v.Type == types.TypeMem
573 }
574
575
576
577 func (v *Value) removeable() bool {
578 if v.Type.IsVoid() {
579
580 return false
581 }
582 if opcodeTable[v.Op].nilCheck {
583
584 return false
585 }
586 if v.Type.IsMemory() {
587
588
589
590 return false
591 }
592 if v.Op.HasSideEffects() {
593
594 return false
595 }
596 return true
597 }
598
599
600
601 func AutoVar(v *Value) (*ir.Name, int64) {
602 if loc, ok := v.Block.Func.RegAlloc[v.ID].(LocalSlot); ok {
603 if v.Type.Size() > loc.Type.Size() {
604 v.Fatalf("v%d: spill/restore type %v doesn't fit in slot type %v", v.ID, v.Type, loc.Type)
605 }
606 return loc.N, loc.Off
607 }
608
609 nameOff := v.Aux.(*AuxNameOffset)
610 return nameOff.Name, nameOff.Offset
611 }
612
613
614 func CanSSA(t *types.Type) bool {
615 types.CalcSize(t)
616 if t.IsSIMD() {
617 return true
618 }
619 sizeLimit := int64(MaxStruct * types.PtrSize)
620 if t.Size() > sizeLimit {
621
622
623
624 if !buildcfg.Experiment.SIMD {
625 return false
626 }
627 }
628 switch t.Kind() {
629 case types.TARRAY:
630
631
632
633 if t.NumElem() <= 1 {
634 return CanSSA(t.Elem())
635 }
636 return false
637 case types.TSTRUCT:
638 if t.NumFields() > MaxStruct {
639 return false
640 }
641 for _, t1 := range t.Fields() {
642 if !CanSSA(t1.Type) {
643 return false
644 }
645 }
646
647
648
649 if !buildcfg.Experiment.SIMD {
650 return true
651 }
652 if t.Size() <= sizeLimit {
653 return true
654 }
655 i, f := t.Registers()
656 return i+f <= MaxStruct
657 default:
658 return true
659 }
660 }
661
View as plain text