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