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