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