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