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 )
388
389
390
391 type SymEffect int8
392
393 const (
394 SymRead SymEffect = 1 << iota
395 SymWrite
396 SymAddr
397
398 SymRdWr = SymRead | SymWrite
399
400 SymNone SymEffect = 0
401 )
402
403
404
405
406
407
408 type Sym interface {
409 Aux
410 CanBeAnSSASym()
411 }
412
413
414
415
416
417
418
419 type ValAndOff int64
420
421 func (x ValAndOff) Val() int32 { return int32(int64(x) >> 32) }
422 func (x ValAndOff) Val64() int64 { return int64(x) >> 32 }
423 func (x ValAndOff) Val16() int16 { return int16(int64(x) >> 32) }
424 func (x ValAndOff) Val8() int8 { return int8(int64(x) >> 32) }
425
426 func (x ValAndOff) Off64() int64 { return int64(int32(x)) }
427 func (x ValAndOff) Off() int32 { return int32(x) }
428
429 func (x ValAndOff) String() string {
430 return fmt.Sprintf("val=%d,off=%d", x.Val(), x.Off())
431 }
432
433
434
435 func validVal(val int64) bool {
436 return val == int64(int32(val))
437 }
438
439 func makeValAndOff(val, off int32) ValAndOff {
440 return ValAndOff(int64(val)<<32 + int64(uint32(off)))
441 }
442
443 func (x ValAndOff) canAdd32(off int32) bool {
444 newoff := x.Off64() + int64(off)
445 return newoff == int64(int32(newoff))
446 }
447 func (x ValAndOff) canAdd64(off int64) bool {
448 newoff := x.Off64() + off
449 return newoff == int64(int32(newoff))
450 }
451
452 func (x ValAndOff) addOffset32(off int32) ValAndOff {
453 if !x.canAdd32(off) {
454 panic("invalid ValAndOff.addOffset32")
455 }
456 return makeValAndOff(x.Val(), x.Off()+off)
457 }
458 func (x ValAndOff) addOffset64(off int64) ValAndOff {
459 if !x.canAdd64(off) {
460 panic("invalid ValAndOff.addOffset64")
461 }
462 return makeValAndOff(x.Val(), x.Off()+int32(off))
463 }
464
465
466
467 type int128 int64
468
469 type BoundsKind uint8
470
471 const (
472 BoundsIndex BoundsKind = iota
473 BoundsIndexU
474 BoundsSliceAlen
475 BoundsSliceAlenU
476 BoundsSliceAcap
477 BoundsSliceAcapU
478 BoundsSliceB
479 BoundsSliceBU
480 BoundsSlice3Alen
481 BoundsSlice3AlenU
482 BoundsSlice3Acap
483 BoundsSlice3AcapU
484 BoundsSlice3B
485 BoundsSlice3BU
486 BoundsSlice3C
487 BoundsSlice3CU
488 BoundsConvert
489 BoundsKindCount
490 )
491
492
493
494 func (b BoundsKind) Code() (rtabi.BoundsErrorCode, bool) {
495 switch b {
496 case BoundsIndex:
497 return rtabi.BoundsIndex, true
498 case BoundsIndexU:
499 return rtabi.BoundsIndex, false
500 case BoundsSliceAlen:
501 return rtabi.BoundsSliceAlen, true
502 case BoundsSliceAlenU:
503 return rtabi.BoundsSliceAlen, false
504 case BoundsSliceAcap:
505 return rtabi.BoundsSliceAcap, true
506 case BoundsSliceAcapU:
507 return rtabi.BoundsSliceAcap, false
508 case BoundsSliceB:
509 return rtabi.BoundsSliceB, true
510 case BoundsSliceBU:
511 return rtabi.BoundsSliceB, false
512 case BoundsSlice3Alen:
513 return rtabi.BoundsSlice3Alen, true
514 case BoundsSlice3AlenU:
515 return rtabi.BoundsSlice3Alen, false
516 case BoundsSlice3Acap:
517 return rtabi.BoundsSlice3Acap, true
518 case BoundsSlice3AcapU:
519 return rtabi.BoundsSlice3Acap, false
520 case BoundsSlice3B:
521 return rtabi.BoundsSlice3B, true
522 case BoundsSlice3BU:
523 return rtabi.BoundsSlice3B, false
524 case BoundsSlice3C:
525 return rtabi.BoundsSlice3C, true
526 case BoundsSlice3CU:
527 return rtabi.BoundsSlice3C, false
528 case BoundsConvert:
529 return rtabi.BoundsConvert, false
530 default:
531 base.Fatalf("bad bounds kind %d", b)
532 return 0, false
533 }
534 }
535
536
537
538
539
540 type arm64BitField int16
541
542
543 type arm64ConditionalParams struct {
544 cond Op
545 nzcv uint8
546 constValue uint8
547 ind bool
548 }
549
View as plain text