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