1
2
3
4
5 package arm64
6
7 import (
8 "math"
9
10 "cmd/compile/internal/base"
11 "cmd/compile/internal/ir"
12 "cmd/compile/internal/logopt"
13 "cmd/compile/internal/ssa"
14 "cmd/compile/internal/ssagen"
15 "cmd/compile/internal/types"
16 "cmd/internal/obj"
17 "cmd/internal/obj/arm64"
18 )
19
20
21 func loadByType(t *types.Type) obj.As {
22 if t.IsFloat() {
23 switch t.Size() {
24 case 4:
25 return arm64.AFMOVS
26 case 8:
27 return arm64.AFMOVD
28 }
29 } else {
30 switch t.Size() {
31 case 1:
32 if t.IsSigned() {
33 return arm64.AMOVB
34 } else {
35 return arm64.AMOVBU
36 }
37 case 2:
38 if t.IsSigned() {
39 return arm64.AMOVH
40 } else {
41 return arm64.AMOVHU
42 }
43 case 4:
44 if t.IsSigned() {
45 return arm64.AMOVW
46 } else {
47 return arm64.AMOVWU
48 }
49 case 8:
50 return arm64.AMOVD
51 }
52 }
53 panic("bad load type")
54 }
55
56
57 func storeByType(t *types.Type) obj.As {
58 if t.IsFloat() {
59 switch t.Size() {
60 case 4:
61 return arm64.AFMOVS
62 case 8:
63 return arm64.AFMOVD
64 }
65 } else {
66 switch t.Size() {
67 case 1:
68 return arm64.AMOVB
69 case 2:
70 return arm64.AMOVH
71 case 4:
72 return arm64.AMOVW
73 case 8:
74 return arm64.AMOVD
75 }
76 }
77 panic("bad store type")
78 }
79
80
81 func makeshift(reg int16, typ int64, s int64) int64 {
82 return int64(reg&31)<<16 | typ | (s&63)<<10
83 }
84
85
86 func genshift(s *ssagen.State, as obj.As, r0, r1, r int16, typ int64, n int64) *obj.Prog {
87 p := s.Prog(as)
88 p.From.Type = obj.TYPE_SHIFT
89 p.From.Offset = makeshift(r1, typ, n)
90 p.Reg = r0
91 if r != 0 {
92 p.To.Type = obj.TYPE_REG
93 p.To.Reg = r
94 }
95 return p
96 }
97
98
99 func genIndexedOperand(v *ssa.Value) obj.Addr {
100
101 mop := obj.Addr{Type: obj.TYPE_MEM, Reg: v.Args[0].Reg()}
102 switch v.Op {
103 case ssa.OpARM64MOVDloadidx8, ssa.OpARM64MOVDstoreidx8, ssa.OpARM64MOVDstorezeroidx8,
104 ssa.OpARM64FMOVDloadidx8, ssa.OpARM64FMOVDstoreidx8:
105 mop.Index = arm64.REG_LSL | 3<<5 | v.Args[1].Reg()&31
106 case ssa.OpARM64MOVWloadidx4, ssa.OpARM64MOVWUloadidx4, ssa.OpARM64MOVWstoreidx4, ssa.OpARM64MOVWstorezeroidx4,
107 ssa.OpARM64FMOVSloadidx4, ssa.OpARM64FMOVSstoreidx4:
108 mop.Index = arm64.REG_LSL | 2<<5 | v.Args[1].Reg()&31
109 case ssa.OpARM64MOVHloadidx2, ssa.OpARM64MOVHUloadidx2, ssa.OpARM64MOVHstoreidx2, ssa.OpARM64MOVHstorezeroidx2:
110 mop.Index = arm64.REG_LSL | 1<<5 | v.Args[1].Reg()&31
111 default:
112 mop.Index = v.Args[1].Reg()
113 }
114 return mop
115 }
116
117 func ssaGenValue(s *ssagen.State, v *ssa.Value) {
118 switch v.Op {
119 case ssa.OpCopy, ssa.OpARM64MOVDreg:
120 if v.Type.IsMemory() {
121 return
122 }
123 x := v.Args[0].Reg()
124 y := v.Reg()
125 if x == y {
126 return
127 }
128 as := arm64.AMOVD
129 if v.Type.IsFloat() {
130 switch v.Type.Size() {
131 case 4:
132 as = arm64.AFMOVS
133 case 8:
134 as = arm64.AFMOVD
135 default:
136 panic("bad float size")
137 }
138 }
139 p := s.Prog(as)
140 p.From.Type = obj.TYPE_REG
141 p.From.Reg = x
142 p.To.Type = obj.TYPE_REG
143 p.To.Reg = y
144 case ssa.OpARM64MOVDnop:
145
146 case ssa.OpLoadReg:
147 if v.Type.IsFlags() {
148 v.Fatalf("load flags not implemented: %v", v.LongString())
149 return
150 }
151 p := s.Prog(loadByType(v.Type))
152 ssagen.AddrAuto(&p.From, v.Args[0])
153 p.To.Type = obj.TYPE_REG
154 p.To.Reg = v.Reg()
155 case ssa.OpStoreReg:
156 if v.Type.IsFlags() {
157 v.Fatalf("store flags not implemented: %v", v.LongString())
158 return
159 }
160 p := s.Prog(storeByType(v.Type))
161 p.From.Type = obj.TYPE_REG
162 p.From.Reg = v.Args[0].Reg()
163 ssagen.AddrAuto(&p.To, v)
164 case ssa.OpARM64ADD,
165 ssa.OpARM64SUB,
166 ssa.OpARM64AND,
167 ssa.OpARM64OR,
168 ssa.OpARM64XOR,
169 ssa.OpARM64BIC,
170 ssa.OpARM64EON,
171 ssa.OpARM64ORN,
172 ssa.OpARM64MUL,
173 ssa.OpARM64MULW,
174 ssa.OpARM64MNEG,
175 ssa.OpARM64MNEGW,
176 ssa.OpARM64MULH,
177 ssa.OpARM64UMULH,
178 ssa.OpARM64MULL,
179 ssa.OpARM64UMULL,
180 ssa.OpARM64DIV,
181 ssa.OpARM64UDIV,
182 ssa.OpARM64DIVW,
183 ssa.OpARM64UDIVW,
184 ssa.OpARM64MOD,
185 ssa.OpARM64UMOD,
186 ssa.OpARM64MODW,
187 ssa.OpARM64UMODW,
188 ssa.OpARM64SLL,
189 ssa.OpARM64SRL,
190 ssa.OpARM64SRA,
191 ssa.OpARM64FADDS,
192 ssa.OpARM64FADDD,
193 ssa.OpARM64FSUBS,
194 ssa.OpARM64FSUBD,
195 ssa.OpARM64FMULS,
196 ssa.OpARM64FMULD,
197 ssa.OpARM64FNMULS,
198 ssa.OpARM64FNMULD,
199 ssa.OpARM64FDIVS,
200 ssa.OpARM64FDIVD,
201 ssa.OpARM64ROR,
202 ssa.OpARM64RORW:
203 r := v.Reg()
204 r1 := v.Args[0].Reg()
205 r2 := v.Args[1].Reg()
206 p := s.Prog(v.Op.Asm())
207 p.From.Type = obj.TYPE_REG
208 p.From.Reg = r2
209 p.Reg = r1
210 p.To.Type = obj.TYPE_REG
211 p.To.Reg = r
212 case ssa.OpARM64FMADDS,
213 ssa.OpARM64FMADDD,
214 ssa.OpARM64FNMADDS,
215 ssa.OpARM64FNMADDD,
216 ssa.OpARM64FMSUBS,
217 ssa.OpARM64FMSUBD,
218 ssa.OpARM64FNMSUBS,
219 ssa.OpARM64FNMSUBD,
220 ssa.OpARM64MADD,
221 ssa.OpARM64MADDW,
222 ssa.OpARM64MSUB,
223 ssa.OpARM64MSUBW:
224 rt := v.Reg()
225 ra := v.Args[0].Reg()
226 rm := v.Args[1].Reg()
227 rn := v.Args[2].Reg()
228 p := s.Prog(v.Op.Asm())
229 p.Reg = ra
230 p.From.Type = obj.TYPE_REG
231 p.From.Reg = rm
232 p.SetFrom3Reg(rn)
233 p.To.Type = obj.TYPE_REG
234 p.To.Reg = rt
235 case ssa.OpARM64ADDconst,
236 ssa.OpARM64SUBconst,
237 ssa.OpARM64ANDconst,
238 ssa.OpARM64ORconst,
239 ssa.OpARM64XORconst,
240 ssa.OpARM64SLLconst,
241 ssa.OpARM64SRLconst,
242 ssa.OpARM64SRAconst,
243 ssa.OpARM64RORconst,
244 ssa.OpARM64RORWconst:
245 p := s.Prog(v.Op.Asm())
246 p.From.Type = obj.TYPE_CONST
247 p.From.Offset = v.AuxInt
248 p.Reg = v.Args[0].Reg()
249 p.To.Type = obj.TYPE_REG
250 p.To.Reg = v.Reg()
251 case ssa.OpARM64ADDSconstflags:
252 p := s.Prog(v.Op.Asm())
253 p.From.Type = obj.TYPE_CONST
254 p.From.Offset = v.AuxInt
255 p.Reg = v.Args[0].Reg()
256 p.To.Type = obj.TYPE_REG
257 p.To.Reg = v.Reg0()
258 case ssa.OpARM64ADCzerocarry:
259 p := s.Prog(v.Op.Asm())
260 p.From.Type = obj.TYPE_REG
261 p.From.Reg = arm64.REGZERO
262 p.Reg = arm64.REGZERO
263 p.To.Type = obj.TYPE_REG
264 p.To.Reg = v.Reg()
265 case ssa.OpARM64ADCSflags,
266 ssa.OpARM64ADDSflags,
267 ssa.OpARM64SBCSflags,
268 ssa.OpARM64SUBSflags:
269 r := v.Reg0()
270 r1 := v.Args[0].Reg()
271 r2 := v.Args[1].Reg()
272 p := s.Prog(v.Op.Asm())
273 p.From.Type = obj.TYPE_REG
274 p.From.Reg = r2
275 p.Reg = r1
276 p.To.Type = obj.TYPE_REG
277 p.To.Reg = r
278 case ssa.OpARM64NEGSflags:
279 p := s.Prog(v.Op.Asm())
280 p.From.Type = obj.TYPE_REG
281 p.From.Reg = v.Args[0].Reg()
282 p.To.Type = obj.TYPE_REG
283 p.To.Reg = v.Reg0()
284 case ssa.OpARM64NGCzerocarry:
285 p := s.Prog(v.Op.Asm())
286 p.From.Type = obj.TYPE_REG
287 p.From.Reg = arm64.REGZERO
288 p.To.Type = obj.TYPE_REG
289 p.To.Reg = v.Reg()
290 case ssa.OpARM64EXTRconst,
291 ssa.OpARM64EXTRWconst:
292 p := s.Prog(v.Op.Asm())
293 p.From.Type = obj.TYPE_CONST
294 p.From.Offset = v.AuxInt
295 p.SetFrom3Reg(v.Args[0].Reg())
296 p.Reg = v.Args[1].Reg()
297 p.To.Type = obj.TYPE_REG
298 p.To.Reg = v.Reg()
299 case ssa.OpARM64MVNshiftLL, ssa.OpARM64NEGshiftLL:
300 genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_LL, v.AuxInt)
301 case ssa.OpARM64MVNshiftRL, ssa.OpARM64NEGshiftRL:
302 genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_LR, v.AuxInt)
303 case ssa.OpARM64MVNshiftRA, ssa.OpARM64NEGshiftRA:
304 genshift(s, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm64.SHIFT_AR, v.AuxInt)
305 case ssa.OpARM64ADDshiftLL,
306 ssa.OpARM64SUBshiftLL,
307 ssa.OpARM64ANDshiftLL,
308 ssa.OpARM64ORshiftLL,
309 ssa.OpARM64XORshiftLL,
310 ssa.OpARM64EONshiftLL,
311 ssa.OpARM64ORNshiftLL,
312 ssa.OpARM64BICshiftLL:
313 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LL, v.AuxInt)
314 case ssa.OpARM64ADDshiftRL,
315 ssa.OpARM64SUBshiftRL,
316 ssa.OpARM64ANDshiftRL,
317 ssa.OpARM64ORshiftRL,
318 ssa.OpARM64XORshiftRL,
319 ssa.OpARM64EONshiftRL,
320 ssa.OpARM64ORNshiftRL,
321 ssa.OpARM64BICshiftRL:
322 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_LR, v.AuxInt)
323 case ssa.OpARM64ADDshiftRA,
324 ssa.OpARM64SUBshiftRA,
325 ssa.OpARM64ANDshiftRA,
326 ssa.OpARM64ORshiftRA,
327 ssa.OpARM64XORshiftRA,
328 ssa.OpARM64EONshiftRA,
329 ssa.OpARM64ORNshiftRA,
330 ssa.OpARM64BICshiftRA:
331 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), v.Reg(), arm64.SHIFT_AR, v.AuxInt)
332 case ssa.OpARM64MOVDconst:
333 p := s.Prog(v.Op.Asm())
334 p.From.Type = obj.TYPE_CONST
335 p.From.Offset = v.AuxInt
336 p.To.Type = obj.TYPE_REG
337 p.To.Reg = v.Reg()
338 case ssa.OpARM64FMOVSconst,
339 ssa.OpARM64FMOVDconst:
340 p := s.Prog(v.Op.Asm())
341 p.From.Type = obj.TYPE_FCONST
342 p.From.Val = math.Float64frombits(uint64(v.AuxInt))
343 p.To.Type = obj.TYPE_REG
344 p.To.Reg = v.Reg()
345 case ssa.OpARM64FCMPS0,
346 ssa.OpARM64FCMPD0:
347 p := s.Prog(v.Op.Asm())
348 p.From.Type = obj.TYPE_FCONST
349 p.From.Val = math.Float64frombits(0)
350 p.Reg = v.Args[0].Reg()
351 case ssa.OpARM64CMP,
352 ssa.OpARM64CMPW,
353 ssa.OpARM64CMN,
354 ssa.OpARM64CMNW,
355 ssa.OpARM64TST,
356 ssa.OpARM64TSTW,
357 ssa.OpARM64FCMPS,
358 ssa.OpARM64FCMPD:
359 p := s.Prog(v.Op.Asm())
360 p.From.Type = obj.TYPE_REG
361 p.From.Reg = v.Args[1].Reg()
362 p.Reg = v.Args[0].Reg()
363 case ssa.OpARM64CMPconst,
364 ssa.OpARM64CMPWconst,
365 ssa.OpARM64CMNconst,
366 ssa.OpARM64CMNWconst,
367 ssa.OpARM64TSTconst,
368 ssa.OpARM64TSTWconst:
369 p := s.Prog(v.Op.Asm())
370 p.From.Type = obj.TYPE_CONST
371 p.From.Offset = v.AuxInt
372 p.Reg = v.Args[0].Reg()
373 case ssa.OpARM64CMPshiftLL, ssa.OpARM64CMNshiftLL, ssa.OpARM64TSTshiftLL:
374 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LL, v.AuxInt)
375 case ssa.OpARM64CMPshiftRL, ssa.OpARM64CMNshiftRL, ssa.OpARM64TSTshiftRL:
376 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_LR, v.AuxInt)
377 case ssa.OpARM64CMPshiftRA, ssa.OpARM64CMNshiftRA, ssa.OpARM64TSTshiftRA:
378 genshift(s, v.Op.Asm(), v.Args[0].Reg(), v.Args[1].Reg(), 0, arm64.SHIFT_AR, v.AuxInt)
379 case ssa.OpARM64MOVDaddr:
380 p := s.Prog(arm64.AMOVD)
381 p.From.Type = obj.TYPE_ADDR
382 p.From.Reg = v.Args[0].Reg()
383 p.To.Type = obj.TYPE_REG
384 p.To.Reg = v.Reg()
385
386 var wantreg string
387
388
389
390
391
392 switch v.Aux.(type) {
393 default:
394 v.Fatalf("aux is of unknown type %T", v.Aux)
395 case *obj.LSym:
396 wantreg = "SB"
397 ssagen.AddAux(&p.From, v)
398 case *ir.Name:
399 wantreg = "SP"
400 ssagen.AddAux(&p.From, v)
401 case nil:
402
403 wantreg = "SP"
404 p.From.Offset = v.AuxInt
405 }
406 if reg := v.Args[0].RegName(); reg != wantreg {
407 v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
408 }
409 case ssa.OpARM64MOVBload,
410 ssa.OpARM64MOVBUload,
411 ssa.OpARM64MOVHload,
412 ssa.OpARM64MOVHUload,
413 ssa.OpARM64MOVWload,
414 ssa.OpARM64MOVWUload,
415 ssa.OpARM64MOVDload,
416 ssa.OpARM64FMOVSload,
417 ssa.OpARM64FMOVDload:
418 p := s.Prog(v.Op.Asm())
419 p.From.Type = obj.TYPE_MEM
420 p.From.Reg = v.Args[0].Reg()
421 ssagen.AddAux(&p.From, v)
422 p.To.Type = obj.TYPE_REG
423 p.To.Reg = v.Reg()
424 case ssa.OpARM64MOVBloadidx,
425 ssa.OpARM64MOVBUloadidx,
426 ssa.OpARM64MOVHloadidx,
427 ssa.OpARM64MOVHUloadidx,
428 ssa.OpARM64MOVWloadidx,
429 ssa.OpARM64MOVWUloadidx,
430 ssa.OpARM64MOVDloadidx,
431 ssa.OpARM64FMOVSloadidx,
432 ssa.OpARM64FMOVDloadidx,
433 ssa.OpARM64MOVHloadidx2,
434 ssa.OpARM64MOVHUloadidx2,
435 ssa.OpARM64MOVWloadidx4,
436 ssa.OpARM64MOVWUloadidx4,
437 ssa.OpARM64MOVDloadidx8,
438 ssa.OpARM64FMOVDloadidx8,
439 ssa.OpARM64FMOVSloadidx4:
440 p := s.Prog(v.Op.Asm())
441 p.From = genIndexedOperand(v)
442 p.To.Type = obj.TYPE_REG
443 p.To.Reg = v.Reg()
444 case ssa.OpARM64LDAR,
445 ssa.OpARM64LDARB,
446 ssa.OpARM64LDARW:
447 p := s.Prog(v.Op.Asm())
448 p.From.Type = obj.TYPE_MEM
449 p.From.Reg = v.Args[0].Reg()
450 ssagen.AddAux(&p.From, v)
451 p.To.Type = obj.TYPE_REG
452 p.To.Reg = v.Reg0()
453 case ssa.OpARM64MOVBstore,
454 ssa.OpARM64MOVHstore,
455 ssa.OpARM64MOVWstore,
456 ssa.OpARM64MOVDstore,
457 ssa.OpARM64FMOVSstore,
458 ssa.OpARM64FMOVDstore,
459 ssa.OpARM64STLRB,
460 ssa.OpARM64STLR,
461 ssa.OpARM64STLRW:
462 p := s.Prog(v.Op.Asm())
463 p.From.Type = obj.TYPE_REG
464 p.From.Reg = v.Args[1].Reg()
465 p.To.Type = obj.TYPE_MEM
466 p.To.Reg = v.Args[0].Reg()
467 ssagen.AddAux(&p.To, v)
468 case ssa.OpARM64MOVBstoreidx,
469 ssa.OpARM64MOVHstoreidx,
470 ssa.OpARM64MOVWstoreidx,
471 ssa.OpARM64MOVDstoreidx,
472 ssa.OpARM64FMOVSstoreidx,
473 ssa.OpARM64FMOVDstoreidx,
474 ssa.OpARM64MOVHstoreidx2,
475 ssa.OpARM64MOVWstoreidx4,
476 ssa.OpARM64FMOVSstoreidx4,
477 ssa.OpARM64MOVDstoreidx8,
478 ssa.OpARM64FMOVDstoreidx8:
479 p := s.Prog(v.Op.Asm())
480 p.To = genIndexedOperand(v)
481 p.From.Type = obj.TYPE_REG
482 p.From.Reg = v.Args[2].Reg()
483 case ssa.OpARM64STP:
484 p := s.Prog(v.Op.Asm())
485 p.From.Type = obj.TYPE_REGREG
486 p.From.Reg = v.Args[1].Reg()
487 p.From.Offset = int64(v.Args[2].Reg())
488 p.To.Type = obj.TYPE_MEM
489 p.To.Reg = v.Args[0].Reg()
490 ssagen.AddAux(&p.To, v)
491 case ssa.OpARM64MOVBstorezero,
492 ssa.OpARM64MOVHstorezero,
493 ssa.OpARM64MOVWstorezero,
494 ssa.OpARM64MOVDstorezero:
495 p := s.Prog(v.Op.Asm())
496 p.From.Type = obj.TYPE_REG
497 p.From.Reg = arm64.REGZERO
498 p.To.Type = obj.TYPE_MEM
499 p.To.Reg = v.Args[0].Reg()
500 ssagen.AddAux(&p.To, v)
501 case ssa.OpARM64MOVBstorezeroidx,
502 ssa.OpARM64MOVHstorezeroidx,
503 ssa.OpARM64MOVWstorezeroidx,
504 ssa.OpARM64MOVDstorezeroidx,
505 ssa.OpARM64MOVHstorezeroidx2,
506 ssa.OpARM64MOVWstorezeroidx4,
507 ssa.OpARM64MOVDstorezeroidx8:
508 p := s.Prog(v.Op.Asm())
509 p.To = genIndexedOperand(v)
510 p.From.Type = obj.TYPE_REG
511 p.From.Reg = arm64.REGZERO
512 case ssa.OpARM64MOVQstorezero:
513 p := s.Prog(v.Op.Asm())
514 p.From.Type = obj.TYPE_REGREG
515 p.From.Reg = arm64.REGZERO
516 p.From.Offset = int64(arm64.REGZERO)
517 p.To.Type = obj.TYPE_MEM
518 p.To.Reg = v.Args[0].Reg()
519 ssagen.AddAux(&p.To, v)
520 case ssa.OpARM64BFI,
521 ssa.OpARM64BFXIL:
522 p := s.Prog(v.Op.Asm())
523 p.From.Type = obj.TYPE_CONST
524 p.From.Offset = v.AuxInt >> 8
525 p.SetFrom3Const(v.AuxInt & 0xff)
526 p.Reg = v.Args[1].Reg()
527 p.To.Type = obj.TYPE_REG
528 p.To.Reg = v.Reg()
529 case ssa.OpARM64SBFIZ,
530 ssa.OpARM64SBFX,
531 ssa.OpARM64UBFIZ,
532 ssa.OpARM64UBFX:
533 p := s.Prog(v.Op.Asm())
534 p.From.Type = obj.TYPE_CONST
535 p.From.Offset = v.AuxInt >> 8
536 p.SetFrom3Const(v.AuxInt & 0xff)
537 p.Reg = v.Args[0].Reg()
538 p.To.Type = obj.TYPE_REG
539 p.To.Reg = v.Reg()
540 case ssa.OpARM64LoweredMuluhilo:
541 r0 := v.Args[0].Reg()
542 r1 := v.Args[1].Reg()
543 p := s.Prog(arm64.AUMULH)
544 p.From.Type = obj.TYPE_REG
545 p.From.Reg = r1
546 p.Reg = r0
547 p.To.Type = obj.TYPE_REG
548 p.To.Reg = v.Reg0()
549 p1 := s.Prog(arm64.AMUL)
550 p1.From.Type = obj.TYPE_REG
551 p1.From.Reg = r1
552 p1.Reg = r0
553 p1.To.Type = obj.TYPE_REG
554 p1.To.Reg = v.Reg1()
555 case ssa.OpARM64LoweredAtomicExchange64,
556 ssa.OpARM64LoweredAtomicExchange32:
557
558
559
560 ld := arm64.ALDAXR
561 st := arm64.ASTLXR
562 if v.Op == ssa.OpARM64LoweredAtomicExchange32 {
563 ld = arm64.ALDAXRW
564 st = arm64.ASTLXRW
565 }
566 r0 := v.Args[0].Reg()
567 r1 := v.Args[1].Reg()
568 out := v.Reg0()
569 p := s.Prog(ld)
570 p.From.Type = obj.TYPE_MEM
571 p.From.Reg = r0
572 p.To.Type = obj.TYPE_REG
573 p.To.Reg = out
574 p1 := s.Prog(st)
575 p1.From.Type = obj.TYPE_REG
576 p1.From.Reg = r1
577 p1.To.Type = obj.TYPE_MEM
578 p1.To.Reg = r0
579 p1.RegTo2 = arm64.REGTMP
580 p2 := s.Prog(arm64.ACBNZ)
581 p2.From.Type = obj.TYPE_REG
582 p2.From.Reg = arm64.REGTMP
583 p2.To.Type = obj.TYPE_BRANCH
584 p2.To.SetTarget(p)
585 case ssa.OpARM64LoweredAtomicExchange64Variant,
586 ssa.OpARM64LoweredAtomicExchange32Variant:
587 swap := arm64.ASWPALD
588 if v.Op == ssa.OpARM64LoweredAtomicExchange32Variant {
589 swap = arm64.ASWPALW
590 }
591 r0 := v.Args[0].Reg()
592 r1 := v.Args[1].Reg()
593 out := v.Reg0()
594
595
596 p := s.Prog(swap)
597 p.From.Type = obj.TYPE_REG
598 p.From.Reg = r1
599 p.To.Type = obj.TYPE_MEM
600 p.To.Reg = r0
601 p.RegTo2 = out
602
603 case ssa.OpARM64LoweredAtomicAdd64,
604 ssa.OpARM64LoweredAtomicAdd32:
605
606
607
608
609 ld := arm64.ALDAXR
610 st := arm64.ASTLXR
611 if v.Op == ssa.OpARM64LoweredAtomicAdd32 {
612 ld = arm64.ALDAXRW
613 st = arm64.ASTLXRW
614 }
615 r0 := v.Args[0].Reg()
616 r1 := v.Args[1].Reg()
617 out := v.Reg0()
618 p := s.Prog(ld)
619 p.From.Type = obj.TYPE_MEM
620 p.From.Reg = r0
621 p.To.Type = obj.TYPE_REG
622 p.To.Reg = out
623 p1 := s.Prog(arm64.AADD)
624 p1.From.Type = obj.TYPE_REG
625 p1.From.Reg = r1
626 p1.To.Type = obj.TYPE_REG
627 p1.To.Reg = out
628 p2 := s.Prog(st)
629 p2.From.Type = obj.TYPE_REG
630 p2.From.Reg = out
631 p2.To.Type = obj.TYPE_MEM
632 p2.To.Reg = r0
633 p2.RegTo2 = arm64.REGTMP
634 p3 := s.Prog(arm64.ACBNZ)
635 p3.From.Type = obj.TYPE_REG
636 p3.From.Reg = arm64.REGTMP
637 p3.To.Type = obj.TYPE_BRANCH
638 p3.To.SetTarget(p)
639 case ssa.OpARM64LoweredAtomicAdd64Variant,
640 ssa.OpARM64LoweredAtomicAdd32Variant:
641
642
643 op := arm64.ALDADDALD
644 if v.Op == ssa.OpARM64LoweredAtomicAdd32Variant {
645 op = arm64.ALDADDALW
646 }
647 r0 := v.Args[0].Reg()
648 r1 := v.Args[1].Reg()
649 out := v.Reg0()
650 p := s.Prog(op)
651 p.From.Type = obj.TYPE_REG
652 p.From.Reg = r1
653 p.To.Type = obj.TYPE_MEM
654 p.To.Reg = r0
655 p.RegTo2 = out
656 p1 := s.Prog(arm64.AADD)
657 p1.From.Type = obj.TYPE_REG
658 p1.From.Reg = r1
659 p1.To.Type = obj.TYPE_REG
660 p1.To.Reg = out
661 case ssa.OpARM64LoweredAtomicCas64,
662 ssa.OpARM64LoweredAtomicCas32:
663
664
665
666
667
668
669 ld := arm64.ALDAXR
670 st := arm64.ASTLXR
671 cmp := arm64.ACMP
672 if v.Op == ssa.OpARM64LoweredAtomicCas32 {
673 ld = arm64.ALDAXRW
674 st = arm64.ASTLXRW
675 cmp = arm64.ACMPW
676 }
677 r0 := v.Args[0].Reg()
678 r1 := v.Args[1].Reg()
679 r2 := v.Args[2].Reg()
680 out := v.Reg0()
681 p := s.Prog(ld)
682 p.From.Type = obj.TYPE_MEM
683 p.From.Reg = r0
684 p.To.Type = obj.TYPE_REG
685 p.To.Reg = arm64.REGTMP
686 p1 := s.Prog(cmp)
687 p1.From.Type = obj.TYPE_REG
688 p1.From.Reg = r1
689 p1.Reg = arm64.REGTMP
690 p2 := s.Prog(arm64.ABNE)
691 p2.To.Type = obj.TYPE_BRANCH
692 p3 := s.Prog(st)
693 p3.From.Type = obj.TYPE_REG
694 p3.From.Reg = r2
695 p3.To.Type = obj.TYPE_MEM
696 p3.To.Reg = r0
697 p3.RegTo2 = arm64.REGTMP
698 p4 := s.Prog(arm64.ACBNZ)
699 p4.From.Type = obj.TYPE_REG
700 p4.From.Reg = arm64.REGTMP
701 p4.To.Type = obj.TYPE_BRANCH
702 p4.To.SetTarget(p)
703 p5 := s.Prog(arm64.ACSET)
704 p5.From.Type = obj.TYPE_REG
705 p5.From.Reg = arm64.COND_EQ
706 p5.To.Type = obj.TYPE_REG
707 p5.To.Reg = out
708 p2.To.SetTarget(p5)
709 case ssa.OpARM64LoweredAtomicCas64Variant,
710 ssa.OpARM64LoweredAtomicCas32Variant:
711
712
713
714
715
716
717
718 cas := arm64.ACASALD
719 cmp := arm64.ACMP
720 mov := arm64.AMOVD
721 if v.Op == ssa.OpARM64LoweredAtomicCas32Variant {
722 cas = arm64.ACASALW
723 cmp = arm64.ACMPW
724 mov = arm64.AMOVW
725 }
726 r0 := v.Args[0].Reg()
727 r1 := v.Args[1].Reg()
728 r2 := v.Args[2].Reg()
729 out := v.Reg0()
730
731
732 p := s.Prog(mov)
733 p.From.Type = obj.TYPE_REG
734 p.From.Reg = r1
735 p.To.Type = obj.TYPE_REG
736 p.To.Reg = arm64.REGTMP
737
738
739 p1 := s.Prog(cas)
740 p1.From.Type = obj.TYPE_REG
741 p1.From.Reg = arm64.REGTMP
742 p1.To.Type = obj.TYPE_MEM
743 p1.To.Reg = r0
744 p1.RegTo2 = r2
745
746
747 p2 := s.Prog(cmp)
748 p2.From.Type = obj.TYPE_REG
749 p2.From.Reg = r1
750 p2.Reg = arm64.REGTMP
751
752
753 p3 := s.Prog(arm64.ACSET)
754 p3.From.Type = obj.TYPE_REG
755 p3.From.Reg = arm64.COND_EQ
756 p3.To.Type = obj.TYPE_REG
757 p3.To.Reg = out
758
759 case ssa.OpARM64LoweredAtomicAnd8,
760 ssa.OpARM64LoweredAtomicAnd32,
761 ssa.OpARM64LoweredAtomicOr8,
762 ssa.OpARM64LoweredAtomicOr32:
763
764
765
766
767 ld := arm64.ALDAXRB
768 st := arm64.ASTLXRB
769 if v.Op == ssa.OpARM64LoweredAtomicAnd32 || v.Op == ssa.OpARM64LoweredAtomicOr32 {
770 ld = arm64.ALDAXRW
771 st = arm64.ASTLXRW
772 }
773 r0 := v.Args[0].Reg()
774 r1 := v.Args[1].Reg()
775 out := v.Reg0()
776 p := s.Prog(ld)
777 p.From.Type = obj.TYPE_MEM
778 p.From.Reg = r0
779 p.To.Type = obj.TYPE_REG
780 p.To.Reg = out
781 p1 := s.Prog(v.Op.Asm())
782 p1.From.Type = obj.TYPE_REG
783 p1.From.Reg = r1
784 p1.To.Type = obj.TYPE_REG
785 p1.To.Reg = out
786 p2 := s.Prog(st)
787 p2.From.Type = obj.TYPE_REG
788 p2.From.Reg = out
789 p2.To.Type = obj.TYPE_MEM
790 p2.To.Reg = r0
791 p2.RegTo2 = arm64.REGTMP
792 p3 := s.Prog(arm64.ACBNZ)
793 p3.From.Type = obj.TYPE_REG
794 p3.From.Reg = arm64.REGTMP
795 p3.To.Type = obj.TYPE_BRANCH
796 p3.To.SetTarget(p)
797 case ssa.OpARM64LoweredAtomicAnd8Variant,
798 ssa.OpARM64LoweredAtomicAnd32Variant:
799 atomic_clear := arm64.ALDCLRALW
800 if v.Op == ssa.OpARM64LoweredAtomicAnd8Variant {
801 atomic_clear = arm64.ALDCLRALB
802 }
803 r0 := v.Args[0].Reg()
804 r1 := v.Args[1].Reg()
805 out := v.Reg0()
806
807
808 p := s.Prog(arm64.AMVN)
809 p.From.Type = obj.TYPE_REG
810 p.From.Reg = r1
811 p.To.Type = obj.TYPE_REG
812 p.To.Reg = arm64.REGTMP
813
814
815 p1 := s.Prog(atomic_clear)
816 p1.From.Type = obj.TYPE_REG
817 p1.From.Reg = arm64.REGTMP
818 p1.To.Type = obj.TYPE_MEM
819 p1.To.Reg = r0
820 p1.RegTo2 = out
821
822
823 p2 := s.Prog(arm64.AAND)
824 p2.From.Type = obj.TYPE_REG
825 p2.From.Reg = r1
826 p2.To.Type = obj.TYPE_REG
827 p2.To.Reg = out
828
829 case ssa.OpARM64LoweredAtomicOr8Variant,
830 ssa.OpARM64LoweredAtomicOr32Variant:
831 atomic_or := arm64.ALDORALW
832 if v.Op == ssa.OpARM64LoweredAtomicOr8Variant {
833 atomic_or = arm64.ALDORALB
834 }
835 r0 := v.Args[0].Reg()
836 r1 := v.Args[1].Reg()
837 out := v.Reg0()
838
839
840 p := s.Prog(atomic_or)
841 p.From.Type = obj.TYPE_REG
842 p.From.Reg = r1
843 p.To.Type = obj.TYPE_MEM
844 p.To.Reg = r0
845 p.RegTo2 = out
846
847
848 p2 := s.Prog(arm64.AORR)
849 p2.From.Type = obj.TYPE_REG
850 p2.From.Reg = r1
851 p2.To.Type = obj.TYPE_REG
852 p2.To.Reg = out
853
854 case ssa.OpARM64MOVBreg,
855 ssa.OpARM64MOVBUreg,
856 ssa.OpARM64MOVHreg,
857 ssa.OpARM64MOVHUreg,
858 ssa.OpARM64MOVWreg,
859 ssa.OpARM64MOVWUreg:
860 a := v.Args[0]
861 for a.Op == ssa.OpCopy || a.Op == ssa.OpARM64MOVDreg {
862 a = a.Args[0]
863 }
864 if a.Op == ssa.OpLoadReg {
865 t := a.Type
866 switch {
867 case v.Op == ssa.OpARM64MOVBreg && t.Size() == 1 && t.IsSigned(),
868 v.Op == ssa.OpARM64MOVBUreg && t.Size() == 1 && !t.IsSigned(),
869 v.Op == ssa.OpARM64MOVHreg && t.Size() == 2 && t.IsSigned(),
870 v.Op == ssa.OpARM64MOVHUreg && t.Size() == 2 && !t.IsSigned(),
871 v.Op == ssa.OpARM64MOVWreg && t.Size() == 4 && t.IsSigned(),
872 v.Op == ssa.OpARM64MOVWUreg && t.Size() == 4 && !t.IsSigned():
873
874 if v.Reg() == v.Args[0].Reg() {
875 return
876 }
877 p := s.Prog(arm64.AMOVD)
878 p.From.Type = obj.TYPE_REG
879 p.From.Reg = v.Args[0].Reg()
880 p.To.Type = obj.TYPE_REG
881 p.To.Reg = v.Reg()
882 return
883 default:
884 }
885 }
886 fallthrough
887 case ssa.OpARM64MVN,
888 ssa.OpARM64NEG,
889 ssa.OpARM64FABSD,
890 ssa.OpARM64FMOVDfpgp,
891 ssa.OpARM64FMOVDgpfp,
892 ssa.OpARM64FMOVSfpgp,
893 ssa.OpARM64FMOVSgpfp,
894 ssa.OpARM64FNEGS,
895 ssa.OpARM64FNEGD,
896 ssa.OpARM64FSQRTS,
897 ssa.OpARM64FSQRTD,
898 ssa.OpARM64FCVTZSSW,
899 ssa.OpARM64FCVTZSDW,
900 ssa.OpARM64FCVTZUSW,
901 ssa.OpARM64FCVTZUDW,
902 ssa.OpARM64FCVTZSS,
903 ssa.OpARM64FCVTZSD,
904 ssa.OpARM64FCVTZUS,
905 ssa.OpARM64FCVTZUD,
906 ssa.OpARM64SCVTFWS,
907 ssa.OpARM64SCVTFWD,
908 ssa.OpARM64SCVTFS,
909 ssa.OpARM64SCVTFD,
910 ssa.OpARM64UCVTFWS,
911 ssa.OpARM64UCVTFWD,
912 ssa.OpARM64UCVTFS,
913 ssa.OpARM64UCVTFD,
914 ssa.OpARM64FCVTSD,
915 ssa.OpARM64FCVTDS,
916 ssa.OpARM64REV,
917 ssa.OpARM64REVW,
918 ssa.OpARM64REV16,
919 ssa.OpARM64REV16W,
920 ssa.OpARM64RBIT,
921 ssa.OpARM64RBITW,
922 ssa.OpARM64CLZ,
923 ssa.OpARM64CLZW,
924 ssa.OpARM64FRINTAD,
925 ssa.OpARM64FRINTMD,
926 ssa.OpARM64FRINTND,
927 ssa.OpARM64FRINTPD,
928 ssa.OpARM64FRINTZD:
929 p := s.Prog(v.Op.Asm())
930 p.From.Type = obj.TYPE_REG
931 p.From.Reg = v.Args[0].Reg()
932 p.To.Type = obj.TYPE_REG
933 p.To.Reg = v.Reg()
934 case ssa.OpARM64LoweredRound32F, ssa.OpARM64LoweredRound64F:
935
936 case ssa.OpARM64VCNT:
937 p := s.Prog(v.Op.Asm())
938 p.From.Type = obj.TYPE_REG
939 p.From.Reg = (v.Args[0].Reg()-arm64.REG_F0)&31 + arm64.REG_ARNG + ((arm64.ARNG_8B & 15) << 5)
940 p.To.Type = obj.TYPE_REG
941 p.To.Reg = (v.Reg()-arm64.REG_F0)&31 + arm64.REG_ARNG + ((arm64.ARNG_8B & 15) << 5)
942 case ssa.OpARM64VUADDLV:
943 p := s.Prog(v.Op.Asm())
944 p.From.Type = obj.TYPE_REG
945 p.From.Reg = (v.Args[0].Reg()-arm64.REG_F0)&31 + arm64.REG_ARNG + ((arm64.ARNG_8B & 15) << 5)
946 p.To.Type = obj.TYPE_REG
947 p.To.Reg = v.Reg() - arm64.REG_F0 + arm64.REG_V0
948 case ssa.OpARM64CSEL, ssa.OpARM64CSEL0:
949 r1 := int16(arm64.REGZERO)
950 if v.Op != ssa.OpARM64CSEL0 {
951 r1 = v.Args[1].Reg()
952 }
953 p := s.Prog(v.Op.Asm())
954 p.From.Type = obj.TYPE_REG
955 p.From.Reg = condBits[ssa.Op(v.AuxInt)]
956 p.Reg = v.Args[0].Reg()
957 p.SetFrom3Reg(r1)
958 p.To.Type = obj.TYPE_REG
959 p.To.Reg = v.Reg()
960 case ssa.OpARM64CSINC, ssa.OpARM64CSINV, ssa.OpARM64CSNEG:
961 p := s.Prog(v.Op.Asm())
962 p.From.Type = obj.TYPE_REG
963 p.From.Reg = condBits[ssa.Op(v.AuxInt)]
964 p.Reg = v.Args[0].Reg()
965 p.SetFrom3Reg(v.Args[1].Reg())
966 p.To.Type = obj.TYPE_REG
967 p.To.Reg = v.Reg()
968 case ssa.OpARM64CSETM:
969 p := s.Prog(arm64.ACSETM)
970 p.From.Type = obj.TYPE_REG
971 p.From.Reg = condBits[ssa.Op(v.AuxInt)]
972 p.To.Type = obj.TYPE_REG
973 p.To.Reg = v.Reg()
974 case ssa.OpARM64DUFFZERO:
975
976 p := s.Prog(obj.ADUFFZERO)
977 p.To.Type = obj.TYPE_MEM
978 p.To.Name = obj.NAME_EXTERN
979 p.To.Sym = ir.Syms.Duffzero
980 p.To.Offset = v.AuxInt
981 case ssa.OpARM64LoweredZero:
982
983
984
985
986 p := s.Prog(arm64.ASTP)
987 p.Scond = arm64.C_XPOST
988 p.From.Type = obj.TYPE_REGREG
989 p.From.Reg = arm64.REGZERO
990 p.From.Offset = int64(arm64.REGZERO)
991 p.To.Type = obj.TYPE_MEM
992 p.To.Reg = arm64.REG_R16
993 p.To.Offset = 16
994 p2 := s.Prog(arm64.ACMP)
995 p2.From.Type = obj.TYPE_REG
996 p2.From.Reg = v.Args[1].Reg()
997 p2.Reg = arm64.REG_R16
998 p3 := s.Prog(arm64.ABLE)
999 p3.To.Type = obj.TYPE_BRANCH
1000 p3.To.SetTarget(p)
1001 case ssa.OpARM64DUFFCOPY:
1002 p := s.Prog(obj.ADUFFCOPY)
1003 p.To.Type = obj.TYPE_MEM
1004 p.To.Name = obj.NAME_EXTERN
1005 p.To.Sym = ir.Syms.Duffcopy
1006 p.To.Offset = v.AuxInt
1007 case ssa.OpARM64LoweredMove:
1008
1009
1010
1011
1012
1013 p := s.Prog(arm64.AMOVD)
1014 p.Scond = arm64.C_XPOST
1015 p.From.Type = obj.TYPE_MEM
1016 p.From.Reg = arm64.REG_R16
1017 p.From.Offset = 8
1018 p.To.Type = obj.TYPE_REG
1019 p.To.Reg = arm64.REGTMP
1020 p2 := s.Prog(arm64.AMOVD)
1021 p2.Scond = arm64.C_XPOST
1022 p2.From.Type = obj.TYPE_REG
1023 p2.From.Reg = arm64.REGTMP
1024 p2.To.Type = obj.TYPE_MEM
1025 p2.To.Reg = arm64.REG_R17
1026 p2.To.Offset = 8
1027 p3 := s.Prog(arm64.ACMP)
1028 p3.From.Type = obj.TYPE_REG
1029 p3.From.Reg = v.Args[2].Reg()
1030 p3.Reg = arm64.REG_R16
1031 p4 := s.Prog(arm64.ABLE)
1032 p4.To.Type = obj.TYPE_BRANCH
1033 p4.To.SetTarget(p)
1034 case ssa.OpARM64CALLstatic, ssa.OpARM64CALLclosure, ssa.OpARM64CALLinter:
1035 s.Call(v)
1036 case ssa.OpARM64LoweredWB:
1037 p := s.Prog(obj.ACALL)
1038 p.To.Type = obj.TYPE_MEM
1039 p.To.Name = obj.NAME_EXTERN
1040 p.To.Sym = v.Aux.(*obj.LSym)
1041 case ssa.OpARM64LoweredPanicBoundsA, ssa.OpARM64LoweredPanicBoundsB, ssa.OpARM64LoweredPanicBoundsC:
1042 p := s.Prog(obj.ACALL)
1043 p.To.Type = obj.TYPE_MEM
1044 p.To.Name = obj.NAME_EXTERN
1045 p.To.Sym = ssagen.BoundsCheckFunc[v.AuxInt]
1046 s.UseArgs(16)
1047 case ssa.OpARM64LoweredNilCheck:
1048
1049 p := s.Prog(arm64.AMOVB)
1050 p.From.Type = obj.TYPE_MEM
1051 p.From.Reg = v.Args[0].Reg()
1052 ssagen.AddAux(&p.From, v)
1053 p.To.Type = obj.TYPE_REG
1054 p.To.Reg = arm64.REGTMP
1055 if logopt.Enabled() {
1056 logopt.LogOpt(v.Pos, "nilcheck", "genssa", v.Block.Func.Name)
1057 }
1058 if base.Debug.Nil != 0 && v.Pos.Line() > 1 {
1059 base.WarnfAt(v.Pos, "generated nil check")
1060 }
1061 case ssa.OpARM64Equal,
1062 ssa.OpARM64NotEqual,
1063 ssa.OpARM64LessThan,
1064 ssa.OpARM64LessEqual,
1065 ssa.OpARM64GreaterThan,
1066 ssa.OpARM64GreaterEqual,
1067 ssa.OpARM64LessThanU,
1068 ssa.OpARM64LessEqualU,
1069 ssa.OpARM64GreaterThanU,
1070 ssa.OpARM64GreaterEqualU,
1071 ssa.OpARM64LessThanF,
1072 ssa.OpARM64LessEqualF,
1073 ssa.OpARM64GreaterThanF,
1074 ssa.OpARM64GreaterEqualF,
1075 ssa.OpARM64NotLessThanF,
1076 ssa.OpARM64NotLessEqualF,
1077 ssa.OpARM64NotGreaterThanF,
1078 ssa.OpARM64NotGreaterEqualF:
1079
1080 p := s.Prog(arm64.ACSET)
1081 p.From.Type = obj.TYPE_REG
1082 p.From.Reg = condBits[v.Op]
1083 p.To.Type = obj.TYPE_REG
1084 p.To.Reg = v.Reg()
1085 case ssa.OpARM64LoweredGetClosurePtr:
1086
1087 ssagen.CheckLoweredGetClosurePtr(v)
1088 case ssa.OpARM64LoweredGetCallerSP:
1089
1090 p := s.Prog(arm64.AMOVD)
1091 p.From.Type = obj.TYPE_ADDR
1092 p.From.Offset = -base.Ctxt.FixedFrameSize()
1093 p.From.Name = obj.NAME_PARAM
1094 p.To.Type = obj.TYPE_REG
1095 p.To.Reg = v.Reg()
1096 case ssa.OpARM64LoweredGetCallerPC:
1097 p := s.Prog(obj.AGETCALLERPC)
1098 p.To.Type = obj.TYPE_REG
1099 p.To.Reg = v.Reg()
1100 case ssa.OpARM64FlagConstant:
1101 v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString())
1102 case ssa.OpARM64InvertFlags:
1103 v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
1104 case ssa.OpClobber, ssa.OpClobberReg:
1105
1106 default:
1107 v.Fatalf("genValue not implemented: %s", v.LongString())
1108 }
1109 }
1110
1111 var condBits = map[ssa.Op]int16{
1112 ssa.OpARM64Equal: arm64.COND_EQ,
1113 ssa.OpARM64NotEqual: arm64.COND_NE,
1114 ssa.OpARM64LessThan: arm64.COND_LT,
1115 ssa.OpARM64LessThanU: arm64.COND_LO,
1116 ssa.OpARM64LessEqual: arm64.COND_LE,
1117 ssa.OpARM64LessEqualU: arm64.COND_LS,
1118 ssa.OpARM64GreaterThan: arm64.COND_GT,
1119 ssa.OpARM64GreaterThanU: arm64.COND_HI,
1120 ssa.OpARM64GreaterEqual: arm64.COND_GE,
1121 ssa.OpARM64GreaterEqualU: arm64.COND_HS,
1122 ssa.OpARM64LessThanF: arm64.COND_MI,
1123 ssa.OpARM64LessEqualF: arm64.COND_LS,
1124 ssa.OpARM64GreaterThanF: arm64.COND_GT,
1125 ssa.OpARM64GreaterEqualF: arm64.COND_GE,
1126
1127
1128 ssa.OpARM64NotLessThanF: arm64.COND_PL,
1129 ssa.OpARM64NotLessEqualF: arm64.COND_HI,
1130 ssa.OpARM64NotGreaterThanF: arm64.COND_LE,
1131 ssa.OpARM64NotGreaterEqualF: arm64.COND_LT,
1132 }
1133
1134 var blockJump = map[ssa.BlockKind]struct {
1135 asm, invasm obj.As
1136 }{
1137 ssa.BlockARM64EQ: {arm64.ABEQ, arm64.ABNE},
1138 ssa.BlockARM64NE: {arm64.ABNE, arm64.ABEQ},
1139 ssa.BlockARM64LT: {arm64.ABLT, arm64.ABGE},
1140 ssa.BlockARM64GE: {arm64.ABGE, arm64.ABLT},
1141 ssa.BlockARM64LE: {arm64.ABLE, arm64.ABGT},
1142 ssa.BlockARM64GT: {arm64.ABGT, arm64.ABLE},
1143 ssa.BlockARM64ULT: {arm64.ABLO, arm64.ABHS},
1144 ssa.BlockARM64UGE: {arm64.ABHS, arm64.ABLO},
1145 ssa.BlockARM64UGT: {arm64.ABHI, arm64.ABLS},
1146 ssa.BlockARM64ULE: {arm64.ABLS, arm64.ABHI},
1147 ssa.BlockARM64Z: {arm64.ACBZ, arm64.ACBNZ},
1148 ssa.BlockARM64NZ: {arm64.ACBNZ, arm64.ACBZ},
1149 ssa.BlockARM64ZW: {arm64.ACBZW, arm64.ACBNZW},
1150 ssa.BlockARM64NZW: {arm64.ACBNZW, arm64.ACBZW},
1151 ssa.BlockARM64TBZ: {arm64.ATBZ, arm64.ATBNZ},
1152 ssa.BlockARM64TBNZ: {arm64.ATBNZ, arm64.ATBZ},
1153 ssa.BlockARM64FLT: {arm64.ABMI, arm64.ABPL},
1154 ssa.BlockARM64FGE: {arm64.ABGE, arm64.ABLT},
1155 ssa.BlockARM64FLE: {arm64.ABLS, arm64.ABHI},
1156 ssa.BlockARM64FGT: {arm64.ABGT, arm64.ABLE},
1157 ssa.BlockARM64LTnoov: {arm64.ABMI, arm64.ABPL},
1158 ssa.BlockARM64GEnoov: {arm64.ABPL, arm64.ABMI},
1159 }
1160
1161
1162 var leJumps = [2][2]ssagen.IndexJump{
1163 {{Jump: arm64.ABEQ, Index: 0}, {Jump: arm64.ABPL, Index: 1}},
1164 {{Jump: arm64.ABMI, Index: 0}, {Jump: arm64.ABEQ, Index: 0}},
1165 }
1166
1167
1168 var gtJumps = [2][2]ssagen.IndexJump{
1169 {{Jump: arm64.ABMI, Index: 1}, {Jump: arm64.ABEQ, Index: 1}},
1170 {{Jump: arm64.ABEQ, Index: 1}, {Jump: arm64.ABPL, Index: 0}},
1171 }
1172
1173 func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
1174 switch b.Kind {
1175 case ssa.BlockPlain:
1176 if b.Succs[0].Block() != next {
1177 p := s.Prog(obj.AJMP)
1178 p.To.Type = obj.TYPE_BRANCH
1179 s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
1180 }
1181
1182 case ssa.BlockDefer:
1183
1184
1185
1186 p := s.Prog(arm64.ACMP)
1187 p.From.Type = obj.TYPE_CONST
1188 p.From.Offset = 0
1189 p.Reg = arm64.REG_R0
1190 p = s.Prog(arm64.ABNE)
1191 p.To.Type = obj.TYPE_BRANCH
1192 s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[1].Block()})
1193 if b.Succs[0].Block() != next {
1194 p := s.Prog(obj.AJMP)
1195 p.To.Type = obj.TYPE_BRANCH
1196 s.Branches = append(s.Branches, ssagen.Branch{P: p, B: b.Succs[0].Block()})
1197 }
1198
1199 case ssa.BlockExit:
1200
1201 case ssa.BlockRet:
1202 s.Prog(obj.ARET)
1203
1204 case ssa.BlockRetJmp:
1205 p := s.Prog(obj.ARET)
1206 p.To.Type = obj.TYPE_MEM
1207 p.To.Name = obj.NAME_EXTERN
1208 p.To.Sym = b.Aux.(*obj.LSym)
1209
1210 case ssa.BlockARM64EQ, ssa.BlockARM64NE,
1211 ssa.BlockARM64LT, ssa.BlockARM64GE,
1212 ssa.BlockARM64LE, ssa.BlockARM64GT,
1213 ssa.BlockARM64ULT, ssa.BlockARM64UGT,
1214 ssa.BlockARM64ULE, ssa.BlockARM64UGE,
1215 ssa.BlockARM64Z, ssa.BlockARM64NZ,
1216 ssa.BlockARM64ZW, ssa.BlockARM64NZW,
1217 ssa.BlockARM64FLT, ssa.BlockARM64FGE,
1218 ssa.BlockARM64FLE, ssa.BlockARM64FGT,
1219 ssa.BlockARM64LTnoov, ssa.BlockARM64GEnoov:
1220 jmp := blockJump[b.Kind]
1221 var p *obj.Prog
1222 switch next {
1223 case b.Succs[0].Block():
1224 p = s.Br(jmp.invasm, b.Succs[1].Block())
1225 case b.Succs[1].Block():
1226 p = s.Br(jmp.asm, b.Succs[0].Block())
1227 default:
1228 if b.Likely != ssa.BranchUnlikely {
1229 p = s.Br(jmp.asm, b.Succs[0].Block())
1230 s.Br(obj.AJMP, b.Succs[1].Block())
1231 } else {
1232 p = s.Br(jmp.invasm, b.Succs[1].Block())
1233 s.Br(obj.AJMP, b.Succs[0].Block())
1234 }
1235 }
1236 if !b.Controls[0].Type.IsFlags() {
1237 p.From.Type = obj.TYPE_REG
1238 p.From.Reg = b.Controls[0].Reg()
1239 }
1240 case ssa.BlockARM64TBZ, ssa.BlockARM64TBNZ:
1241 jmp := blockJump[b.Kind]
1242 var p *obj.Prog
1243 switch next {
1244 case b.Succs[0].Block():
1245 p = s.Br(jmp.invasm, b.Succs[1].Block())
1246 case b.Succs[1].Block():
1247 p = s.Br(jmp.asm, b.Succs[0].Block())
1248 default:
1249 if b.Likely != ssa.BranchUnlikely {
1250 p = s.Br(jmp.asm, b.Succs[0].Block())
1251 s.Br(obj.AJMP, b.Succs[1].Block())
1252 } else {
1253 p = s.Br(jmp.invasm, b.Succs[1].Block())
1254 s.Br(obj.AJMP, b.Succs[0].Block())
1255 }
1256 }
1257 p.From.Offset = b.AuxInt
1258 p.From.Type = obj.TYPE_CONST
1259 p.Reg = b.Controls[0].Reg()
1260
1261 case ssa.BlockARM64LEnoov:
1262 s.CombJump(b, next, &leJumps)
1263 case ssa.BlockARM64GTnoov:
1264 s.CombJump(b, next, >Jumps)
1265 default:
1266 b.Fatalf("branch not implemented: %s", b.LongString())
1267 }
1268 }
1269
View as plain text