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