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/types"
12 "cmd/internal/obj"
13 "fmt"
14 rtabi "internal/abi"
15 "strings"
16 )
17
18
19
20
21
22
23
24 type Op int32
25
26 type opInfo struct {
27 name string
28 reg regInfo
29 auxType auxType
30 argLen int32
31 asm obj.As
32 generic bool
33 rematerializeable bool
34 commutative bool
35 resultInArg0 bool
36 resultNotInArgs bool
37 clobberFlags bool
38 needIntTemp bool
39 call bool
40 tailCall bool
41 nilCheck bool
42 faultOnNilArg0 bool
43 faultOnNilArg1 bool
44 usesScratch bool
45 hasSideEffects bool
46 zeroWidth bool
47 unsafePoint bool
48 fixedReg bool
49 addrSinkArg0 bool
50 addrSinkArg1 bool
51 symEffect SymEffect
52 scale uint8
53 }
54
55 type inputInfo struct {
56 idx int
57 regs regMask
58 }
59
60 type outputInfo struct {
61 idx int
62 regs regMask
63 }
64
65 type regInfo struct {
66
67
68
69
70
71 inputs []inputInfo
72
73
74 clobbers regMask
75
76 clobbersArg0 bool
77
78 clobbersArg1 bool
79
80 outputs []outputInfo
81 }
82
83 func (r *regInfo) String() string {
84 s := ""
85 s += "INS:\n"
86 for _, i := range r.inputs {
87 mask := fmt.Sprintf("%64b", i.regs)
88 mask = strings.ReplaceAll(mask, "0", ".")
89 s += fmt.Sprintf("%2d |%s|\n", i.idx, mask)
90 }
91 s += "OUTS:\n"
92 for _, i := range r.outputs {
93 mask := fmt.Sprintf("%64b", i.regs)
94 mask = strings.ReplaceAll(mask, "0", ".")
95 s += fmt.Sprintf("%2d |%s|\n", i.idx, mask)
96 }
97 s += "CLOBBERS:\n"
98 mask := fmt.Sprintf("%64b", r.clobbers)
99 mask = strings.ReplaceAll(mask, "0", ".")
100 s += fmt.Sprintf(" |%s|\n", mask)
101 return s
102 }
103
104 type auxType int8
105
106 type AuxNameOffset struct {
107 Name *ir.Name
108 Offset int64
109 }
110
111 func (a *AuxNameOffset) CanBeAnSSAAux() {}
112 func (a *AuxNameOffset) String() string {
113 return fmt.Sprintf("%s+%d", a.Name.Sym().Name, a.Offset)
114 }
115
116 func (a *AuxNameOffset) FrameOffset() int64 {
117 return a.Name.FrameOffset() + a.Offset
118 }
119
120 type AuxCall struct {
121 Fn *obj.LSym
122 reg *regInfo
123 abiInfo *abi.ABIParamResultInfo
124 }
125
126
127
128
129
130
131
132
133
134
135
136 func (a *AuxCall) Reg(i *regInfo, c *Config) *regInfo {
137 if a.reg.clobbers != 0 {
138
139 return a.reg
140 }
141 if a.abiInfo.InRegistersUsed()+a.abiInfo.OutRegistersUsed() == 0 {
142
143 a.reg = i
144 return a.reg
145 }
146
147 k := len(i.inputs)
148 for _, p := range a.abiInfo.InParams() {
149 for _, r := range p.Registers {
150 m := archRegForAbiReg(r, c)
151 a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)})
152 k++
153 }
154 }
155 a.reg.inputs = append(a.reg.inputs, i.inputs...)
156 k = len(i.outputs)
157 for _, p := range a.abiInfo.OutParams() {
158 for _, r := range p.Registers {
159 m := archRegForAbiReg(r, c)
160 a.reg.outputs = append(a.reg.outputs, outputInfo{idx: k, regs: (1 << m)})
161 k++
162 }
163 }
164 a.reg.outputs = append(a.reg.outputs, i.outputs...)
165 a.reg.clobbers = i.clobbers
166 return a.reg
167 }
168 func (a *AuxCall) ABI() *abi.ABIConfig {
169 return a.abiInfo.Config()
170 }
171 func (a *AuxCall) ABIInfo() *abi.ABIParamResultInfo {
172 return a.abiInfo
173 }
174 func (a *AuxCall) ResultReg(c *Config) *regInfo {
175 if a.abiInfo.OutRegistersUsed() == 0 {
176 return a.reg
177 }
178 if len(a.reg.inputs) > 0 {
179 return a.reg
180 }
181 k := 0
182 for _, p := range a.abiInfo.OutParams() {
183 for _, r := range p.Registers {
184 m := archRegForAbiReg(r, c)
185 a.reg.inputs = append(a.reg.inputs, inputInfo{idx: k, regs: (1 << m)})
186 k++
187 }
188 }
189 return a.reg
190 }
191
192
193
194 func archRegForAbiReg(r abi.RegIndex, c *Config) uint8 {
195 var m int8
196 if int(r) < len(c.intParamRegs) {
197 m = c.intParamRegs[r]
198 } else {
199 m = c.floatParamRegs[int(r)-len(c.intParamRegs)]
200 }
201 return uint8(m)
202 }
203
204
205
206 func ObjRegForAbiReg(r abi.RegIndex, c *Config) int16 {
207 m := archRegForAbiReg(r, c)
208 return c.registers[m].objNum
209 }
210
211
212
213
214
215
216
217 func (a *AuxCall) ArgWidth() int64 {
218 return a.abiInfo.ArgWidth()
219 }
220
221
222 func (a *AuxCall) ParamAssignmentForResult(which int64) *abi.ABIParamAssignment {
223 return a.abiInfo.OutParam(int(which))
224 }
225
226
227 func (a *AuxCall) OffsetOfResult(which int64) int64 {
228 n := int64(a.abiInfo.OutParam(int(which)).Offset())
229 return n
230 }
231
232
233
234 func (a *AuxCall) OffsetOfArg(which int64) int64 {
235 n := int64(a.abiInfo.InParam(int(which)).Offset())
236 return n
237 }
238
239
240 func (a *AuxCall) RegsOfResult(which int64) []abi.RegIndex {
241 return a.abiInfo.OutParam(int(which)).Registers
242 }
243
244
245
246 func (a *AuxCall) RegsOfArg(which int64) []abi.RegIndex {
247 return a.abiInfo.InParam(int(which)).Registers
248 }
249
250
251 func (a *AuxCall) NameOfResult(which int64) *ir.Name {
252 return a.abiInfo.OutParam(int(which)).Name
253 }
254
255
256 func (a *AuxCall) TypeOfResult(which int64) *types.Type {
257 return a.abiInfo.OutParam(int(which)).Type
258 }
259
260
261
262 func (a *AuxCall) TypeOfArg(which int64) *types.Type {
263 return a.abiInfo.InParam(int(which)).Type
264 }
265
266
267 func (a *AuxCall) SizeOfResult(which int64) int64 {
268 return a.TypeOfResult(which).Size()
269 }
270
271
272
273 func (a *AuxCall) SizeOfArg(which int64) int64 {
274 return a.TypeOfArg(which).Size()
275 }
276
277
278 func (a *AuxCall) NResults() int64 {
279 return int64(len(a.abiInfo.OutParams()))
280 }
281
282
283
284 func (a *AuxCall) LateExpansionResultType() *types.Type {
285 var tys []*types.Type
286 for i := int64(0); i < a.NResults(); i++ {
287 tys = append(tys, a.TypeOfResult(i))
288 }
289 tys = append(tys, types.TypeMem)
290 return types.NewResults(tys)
291 }
292
293
294 func (a *AuxCall) NArgs() int64 {
295 return int64(len(a.abiInfo.InParams()))
296 }
297
298
299 func (a *AuxCall) String() string {
300 var fn string
301 if a.Fn == nil {
302 fn = "AuxCall{nil"
303 } else {
304 fn = fmt.Sprintf("AuxCall{%v", a.Fn)
305 }
306
307
308 return fn + "}"
309 }
310
311
312 func StaticAuxCall(sym *obj.LSym, paramResultInfo *abi.ABIParamResultInfo) *AuxCall {
313 if paramResultInfo == nil {
314 panic(fmt.Errorf("Nil paramResultInfo, sym=%v", sym))
315 }
316 var reg *regInfo
317 if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
318 reg = ®Info{}
319 }
320 return &AuxCall{Fn: sym, abiInfo: paramResultInfo, reg: reg}
321 }
322
323
324 func InterfaceAuxCall(paramResultInfo *abi.ABIParamResultInfo) *AuxCall {
325 var reg *regInfo
326 if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
327 reg = ®Info{}
328 }
329 return &AuxCall{Fn: nil, abiInfo: paramResultInfo, reg: reg}
330 }
331
332
333 func ClosureAuxCall(paramResultInfo *abi.ABIParamResultInfo) *AuxCall {
334 var reg *regInfo
335 if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
336 reg = ®Info{}
337 }
338 return &AuxCall{Fn: nil, abiInfo: paramResultInfo, reg: reg}
339 }
340
341 func (*AuxCall) CanBeAnSSAAux() {}
342
343
344 func OwnAuxCall(fn *obj.LSym, paramResultInfo *abi.ABIParamResultInfo) *AuxCall {
345
346 var reg *regInfo
347 if paramResultInfo.InRegistersUsed()+paramResultInfo.OutRegistersUsed() > 0 {
348 reg = ®Info{}
349 }
350 return &AuxCall{Fn: fn, abiInfo: paramResultInfo, reg: reg}
351 }
352
353 const (
354 auxNone auxType = iota
355 auxBool
356 auxInt8
357 auxInt16
358 auxInt32
359 auxInt64
360 auxInt128
361 auxUInt8
362 auxFloat32
363 auxFloat64
364 auxFlagConstant
365 auxCCop
366 auxNameOffsetInt8
367 auxString
368 auxSym
369 auxSymOff
370 auxSymValAndOff
371 auxTyp
372 auxTypSize
373 auxCall
374 auxCallOff
375
376 auxPanicBoundsC
377 auxPanicBoundsCC
378
379
380 auxARM64BitField
381 auxARM64ConditionalParams
382 auxS390XRotateParams
383 auxS390XCCMask
384 auxS390XCCMaskInt8
385 auxS390XCCMaskUint8
386 )
387
388
389
390 type SymEffect int8
391
392 const (
393 SymRead SymEffect = 1 << iota
394 SymWrite
395 SymAddr
396
397 SymRdWr = SymRead | SymWrite
398
399 SymNone SymEffect = 0
400 )
401
402
403
404
405
406
407 type Sym interface {
408 Aux
409 CanBeAnSSASym()
410 }
411
412
413
414
415
416
417
418 type ValAndOff int64
419
420 func (x ValAndOff) Val() int32 { return int32(int64(x) >> 32) }
421 func (x ValAndOff) Val64() int64 { return int64(x) >> 32 }
422 func (x ValAndOff) Val16() int16 { return int16(int64(x) >> 32) }
423 func (x ValAndOff) Val8() int8 { return int8(int64(x) >> 32) }
424
425 func (x ValAndOff) Off64() int64 { return int64(int32(x)) }
426 func (x ValAndOff) Off() int32 { return int32(x) }
427
428 func (x ValAndOff) String() string {
429 return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off())
430 }
431
432
433
434 func validVal(val int64) bool {
435 return val == int64(int32(val))
436 }
437
438 func makeValAndOff(val, off int32) ValAndOff {
439 return ValAndOff(int64(val)<<32 + int64(uint32(off)))
440 }
441
442 func (x ValAndOff) canAdd32(off int32) bool {
443 newoff := x.Off64() + int64(off)
444 return newoff == int64(int32(newoff))
445 }
446 func (x ValAndOff) canAdd64(off int64) bool {
447 newoff := x.Off64() + off
448 return newoff == int64(int32(newoff))
449 }
450
451 func (x ValAndOff) addOffset32(off int32) ValAndOff {
452 if !x.canAdd32(off) {
453 panic("invalid ValAndOff.addOffset32")
454 }
455 return makeValAndOff(x.Val(), x.Off()+off)
456 }
457 func (x ValAndOff) addOffset64(off int64) ValAndOff {
458 if !x.canAdd64(off) {
459 panic("invalid ValAndOff.addOffset64")
460 }
461 return makeValAndOff(x.Val(), x.Off()+int32(off))
462 }
463
464
465
466 type int128 int64
467
468 type BoundsKind uint8
469
470 const (
471 BoundsIndex BoundsKind = iota
472 BoundsIndexU
473 BoundsSliceAlen
474 BoundsSliceAlenU
475 BoundsSliceAcap
476 BoundsSliceAcapU
477 BoundsSliceB
478 BoundsSliceBU
479 BoundsSlice3Alen
480 BoundsSlice3AlenU
481 BoundsSlice3Acap
482 BoundsSlice3AcapU
483 BoundsSlice3B
484 BoundsSlice3BU
485 BoundsSlice3C
486 BoundsSlice3CU
487 BoundsConvert
488 BoundsKindCount
489 )
490
491
492
493 func (b BoundsKind) Code() (rtabi.BoundsErrorCode, bool) {
494 switch b {
495 case BoundsIndex:
496 return rtabi.BoundsIndex, true
497 case BoundsIndexU:
498 return rtabi.BoundsIndex, false
499 case BoundsSliceAlen:
500 return rtabi.BoundsSliceAlen, true
501 case BoundsSliceAlenU:
502 return rtabi.BoundsSliceAlen, false
503 case BoundsSliceAcap:
504 return rtabi.BoundsSliceAcap, true
505 case BoundsSliceAcapU:
506 return rtabi.BoundsSliceAcap, false
507 case BoundsSliceB:
508 return rtabi.BoundsSliceB, true
509 case BoundsSliceBU:
510 return rtabi.BoundsSliceB, false
511 case BoundsSlice3Alen:
512 return rtabi.BoundsSlice3Alen, true
513 case BoundsSlice3AlenU:
514 return rtabi.BoundsSlice3Alen, false
515 case BoundsSlice3Acap:
516 return rtabi.BoundsSlice3Acap, true
517 case BoundsSlice3AcapU:
518 return rtabi.BoundsSlice3Acap, false
519 case BoundsSlice3B:
520 return rtabi.BoundsSlice3B, true
521 case BoundsSlice3BU:
522 return rtabi.BoundsSlice3B, false
523 case BoundsSlice3C:
524 return rtabi.BoundsSlice3C, true
525 case BoundsSlice3CU:
526 return rtabi.BoundsSlice3C, false
527 case BoundsConvert:
528 return rtabi.BoundsConvert, false
529 default:
530 base.Fatalf("bad bounds kind %d", b)
531 return 0, false
532 }
533 }
534
535
536
537
538
539 type arm64BitField int16
540
541
542 type arm64ConditionalParams struct {
543 cond Op
544 nzcv uint8
545 constValue uint8
546 ind bool
547 }
548
View as plain text