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