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 var p1 *obj.Prog
810 var p2 *obj.Prog
811 for p := c.cursym.Func().Text; p != nil; p = p.Link {
812 o := p.As
813 switch o {
814 case obj.ATEXT:
815 autosize = int32(textstksiz)
816
817 if p.Mark&LEAF != 0 && autosize == 0 {
818
819 p.From.Sym.Set(obj.AttrNoFrame, true)
820 }
821
822 if !p.From.Sym.NoFrame() {
823
824
825 autosize += int32(c.ctxt.Arch.FixedFrameSize)
826 }
827
828 if p.Mark&LEAF != 0 && autosize < abi.StackSmall {
829
830
831 p.From.Sym.Set(obj.AttrNoSplit, true)
832 }
833
834 p.To.Offset = int64(autosize)
835
836 q = p
837
838 if NeedTOCpointer(c.ctxt) && !isNOTOCfunc(c.cursym.Name) {
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860 q = obj.Appendp(q, c.newprog)
861 q.As = AWORD
862 q.Pos = p.Pos
863 q.From.Type = obj.TYPE_CONST
864 q.From.Offset = 0x3c4c0000
865 q = obj.Appendp(q, c.newprog)
866 q.As = AWORD
867 q.Pos = p.Pos
868 q.From.Type = obj.TYPE_CONST
869 q.From.Offset = 0x38420000
870 c.cursym.AddRel(c.ctxt, obj.Reloc{
871 Type: objabi.R_ADDRPOWER_PCREL,
872 Off: 0,
873 Siz: 8,
874 Sym: c.ctxt.Lookup(".TOC."),
875 })
876 }
877
878 if !c.cursym.Func().Text.From.Sym.NoSplit() {
879 q = c.stacksplit(q, autosize)
880 }
881
882 if autosize != 0 {
883 var prologueEnd *obj.Prog
884
885
886
887 if autosize >= -BIG && autosize <= BIG {
888
889 q = obj.Appendp(q, c.newprog)
890 q.As = AMOVD
891 q.Pos = p.Pos
892 q.From.Type = obj.TYPE_REG
893 q.From.Reg = REG_LR
894 q.To.Type = obj.TYPE_REG
895 q.To.Reg = REGTMP
896 prologueEnd = q
897
898 q = obj.Appendp(q, c.newprog)
899 q.As = AMOVDU
900 q.Pos = p.Pos
901 q.From.Type = obj.TYPE_REG
902 q.From.Reg = REGTMP
903 q.To.Type = obj.TYPE_MEM
904 q.To.Offset = int64(-autosize)
905 q.To.Reg = REGSP
906 q.Spadj = autosize
907 } else {
908
909
910
911
912
913
914 q = obj.Appendp(q, c.newprog)
915 q.As = AMOVD
916 q.Pos = p.Pos
917 q.From.Type = obj.TYPE_REG
918 q.From.Reg = REG_LR
919 q.To.Type = obj.TYPE_REG
920 q.To.Reg = REG_R29
921
922 q = c.ctxt.StartUnsafePoint(q, c.newprog)
923
924 q = obj.Appendp(q, c.newprog)
925 q.As = AMOVD
926 q.Pos = p.Pos
927 q.From.Type = obj.TYPE_REG
928 q.From.Reg = REG_R29
929 q.To.Type = obj.TYPE_MEM
930 q.To.Offset = int64(-autosize)
931 q.To.Reg = REGSP
932
933 prologueEnd = q
934
935 q = obj.Appendp(q, c.newprog)
936 q.As = AADD
937 q.Pos = p.Pos
938 q.From.Type = obj.TYPE_CONST
939 q.From.Offset = int64(-autosize)
940 q.To.Type = obj.TYPE_REG
941 q.To.Reg = REGSP
942 q.Spadj = +autosize
943
944 q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
945 }
946 prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
947 } else if c.cursym.Func().Text.Mark&LEAF == 0 {
948
949
950
951 c.cursym.Func().Text.Mark |= LEAF
952 }
953
954 if c.cursym.Func().Text.Mark&LEAF != 0 {
955 c.cursym.Set(obj.AttrLeaf, true)
956 break
957 }
958
959 if NeedTOCpointer(c.ctxt) {
960 q = obj.Appendp(q, c.newprog)
961 q.As = AMOVD
962 q.Pos = p.Pos
963 q.From.Type = obj.TYPE_REG
964 q.From.Reg = REG_R2
965 q.To.Type = obj.TYPE_MEM
966 q.To.Reg = REGSP
967 q.To.Offset = 24
968 }
969
970 if c.cursym.Func().Text.From.Sym.Wrapper() {
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988 q = obj.Appendp(q, c.newprog)
989
990 q.As = AMOVD
991 q.From.Type = obj.TYPE_MEM
992 q.From.Reg = REGG
993 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize)
994 q.To.Type = obj.TYPE_REG
995 q.To.Reg = REG_R22
996
997 q = obj.Appendp(q, c.newprog)
998 q.As = ACMP
999 q.From.Type = obj.TYPE_REG
1000 q.From.Reg = REG_R22
1001 q.To.Type = obj.TYPE_CONST
1002 q.To.Offset = 0
1003
1004 q = obj.Appendp(q, c.newprog)
1005 q.As = ABEQ
1006 q.To.Type = obj.TYPE_BRANCH
1007 p1 = q
1008
1009 q = obj.Appendp(q, c.newprog)
1010 q.As = AMOVD
1011 q.From.Type = obj.TYPE_MEM
1012 q.From.Reg = REG_R22
1013 q.From.Offset = 0
1014 q.To.Type = obj.TYPE_REG
1015 q.To.Reg = REG_R23
1016
1017 q = obj.Appendp(q, c.newprog)
1018 q.As = AADD
1019 q.From.Type = obj.TYPE_CONST
1020 q.From.Offset = int64(autosize) + c.ctxt.Arch.FixedFrameSize
1021 q.Reg = REGSP
1022 q.To.Type = obj.TYPE_REG
1023 q.To.Reg = REG_R24
1024
1025 q = obj.Appendp(q, c.newprog)
1026 q.As = ACMP
1027 q.From.Type = obj.TYPE_REG
1028 q.From.Reg = REG_R23
1029 q.To.Type = obj.TYPE_REG
1030 q.To.Reg = REG_R24
1031
1032 q = obj.Appendp(q, c.newprog)
1033 q.As = ABNE
1034 q.To.Type = obj.TYPE_BRANCH
1035 p2 = q
1036
1037 q = obj.Appendp(q, c.newprog)
1038 q.As = AADD
1039 q.From.Type = obj.TYPE_CONST
1040 q.From.Offset = c.ctxt.Arch.FixedFrameSize
1041 q.Reg = REGSP
1042 q.To.Type = obj.TYPE_REG
1043 q.To.Reg = REG_R25
1044
1045 q = obj.Appendp(q, c.newprog)
1046 q.As = AMOVD
1047 q.From.Type = obj.TYPE_REG
1048 q.From.Reg = REG_R25
1049 q.To.Type = obj.TYPE_MEM
1050 q.To.Reg = REG_R22
1051 q.To.Offset = 0
1052
1053 q = obj.Appendp(q, c.newprog)
1054
1055 q.As = obj.ANOP
1056 p1.To.SetTarget(q)
1057 p2.To.SetTarget(q)
1058 }
1059
1060 case obj.ARET:
1061 if p.From.Type == obj.TYPE_CONST {
1062 c.ctxt.Diag("using BECOME (%v) is not supported!", p)
1063 break
1064 }
1065
1066 retTarget := p.To.Sym
1067
1068 if c.cursym.Func().Text.Mark&LEAF != 0 {
1069 if autosize == 0 {
1070 p.As = ABR
1071 p.From = obj.Addr{}
1072 if retTarget == nil {
1073 p.To.Type = obj.TYPE_REG
1074 p.To.Reg = REG_LR
1075 } else {
1076 p.To.Type = obj.TYPE_BRANCH
1077 p.To.Sym = retTarget
1078 }
1079 p.Mark |= BRANCH
1080 break
1081 }
1082
1083 p.As = AADD
1084 p.From.Type = obj.TYPE_CONST
1085 p.From.Offset = int64(autosize)
1086 p.To.Type = obj.TYPE_REG
1087 p.To.Reg = REGSP
1088 p.Spadj = -autosize
1089
1090 q = c.newprog()
1091 q.As = ABR
1092 q.Pos = p.Pos
1093 if retTarget == nil {
1094 q.To.Type = obj.TYPE_REG
1095 q.To.Reg = REG_LR
1096 } else {
1097 q.To.Type = obj.TYPE_BRANCH
1098 q.To.Sym = retTarget
1099 }
1100 q.Mark |= BRANCH
1101 q.Spadj = +autosize
1102
1103 q.Link = p.Link
1104 p.Link = q
1105 break
1106 }
1107
1108 p.As = AMOVD
1109 p.From.Type = obj.TYPE_MEM
1110 p.From.Offset = 0
1111 p.From.Reg = REGSP
1112 p.To.Type = obj.TYPE_REG
1113 p.To.Reg = REGTMP
1114
1115 q = c.newprog()
1116 q.As = AMOVD
1117 q.Pos = p.Pos
1118 q.From.Type = obj.TYPE_REG
1119 q.From.Reg = REGTMP
1120 q.To.Type = obj.TYPE_REG
1121 q.To.Reg = REG_LR
1122
1123 q.Link = p.Link
1124 p.Link = q
1125 p = q
1126
1127 if false {
1128
1129 q = c.newprog()
1130
1131 q.As = AMOVD
1132 q.Pos = p.Pos
1133 q.From.Type = obj.TYPE_MEM
1134 q.From.Offset = 0
1135 q.From.Reg = REGTMP
1136 q.To.Type = obj.TYPE_REG
1137 q.To.Reg = REGTMP
1138
1139 q.Link = p.Link
1140 p.Link = q
1141 p = q
1142 }
1143 prev := p
1144 if autosize != 0 {
1145 q = c.newprog()
1146 q.As = AADD
1147 q.Pos = p.Pos
1148 q.From.Type = obj.TYPE_CONST
1149 q.From.Offset = int64(autosize)
1150 q.To.Type = obj.TYPE_REG
1151 q.To.Reg = REGSP
1152 q.Spadj = -autosize
1153
1154 q.Link = p.Link
1155 prev.Link = q
1156 prev = q
1157 }
1158
1159 q1 = c.newprog()
1160 q1.As = ABR
1161 q1.Pos = p.Pos
1162 if retTarget == nil {
1163 q1.To.Type = obj.TYPE_REG
1164 q1.To.Reg = REG_LR
1165 } else {
1166 q1.To.Type = obj.TYPE_BRANCH
1167 q1.To.Sym = retTarget
1168 }
1169 q1.Mark |= BRANCH
1170 q1.Spadj = +autosize
1171
1172 q1.Link = q.Link
1173 prev.Link = q1
1174 case AADD:
1175 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
1176 p.Spadj = int32(-p.From.Offset)
1177 }
1178 case AMOVDU:
1179 if p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
1180 p.Spadj = int32(-p.To.Offset)
1181 }
1182 if p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP {
1183 p.Spadj = int32(-p.From.Offset)
1184 }
1185 case obj.AGETCALLERPC:
1186 if cursym.Leaf() {
1187
1188 p.As = AMOVD
1189 p.From.Type = obj.TYPE_REG
1190 p.From.Reg = REG_LR
1191 } else {
1192
1193 p.As = AMOVD
1194 p.From.Type = obj.TYPE_MEM
1195 p.From.Reg = REGSP
1196 }
1197 }
1198
1199 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 && p.As != ACMPU {
1200 f := c.cursym.Func()
1201 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
1202 c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
1203 if ctxt.Debugvlog || !ctxt.IsAsm {
1204 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
1205 if !ctxt.IsAsm {
1206 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
1207 ctxt.DiagFlush()
1208 log.Fatalf("bad SPWRITE")
1209 }
1210 }
1211 }
1212 }
1213 }
1214 }
1215
1216
1262 func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
1263 if c.ctxt.Flag_maymorestack != "" {
1264 if c.ctxt.Flag_shared || c.ctxt.Flag_dynlink {
1265
1266
1267 c.ctxt.Diag("maymorestack with -shared or -dynlink is not supported")
1268 }
1269
1270
1271
1272 p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
1273
1274
1275 frameSize := 8 + c.ctxt.Arch.FixedFrameSize
1276
1277
1278 p = obj.Appendp(p, c.newprog)
1279 p.As = AMOVD
1280 p.From.Type = obj.TYPE_REG
1281 p.From.Reg = REG_LR
1282 p.To.Type = obj.TYPE_REG
1283 p.To.Reg = REGTMP
1284
1285 p = obj.Appendp(p, c.newprog)
1286 p.As = AMOVDU
1287 p.From.Type = obj.TYPE_REG
1288 p.From.Reg = REGTMP
1289 p.To.Type = obj.TYPE_MEM
1290 p.To.Offset = -frameSize
1291 p.To.Reg = REGSP
1292 p.Spadj = int32(frameSize)
1293
1294
1295 p = obj.Appendp(p, c.newprog)
1296 p.As = AMOVD
1297 p.From.Type = obj.TYPE_REG
1298 p.From.Reg = REGCTXT
1299 p.To.Type = obj.TYPE_MEM
1300 p.To.Offset = 8
1301 p.To.Reg = REGSP
1302
1303
1304 p = obj.Appendp(p, c.newprog)
1305 p.As = ABL
1306 p.To.Type = obj.TYPE_BRANCH
1307
1308 p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
1309
1310
1311
1312
1313 p = obj.Appendp(p, c.newprog)
1314 p.As = AMOVD
1315 p.From.Type = obj.TYPE_MEM
1316 p.From.Offset = 8
1317 p.From.Reg = REGSP
1318 p.To.Type = obj.TYPE_REG
1319 p.To.Reg = REGCTXT
1320
1321
1322 p = obj.Appendp(p, c.newprog)
1323 p.As = AMOVD
1324 p.From.Type = obj.TYPE_MEM
1325 p.From.Offset = 0
1326 p.From.Reg = REGSP
1327 p.To.Type = obj.TYPE_REG
1328 p.To.Reg = REGTMP
1329
1330
1331 p = obj.Appendp(p, c.newprog)
1332 p.As = AMOVD
1333 p.From.Type = obj.TYPE_REG
1334 p.From.Reg = REGTMP
1335 p.To.Type = obj.TYPE_REG
1336 p.To.Reg = REG_LR
1337
1338
1339 p = obj.Appendp(p, c.newprog)
1340 p.As = AADD
1341 p.From.Type = obj.TYPE_CONST
1342 p.From.Offset = frameSize
1343 p.To.Type = obj.TYPE_REG
1344 p.To.Reg = REGSP
1345 p.Spadj = -int32(frameSize)
1346
1347
1348 p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
1349 }
1350
1351
1352 startPred := p
1353
1354
1355 p = obj.Appendp(p, c.newprog)
1356
1357 p.As = AMOVD
1358 p.From.Type = obj.TYPE_MEM
1359 p.From.Reg = REGG
1360 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
1361 if c.cursym.CFunc() {
1362 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
1363 }
1364 p.To.Type = obj.TYPE_REG
1365 p.To.Reg = REG_R22
1366
1367
1368
1369
1370
1371 p = c.ctxt.StartUnsafePoint(p, c.newprog)
1372
1373 var q *obj.Prog
1374 if framesize <= abi.StackSmall {
1375
1376
1377 p = obj.Appendp(p, c.newprog)
1378
1379 p.As = ACMPU
1380 p.From.Type = obj.TYPE_REG
1381 p.From.Reg = REG_R22
1382 p.To.Type = obj.TYPE_REG
1383 p.To.Reg = REGSP
1384 } else {
1385
1386 offset := int64(framesize) - abi.StackSmall
1387 if framesize > abi.StackBig {
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397 if offset <= 0xffff {
1398 p = obj.Appendp(p, c.newprog)
1399 p.As = ACMPU
1400 p.From.Type = obj.TYPE_REG
1401 p.From.Reg = REGSP
1402 p.To.Type = obj.TYPE_CONST
1403 p.To.Offset = offset
1404 } else {
1405
1406 p = obj.Appendp(p, c.newprog)
1407 p.As = AMOVD
1408 p.From.Type = obj.TYPE_CONST
1409 p.From.Offset = offset
1410 p.To.Type = obj.TYPE_REG
1411 p.To.Reg = REG_R23
1412
1413 p = obj.Appendp(p, c.newprog)
1414 p.As = ACMPU
1415 p.From.Type = obj.TYPE_REG
1416 p.From.Reg = REGSP
1417 p.To.Type = obj.TYPE_REG
1418 p.To.Reg = REG_R23
1419 }
1420
1421 p = obj.Appendp(p, c.newprog)
1422 q = p
1423 p.As = ABLT
1424 p.To.Type = obj.TYPE_BRANCH
1425 }
1426
1427
1428
1429
1430 p = obj.Appendp(p, c.newprog)
1431
1432 p.As = AADD
1433 p.From.Type = obj.TYPE_CONST
1434 p.From.Offset = -offset
1435 p.Reg = REGSP
1436 p.To.Type = obj.TYPE_REG
1437 p.To.Reg = REG_R23
1438
1439 p = obj.Appendp(p, c.newprog)
1440 p.As = ACMPU
1441 p.From.Type = obj.TYPE_REG
1442 p.From.Reg = REG_R22
1443 p.To.Type = obj.TYPE_REG
1444 p.To.Reg = REG_R23
1445 }
1446
1447
1448 p = obj.Appendp(p, c.newprog)
1449 q1 := p
1450
1451 p.As = ABLT
1452 p.To.Type = obj.TYPE_BRANCH
1453
1454 p = obj.Appendp(p, c.newprog)
1455 p.As = obj.ANOP
1456
1457 if q != nil {
1458 q.To.SetTarget(p)
1459 }
1460
1461
1462
1463
1464 spill := c.cursym.Func().SpillRegisterArgs(p, c.newprog)
1465
1466
1467 p = obj.Appendp(spill, c.newprog)
1468 p.As = AMOVD
1469 p.From.Type = obj.TYPE_REG
1470 p.From.Reg = REG_LR
1471 p.To.Type = obj.TYPE_REG
1472 p.To.Reg = REG_R5
1473
1474 p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
1475
1476 var morestacksym *obj.LSym
1477 if c.cursym.CFunc() {
1478 morestacksym = c.ctxt.Lookup("runtime.morestackc")
1479 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
1480 morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt")
1481 } else {
1482 morestacksym = c.ctxt.Lookup("runtime.morestack")
1483 }
1484
1485 if NeedTOCpointer(c.ctxt) {
1486
1487
1488
1489
1490
1491
1492
1493 p = obj.Appendp(p, c.newprog)
1494 p.As = AMOVD
1495 p.From.Type = obj.TYPE_REG
1496 p.From.Reg = REG_R2
1497 p.To.Type = obj.TYPE_MEM
1498 p.To.Reg = REGSP
1499 p.To.Offset = 8
1500 }
1501
1502 if c.ctxt.Flag_dynlink {
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518 p = obj.Appendp(p, c.newprog)
1519 p.As = AMOVD
1520 p.From.Type = obj.TYPE_MEM
1521 p.From.Sym = morestacksym
1522 p.From.Name = obj.NAME_GOTREF
1523 p.To.Type = obj.TYPE_REG
1524 p.To.Reg = REG_R12
1525
1526
1527 p = obj.Appendp(p, c.newprog)
1528 p.As = AMOVD
1529 p.From.Type = obj.TYPE_REG
1530 p.From.Reg = REG_R12
1531 p.To.Type = obj.TYPE_REG
1532 p.To.Reg = REG_LR
1533
1534
1535 p = obj.Appendp(p, c.newprog)
1536 p.As = obj.ACALL
1537 p.To.Type = obj.TYPE_REG
1538 p.To.Reg = REG_LR
1539 } else {
1540
1541 p = obj.Appendp(p, c.newprog)
1542
1543 p.As = ABL
1544 p.To.Type = obj.TYPE_BRANCH
1545 p.To.Sym = morestacksym
1546 }
1547
1548 if NeedTOCpointer(c.ctxt) {
1549
1550 p = obj.Appendp(p, c.newprog)
1551 p.As = AMOVD
1552 p.From.Type = obj.TYPE_MEM
1553 p.From.Reg = REGSP
1554 p.From.Offset = 8
1555 p.To.Type = obj.TYPE_REG
1556 p.To.Reg = REG_R2
1557 }
1558
1559
1560 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
1561 unspill := c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
1562
1563
1564 p = obj.Appendp(unspill, c.newprog)
1565 p.As = ABR
1566 p.To.Type = obj.TYPE_BRANCH
1567 p.To.SetTarget(startPred.Link)
1568
1569
1570 p = obj.Appendp(p, c.newprog)
1571
1572 p.As = obj.ANOP
1573 q1.To.SetTarget(p)
1574
1575 return p
1576 }
1577
1578
1579
1580
1581
1582 var unaryDst = map[obj.As]bool{
1583 AXXSETACCZ: true,
1584 AXXMTACC: true,
1585 AXXMFACC: true,
1586 }
1587
1588 var Linkppc64 = obj.LinkArch{
1589 Arch: sys.ArchPPC64,
1590 Init: buildop,
1591 Preprocess: preprocess,
1592 Assemble: span9,
1593 Progedit: progedit,
1594 UnaryDst: unaryDst,
1595 DWARFRegisters: PPC64DWARFRegisters,
1596 }
1597
1598 var Linkppc64le = obj.LinkArch{
1599 Arch: sys.ArchPPC64LE,
1600 Init: buildop,
1601 Preprocess: preprocess,
1602 Assemble: span9,
1603 Progedit: progedit,
1604 UnaryDst: unaryDst,
1605 DWARFRegisters: PPC64DWARFRegisters,
1606 }
1607
View as plain text