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