1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package arm64
32
33 import (
34 "cmd/internal/obj"
35 "cmd/internal/objabi"
36 "cmd/internal/src"
37 "cmd/internal/sys"
38 "internal/buildcfg"
39 "log"
40 "math"
41 )
42
43 var complements = []obj.As{
44 AADD: ASUB,
45 AADDW: ASUBW,
46 ASUB: AADD,
47 ASUBW: AADDW,
48 ACMP: ACMN,
49 ACMPW: ACMNW,
50 ACMN: ACMP,
51 ACMNW: ACMPW,
52 }
53
54 func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
55
56 p = obj.Appendp(p, c.newprog)
57
58 p.As = AMOVD
59 p.From.Type = obj.TYPE_MEM
60 p.From.Reg = REGG
61 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
62 if c.cursym.CFunc() {
63 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
64 }
65 p.To.Type = obj.TYPE_REG
66 p.To.Reg = REG_R1
67
68
69
70
71
72 p = c.ctxt.StartUnsafePoint(p, c.newprog)
73
74 q := (*obj.Prog)(nil)
75 if framesize <= objabi.StackSmall {
76
77
78
79 p = obj.Appendp(p, c.newprog)
80
81 p.As = AMOVD
82 p.From.Type = obj.TYPE_REG
83 p.From.Reg = REGSP
84 p.To.Type = obj.TYPE_REG
85 p.To.Reg = REG_R2
86
87 p = obj.Appendp(p, c.newprog)
88 p.As = ACMP
89 p.From.Type = obj.TYPE_REG
90 p.From.Reg = REG_R1
91 p.Reg = REG_R2
92 } else if framesize <= objabi.StackBig {
93
94
95
96 p = obj.Appendp(p, c.newprog)
97
98 p.As = ASUB
99 p.From.Type = obj.TYPE_CONST
100 p.From.Offset = int64(framesize) - objabi.StackSmall
101 p.Reg = REGSP
102 p.To.Type = obj.TYPE_REG
103 p.To.Reg = REG_R2
104
105 p = obj.Appendp(p, c.newprog)
106 p.As = ACMP
107 p.From.Type = obj.TYPE_REG
108 p.From.Reg = REG_R1
109 p.Reg = REG_R2
110 } else {
111
112
113
114
115
116
117
118
119
120
121
122
123 p = obj.Appendp(p, c.newprog)
124 p.As = ASUBS
125 p.From.Type = obj.TYPE_CONST
126 p.From.Offset = int64(framesize) - objabi.StackSmall
127 p.Reg = REGSP
128 p.To.Type = obj.TYPE_REG
129 p.To.Reg = REG_R2
130
131 p = obj.Appendp(p, c.newprog)
132 q = p
133 p.As = ABLO
134 p.To.Type = obj.TYPE_BRANCH
135
136 p = obj.Appendp(p, c.newprog)
137 p.As = ACMP
138 p.From.Type = obj.TYPE_REG
139 p.From.Reg = REG_R1
140 p.Reg = REG_R2
141 }
142
143
144 bls := obj.Appendp(p, c.newprog)
145 bls.As = ABLS
146 bls.To.Type = obj.TYPE_BRANCH
147
148 end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
149
150 var last *obj.Prog
151 for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
152 }
153
154
155
156
157 spfix := obj.Appendp(last, c.newprog)
158 spfix.As = obj.ANOP
159 spfix.Spadj = -framesize
160
161 pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
162 pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
163
164
165 movlr := obj.Appendp(pcdata, c.newprog)
166 movlr.As = AMOVD
167 movlr.From.Type = obj.TYPE_REG
168 movlr.From.Reg = REGLINK
169 movlr.To.Type = obj.TYPE_REG
170 movlr.To.Reg = REG_R3
171 if q != nil {
172 q.To.SetTarget(movlr)
173 }
174 bls.To.SetTarget(movlr)
175
176 debug := movlr
177 if false {
178 debug = obj.Appendp(debug, c.newprog)
179 debug.As = AMOVD
180 debug.From.Type = obj.TYPE_CONST
181 debug.From.Offset = int64(framesize)
182 debug.To.Type = obj.TYPE_REG
183 debug.To.Reg = REGTMP
184 }
185
186
187 call := obj.Appendp(debug, c.newprog)
188 call.As = ABL
189 call.To.Type = obj.TYPE_BRANCH
190 morestack := "runtime.morestack"
191 switch {
192 case c.cursym.CFunc():
193 morestack = "runtime.morestackc"
194 case !c.cursym.Func().Text.From.Sym.NeedCtxt():
195 morestack = "runtime.morestack_noctxt"
196 }
197 call.To.Sym = c.ctxt.Lookup(morestack)
198
199 pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
200
201
202 jmp := obj.Appendp(pcdata, c.newprog)
203 jmp.As = AB
204 jmp.To.Type = obj.TYPE_BRANCH
205 jmp.To.SetTarget(c.cursym.Func().Text.Link)
206 jmp.Spadj = +framesize
207
208 return end
209 }
210
211 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
212 c := ctxt7{ctxt: ctxt, newprog: newprog}
213
214 p.From.Class = 0
215 p.To.Class = 0
216
217
218
219
220
221 if p.From.Type == obj.TYPE_CONST && p.From.Offset == 0 {
222 p.From.Type = obj.TYPE_REG
223 p.From.Reg = REGZERO
224 }
225 if p.To.Type == obj.TYPE_CONST && p.To.Offset == 0 {
226 p.To.Type = obj.TYPE_REG
227 p.To.Reg = REGZERO
228 }
229
230
231 switch p.As {
232 case AB,
233 ABL,
234 obj.ARET,
235 obj.ADUFFZERO,
236 obj.ADUFFCOPY:
237 if p.To.Sym != nil {
238 p.To.Type = obj.TYPE_BRANCH
239 }
240 break
241 }
242
243
244 switch p.As {
245 case AFMOVS:
246 if p.From.Type == obj.TYPE_FCONST {
247 f64 := p.From.Val.(float64)
248 f32 := float32(f64)
249 if c.chipfloat7(f64) > 0 {
250 break
251 }
252 if math.Float32bits(f32) == 0 {
253 p.From.Type = obj.TYPE_REG
254 p.From.Reg = REGZERO
255 break
256 }
257 p.From.Type = obj.TYPE_MEM
258 p.From.Sym = c.ctxt.Float32Sym(f32)
259 p.From.Name = obj.NAME_EXTERN
260 p.From.Offset = 0
261 }
262
263 case AFMOVD:
264 if p.From.Type == obj.TYPE_FCONST {
265 f64 := p.From.Val.(float64)
266 if c.chipfloat7(f64) > 0 {
267 break
268 }
269 if math.Float64bits(f64) == 0 {
270 p.From.Type = obj.TYPE_REG
271 p.From.Reg = REGZERO
272 break
273 }
274 p.From.Type = obj.TYPE_MEM
275 p.From.Sym = c.ctxt.Float64Sym(f64)
276 p.From.Name = obj.NAME_EXTERN
277 p.From.Offset = 0
278 }
279
280 break
281 }
282
283
284
285 switch p.As {
286 case AADD, ASUB, ACMP, ACMN:
287 if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && p.From.Offset != -1<<63 {
288 p.From.Offset = -p.From.Offset
289 p.As = complements[p.As]
290 }
291 case AADDW, ASUBW, ACMPW, ACMNW:
292 if p.From.Type == obj.TYPE_CONST && p.From.Offset < 0 && int32(p.From.Offset) != -1<<31 {
293 p.From.Offset = -p.From.Offset
294 p.As = complements[p.As]
295 }
296 }
297
298
299
300
301
302
303
304 if (isANDWop(p.As) || isADDWop(p.As) || p.As == AMOVW) && p.From.Type == obj.TYPE_CONST {
305 v := p.From.Offset & 0xffffffff
306 p.From.Offset = v | v<<32
307 }
308
309 if c.ctxt.Flag_dynlink {
310 c.rewriteToUseGot(p)
311 }
312 }
313
314
315 func (c *ctxt7) rewriteToUseGot(p *obj.Prog) {
316 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
317
318
319
320
321
322 var sym *obj.LSym
323 if p.As == obj.ADUFFZERO {
324 sym = c.ctxt.Lookup("runtime.duffzero")
325 } else {
326 sym = c.ctxt.Lookup("runtime.duffcopy")
327 }
328 offset := p.To.Offset
329 p.As = AMOVD
330 p.From.Type = obj.TYPE_MEM
331 p.From.Name = obj.NAME_GOTREF
332 p.From.Sym = sym
333 p.To.Type = obj.TYPE_REG
334 p.To.Reg = REGTMP
335 p.To.Name = obj.NAME_NONE
336 p.To.Offset = 0
337 p.To.Sym = nil
338 p1 := obj.Appendp(p, c.newprog)
339 p1.As = AADD
340 p1.From.Type = obj.TYPE_CONST
341 p1.From.Offset = offset
342 p1.To.Type = obj.TYPE_REG
343 p1.To.Reg = REGTMP
344 p2 := obj.Appendp(p1, c.newprog)
345 p2.As = obj.ACALL
346 p2.To.Type = obj.TYPE_REG
347 p2.To.Reg = REGTMP
348 }
349
350
351
352
353 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
354
355
356 if p.As != AMOVD {
357 c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
358 }
359 if p.To.Type != obj.TYPE_REG {
360 c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
361 }
362 p.From.Type = obj.TYPE_MEM
363 p.From.Name = obj.NAME_GOTREF
364 if p.From.Offset != 0 {
365 q := obj.Appendp(p, c.newprog)
366 q.As = AADD
367 q.From.Type = obj.TYPE_CONST
368 q.From.Offset = p.From.Offset
369 q.To = p.To
370 p.From.Offset = 0
371 }
372 }
373 if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
374 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
375 }
376 var source *obj.Addr
377
378
379
380 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
381 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
382 c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
383 }
384 source = &p.From
385 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
386 source = &p.To
387 } else {
388 return
389 }
390 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
391 return
392 }
393 if source.Sym.Type == objabi.STLSBSS {
394 return
395 }
396 if source.Type != obj.TYPE_MEM {
397 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
398 }
399 p1 := obj.Appendp(p, c.newprog)
400 p2 := obj.Appendp(p1, c.newprog)
401 p1.As = AMOVD
402 p1.From.Type = obj.TYPE_MEM
403 p1.From.Sym = source.Sym
404 p1.From.Name = obj.NAME_GOTREF
405 p1.To.Type = obj.TYPE_REG
406 p1.To.Reg = REGTMP
407
408 p2.As = p.As
409 p2.From = p.From
410 p2.To = p.To
411 if p.From.Name == obj.NAME_EXTERN {
412 p2.From.Reg = REGTMP
413 p2.From.Name = obj.NAME_NONE
414 p2.From.Sym = nil
415 } else if p.To.Name == obj.NAME_EXTERN {
416 p2.To.Reg = REGTMP
417 p2.To.Name = obj.NAME_NONE
418 p2.To.Sym = nil
419 } else {
420 return
421 }
422 obj.Nopout(p)
423 }
424
425 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
426 if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
427 return
428 }
429
430 c := ctxt7{ctxt: ctxt, newprog: newprog, cursym: cursym}
431
432 p := c.cursym.Func().Text
433 textstksiz := p.To.Offset
434 if textstksiz == -8 {
435
436 p.From.Sym.Set(obj.AttrNoFrame, true)
437 textstksiz = 0
438 }
439 if textstksiz < 0 {
440 c.ctxt.Diag("negative frame size %d - did you mean NOFRAME?", textstksiz)
441 }
442 if p.From.Sym.NoFrame() {
443 if textstksiz != 0 {
444 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
445 }
446 }
447
448 c.cursym.Func().Args = p.To.Val.(int32)
449 c.cursym.Func().Locals = int32(textstksiz)
450
451
454 for p := c.cursym.Func().Text; p != nil; p = p.Link {
455 switch p.As {
456 case obj.ATEXT:
457 p.Mark |= LEAF
458
459 case ABL,
460 obj.ADUFFZERO,
461 obj.ADUFFCOPY:
462 c.cursym.Func().Text.Mark &^= LEAF
463 }
464 }
465
466 var q *obj.Prog
467 var q1 *obj.Prog
468 var retjmp *obj.LSym
469 for p := c.cursym.Func().Text; p != nil; p = p.Link {
470 o := p.As
471 switch o {
472 case obj.ATEXT:
473 c.cursym.Func().Text = p
474 c.autosize = int32(textstksiz)
475
476 if p.Mark&LEAF != 0 && c.autosize == 0 {
477
478 p.From.Sym.Set(obj.AttrNoFrame, true)
479 }
480
481 if !p.From.Sym.NoFrame() {
482
483
484 c.autosize += 8
485 }
486
487 if c.autosize != 0 {
488 extrasize := int32(0)
489 if c.autosize%16 == 8 {
490
491 extrasize = 8
492 } else if c.autosize&(16-1) == 0 {
493
494 extrasize = 16
495 } else {
496 c.ctxt.Diag("%v: unaligned frame size %d - must be 16 aligned", p, c.autosize-8)
497 }
498 c.autosize += extrasize
499 c.cursym.Func().Locals += extrasize
500
501
502
503 p.To.Offset = int64(c.autosize) | int64(extrasize)<<32
504 } else {
505
506 p.To.Offset = 0
507 }
508
509 if c.autosize == 0 && c.cursym.Func().Text.Mark&LEAF == 0 {
510 if c.ctxt.Debugvlog {
511 c.ctxt.Logf("save suppressed in: %s\n", c.cursym.Func().Text.From.Sym.Name)
512 }
513 c.cursym.Func().Text.Mark |= LEAF
514 }
515
516 if cursym.Func().Text.Mark&LEAF != 0 {
517 cursym.Set(obj.AttrLeaf, true)
518 if p.From.Sym.NoFrame() {
519 break
520 }
521 }
522
523 if p.Mark&LEAF != 0 && c.autosize < objabi.StackSmall {
524
525
526 p.From.Sym.Set(obj.AttrNoSplit, true)
527 }
528
529 if !p.From.Sym.NoSplit() {
530 p = c.stacksplit(p, c.autosize)
531 }
532
533 var prologueEnd *obj.Prog
534
535 aoffset := c.autosize
536 if aoffset > 0xF0 {
537 aoffset = 0xF0
538 }
539
540
541
542 q = p
543 if c.autosize > aoffset {
544
545
546
547
548
549
550 q = c.ctxt.StartUnsafePoint(q, c.newprog)
551
552 q = obj.Appendp(q, c.newprog)
553 q.Pos = p.Pos
554 q.As = ASUB
555 q.From.Type = obj.TYPE_CONST
556 q.From.Offset = int64(c.autosize)
557 q.Reg = REGSP
558 q.To.Type = obj.TYPE_REG
559 q.To.Reg = REGTMP
560
561 prologueEnd = q
562
563 q = obj.Appendp(q, c.newprog)
564 q.Pos = p.Pos
565 q.As = AMOVD
566 q.From.Type = obj.TYPE_REG
567 q.From.Reg = REGLINK
568 q.To.Type = obj.TYPE_MEM
569 q.To.Reg = REGTMP
570
571 q1 = obj.Appendp(q, c.newprog)
572 q1.Pos = p.Pos
573 q1.As = AMOVD
574 q1.From.Type = obj.TYPE_REG
575 q1.From.Reg = REGTMP
576 q1.To.Type = obj.TYPE_REG
577 q1.To.Reg = REGSP
578 q1.Spadj = c.autosize
579
580 if buildcfg.GOOS == "ios" {
581
582
583
584 q1 = obj.Appendp(q1, c.newprog)
585 q1.Pos = p.Pos
586 q1.As = AMOVD
587 q1.From.Type = obj.TYPE_REG
588 q1.From.Reg = REGLINK
589 q1.To.Type = obj.TYPE_MEM
590 q1.To.Reg = REGSP
591 }
592
593 q1 = c.ctxt.EndUnsafePoint(q1, c.newprog, -1)
594 } else {
595
596 q1 = obj.Appendp(q, c.newprog)
597 q1.As = AMOVD
598 q1.Pos = p.Pos
599 q1.From.Type = obj.TYPE_REG
600 q1.From.Reg = REGLINK
601 q1.To.Type = obj.TYPE_MEM
602 q1.Scond = C_XPRE
603 q1.To.Offset = int64(-aoffset)
604 q1.To.Reg = REGSP
605 q1.Spadj = aoffset
606
607 prologueEnd = q1
608 }
609
610 prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
611
612
613 q1 = obj.Appendp(q1, c.newprog)
614 q1.Pos = p.Pos
615 q1.As = AMOVD
616 q1.From.Type = obj.TYPE_REG
617 q1.From.Reg = REGFP
618 q1.To.Type = obj.TYPE_MEM
619 q1.To.Reg = REGSP
620 q1.To.Offset = -8
621
622 q1 = obj.Appendp(q1, c.newprog)
623 q1.Pos = p.Pos
624 q1.As = ASUB
625 q1.From.Type = obj.TYPE_CONST
626 q1.From.Offset = 8
627 q1.Reg = REGSP
628 q1.To.Type = obj.TYPE_REG
629 q1.To.Reg = REGFP
630
631 if c.cursym.Func().Text.From.Sym.Wrapper() {
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650 q = q1
651
652
653 q = obj.Appendp(q, c.newprog)
654 q.As = AMOVD
655 q.From.Type = obj.TYPE_MEM
656 q.From.Reg = REGG
657 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize)
658 q.To.Type = obj.TYPE_REG
659 q.To.Reg = REG_R1
660
661
662 cbnz := obj.Appendp(q, c.newprog)
663 cbnz.As = ACBNZ
664 cbnz.From.Type = obj.TYPE_REG
665 cbnz.From.Reg = REG_R1
666 cbnz.To.Type = obj.TYPE_BRANCH
667
668
669 end := obj.Appendp(cbnz, c.newprog)
670 end.As = obj.ANOP
671
672
673 var last *obj.Prog
674 for last = end; last.Link != nil; last = last.Link {
675 }
676
677
678 mov := obj.Appendp(last, c.newprog)
679 mov.As = AMOVD
680 mov.From.Type = obj.TYPE_MEM
681 mov.From.Reg = REG_R1
682 mov.From.Offset = 0
683 mov.To.Type = obj.TYPE_REG
684 mov.To.Reg = REG_R2
685
686
687 cbnz.To.SetTarget(mov)
688
689
690 q = obj.Appendp(mov, c.newprog)
691 q.As = AADD
692 q.From.Type = obj.TYPE_CONST
693 q.From.Offset = int64(c.autosize) + 8
694 q.Reg = REGSP
695 q.To.Type = obj.TYPE_REG
696 q.To.Reg = REG_R3
697
698
699 q = obj.Appendp(q, c.newprog)
700 q.As = ACMP
701 q.From.Type = obj.TYPE_REG
702 q.From.Reg = REG_R2
703 q.Reg = REG_R3
704
705
706 q = obj.Appendp(q, c.newprog)
707 q.As = ABNE
708 q.To.Type = obj.TYPE_BRANCH
709 q.To.SetTarget(end)
710
711
712 q = obj.Appendp(q, c.newprog)
713 q.As = AADD
714 q.From.Type = obj.TYPE_CONST
715 q.From.Offset = 8
716 q.Reg = REGSP
717 q.To.Type = obj.TYPE_REG
718 q.To.Reg = REG_R4
719
720
721 q = obj.Appendp(q, c.newprog)
722 q.As = AMOVD
723 q.From.Type = obj.TYPE_REG
724 q.From.Reg = REG_R4
725 q.To.Type = obj.TYPE_MEM
726 q.To.Reg = REG_R1
727 q.To.Offset = 0
728
729
730 q = obj.Appendp(q, c.newprog)
731 q.As = AB
732 q.To.Type = obj.TYPE_BRANCH
733 q.To.SetTarget(end)
734 }
735
736 case obj.ARET:
737 nocache(p)
738 if p.From.Type == obj.TYPE_CONST {
739 c.ctxt.Diag("using BECOME (%v) is not supported!", p)
740 break
741 }
742
743 retjmp = p.To.Sym
744 p.To = obj.Addr{}
745 if c.cursym.Func().Text.Mark&LEAF != 0 {
746 if c.autosize != 0 {
747 p.As = AADD
748 p.From.Type = obj.TYPE_CONST
749 p.From.Offset = int64(c.autosize)
750 p.To.Type = obj.TYPE_REG
751 p.To.Reg = REGSP
752 p.Spadj = -c.autosize
753
754
755 p = obj.Appendp(p, c.newprog)
756 p.As = ASUB
757 p.From.Type = obj.TYPE_CONST
758 p.From.Offset = 8
759 p.Reg = REGSP
760 p.To.Type = obj.TYPE_REG
761 p.To.Reg = REGFP
762 }
763 } else {
764
765
766
767 p.As = AMOVD
768 p.From.Type = obj.TYPE_MEM
769 p.From.Reg = REGSP
770 p.From.Offset = -8
771 p.To.Type = obj.TYPE_REG
772 p.To.Reg = REGFP
773 p = obj.Appendp(p, c.newprog)
774
775 aoffset := c.autosize
776
777 if aoffset <= 0xF0 {
778 p.As = AMOVD
779 p.From.Type = obj.TYPE_MEM
780 p.Scond = C_XPOST
781 p.From.Offset = int64(aoffset)
782 p.From.Reg = REGSP
783 p.To.Type = obj.TYPE_REG
784 p.To.Reg = REGLINK
785 p.Spadj = -aoffset
786 } else {
787 p.As = AMOVD
788 p.From.Type = obj.TYPE_MEM
789 p.From.Offset = 0
790 p.From.Reg = REGSP
791 p.To.Type = obj.TYPE_REG
792 p.To.Reg = REGLINK
793
794 q = newprog()
795 q.As = AADD
796 q.From.Type = obj.TYPE_CONST
797 q.From.Offset = int64(aoffset)
798 q.To.Type = obj.TYPE_REG
799 q.To.Reg = REGSP
800 q.Link = p.Link
801 q.Spadj = int32(-q.From.Offset)
802 q.Pos = p.Pos
803 p.Link = q
804 p = q
805 }
806 }
807
808
809
810
811
812
813 const debugRETZERO = false
814 if debugRETZERO {
815 if p.As != obj.ARET {
816 q = newprog()
817 q.Pos = p.Pos
818 q.Link = p.Link
819 p.Link = q
820 p = q
821 }
822 p.As = AADR
823 p.From.Type = obj.TYPE_BRANCH
824 p.From.Offset = 0
825 p.To.Type = obj.TYPE_REG
826 p.To.Reg = REGTMP
827
828 }
829
830 if p.As != obj.ARET {
831 q = newprog()
832 q.Pos = p.Pos
833 q.Link = p.Link
834 p.Link = q
835 p = q
836 }
837
838 if retjmp != nil {
839 p.As = AB
840 p.To.Type = obj.TYPE_BRANCH
841 p.To.Sym = retjmp
842 p.Spadj = +c.autosize
843 break
844 }
845
846 p.As = obj.ARET
847 p.To.Type = obj.TYPE_MEM
848 p.To.Offset = 0
849 p.To.Reg = REGLINK
850 p.Spadj = +c.autosize
851
852 case AADD, ASUB:
853 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
854 if p.As == AADD {
855 p.Spadj = int32(-p.From.Offset)
856 } else {
857 p.Spadj = int32(+p.From.Offset)
858 }
859 }
860
861 case obj.AGETCALLERPC:
862 if cursym.Leaf() {
863
864 p.As = AMOVD
865 p.From.Type = obj.TYPE_REG
866 p.From.Reg = REGLINK
867 } else {
868
869 p.As = AMOVD
870 p.From.Type = obj.TYPE_MEM
871 p.From.Reg = REGSP
872 }
873
874 case obj.ADUFFCOPY:
875
876
877
878
879
880
881
882 q1 := p
883
884 q4 := obj.Appendp(p, c.newprog)
885 q4.Pos = p.Pos
886 q4.As = obj.ADUFFCOPY
887 q4.To = p.To
888
889 q1.As = AADR
890 q1.From.Type = obj.TYPE_BRANCH
891 q1.To.Type = obj.TYPE_REG
892 q1.To.Reg = REG_R27
893
894 q2 := obj.Appendp(q1, c.newprog)
895 q2.Pos = p.Pos
896 q2.As = ASTP
897 q2.From.Type = obj.TYPE_REGREG
898 q2.From.Reg = REGFP
899 q2.From.Offset = int64(REG_R27)
900 q2.To.Type = obj.TYPE_MEM
901 q2.To.Reg = REGSP
902 q2.To.Offset = -24
903
904
905 q3 := obj.Appendp(q2, c.newprog)
906 q3.Pos = p.Pos
907 q3.As = ASUB
908 q3.From.Type = obj.TYPE_CONST
909 q3.From.Offset = 24
910 q3.Reg = REGSP
911 q3.To.Type = obj.TYPE_REG
912 q3.To.Reg = REGFP
913
914 q5 := obj.Appendp(q4, c.newprog)
915 q5.Pos = p.Pos
916 q5.As = ASUB
917 q5.From.Type = obj.TYPE_CONST
918 q5.From.Offset = 8
919 q5.Reg = REGSP
920 q5.To.Type = obj.TYPE_REG
921 q5.To.Reg = REGFP
922 q1.From.SetTarget(q5)
923 p = q5
924
925 case obj.ADUFFZERO:
926
927
928
929
930
931
932
933 q1 := p
934
935 q4 := obj.Appendp(p, c.newprog)
936 q4.Pos = p.Pos
937 q4.As = obj.ADUFFZERO
938 q4.To = p.To
939
940 q1.As = AADR
941 q1.From.Type = obj.TYPE_BRANCH
942 q1.To.Type = obj.TYPE_REG
943 q1.To.Reg = REG_R27
944
945 q2 := obj.Appendp(q1, c.newprog)
946 q2.Pos = p.Pos
947 q2.As = ASTP
948 q2.From.Type = obj.TYPE_REGREG
949 q2.From.Reg = REGFP
950 q2.From.Offset = int64(REG_R27)
951 q2.To.Type = obj.TYPE_MEM
952 q2.To.Reg = REGSP
953 q2.To.Offset = -24
954
955
956 q3 := obj.Appendp(q2, c.newprog)
957 q3.Pos = p.Pos
958 q3.As = ASUB
959 q3.From.Type = obj.TYPE_CONST
960 q3.From.Offset = 24
961 q3.Reg = REGSP
962 q3.To.Type = obj.TYPE_REG
963 q3.To.Reg = REGFP
964
965 q5 := obj.Appendp(q4, c.newprog)
966 q5.Pos = p.Pos
967 q5.As = ASUB
968 q5.From.Type = obj.TYPE_CONST
969 q5.From.Offset = 8
970 q5.Reg = REGSP
971 q5.To.Type = obj.TYPE_REG
972 q5.To.Reg = REGFP
973 q1.From.SetTarget(q5)
974 p = q5
975 }
976
977 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
978 f := c.cursym.Func()
979 if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
980 c.cursym.Func().FuncFlag |= objabi.FuncFlag_SPWRITE
981 if ctxt.Debugvlog || !ctxt.IsAsm {
982 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
983 if !ctxt.IsAsm {
984 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
985 ctxt.DiagFlush()
986 log.Fatalf("bad SPWRITE")
987 }
988 }
989 }
990 }
991 }
992 }
993
994 func nocache(p *obj.Prog) {
995 p.Optab = 0
996 p.From.Class = 0
997 p.To.Class = 0
998 }
999
1000 var unaryDst = map[obj.As]bool{
1001 AWORD: true,
1002 ADWORD: true,
1003 ABL: true,
1004 AB: true,
1005 ACLREX: true,
1006 }
1007
1008 var Linkarm64 = obj.LinkArch{
1009 Arch: sys.ArchARM64,
1010 Init: buildop,
1011 Preprocess: preprocess,
1012 Assemble: span7,
1013 Progedit: progedit,
1014 UnaryDst: unaryDst,
1015 DWARFRegisters: ARM64DWARFRegisters,
1016 }
1017
View as plain text