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
908
909
910
911
912 q = obj.Appendp(q, c.newprog)
913 q.As = AMOVD
914 q.Pos = p.Pos
915 q.From.Type = obj.TYPE_REG
916 q.From.Reg = REG_LR
917 q.To.Type = obj.TYPE_REG
918 q.To.Reg = REG_R29
919
920 q = c.ctxt.StartUnsafePoint(q, c.newprog)
921
922 q = obj.Appendp(q, c.newprog)
923 q.As = AMOVD
924 q.Pos = p.Pos
925 q.From.Type = obj.TYPE_REG
926 q.From.Reg = REG_R29
927 q.To.Type = obj.TYPE_MEM
928 q.To.Offset = int64(-autosize)
929 q.To.Reg = REGSP
930
931 prologueEnd = q
932
933 q = obj.Appendp(q, c.newprog)
934 q.As = AADD
935 q.Pos = p.Pos
936 q.From.Type = obj.TYPE_CONST
937 q.From.Offset = int64(-autosize)
938 q.To.Type = obj.TYPE_REG
939 q.To.Reg = REGSP
940 q.Spadj = +autosize
941
942 q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
943 }
944 prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
945 } else if c.cursym.Func().Text.Mark&LEAF == 0 {
946
947
948
949 c.cursym.Func().Text.Mark |= LEAF
950 }
951
952 if c.cursym.Func().Text.Mark&LEAF != 0 {
953 c.cursym.Set(obj.AttrLeaf, true)
954 break
955 }
956
957 if NeedTOCpointer(c.ctxt) {
958 q = obj.Appendp(q, c.newprog)
959 q.As = AMOVD
960 q.Pos = p.Pos
961 q.From.Type = obj.TYPE_REG
962 q.From.Reg = REG_R2
963 q.To.Type = obj.TYPE_MEM
964 q.To.Reg = REGSP
965 q.To.Offset = 24
966 }
967
968 case obj.ARET:
969 if p.From.Type == obj.TYPE_CONST {
970 c.ctxt.Diag("using BECOME (%v) is not supported!", p)
971 break
972 }
973
974 retTarget := p.To.Sym
975
976 if c.cursym.Func().Text.Mark&LEAF != 0 {
977 if autosize == 0 {
978 p.As = ABR
979 p.From = obj.Addr{}
980 if retTarget == nil {
981 p.To.Type = obj.TYPE_REG
982 p.To.Reg = REG_LR
983 } else {
984 p.To.Type = obj.TYPE_BRANCH
985 p.To.Sym = retTarget
986 }
987 p.Mark |= BRANCH
988 break
989 }
990
991 p.As = AADD
992 p.From.Type = obj.TYPE_CONST
993 p.From.Offset = int64(autosize)
994 p.To.Type = obj.TYPE_REG
995 p.To.Reg = REGSP
996 p.Spadj = -autosize
997
998 q = c.newprog()
999 q.As = ABR
1000 q.Pos = p.Pos
1001 if retTarget == nil {
1002 q.To.Type = obj.TYPE_REG
1003 q.To.Reg = REG_LR
1004 } else {
1005 q.To.Type = obj.TYPE_BRANCH
1006 q.To.Sym = retTarget
1007 }
1008 q.Mark |= BRANCH
1009 q.Spadj = +autosize
1010
1011 q.Link = p.Link
1012 p.Link = q
1013 break
1014 }
1015
1016 p.As = AMOVD
1017 p.From.Type = obj.TYPE_MEM
1018 p.From.Offset = 0
1019 p.From.Reg = REGSP
1020 p.To.Type = obj.TYPE_REG
1021 p.To.Reg = REGTMP
1022
1023 q = c.newprog()
1024 q.As = AMOVD
1025 q.Pos = p.Pos
1026 q.From.Type = obj.TYPE_REG
1027 q.From.Reg = REGTMP
1028 q.To.Type = obj.TYPE_REG
1029 q.To.Reg = REG_LR
1030
1031 q.Link = p.Link
1032 p.Link = q
1033 p = q
1034
1035 if false {
1036
1037 q = c.newprog()
1038
1039 q.As = AMOVD
1040 q.Pos = p.Pos
1041 q.From.Type = obj.TYPE_MEM
1042 q.From.Offset = 0
1043 q.From.Reg = REGTMP
1044 q.To.Type = obj.TYPE_REG
1045 q.To.Reg = REGTMP
1046
1047 q.Link = p.Link
1048 p.Link = q
1049 p = q
1050 }
1051 prev := p
1052 if autosize != 0 {
1053 q = c.newprog()
1054 q.As = AADD
1055 q.Pos = p.Pos
1056 q.From.Type = obj.TYPE_CONST
1057 q.From.Offset = int64(autosize)
1058 q.To.Type = obj.TYPE_REG
1059 q.To.Reg = REGSP
1060 q.Spadj = -autosize
1061
1062 q.Link = p.Link
1063 prev.Link = q
1064 prev = q
1065 }
1066
1067 q1 = c.newprog()
1068 q1.As = ABR
1069 q1.Pos = p.Pos
1070 if retTarget == nil {
1071 q1.To.Type = obj.TYPE_REG
1072 q1.To.Reg = REG_LR
1073 } else {
1074 q1.To.Type = obj.TYPE_BRANCH
1075 q1.To.Sym = retTarget
1076 }
1077 q1.Mark |= BRANCH
1078 q1.Spadj = +autosize
1079
1080 q1.Link = q.Link
1081 prev.Link = q1
1082 case AADD:
1083 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
1084 p.Spadj = int32(-p.From.Offset)
1085 }
1086 case AMOVDU:
1087 if p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
1088 p.Spadj = int32(-p.To.Offset)
1089 }
1090 if p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP {
1091 p.Spadj = int32(-p.From.Offset)
1092 }
1093 case obj.AGETCALLERPC:
1094 if cursym.Leaf() {
1095
1096 p.As = AMOVD
1097 p.From.Type = obj.TYPE_REG
1098 p.From.Reg = REG_LR
1099 } else {
1100
1101 p.As = AMOVD
1102 p.From.Type = obj.TYPE_MEM
1103 p.From.Reg = REGSP
1104 }
1105 }
1106
1107 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 && p.As != ACMPU {
1108 f := c.cursym.Func()
1109 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
1110 c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
1111 if ctxt.Debugvlog || !ctxt.IsAsm {
1112 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
1113 if !ctxt.IsAsm {
1114 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
1115 ctxt.DiagFlush()
1116 log.Fatalf("bad SPWRITE")
1117 }
1118 }
1119 }
1120 }
1121 }
1122 }
1123
1124
1170 func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
1171 if c.ctxt.Flag_maymorestack != "" {
1172 if c.ctxt.Flag_shared || c.ctxt.Flag_dynlink {
1173
1174
1175 c.ctxt.Diag("maymorestack with -shared or -dynlink is not supported")
1176 }
1177
1178
1179
1180 p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
1181
1182
1183 frameSize := 8 + c.ctxt.Arch.FixedFrameSize
1184
1185
1186 p = obj.Appendp(p, c.newprog)
1187 p.As = AMOVD
1188 p.From.Type = obj.TYPE_REG
1189 p.From.Reg = REG_LR
1190 p.To.Type = obj.TYPE_REG
1191 p.To.Reg = REGTMP
1192
1193 p = obj.Appendp(p, c.newprog)
1194 p.As = AMOVDU
1195 p.From.Type = obj.TYPE_REG
1196 p.From.Reg = REGTMP
1197 p.To.Type = obj.TYPE_MEM
1198 p.To.Offset = -frameSize
1199 p.To.Reg = REGSP
1200 p.Spadj = int32(frameSize)
1201
1202
1203 p = obj.Appendp(p, c.newprog)
1204 p.As = AMOVD
1205 p.From.Type = obj.TYPE_REG
1206 p.From.Reg = REGCTXT
1207 p.To.Type = obj.TYPE_MEM
1208 p.To.Offset = 8
1209 p.To.Reg = REGSP
1210
1211
1212 p = obj.Appendp(p, c.newprog)
1213 p.As = ABL
1214 p.To.Type = obj.TYPE_BRANCH
1215
1216 p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
1217
1218
1219
1220
1221 p = obj.Appendp(p, c.newprog)
1222 p.As = AMOVD
1223 p.From.Type = obj.TYPE_MEM
1224 p.From.Offset = 8
1225 p.From.Reg = REGSP
1226 p.To.Type = obj.TYPE_REG
1227 p.To.Reg = REGCTXT
1228
1229
1230 p = obj.Appendp(p, c.newprog)
1231 p.As = AMOVD
1232 p.From.Type = obj.TYPE_MEM
1233 p.From.Offset = 0
1234 p.From.Reg = REGSP
1235 p.To.Type = obj.TYPE_REG
1236 p.To.Reg = REGTMP
1237
1238
1239 p = obj.Appendp(p, c.newprog)
1240 p.As = AMOVD
1241 p.From.Type = obj.TYPE_REG
1242 p.From.Reg = REGTMP
1243 p.To.Type = obj.TYPE_REG
1244 p.To.Reg = REG_LR
1245
1246
1247 p = obj.Appendp(p, c.newprog)
1248 p.As = AADD
1249 p.From.Type = obj.TYPE_CONST
1250 p.From.Offset = frameSize
1251 p.To.Type = obj.TYPE_REG
1252 p.To.Reg = REGSP
1253 p.Spadj = -int32(frameSize)
1254
1255
1256 p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
1257 }
1258
1259
1260 startPred := p
1261
1262
1263 p = obj.Appendp(p, c.newprog)
1264
1265 p.As = AMOVD
1266 p.From.Type = obj.TYPE_MEM
1267 p.From.Reg = REGG
1268 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
1269 if c.cursym.CFunc() {
1270 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
1271 }
1272 p.To.Type = obj.TYPE_REG
1273 p.To.Reg = REG_R22
1274
1275
1276
1277
1278
1279 p = c.ctxt.StartUnsafePoint(p, c.newprog)
1280
1281 var q *obj.Prog
1282 if framesize <= abi.StackSmall {
1283
1284
1285 p = obj.Appendp(p, c.newprog)
1286
1287 p.As = ACMPU
1288 p.From.Type = obj.TYPE_REG
1289 p.From.Reg = REG_R22
1290 p.To.Type = obj.TYPE_REG
1291 p.To.Reg = REGSP
1292 } else {
1293
1294 offset := int64(framesize) - abi.StackSmall
1295 if framesize > abi.StackBig {
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305 if offset <= 0xffff {
1306 p = obj.Appendp(p, c.newprog)
1307 p.As = ACMPU
1308 p.From.Type = obj.TYPE_REG
1309 p.From.Reg = REGSP
1310 p.To.Type = obj.TYPE_CONST
1311 p.To.Offset = offset
1312 } else {
1313
1314 p = obj.Appendp(p, c.newprog)
1315 p.As = AMOVD
1316 p.From.Type = obj.TYPE_CONST
1317 p.From.Offset = offset
1318 p.To.Type = obj.TYPE_REG
1319 p.To.Reg = REG_R23
1320
1321 p = obj.Appendp(p, c.newprog)
1322 p.As = ACMPU
1323 p.From.Type = obj.TYPE_REG
1324 p.From.Reg = REGSP
1325 p.To.Type = obj.TYPE_REG
1326 p.To.Reg = REG_R23
1327 }
1328
1329 p = obj.Appendp(p, c.newprog)
1330 q = p
1331 p.As = ABLT
1332 p.To.Type = obj.TYPE_BRANCH
1333 }
1334
1335
1336
1337
1338 p = obj.Appendp(p, c.newprog)
1339
1340 p.As = AADD
1341 p.From.Type = obj.TYPE_CONST
1342 p.From.Offset = -offset
1343 p.Reg = REGSP
1344 p.To.Type = obj.TYPE_REG
1345 p.To.Reg = REG_R23
1346
1347 p = obj.Appendp(p, c.newprog)
1348 p.As = ACMPU
1349 p.From.Type = obj.TYPE_REG
1350 p.From.Reg = REG_R22
1351 p.To.Type = obj.TYPE_REG
1352 p.To.Reg = REG_R23
1353 }
1354
1355
1356 p = obj.Appendp(p, c.newprog)
1357 q1 := p
1358
1359 p.As = ABLT
1360 p.To.Type = obj.TYPE_BRANCH
1361
1362 p = obj.Appendp(p, c.newprog)
1363 p.As = obj.ANOP
1364
1365 if q != nil {
1366 q.To.SetTarget(p)
1367 }
1368
1369
1370
1371
1372 spill := c.cursym.Func().SpillRegisterArgs(p, c.newprog)
1373
1374
1375 p = obj.Appendp(spill, c.newprog)
1376 p.As = AMOVD
1377 p.From.Type = obj.TYPE_REG
1378 p.From.Reg = REG_LR
1379 p.To.Type = obj.TYPE_REG
1380 p.To.Reg = REG_R5
1381
1382 p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
1383
1384 var morestacksym *obj.LSym
1385 if c.cursym.CFunc() {
1386 morestacksym = c.ctxt.Lookup("runtime.morestackc")
1387 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
1388 morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt")
1389 } else {
1390 morestacksym = c.ctxt.Lookup("runtime.morestack")
1391 }
1392
1393 if NeedTOCpointer(c.ctxt) {
1394
1395
1396
1397
1398
1399
1400
1401 p = obj.Appendp(p, c.newprog)
1402 p.As = AMOVD
1403 p.From.Type = obj.TYPE_REG
1404 p.From.Reg = REG_R2
1405 p.To.Type = obj.TYPE_MEM
1406 p.To.Reg = REGSP
1407 p.To.Offset = 8
1408 }
1409
1410 if c.ctxt.Flag_dynlink {
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426 p = obj.Appendp(p, c.newprog)
1427 p.As = AMOVD
1428 p.From.Type = obj.TYPE_MEM
1429 p.From.Sym = morestacksym
1430 p.From.Name = obj.NAME_GOTREF
1431 p.To.Type = obj.TYPE_REG
1432 p.To.Reg = REG_R12
1433
1434
1435 p = obj.Appendp(p, c.newprog)
1436 p.As = AMOVD
1437 p.From.Type = obj.TYPE_REG
1438 p.From.Reg = REG_R12
1439 p.To.Type = obj.TYPE_REG
1440 p.To.Reg = REG_LR
1441
1442
1443 p = obj.Appendp(p, c.newprog)
1444 p.As = obj.ACALL
1445 p.To.Type = obj.TYPE_REG
1446 p.To.Reg = REG_LR
1447 } else {
1448
1449 p = obj.Appendp(p, c.newprog)
1450
1451 p.As = ABL
1452 p.To.Type = obj.TYPE_BRANCH
1453 p.To.Sym = morestacksym
1454 }
1455
1456 if NeedTOCpointer(c.ctxt) {
1457
1458 p = obj.Appendp(p, c.newprog)
1459 p.As = AMOVD
1460 p.From.Type = obj.TYPE_MEM
1461 p.From.Reg = REGSP
1462 p.From.Offset = 8
1463 p.To.Type = obj.TYPE_REG
1464 p.To.Reg = REG_R2
1465 }
1466
1467
1468 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
1469 unspill := c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
1470
1471
1472 p = obj.Appendp(unspill, c.newprog)
1473 p.As = ABR
1474 p.To.Type = obj.TYPE_BRANCH
1475 p.To.SetTarget(startPred.Link)
1476
1477
1478 p = obj.Appendp(p, c.newprog)
1479
1480 p.As = obj.ANOP
1481 q1.To.SetTarget(p)
1482
1483 return p
1484 }
1485
1486
1487
1488
1489
1490 var unaryDst = map[obj.As]bool{
1491 AXXSETACCZ: true,
1492 AXXMTACC: true,
1493 AXXMFACC: true,
1494 }
1495
1496 var Linkppc64 = obj.LinkArch{
1497 Arch: sys.ArchPPC64,
1498 Init: buildop,
1499 Preprocess: preprocess,
1500 Assemble: span9,
1501 Progedit: progedit,
1502 UnaryDst: unaryDst,
1503 DWARFRegisters: PPC64DWARFRegisters,
1504 }
1505
1506 var Linkppc64le = obj.LinkArch{
1507 Arch: sys.ArchPPC64LE,
1508 Init: buildop,
1509 Preprocess: preprocess,
1510 Assemble: span9,
1511 Progedit: progedit,
1512 UnaryDst: unaryDst,
1513 DWARFRegisters: PPC64DWARFRegisters,
1514 }
1515
View as plain text