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 package ppc64
31
32 import (
33 "cmd/internal/obj"
34 "cmd/internal/objabi"
35 "cmd/internal/src"
36 "cmd/internal/sys"
37 "internal/abi"
38 "log"
39 "math/bits"
40 "strings"
41 )
42
43
44
45
46
47
48 func isPPC64DoublewordRotateMask(v64 int64) bool {
49
50 v := uint64(v64)
51 vp := (v & -v) + v
52
53 vn := ^v
54 vpn := (vn & -vn) + vn
55 return (v&vp == 0 || vn&vpn == 0) && v != 0
56 }
57
58
59
60
61 func encodePPC64RLDCMask(mask int64) (mb, me int) {
62
63 mb = bits.LeadingZeros64(uint64(mask))
64 me = 64 - bits.TrailingZeros64(uint64(mask))
65 mbn := bits.LeadingZeros64(^uint64(mask))
66 men := 64 - bits.TrailingZeros64(^uint64(mask))
67
68 if mb == 0 && me == 64 {
69
70 mb, me = men, mbn
71 }
72
73 return mb, me - 1
74 }
75
76
77
78
79 func isNOTOCfunc(name string) bool {
80 switch {
81 case name == "runtime.duffzero":
82 return true
83 case name == "runtime.duffcopy":
84 return true
85 case strings.HasPrefix(name, "runtime.elf_"):
86 return true
87 default:
88 return false
89 }
90 }
91
92 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
93 p.From.Class = 0
94 p.To.Class = 0
95
96 c := ctxt9{ctxt: ctxt, newprog: newprog}
97
98
99 switch p.As {
100 case ABR,
101 ABL,
102 obj.ARET,
103 obj.ADUFFZERO,
104 obj.ADUFFCOPY:
105 if p.To.Sym != nil {
106 p.To.Type = obj.TYPE_BRANCH
107 }
108 }
109
110
111 switch p.As {
112 case AFMOVS:
113 if p.From.Type == obj.TYPE_FCONST {
114 f32 := float32(p.From.Val.(float64))
115 p.From.Type = obj.TYPE_MEM
116 p.From.Sym = ctxt.Float32Sym(f32)
117 p.From.Name = obj.NAME_EXTERN
118 p.From.Offset = 0
119 }
120
121 case AFMOVD:
122 if p.From.Type == obj.TYPE_FCONST {
123 f64 := p.From.Val.(float64)
124
125 if f64 != 0 {
126 p.From.Type = obj.TYPE_MEM
127 p.From.Sym = ctxt.Float64Sym(f64)
128 p.From.Name = obj.NAME_EXTERN
129 p.From.Offset = 0
130 }
131 }
132
133 case AMOVW, AMOVWZ:
134
135 if p.From.Type == obj.TYPE_CONST && p.From.Offset != 0 && p.From.Offset&0xFFFF == 0 {
136
137 p.As = AADDIS
138
139 if p.From.Offset >= 0x80000000 {
140 p.As = AORIS
141 }
142 p.Reg = REG_R0
143 p.From.Offset >>= 16
144 }
145
146 case AMOVD:
147
148 if p.From.Type != obj.TYPE_CONST || p.From.Name != obj.NAME_NONE || p.From.Reg != 0 {
149 break
150 }
151
152
153 isS32 := int64(int32(p.From.Offset)) == p.From.Offset
154 isU32 := uint64(uint32(p.From.Offset)) == uint64(p.From.Offset)
155
156 isS34 := pfxEnabled && (p.From.Offset<<30)>>30 == p.From.Offset
157
158
159 switch {
160 case isS32 && p.From.Offset&0xFFFF == 0 && p.From.Offset != 0:
161 p.As = AADDIS
162 p.From.Offset >>= 16
163 p.Reg = REG_R0
164
165 case isU32 && p.From.Offset&0xFFFF == 0 && p.From.Offset != 0:
166 p.As = AORIS
167 p.From.Offset >>= 16
168 p.Reg = REG_R0
169
170 case isS32 || isU32 || isS34:
171
172
173
174 default:
175
176 val := p.From.Offset
177 shift := bits.TrailingZeros64(uint64(val))
178 mask := int64(0xFFFF) << shift
179 if val&mask == val || (val>>(shift+16) == -1 && (val>>shift)<<shift == val) {
180
181 q := obj.Appendp(p, c.newprog)
182 q.As = ASLD
183 q.From.SetConst(int64(shift))
184 q.To = p.To
185 p.From.Offset >>= shift
186 p = q
187 } else if isPPC64DoublewordRotateMask(val) {
188
189 mb, me := encodePPC64RLDCMask(val)
190 q := obj.Appendp(p, c.newprog)
191 q.As = ARLDC
192 q.AddRestSourceConst((^int64(me)) & 0x3F)
193 q.AddRestSourceConst(int64(mb))
194 q.From = p.To
195 q.To = p.To
196 p.From.Offset = -1
197 p = q
198 } else {
199
200 p.From.Type = obj.TYPE_MEM
201 p.From.Sym = ctxt.Int64Sym(p.From.Offset)
202 p.From.Name = obj.NAME_EXTERN
203 p.From.Offset = 0
204 }
205 }
206 }
207
208 switch p.As {
209
210 case ASUBC:
211 if p.From.Type == obj.TYPE_CONST {
212 p.From.Offset = -p.From.Offset
213 p.As = AADDC
214 }
215
216 case ASUBCCC:
217 if p.From.Type == obj.TYPE_CONST {
218 p.From.Offset = -p.From.Offset
219 p.As = AADDCCC
220 }
221
222 case ASUB:
223 if p.From.Type == obj.TYPE_CONST {
224 p.From.Offset = -p.From.Offset
225 p.As = AADD
226 }
227
228
229 case AADD:
230
231 if p.From.Type == obj.TYPE_CONST && p.From.Offset&0xFFFF == 0 && int64(int32(p.From.Offset)) == p.From.Offset && p.From.Offset != 0 {
232 p.As = AADDIS
233 p.From.Offset >>= 16
234 }
235 case AOR:
236 if p.From.Type == obj.TYPE_CONST && uint64(p.From.Offset)&0xFFFFFFFF0000FFFF == 0 && p.From.Offset != 0 {
237 p.As = AORIS
238 p.From.Offset >>= 16
239 }
240 case AXOR:
241 if p.From.Type == obj.TYPE_CONST && uint64(p.From.Offset)&0xFFFFFFFF0000FFFF == 0 && p.From.Offset != 0 {
242 p.As = AXORIS
243 p.From.Offset >>= 16
244 }
245 case AANDCC:
246 if p.From.Type == obj.TYPE_CONST && uint64(p.From.Offset)&0xFFFFFFFF0000FFFF == 0 && p.From.Offset != 0 {
247 p.As = AANDISCC
248 p.From.Offset >>= 16
249 }
250
251
252
253
254
255
256
257
258 case AVSHASIGMAW, AVSHASIGMAD, AADDEX, AXXSLDWI, AXXPERMDI:
259 if len(p.RestArgs) == 2 && p.Reg == 0 && p.RestArgs[0].Addr.Type == obj.TYPE_CONST && p.RestArgs[1].Addr.Type == obj.TYPE_REG {
260 p.Reg = p.RestArgs[1].Addr.Reg
261 p.RestArgs = p.RestArgs[:1]
262 }
263 }
264
265 if c.ctxt.Headtype == objabi.Haix {
266 c.rewriteToUseTOC(p)
267 } else if c.ctxt.Flag_dynlink {
268 c.rewriteToUseGot(p)
269 }
270 }
271
272
273
274 func (c *ctxt9) rewriteToUseTOC(p *obj.Prog) {
275 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
276 return
277 }
278
279 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
280
281
282 if !c.ctxt.Flag_dynlink {
283 return
284 }
285
286
287
288
289
290
291 var sym *obj.LSym
292 if p.As == obj.ADUFFZERO {
293 sym = c.ctxt.Lookup("runtime.duffzero")
294 } else {
295 sym = c.ctxt.Lookup("runtime.duffcopy")
296 }
297
298 symtoc := c.ctxt.LookupInit("TOC."+sym.Name, func(s *obj.LSym) {
299 s.Type = objabi.SDATA
300 s.Set(obj.AttrDuplicateOK, true)
301 s.Set(obj.AttrStatic, true)
302 c.ctxt.Data = append(c.ctxt.Data, s)
303 s.WriteAddr(c.ctxt, 0, 8, sym, 0)
304 })
305
306 offset := p.To.Offset
307 p.As = AMOVD
308 p.From.Type = obj.TYPE_MEM
309 p.From.Name = obj.NAME_TOCREF
310 p.From.Sym = symtoc
311 p.To.Type = obj.TYPE_REG
312 p.To.Reg = REG_R12
313 p.To.Name = obj.NAME_NONE
314 p.To.Offset = 0
315 p.To.Sym = nil
316 p1 := obj.Appendp(p, c.newprog)
317 p1.As = AADD
318 p1.From.Type = obj.TYPE_CONST
319 p1.From.Offset = offset
320 p1.To.Type = obj.TYPE_REG
321 p1.To.Reg = REG_R12
322 p2 := obj.Appendp(p1, c.newprog)
323 p2.As = AMOVD
324 p2.From.Type = obj.TYPE_REG
325 p2.From.Reg = REG_R12
326 p2.To.Type = obj.TYPE_REG
327 p2.To.Reg = REG_LR
328 p3 := obj.Appendp(p2, c.newprog)
329 p3.As = obj.ACALL
330 p3.To.Type = obj.TYPE_REG
331 p3.To.Reg = REG_LR
332 }
333
334 var source *obj.Addr
335 if p.From.Name == obj.NAME_EXTERN || p.From.Name == obj.NAME_STATIC {
336 if p.From.Type == obj.TYPE_ADDR {
337 if p.As == ADWORD {
338
339 return
340 }
341 if p.As != AMOVD {
342 c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v", p)
343 return
344 }
345 if p.To.Type != obj.TYPE_REG {
346 c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v", p)
347 return
348 }
349 } else if p.From.Type != obj.TYPE_MEM {
350 c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
351 return
352 }
353 source = &p.From
354
355 } else if p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC {
356 if p.To.Type != obj.TYPE_MEM {
357 c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
358 return
359 }
360 if source != nil {
361 c.ctxt.Diag("cannot handle symbols on both sides in %v", p)
362 return
363 }
364 source = &p.To
365 } else {
366 return
367
368 }
369
370 if source.Sym == nil {
371 c.ctxt.Diag("do not know how to handle nil symbol in %v", p)
372 return
373 }
374
375 if source.Sym.Type == objabi.STLSBSS {
376 return
377 }
378
379
380 symtoc := c.ctxt.LookupInit("TOC."+source.Sym.Name, func(s *obj.LSym) {
381 s.Type = objabi.SDATA
382 s.Set(obj.AttrDuplicateOK, true)
383 s.Set(obj.AttrStatic, true)
384 c.ctxt.Data = append(c.ctxt.Data, s)
385 s.WriteAddr(c.ctxt, 0, 8, source.Sym, 0)
386 })
387
388 if source.Type == obj.TYPE_ADDR {
389
390
391 p.From.Type = obj.TYPE_MEM
392 p.From.Sym = symtoc
393 p.From.Name = obj.NAME_TOCREF
394
395 if p.From.Offset != 0 {
396 q := obj.Appendp(p, c.newprog)
397 q.As = AADD
398 q.From.Type = obj.TYPE_CONST
399 q.From.Offset = p.From.Offset
400 p.From.Offset = 0
401 q.To = p.To
402 }
403 return
404
405 }
406
407
408
409
410
411 q := obj.Appendp(p, c.newprog)
412 q.As = AMOVD
413 q.From.Type = obj.TYPE_MEM
414 q.From.Sym = symtoc
415 q.From.Name = obj.NAME_TOCREF
416 q.To.Type = obj.TYPE_REG
417 q.To.Reg = REGTMP
418
419 q = obj.Appendp(q, c.newprog)
420 q.As = p.As
421 q.From = p.From
422 q.To = p.To
423 if p.From.Name != obj.NAME_NONE {
424 q.From.Type = obj.TYPE_MEM
425 q.From.Reg = REGTMP
426 q.From.Name = obj.NAME_NONE
427 q.From.Sym = nil
428 } else if p.To.Name != obj.NAME_NONE {
429 q.To.Type = obj.TYPE_MEM
430 q.To.Reg = REGTMP
431 q.To.Name = obj.NAME_NONE
432 q.To.Sym = nil
433 } else {
434 c.ctxt.Diag("unreachable case in rewriteToUseTOC with %v", p)
435 }
436
437 obj.Nopout(p)
438 }
439
440
441 func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
442 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
443
444
445
446
447
448
449 var sym *obj.LSym
450 if p.As == obj.ADUFFZERO {
451 sym = c.ctxt.LookupABI("runtime.duffzero", obj.ABIInternal)
452 } else {
453 sym = c.ctxt.LookupABI("runtime.duffcopy", obj.ABIInternal)
454 }
455 offset := p.To.Offset
456 p.As = AMOVD
457 p.From.Type = obj.TYPE_MEM
458 p.From.Name = obj.NAME_GOTREF
459 p.From.Sym = sym
460 p.To.Type = obj.TYPE_REG
461 p.To.Reg = REG_R12
462 p.To.Name = obj.NAME_NONE
463 p.To.Offset = 0
464 p.To.Sym = nil
465 p1 := obj.Appendp(p, c.newprog)
466 p1.As = AADD
467 p1.From.Type = obj.TYPE_CONST
468 p1.From.Offset = offset
469 p1.To.Type = obj.TYPE_REG
470 p1.To.Reg = REG_R12
471 p2 := obj.Appendp(p1, c.newprog)
472 p2.As = AMOVD
473 p2.From.Type = obj.TYPE_REG
474 p2.From.Reg = REG_R12
475 p2.To.Type = obj.TYPE_REG
476 p2.To.Reg = REG_LR
477 p3 := obj.Appendp(p2, c.newprog)
478 p3.As = obj.ACALL
479 p3.To.Type = obj.TYPE_REG
480 p3.To.Reg = REG_LR
481 }
482
483
484
485
486 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
487
488
489 if p.As != AMOVD {
490 c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
491 }
492 if p.To.Type != obj.TYPE_REG {
493 c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
494 }
495 p.From.Type = obj.TYPE_MEM
496 p.From.Name = obj.NAME_GOTREF
497 if p.From.Offset != 0 {
498 q := obj.Appendp(p, c.newprog)
499 q.As = AADD
500 q.From.Type = obj.TYPE_CONST
501 q.From.Offset = p.From.Offset
502 q.To = p.To
503 p.From.Offset = 0
504 }
505 }
506 if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
507 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
508 }
509 var source *obj.Addr
510
511
512
513 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
514 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
515 c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
516 }
517 source = &p.From
518 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
519 source = &p.To
520 } else {
521 return
522 }
523 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
524 return
525 }
526 if source.Sym.Type == objabi.STLSBSS {
527 return
528 }
529 if source.Type != obj.TYPE_MEM {
530 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
531 }
532 p1 := obj.Appendp(p, c.newprog)
533 p2 := obj.Appendp(p1, c.newprog)
534
535 p1.As = AMOVD
536 p1.From.Type = obj.TYPE_MEM
537 p1.From.Sym = source.Sym
538 p1.From.Name = obj.NAME_GOTREF
539 p1.To.Type = obj.TYPE_REG
540 p1.To.Reg = REGTMP
541
542 p2.As = p.As
543 p2.From = p.From
544 p2.To = p.To
545 if p.From.Name == obj.NAME_EXTERN {
546 p2.From.Reg = REGTMP
547 p2.From.Name = obj.NAME_NONE
548 p2.From.Sym = nil
549 } else if p.To.Name == obj.NAME_EXTERN {
550 p2.To.Reg = REGTMP
551 p2.To.Name = obj.NAME_NONE
552 p2.To.Sym = nil
553 } else {
554 return
555 }
556 obj.Nopout(p)
557 }
558
559 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
560
561 if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
562 return
563 }
564
565 c := ctxt9{ctxt: ctxt, cursym: cursym, newprog: newprog}
566
567 p := c.cursym.Func().Text
568 textstksiz := p.To.Offset
569 if textstksiz == -8 {
570
571 p.From.Sym.Set(obj.AttrNoFrame, true)
572 textstksiz = 0
573 }
574 if textstksiz%8 != 0 {
575 c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
576 }
577 if p.From.Sym.NoFrame() {
578 if textstksiz != 0 {
579 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
580 }
581 }
582
583 c.cursym.Func().Args = p.To.Val.(int32)
584 c.cursym.Func().Locals = int32(textstksiz)
585
586
591
592 var q *obj.Prog
593 var q1 *obj.Prog
594 for p := c.cursym.Func().Text; p != nil; p = p.Link {
595 switch p.As {
596
597 case obj.ATEXT:
598 q = p
599
600 p.Mark |= LABEL | LEAF | SYNC
601 if p.Link != nil {
602 p.Link.Mark |= LABEL
603 }
604
605 case ANOR:
606 q = p
607 if p.To.Type == obj.TYPE_REG {
608 if p.To.Reg == REGZERO {
609 p.Mark |= LABEL | SYNC
610 }
611 }
612
613 case ALWAR,
614 ALBAR,
615 ASTBCCC,
616 ASTWCCC,
617 AEIEIO,
618 AICBI,
619 AISYNC,
620 ATLBIE,
621 ATLBIEL,
622 ASLBIA,
623 ASLBIE,
624 ASLBMFEE,
625 ASLBMFEV,
626 ASLBMTE,
627 ADCBF,
628 ADCBI,
629 ADCBST,
630 ADCBT,
631 ADCBTST,
632 ADCBZ,
633 ASYNC,
634 ATLBSYNC,
635 APTESYNC,
636 ALWSYNC,
637 ATW,
638 AWORD,
639 ARFI,
640 ARFCI,
641 ARFID,
642 AHRFID:
643 q = p
644 p.Mark |= LABEL | SYNC
645 continue
646
647 case AMOVW, AMOVWZ, AMOVD:
648 q = p
649 if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL {
650 p.Mark |= LABEL | SYNC
651 }
652 continue
653
654 case AFABS,
655 AFABSCC,
656 AFADD,
657 AFADDCC,
658 AFCTIW,
659 AFCTIWCC,
660 AFCTIWZ,
661 AFCTIWZCC,
662 AFDIV,
663 AFDIVCC,
664 AFMADD,
665 AFMADDCC,
666 AFMOVD,
667 AFMOVDU,
668
669 AFMOVS,
670 AFMOVSU,
671
672
673 AFMSUB,
674 AFMSUBCC,
675 AFMUL,
676 AFMULCC,
677 AFNABS,
678 AFNABSCC,
679 AFNEG,
680 AFNEGCC,
681 AFNMADD,
682 AFNMADDCC,
683 AFNMSUB,
684 AFNMSUBCC,
685 AFRSP,
686 AFRSPCC,
687 AFSUB,
688 AFSUBCC:
689 q = p
690
691 p.Mark |= FLOAT
692 continue
693
694 case ABL,
695 ABCL,
696 obj.ADUFFZERO,
697 obj.ADUFFCOPY:
698 c.cursym.Func().Text.Mark &^= LEAF
699 fallthrough
700
701 case ABC,
702 ABEQ,
703 ABGE,
704 ABGT,
705 ABLE,
706 ABLT,
707 ABNE,
708 ABR,
709 ABVC,
710 ABVS:
711 p.Mark |= BRANCH
712 q = p
713 q1 = p.To.Target()
714 if q1 != nil {
715
716
717 if q1.Mark&LEAF == 0 {
718 q1.Mark |= LABEL
719 }
720 } else {
721 p.Mark |= LABEL
722 }
723 q1 = p.Link
724 if q1 != nil {
725 q1.Mark |= LABEL
726 }
727 continue
728
729 case AFCMPO, AFCMPU:
730 q = p
731 p.Mark |= FCMP | FLOAT
732 continue
733
734 case obj.ARET:
735 q = p
736 if p.Link != nil {
737 p.Link.Mark |= LABEL
738 }
739 continue
740
741 case obj.ANOP:
742
743
744 continue
745
746 default:
747 q = p
748 continue
749 }
750 }
751
752 autosize := int32(0)
753 var p1 *obj.Prog
754 var p2 *obj.Prog
755 for p := c.cursym.Func().Text; p != nil; p = p.Link {
756 o := p.As
757 switch o {
758 case obj.ATEXT:
759 autosize = int32(textstksiz)
760
761 if p.Mark&LEAF != 0 && autosize == 0 {
762
763 p.From.Sym.Set(obj.AttrNoFrame, true)
764 }
765
766 if !p.From.Sym.NoFrame() {
767
768
769 autosize += int32(c.ctxt.Arch.FixedFrameSize)
770 }
771
772 if p.Mark&LEAF != 0 && autosize < abi.StackSmall {
773
774
775 p.From.Sym.Set(obj.AttrNoSplit, true)
776 }
777
778 p.To.Offset = int64(autosize)
779
780 q = p
781
782 if NeedTOCpointer(c.ctxt) && !isNOTOCfunc(c.cursym.Name) {
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804 q = obj.Appendp(q, c.newprog)
805 q.As = AWORD
806 q.Pos = p.Pos
807 q.From.Type = obj.TYPE_CONST
808 q.From.Offset = 0x3c4c0000
809 q = obj.Appendp(q, c.newprog)
810 q.As = AWORD
811 q.Pos = p.Pos
812 q.From.Type = obj.TYPE_CONST
813 q.From.Offset = 0x38420000
814 rel := obj.Addrel(c.cursym)
815 rel.Off = 0
816 rel.Siz = 8
817 rel.Sym = c.ctxt.Lookup(".TOC.")
818 rel.Type = objabi.R_ADDRPOWER_PCREL
819 }
820
821 if !c.cursym.Func().Text.From.Sym.NoSplit() {
822 q = c.stacksplit(q, autosize)
823 }
824
825 if autosize != 0 {
826 var prologueEnd *obj.Prog
827
828
829
830 if autosize >= -BIG && autosize <= BIG {
831
832 q = obj.Appendp(q, c.newprog)
833 q.As = AMOVD
834 q.Pos = p.Pos
835 q.From.Type = obj.TYPE_REG
836 q.From.Reg = REG_LR
837 q.To.Type = obj.TYPE_REG
838 q.To.Reg = REGTMP
839 prologueEnd = q
840
841 q = obj.Appendp(q, c.newprog)
842 q.As = AMOVDU
843 q.Pos = p.Pos
844 q.From.Type = obj.TYPE_REG
845 q.From.Reg = REGTMP
846 q.To.Type = obj.TYPE_MEM
847 q.To.Offset = int64(-autosize)
848 q.To.Reg = REGSP
849 q.Spadj = autosize
850 } else {
851
852
853
854
855
856
857 q = obj.Appendp(q, c.newprog)
858 q.As = AMOVD
859 q.Pos = p.Pos
860 q.From.Type = obj.TYPE_REG
861 q.From.Reg = REG_LR
862 q.To.Type = obj.TYPE_REG
863 q.To.Reg = REG_R29
864
865 q = c.ctxt.StartUnsafePoint(q, c.newprog)
866
867 q = obj.Appendp(q, c.newprog)
868 q.As = AMOVD
869 q.Pos = p.Pos
870 q.From.Type = obj.TYPE_REG
871 q.From.Reg = REG_R29
872 q.To.Type = obj.TYPE_MEM
873 q.To.Offset = int64(-autosize)
874 q.To.Reg = REGSP
875
876 prologueEnd = q
877
878 q = obj.Appendp(q, c.newprog)
879 q.As = AADD
880 q.Pos = p.Pos
881 q.From.Type = obj.TYPE_CONST
882 q.From.Offset = int64(-autosize)
883 q.To.Type = obj.TYPE_REG
884 q.To.Reg = REGSP
885 q.Spadj = +autosize
886
887 q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
888 }
889 prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
890 } else if c.cursym.Func().Text.Mark&LEAF == 0 {
891
892
893
894 c.cursym.Func().Text.Mark |= LEAF
895 }
896
897 if c.cursym.Func().Text.Mark&LEAF != 0 {
898 c.cursym.Set(obj.AttrLeaf, true)
899 break
900 }
901
902 if NeedTOCpointer(c.ctxt) {
903 q = obj.Appendp(q, c.newprog)
904 q.As = AMOVD
905 q.Pos = p.Pos
906 q.From.Type = obj.TYPE_REG
907 q.From.Reg = REG_R2
908 q.To.Type = obj.TYPE_MEM
909 q.To.Reg = REGSP
910 q.To.Offset = 24
911 }
912
913 if c.cursym.Func().Text.From.Sym.Wrapper() {
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931 q = obj.Appendp(q, c.newprog)
932
933 q.As = AMOVD
934 q.From.Type = obj.TYPE_MEM
935 q.From.Reg = REGG
936 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize)
937 q.To.Type = obj.TYPE_REG
938 q.To.Reg = REG_R22
939
940 q = obj.Appendp(q, c.newprog)
941 q.As = ACMP
942 q.From.Type = obj.TYPE_REG
943 q.From.Reg = REG_R0
944 q.To.Type = obj.TYPE_REG
945 q.To.Reg = REG_R22
946
947 q = obj.Appendp(q, c.newprog)
948 q.As = ABEQ
949 q.To.Type = obj.TYPE_BRANCH
950 p1 = q
951
952 q = obj.Appendp(q, c.newprog)
953 q.As = AMOVD
954 q.From.Type = obj.TYPE_MEM
955 q.From.Reg = REG_R22
956 q.From.Offset = 0
957 q.To.Type = obj.TYPE_REG
958 q.To.Reg = REG_R23
959
960 q = obj.Appendp(q, c.newprog)
961 q.As = AADD
962 q.From.Type = obj.TYPE_CONST
963 q.From.Offset = int64(autosize) + c.ctxt.Arch.FixedFrameSize
964 q.Reg = REGSP
965 q.To.Type = obj.TYPE_REG
966 q.To.Reg = REG_R24
967
968 q = obj.Appendp(q, c.newprog)
969 q.As = ACMP
970 q.From.Type = obj.TYPE_REG
971 q.From.Reg = REG_R23
972 q.To.Type = obj.TYPE_REG
973 q.To.Reg = REG_R24
974
975 q = obj.Appendp(q, c.newprog)
976 q.As = ABNE
977 q.To.Type = obj.TYPE_BRANCH
978 p2 = q
979
980 q = obj.Appendp(q, c.newprog)
981 q.As = AADD
982 q.From.Type = obj.TYPE_CONST
983 q.From.Offset = c.ctxt.Arch.FixedFrameSize
984 q.Reg = REGSP
985 q.To.Type = obj.TYPE_REG
986 q.To.Reg = REG_R25
987
988 q = obj.Appendp(q, c.newprog)
989 q.As = AMOVD
990 q.From.Type = obj.TYPE_REG
991 q.From.Reg = REG_R25
992 q.To.Type = obj.TYPE_MEM
993 q.To.Reg = REG_R22
994 q.To.Offset = 0
995
996 q = obj.Appendp(q, c.newprog)
997
998 q.As = obj.ANOP
999 p1.To.SetTarget(q)
1000 p2.To.SetTarget(q)
1001 }
1002
1003 case obj.ARET:
1004 if p.From.Type == obj.TYPE_CONST {
1005 c.ctxt.Diag("using BECOME (%v) is not supported!", p)
1006 break
1007 }
1008
1009 retTarget := p.To.Sym
1010
1011 if c.cursym.Func().Text.Mark&LEAF != 0 {
1012 if autosize == 0 {
1013 p.As = ABR
1014 p.From = obj.Addr{}
1015 if retTarget == nil {
1016 p.To.Type = obj.TYPE_REG
1017 p.To.Reg = REG_LR
1018 } else {
1019 p.To.Type = obj.TYPE_BRANCH
1020 p.To.Sym = retTarget
1021 }
1022 p.Mark |= BRANCH
1023 break
1024 }
1025
1026 p.As = AADD
1027 p.From.Type = obj.TYPE_CONST
1028 p.From.Offset = int64(autosize)
1029 p.To.Type = obj.TYPE_REG
1030 p.To.Reg = REGSP
1031 p.Spadj = -autosize
1032
1033 q = c.newprog()
1034 q.As = ABR
1035 q.Pos = p.Pos
1036 if retTarget == nil {
1037 q.To.Type = obj.TYPE_REG
1038 q.To.Reg = REG_LR
1039 } else {
1040 q.To.Type = obj.TYPE_BRANCH
1041 q.To.Sym = retTarget
1042 }
1043 q.Mark |= BRANCH
1044 q.Spadj = +autosize
1045
1046 q.Link = p.Link
1047 p.Link = q
1048 break
1049 }
1050
1051 p.As = AMOVD
1052 p.From.Type = obj.TYPE_MEM
1053 p.From.Offset = 0
1054 p.From.Reg = REGSP
1055 p.To.Type = obj.TYPE_REG
1056 p.To.Reg = REGTMP
1057
1058 q = c.newprog()
1059 q.As = AMOVD
1060 q.Pos = p.Pos
1061 q.From.Type = obj.TYPE_REG
1062 q.From.Reg = REGTMP
1063 q.To.Type = obj.TYPE_REG
1064 q.To.Reg = REG_LR
1065
1066 q.Link = p.Link
1067 p.Link = q
1068 p = q
1069
1070 if false {
1071
1072 q = c.newprog()
1073
1074 q.As = AMOVD
1075 q.Pos = p.Pos
1076 q.From.Type = obj.TYPE_MEM
1077 q.From.Offset = 0
1078 q.From.Reg = REGTMP
1079 q.To.Type = obj.TYPE_REG
1080 q.To.Reg = REGTMP
1081
1082 q.Link = p.Link
1083 p.Link = q
1084 p = q
1085 }
1086 prev := p
1087 if autosize != 0 {
1088 q = c.newprog()
1089 q.As = AADD
1090 q.Pos = p.Pos
1091 q.From.Type = obj.TYPE_CONST
1092 q.From.Offset = int64(autosize)
1093 q.To.Type = obj.TYPE_REG
1094 q.To.Reg = REGSP
1095 q.Spadj = -autosize
1096
1097 q.Link = p.Link
1098 prev.Link = q
1099 prev = q
1100 }
1101
1102 q1 = c.newprog()
1103 q1.As = ABR
1104 q1.Pos = p.Pos
1105 if retTarget == nil {
1106 q1.To.Type = obj.TYPE_REG
1107 q1.To.Reg = REG_LR
1108 } else {
1109 q1.To.Type = obj.TYPE_BRANCH
1110 q1.To.Sym = retTarget
1111 }
1112 q1.Mark |= BRANCH
1113 q1.Spadj = +autosize
1114
1115 q1.Link = q.Link
1116 prev.Link = q1
1117 case AADD:
1118 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
1119 p.Spadj = int32(-p.From.Offset)
1120 }
1121 case AMOVDU:
1122 if p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
1123 p.Spadj = int32(-p.To.Offset)
1124 }
1125 if p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP {
1126 p.Spadj = int32(-p.From.Offset)
1127 }
1128 case obj.AGETCALLERPC:
1129 if cursym.Leaf() {
1130
1131 p.As = AMOVD
1132 p.From.Type = obj.TYPE_REG
1133 p.From.Reg = REG_LR
1134 } else {
1135
1136 p.As = AMOVD
1137 p.From.Type = obj.TYPE_MEM
1138 p.From.Reg = REGSP
1139 }
1140 }
1141
1142 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 && p.As != ACMPU {
1143 f := c.cursym.Func()
1144 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
1145 c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
1146 if ctxt.Debugvlog || !ctxt.IsAsm {
1147 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
1148 if !ctxt.IsAsm {
1149 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
1150 ctxt.DiagFlush()
1151 log.Fatalf("bad SPWRITE")
1152 }
1153 }
1154 }
1155 }
1156 }
1157 }
1158
1159
1205 func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
1206 if c.ctxt.Flag_maymorestack != "" {
1207 if c.ctxt.Flag_shared || c.ctxt.Flag_dynlink {
1208
1209
1210 c.ctxt.Diag("maymorestack with -shared or -dynlink is not supported")
1211 }
1212
1213
1214
1215 p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
1216
1217
1218 frameSize := 8 + c.ctxt.Arch.FixedFrameSize
1219
1220
1221 p = obj.Appendp(p, c.newprog)
1222 p.As = AMOVD
1223 p.From.Type = obj.TYPE_REG
1224 p.From.Reg = REG_LR
1225 p.To.Type = obj.TYPE_REG
1226 p.To.Reg = REGTMP
1227
1228 p = obj.Appendp(p, c.newprog)
1229 p.As = AMOVDU
1230 p.From.Type = obj.TYPE_REG
1231 p.From.Reg = REGTMP
1232 p.To.Type = obj.TYPE_MEM
1233 p.To.Offset = -frameSize
1234 p.To.Reg = REGSP
1235 p.Spadj = int32(frameSize)
1236
1237
1238 p = obj.Appendp(p, c.newprog)
1239 p.As = AMOVD
1240 p.From.Type = obj.TYPE_REG
1241 p.From.Reg = REGCTXT
1242 p.To.Type = obj.TYPE_MEM
1243 p.To.Offset = 8
1244 p.To.Reg = REGSP
1245
1246
1247 p = obj.Appendp(p, c.newprog)
1248 p.As = ABL
1249 p.To.Type = obj.TYPE_BRANCH
1250
1251 p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
1252
1253
1254
1255
1256 p = obj.Appendp(p, c.newprog)
1257 p.As = AMOVD
1258 p.From.Type = obj.TYPE_MEM
1259 p.From.Offset = 8
1260 p.From.Reg = REGSP
1261 p.To.Type = obj.TYPE_REG
1262 p.To.Reg = REGCTXT
1263
1264
1265 p = obj.Appendp(p, c.newprog)
1266 p.As = AMOVD
1267 p.From.Type = obj.TYPE_MEM
1268 p.From.Offset = 0
1269 p.From.Reg = REGSP
1270 p.To.Type = obj.TYPE_REG
1271 p.To.Reg = REGTMP
1272
1273
1274 p = obj.Appendp(p, c.newprog)
1275 p.As = AMOVD
1276 p.From.Type = obj.TYPE_REG
1277 p.From.Reg = REGTMP
1278 p.To.Type = obj.TYPE_REG
1279 p.To.Reg = REG_LR
1280
1281
1282 p = obj.Appendp(p, c.newprog)
1283 p.As = AADD
1284 p.From.Type = obj.TYPE_CONST
1285 p.From.Offset = frameSize
1286 p.To.Type = obj.TYPE_REG
1287 p.To.Reg = REGSP
1288 p.Spadj = -int32(frameSize)
1289
1290
1291 p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
1292 }
1293
1294
1295 startPred := p
1296
1297
1298 p = obj.Appendp(p, c.newprog)
1299
1300 p.As = AMOVD
1301 p.From.Type = obj.TYPE_MEM
1302 p.From.Reg = REGG
1303 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
1304 if c.cursym.CFunc() {
1305 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
1306 }
1307 p.To.Type = obj.TYPE_REG
1308 p.To.Reg = REG_R22
1309
1310
1311
1312
1313
1314 p = c.ctxt.StartUnsafePoint(p, c.newprog)
1315
1316 var q *obj.Prog
1317 if framesize <= abi.StackSmall {
1318
1319
1320 p = obj.Appendp(p, c.newprog)
1321
1322 p.As = ACMPU
1323 p.From.Type = obj.TYPE_REG
1324 p.From.Reg = REG_R22
1325 p.To.Type = obj.TYPE_REG
1326 p.To.Reg = REGSP
1327 } else {
1328
1329 offset := int64(framesize) - abi.StackSmall
1330 if framesize > abi.StackBig {
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340 if offset <= 0xffff {
1341 p = obj.Appendp(p, c.newprog)
1342 p.As = ACMPU
1343 p.From.Type = obj.TYPE_REG
1344 p.From.Reg = REGSP
1345 p.To.Type = obj.TYPE_CONST
1346 p.To.Offset = offset
1347 } else {
1348
1349 p = obj.Appendp(p, c.newprog)
1350 p.As = AMOVD
1351 p.From.Type = obj.TYPE_CONST
1352 p.From.Offset = offset
1353 p.To.Type = obj.TYPE_REG
1354 p.To.Reg = REG_R23
1355
1356 p = obj.Appendp(p, c.newprog)
1357 p.As = ACMPU
1358 p.From.Type = obj.TYPE_REG
1359 p.From.Reg = REGSP
1360 p.To.Type = obj.TYPE_REG
1361 p.To.Reg = REG_R23
1362 }
1363
1364 p = obj.Appendp(p, c.newprog)
1365 q = p
1366 p.As = ABLT
1367 p.To.Type = obj.TYPE_BRANCH
1368 }
1369
1370
1371
1372
1373 p = obj.Appendp(p, c.newprog)
1374
1375 p.As = AADD
1376 p.From.Type = obj.TYPE_CONST
1377 p.From.Offset = -offset
1378 p.Reg = REGSP
1379 p.To.Type = obj.TYPE_REG
1380 p.To.Reg = REG_R23
1381
1382 p = obj.Appendp(p, c.newprog)
1383 p.As = ACMPU
1384 p.From.Type = obj.TYPE_REG
1385 p.From.Reg = REG_R22
1386 p.To.Type = obj.TYPE_REG
1387 p.To.Reg = REG_R23
1388 }
1389
1390
1391 p = obj.Appendp(p, c.newprog)
1392 q1 := p
1393
1394 p.As = ABLT
1395 p.To.Type = obj.TYPE_BRANCH
1396
1397 p = obj.Appendp(p, c.newprog)
1398 p.As = obj.ANOP
1399
1400 if q != nil {
1401 q.To.SetTarget(p)
1402 }
1403
1404
1405
1406
1407 spill := c.cursym.Func().SpillRegisterArgs(p, c.newprog)
1408
1409
1410 p = obj.Appendp(spill, c.newprog)
1411 p.As = AMOVD
1412 p.From.Type = obj.TYPE_REG
1413 p.From.Reg = REG_LR
1414 p.To.Type = obj.TYPE_REG
1415 p.To.Reg = REG_R5
1416
1417 p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
1418
1419 var morestacksym *obj.LSym
1420 if c.cursym.CFunc() {
1421 morestacksym = c.ctxt.Lookup("runtime.morestackc")
1422 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
1423 morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt")
1424 } else {
1425 morestacksym = c.ctxt.Lookup("runtime.morestack")
1426 }
1427
1428 if NeedTOCpointer(c.ctxt) {
1429
1430
1431
1432
1433
1434
1435
1436 p = obj.Appendp(p, c.newprog)
1437 p.As = AMOVD
1438 p.From.Type = obj.TYPE_REG
1439 p.From.Reg = REG_R2
1440 p.To.Type = obj.TYPE_MEM
1441 p.To.Reg = REGSP
1442 p.To.Offset = 8
1443 }
1444
1445 if c.ctxt.Flag_dynlink {
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461 p = obj.Appendp(p, c.newprog)
1462 p.As = AMOVD
1463 p.From.Type = obj.TYPE_MEM
1464 p.From.Sym = morestacksym
1465 p.From.Name = obj.NAME_GOTREF
1466 p.To.Type = obj.TYPE_REG
1467 p.To.Reg = REG_R12
1468
1469
1470 p = obj.Appendp(p, c.newprog)
1471 p.As = AMOVD
1472 p.From.Type = obj.TYPE_REG
1473 p.From.Reg = REG_R12
1474 p.To.Type = obj.TYPE_REG
1475 p.To.Reg = REG_LR
1476
1477
1478 p = obj.Appendp(p, c.newprog)
1479 p.As = obj.ACALL
1480 p.To.Type = obj.TYPE_REG
1481 p.To.Reg = REG_LR
1482 } else {
1483
1484 p = obj.Appendp(p, c.newprog)
1485
1486 p.As = ABL
1487 p.To.Type = obj.TYPE_BRANCH
1488 p.To.Sym = morestacksym
1489 }
1490
1491 if NeedTOCpointer(c.ctxt) {
1492
1493 p = obj.Appendp(p, c.newprog)
1494 p.As = AMOVD
1495 p.From.Type = obj.TYPE_MEM
1496 p.From.Reg = REGSP
1497 p.From.Offset = 8
1498 p.To.Type = obj.TYPE_REG
1499 p.To.Reg = REG_R2
1500 }
1501
1502
1503 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
1504 unspill := c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
1505
1506
1507 p = obj.Appendp(unspill, c.newprog)
1508 p.As = ABR
1509 p.To.Type = obj.TYPE_BRANCH
1510 p.To.SetTarget(startPred.Link)
1511
1512
1513 p = obj.Appendp(p, c.newprog)
1514
1515 p.As = obj.ANOP
1516 q1.To.SetTarget(p)
1517
1518 return p
1519 }
1520
1521
1522
1523
1524
1525 var unaryDst = map[obj.As]bool{
1526 AXXSETACCZ: true,
1527 AXXMTACC: true,
1528 AXXMFACC: true,
1529 }
1530
1531 var Linkppc64 = obj.LinkArch{
1532 Arch: sys.ArchPPC64,
1533 Init: buildop,
1534 Preprocess: preprocess,
1535 Assemble: span9,
1536 Progedit: progedit,
1537 UnaryDst: unaryDst,
1538 DWARFRegisters: PPC64DWARFRegisters,
1539 }
1540
1541 var Linkppc64le = obj.LinkArch{
1542 Arch: sys.ArchPPC64LE,
1543 Init: buildop,
1544 Preprocess: preprocess,
1545 Assemble: span9,
1546 Progedit: progedit,
1547 UnaryDst: unaryDst,
1548 DWARFRegisters: PPC64DWARFRegisters,
1549 }
1550
View as plain text