1 // cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
3 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
4 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
5 // Portions Copyright © 1997-1999 Vita Nuova Limited
6 // Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
7 // Portions Copyright © 2004,2006 Bruce Ellis
8 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
9 // Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
10 // Portions Copyright © 2009 The Go Authors. All rights reserved.
12 // Permission is hereby granted, free of charge, to any person obtaining a copy
13 // of this software and associated documentation files (the "Software"), to deal
14 // in the Software without restriction, including without limitation the rights
15 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 // copies of the Software, and to permit persons to whom the Software is
17 // furnished to do so, subject to the following conditions:
19 // The above copyright notice and this permission notice shall be included in
20 // all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42 // Test if this value can encoded as a mask for
43 // li -1, rx; rlic rx,rx,sh,mb.
44 // Masks can also extend from the msb and wrap to
45 // the lsb too. That is, the valid masks are 32 bit strings
46 // of the form: 0..01..10..0 or 1..10..01..1 or 1...1
47 func isPPC64DoublewordRotateMask(v64 int64) bool {
48 // Isolate rightmost 1 (if none 0) and add.
51 // Likewise, for the wrapping case.
53 vpn := (vn & -vn) + vn
54 return (v&vp == 0 || vn&vpn == 0) && v != 0
57 // Encode a doubleword rotate mask into mb (mask begin) and
58 // me (mask end, inclusive). Note, POWER ISA labels bits in
60 func encodePPC64RLDCMask(mask int64) (mb, me int) {
61 // Determine boundaries and then decode them
62 mb = bits.LeadingZeros64(uint64(mask))
63 me = 64 - bits.TrailingZeros64(uint64(mask))
64 mbn := bits.LeadingZeros64(^uint64(mask))
65 men := 64 - bits.TrailingZeros64(^uint64(mask))
66 // Check for a wrapping mask (e.g bits at 0 and 63)
67 if mb == 0 && me == 64 {
68 // swap the inverted values
71 // Note, me is inclusive.
75 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
79 c := ctxt9{ctxt: ctxt, newprog: newprog}
81 // Rewrite BR/BL to symbol as TYPE_BRANCH.
89 p.To.Type = obj.TYPE_BRANCH
93 // Rewrite float constants to values stored in memory.
96 if p.From.Type == obj.TYPE_FCONST {
97 f32 := float32(p.From.Val.(float64))
98 p.From.Type = obj.TYPE_MEM
99 p.From.Sym = ctxt.Float32Sym(f32)
100 p.From.Name = obj.NAME_EXTERN
105 if p.From.Type == obj.TYPE_FCONST {
106 f64 := p.From.Val.(float64)
107 // Constant not needed in memory for float +/- 0
109 p.From.Type = obj.TYPE_MEM
110 p.From.Sym = ctxt.Float64Sym(f64)
111 p.From.Name = obj.NAME_EXTERN
117 // 32b constants (signed and unsigned) can be generated via 1 or 2 instructions. They can be assembled directly.
118 isS32 := int64(int32(p.From.Offset)) == p.From.Offset
119 isU32 := uint64(uint32(p.From.Offset)) == uint64(p.From.Offset)
121 // If prefixed instructions are supported, a 34b signed constant can be generated by one pli instruction.
122 isS34 := pfxEnabled && (p.From.Offset<<30)>>30 == p.From.Offset
123 if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && !isS32 && !isU32 && !isS34 {
125 // Is this a shifted 16b constant? If so, rewrite it to avoid a creating and loading a constant.
127 shift := bits.TrailingZeros64(uint64(val))
128 mask := 0xFFFF << shift
129 if val&int64(mask) == val || (val>>(shift+16) == -1 && (val>>shift)<<shift == val) {
130 // Rewrite this value into MOVD $const>>shift, Rto; SLD $shift, Rto
131 q := obj.Appendp(p, c.newprog)
133 q.From.SetConst(int64(shift))
135 p.From.Offset >>= shift
137 // Is this constant a mask value? If so, generate MOVD $-1, Rto; RLDIC Rto, ^me, mb, Rto
138 } else if isPPC64DoublewordRotateMask(val) {
139 mb, me := encodePPC64RLDCMask(val)
140 q := obj.Appendp(p, c.newprog)
142 q.AddRestSourceConst((^int64(me)) & 0x3F)
143 q.AddRestSourceConst(int64(mb))
149 // Load the constant from memory.
150 p.From.Type = obj.TYPE_MEM
151 p.From.Sym = ctxt.Int64Sym(p.From.Offset)
152 p.From.Name = obj.NAME_EXTERN
159 // Rewrite SUB constants into ADD.
161 if p.From.Type == obj.TYPE_CONST {
162 p.From.Offset = -p.From.Offset
167 if p.From.Type == obj.TYPE_CONST {
168 p.From.Offset = -p.From.Offset
173 if p.From.Type == obj.TYPE_CONST {
174 p.From.Offset = -p.From.Offset
178 // To maintain backwards compatibility, we accept some 4 argument usage of
179 // several opcodes which was likely not intended, but did work. These are not
180 // added to optab to avoid the chance this behavior might be used with newer
183 // Rewrite argument ordering like "ADDEX R3, $3, R4, R5" into
184 // "ADDEX R3, R4, $3, R5"
185 case AVSHASIGMAW, AVSHASIGMAD, AADDEX, AXXSLDWI, AXXPERMDI:
186 if len(p.RestArgs) == 2 && p.Reg == 0 && p.RestArgs[0].Addr.Type == obj.TYPE_CONST && p.RestArgs[1].Addr.Type == obj.TYPE_REG {
187 p.Reg = p.RestArgs[1].Addr.Reg
188 p.RestArgs = p.RestArgs[:1]
192 if c.ctxt.Headtype == objabi.Haix {
194 } else if c.ctxt.Flag_dynlink {
199 // Rewrite p, if necessary, to access a symbol using its TOC anchor.
200 // This code is for AIX only.
201 func (c *ctxt9) rewriteToUseTOC(p *obj.Prog) {
202 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
206 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
207 // ADUFFZERO/ADUFFCOPY is considered as an ABL except in dynamic
208 // link where it should be an indirect call.
209 if !c.ctxt.Flag_dynlink {
214 // MOVD runtime.duffxxx@TOC, R12
219 if p.As == obj.ADUFFZERO {
220 sym = c.ctxt.Lookup("runtime.duffzero")
222 sym = c.ctxt.Lookup("runtime.duffcopy")
224 // Retrieve or create the TOC anchor.
225 symtoc := c.ctxt.LookupInit("TOC."+sym.Name, func(s *obj.LSym) {
226 s.Type = objabi.SDATA
227 s.Set(obj.AttrDuplicateOK, true)
228 s.Set(obj.AttrStatic, true)
229 c.ctxt.Data = append(c.ctxt.Data, s)
230 s.WriteAddr(c.ctxt, 0, 8, sym, 0)
233 offset := p.To.Offset
235 p.From.Type = obj.TYPE_MEM
236 p.From.Name = obj.NAME_TOCREF
238 p.To.Type = obj.TYPE_REG
240 p.To.Name = obj.NAME_NONE
243 p1 := obj.Appendp(p, c.newprog)
245 p1.From.Type = obj.TYPE_CONST
246 p1.From.Offset = offset
247 p1.To.Type = obj.TYPE_REG
249 p2 := obj.Appendp(p1, c.newprog)
251 p2.From.Type = obj.TYPE_REG
252 p2.From.Reg = REG_R12
253 p2.To.Type = obj.TYPE_REG
255 p3 := obj.Appendp(p2, c.newprog)
257 p3.To.Type = obj.TYPE_REG
262 if p.From.Name == obj.NAME_EXTERN || p.From.Name == obj.NAME_STATIC {
263 if p.From.Type == obj.TYPE_ADDR {
265 // ADWORD $sym doesn't need TOC anchor
269 c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v", p)
272 if p.To.Type != obj.TYPE_REG {
273 c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v", p)
276 } else if p.From.Type != obj.TYPE_MEM {
277 c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
282 } else if p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC {
283 if p.To.Type != obj.TYPE_MEM {
284 c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
288 c.ctxt.Diag("cannot handle symbols on both sides in %v", p)
297 if source.Sym == nil {
298 c.ctxt.Diag("do not know how to handle nil symbol in %v", p)
302 if source.Sym.Type == objabi.STLSBSS {
306 // Retrieve or create the TOC anchor.
307 symtoc := c.ctxt.LookupInit("TOC."+source.Sym.Name, func(s *obj.LSym) {
308 s.Type = objabi.SDATA
309 s.Set(obj.AttrDuplicateOK, true)
310 s.Set(obj.AttrStatic, true)
311 c.ctxt.Data = append(c.ctxt.Data, s)
312 s.WriteAddr(c.ctxt, 0, 8, source.Sym, 0)
315 if source.Type == obj.TYPE_ADDR {
316 // MOVD $sym, Rx becomes MOVD symtoc, Rx
317 // MOVD $sym+<off>, Rx becomes MOVD symtoc, Rx; ADD <off>, Rx
318 p.From.Type = obj.TYPE_MEM
320 p.From.Name = obj.NAME_TOCREF
322 if p.From.Offset != 0 {
323 q := obj.Appendp(p, c.newprog)
325 q.From.Type = obj.TYPE_CONST
326 q.From.Offset = p.From.Offset
334 // MOVx sym, Ry becomes MOVD symtoc, REGTMP; MOVx (REGTMP), Ry
335 // MOVx Ry, sym becomes MOVD symtoc, REGTMP; MOVx Ry, (REGTMP)
336 // An addition may be inserted between the two MOVs if there is an offset.
338 q := obj.Appendp(p, c.newprog)
340 q.From.Type = obj.TYPE_MEM
342 q.From.Name = obj.NAME_TOCREF
343 q.To.Type = obj.TYPE_REG
346 q = obj.Appendp(q, c.newprog)
350 if p.From.Name != obj.NAME_NONE {
351 q.From.Type = obj.TYPE_MEM
353 q.From.Name = obj.NAME_NONE
355 } else if p.To.Name != obj.NAME_NONE {
356 q.To.Type = obj.TYPE_MEM
358 q.To.Name = obj.NAME_NONE
361 c.ctxt.Diag("unreachable case in rewriteToUseTOC with %v", p)
367 // Rewrite p, if necessary, to access global data via the global offset table.
368 func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
369 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
372 // MOVD runtime.duffxxx@GOT, R12
377 if p.As == obj.ADUFFZERO {
378 sym = c.ctxt.LookupABI("runtime.duffzero", obj.ABIInternal)
380 sym = c.ctxt.LookupABI("runtime.duffcopy", obj.ABIInternal)
382 offset := p.To.Offset
384 p.From.Type = obj.TYPE_MEM
385 p.From.Name = obj.NAME_GOTREF
387 p.To.Type = obj.TYPE_REG
389 p.To.Name = obj.NAME_NONE
392 p1 := obj.Appendp(p, c.newprog)
394 p1.From.Type = obj.TYPE_CONST
395 p1.From.Offset = offset
396 p1.To.Type = obj.TYPE_REG
398 p2 := obj.Appendp(p1, c.newprog)
400 p2.From.Type = obj.TYPE_REG
401 p2.From.Reg = REG_R12
402 p2.To.Type = obj.TYPE_REG
404 p3 := obj.Appendp(p2, c.newprog)
406 p3.To.Type = obj.TYPE_REG
410 // We only care about global data: NAME_EXTERN means a global
411 // symbol in the Go sense, and p.Sym.Local is true for a few
412 // internally defined symbols.
413 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
414 // MOVD $sym, Rx becomes MOVD sym@GOT, Rx
415 // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx
417 c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
419 if p.To.Type != obj.TYPE_REG {
420 c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
422 p.From.Type = obj.TYPE_MEM
423 p.From.Name = obj.NAME_GOTREF
424 if p.From.Offset != 0 {
425 q := obj.Appendp(p, c.newprog)
427 q.From.Type = obj.TYPE_CONST
428 q.From.Offset = p.From.Offset
433 if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
434 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
437 // MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry
438 // MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVx Ry, (REGTMP)
439 // An addition may be inserted between the two MOVs if there is an offset.
440 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
441 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
442 c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
445 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
450 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
453 if source.Sym.Type == objabi.STLSBSS {
456 if source.Type != obj.TYPE_MEM {
457 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
459 p1 := obj.Appendp(p, c.newprog)
460 p2 := obj.Appendp(p1, c.newprog)
463 p1.From.Type = obj.TYPE_MEM
464 p1.From.Sym = source.Sym
465 p1.From.Name = obj.NAME_GOTREF
466 p1.To.Type = obj.TYPE_REG
472 if p.From.Name == obj.NAME_EXTERN {
474 p2.From.Name = obj.NAME_NONE
476 } else if p.To.Name == obj.NAME_EXTERN {
478 p2.To.Name = obj.NAME_NONE
486 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
487 // TODO(minux): add morestack short-cuts with small fixed frame-size.
488 if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
492 c := ctxt9{ctxt: ctxt, cursym: cursym, newprog: newprog}
494 p := c.cursym.Func().Text
495 textstksiz := p.To.Offset
496 if textstksiz == -8 {
497 // Compatibility hack.
498 p.From.Sym.Set(obj.AttrNoFrame, true)
501 if textstksiz%8 != 0 {
502 c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
504 if p.From.Sym.NoFrame() {
506 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
510 c.cursym.Func().Args = p.To.Val.(int32)
511 c.cursym.Func().Locals = int32(textstksiz)
514 * find leaf subroutines
516 * expand BECOME pseudo
521 for p := c.cursym.Func().Text; p != nil; p = p.Link {
523 /* too hard, just leave alone */
527 p.Mark |= LABEL | LEAF | SYNC
534 if p.To.Type == obj.TYPE_REG {
535 if p.To.Reg == REGZERO {
536 p.Mark |= LABEL | SYNC
571 p.Mark |= LABEL | SYNC
574 case AMOVW, AMOVWZ, AMOVD:
576 if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL {
577 p.Mark |= LABEL | SYNC
625 c.cursym.Func().Text.Mark &^= LEAF
642 // NOPs are not removed due to #40689.
644 if q1.Mark&LEAF == 0 {
658 p.Mark |= FCMP | FLOAT
669 // NOPs are not removed due to
682 for p := c.cursym.Func().Text; p != nil; p = p.Link {
686 autosize = int32(textstksiz)
688 if p.Mark&LEAF != 0 && autosize == 0 {
689 // A leaf function with no locals has no frame.
690 p.From.Sym.Set(obj.AttrNoFrame, true)
693 if !p.From.Sym.NoFrame() {
694 // If there is a stack frame at all, it includes
695 // space to save the LR.
696 autosize += int32(c.ctxt.Arch.FixedFrameSize)
699 if p.Mark&LEAF != 0 && autosize < abi.StackSmall {
700 // A leaf function with a small stack can be marked
701 // NOSPLIT, avoiding a stack check.
702 p.From.Sym.Set(obj.AttrNoSplit, true)
705 p.To.Offset = int64(autosize)
709 if NeedTOCpointer(c.ctxt) && c.cursym.Name != "runtime.duffzero" && c.cursym.Name != "runtime.duffcopy" {
710 // When compiling Go into PIC, without PCrel support, all functions must start
711 // with instructions to load the TOC pointer into r2:
713 // addis r2, r12, .TOC.-func@ha
714 // addi r2, r2, .TOC.-func@l+4
716 // We could probably skip this prologue in some situations
717 // but it's a bit subtle. However, it is both safe and
718 // necessary to leave the prologue off duffzero and
719 // duffcopy as we rely on being able to jump to a specific
720 // instruction offset for them.
722 // These are AWORDS because there is no (afaict) way to
723 // generate the addis instruction except as part of the
724 // load of a large constant, and in that case there is no
725 // way to use r12 as the source.
727 // Note that the same condition is tested in
728 // putelfsym in cmd/link/internal/ld/symtab.go
729 // where we set the st_other field to indicate
730 // the presence of these instructions.
731 q = obj.Appendp(q, c.newprog)
734 q.From.Type = obj.TYPE_CONST
735 q.From.Offset = 0x3c4c0000
736 q = obj.Appendp(q, c.newprog)
739 q.From.Type = obj.TYPE_CONST
740 q.From.Offset = 0x38420000
741 rel := obj.Addrel(c.cursym)
744 rel.Sym = c.ctxt.Lookup(".TOC.")
745 rel.Type = objabi.R_ADDRPOWER_PCREL
748 if !c.cursym.Func().Text.From.Sym.NoSplit() {
749 q = c.stacksplit(q, autosize) // emit split check
753 var prologueEnd *obj.Prog
754 // Save the link register and update the SP. MOVDU is used unless
755 // the frame size is too large. The link register must be saved
756 // even for non-empty leaf functions so that traceback works.
757 if autosize >= -BIG && autosize <= BIG {
758 // Use MOVDU to adjust R1 when saving R31, if autosize is small.
759 q = obj.Appendp(q, c.newprog)
762 q.From.Type = obj.TYPE_REG
764 q.To.Type = obj.TYPE_REG
768 q = obj.Appendp(q, c.newprog)
771 q.From.Type = obj.TYPE_REG
773 q.To.Type = obj.TYPE_MEM
774 q.To.Offset = int64(-autosize)
778 // Frame size is too large for a MOVDU instruction.
779 // Store link register before decrementing SP, so if a signal comes
780 // during the execution of the function prologue, the traceback
781 // code will not see a half-updated stack frame.
782 // This sequence is not async preemptible, as if we open a frame
783 // at the current SP, it will clobber the saved LR.
784 q = obj.Appendp(q, c.newprog)
787 q.From.Type = obj.TYPE_REG
789 q.To.Type = obj.TYPE_REG
790 q.To.Reg = REG_R29 // REGTMP may be used to synthesize large offset in the next instruction
792 q = c.ctxt.StartUnsafePoint(q, c.newprog)
794 q = obj.Appendp(q, c.newprog)
797 q.From.Type = obj.TYPE_REG
799 q.To.Type = obj.TYPE_MEM
800 q.To.Offset = int64(-autosize)
805 q = obj.Appendp(q, c.newprog)
808 q.From.Type = obj.TYPE_CONST
809 q.From.Offset = int64(-autosize)
810 q.To.Type = obj.TYPE_REG
814 q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
816 prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
817 } else if c.cursym.Func().Text.Mark&LEAF == 0 {
818 // A very few functions that do not return to their caller
819 // (e.g. gogo) are not identified as leaves but still have
821 c.cursym.Func().Text.Mark |= LEAF
824 if c.cursym.Func().Text.Mark&LEAF != 0 {
825 c.cursym.Set(obj.AttrLeaf, true)
829 if NeedTOCpointer(c.ctxt) {
830 q = obj.Appendp(q, c.newprog)
833 q.From.Type = obj.TYPE_REG
835 q.To.Type = obj.TYPE_MEM
840 if c.cursym.Func().Text.From.Sym.Wrapper() {
841 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
843 // MOVD g_panic(g), R3
846 // MOVD panic_argp(R3), R4
847 // ADD $(autosize+8), R1, R5
851 // MOVD R6, panic_argp(R3)
855 // The NOP is needed to give the jumps somewhere to land.
856 // It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes.
858 q = obj.Appendp(q, c.newprog)
861 q.From.Type = obj.TYPE_MEM
863 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
864 q.To.Type = obj.TYPE_REG
867 q = obj.Appendp(q, c.newprog)
869 q.From.Type = obj.TYPE_REG
871 q.To.Type = obj.TYPE_REG
874 q = obj.Appendp(q, c.newprog)
876 q.To.Type = obj.TYPE_BRANCH
879 q = obj.Appendp(q, c.newprog)
881 q.From.Type = obj.TYPE_MEM
883 q.From.Offset = 0 // Panic.argp
884 q.To.Type = obj.TYPE_REG
887 q = obj.Appendp(q, c.newprog)
889 q.From.Type = obj.TYPE_CONST
890 q.From.Offset = int64(autosize) + c.ctxt.Arch.FixedFrameSize
892 q.To.Type = obj.TYPE_REG
895 q = obj.Appendp(q, c.newprog)
897 q.From.Type = obj.TYPE_REG
899 q.To.Type = obj.TYPE_REG
902 q = obj.Appendp(q, c.newprog)
904 q.To.Type = obj.TYPE_BRANCH
907 q = obj.Appendp(q, c.newprog)
909 q.From.Type = obj.TYPE_CONST
910 q.From.Offset = c.ctxt.Arch.FixedFrameSize
912 q.To.Type = obj.TYPE_REG
915 q = obj.Appendp(q, c.newprog)
917 q.From.Type = obj.TYPE_REG
919 q.To.Type = obj.TYPE_MEM
921 q.To.Offset = 0 // Panic.argp
923 q = obj.Appendp(q, c.newprog)
931 if p.From.Type == obj.TYPE_CONST {
932 c.ctxt.Diag("using BECOME (%v) is not supported!", p)
936 retTarget := p.To.Sym
938 if c.cursym.Func().Text.Mark&LEAF != 0 {
942 if retTarget == nil {
943 p.To.Type = obj.TYPE_REG
946 p.To.Type = obj.TYPE_BRANCH
954 p.From.Type = obj.TYPE_CONST
955 p.From.Offset = int64(autosize)
956 p.To.Type = obj.TYPE_REG
963 if retTarget == nil {
964 q.To.Type = obj.TYPE_REG
967 q.To.Type = obj.TYPE_BRANCH
979 p.From.Type = obj.TYPE_MEM
982 p.To.Type = obj.TYPE_REG
988 q.From.Type = obj.TYPE_REG
990 q.To.Type = obj.TYPE_REG
1003 q.From.Type = obj.TYPE_MEM
1006 q.To.Type = obj.TYPE_REG
1018 q.From.Type = obj.TYPE_CONST
1019 q.From.Offset = int64(autosize)
1020 q.To.Type = obj.TYPE_REG
1032 if retTarget == nil {
1033 q1.To.Type = obj.TYPE_REG
1036 q1.To.Type = obj.TYPE_BRANCH
1037 q1.To.Sym = retTarget
1040 q1.Spadj = +autosize
1045 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
1046 p.Spadj = int32(-p.From.Offset)
1049 if p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
1050 p.Spadj = int32(-p.To.Offset)
1052 if p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP {
1053 p.Spadj = int32(-p.From.Offset)
1055 case obj.AGETCALLERPC:
1059 p.From.Type = obj.TYPE_REG
1062 /* MOVD (RSP), Rd */
1064 p.From.Type = obj.TYPE_MEM
1069 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 && p.As != ACMPU {
1070 f := c.cursym.Func()
1071 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
1072 c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
1073 if ctxt.Debugvlog || !ctxt.IsAsm {
1074 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
1076 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
1078 log.Fatalf("bad SPWRITE")
1087 // instruction scheduling
1094 q1 = firstp; // top of block
1095 o = 0; // count of instructions
1096 for(p = firstp; p != nil; p = p1) {
1099 if(p->mark & NOSCHED){
1103 for(; p != nil; p = p->link){
1104 if(!(p->mark & NOSCHED))
1113 if(p->mark & (LABEL|SYNC)) {
1119 if(p->mark & (BRANCH|SYNC)) {
1132 func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
1133 if c.ctxt.Flag_maymorestack != "" {
1134 if c.ctxt.Flag_shared || c.ctxt.Flag_dynlink {
1135 // See the call to morestack for why these are
1136 // complicated to support.
1137 c.ctxt.Diag("maymorestack with -shared or -dynlink is not supported")
1140 // Spill arguments. This has to happen before we open
1141 // any more frame space.
1142 p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
1144 // Save LR and REGCTXT
1145 frameSize := 8 + c.ctxt.Arch.FixedFrameSize
1148 p = obj.Appendp(p, c.newprog)
1150 p.From.Type = obj.TYPE_REG
1152 p.To.Type = obj.TYPE_REG
1154 // MOVDU REGTMP, -16(SP)
1155 p = obj.Appendp(p, c.newprog)
1157 p.From.Type = obj.TYPE_REG
1159 p.To.Type = obj.TYPE_MEM
1160 p.To.Offset = -frameSize
1162 p.Spadj = int32(frameSize)
1164 // MOVD REGCTXT, 8(SP)
1165 p = obj.Appendp(p, c.newprog)
1167 p.From.Type = obj.TYPE_REG
1168 p.From.Reg = REGCTXT
1169 p.To.Type = obj.TYPE_MEM
1174 p = obj.Appendp(p, c.newprog)
1176 p.To.Type = obj.TYPE_BRANCH
1177 // See ../x86/obj6.go
1178 p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
1180 // Restore LR and REGCTXT
1182 // MOVD 8(SP), REGCTXT
1183 p = obj.Appendp(p, c.newprog)
1185 p.From.Type = obj.TYPE_MEM
1188 p.To.Type = obj.TYPE_REG
1191 // MOVD 0(SP), REGTMP
1192 p = obj.Appendp(p, c.newprog)
1194 p.From.Type = obj.TYPE_MEM
1197 p.To.Type = obj.TYPE_REG
1201 p = obj.Appendp(p, c.newprog)
1203 p.From.Type = obj.TYPE_REG
1205 p.To.Type = obj.TYPE_REG
1209 p = obj.Appendp(p, c.newprog)
1211 p.From.Type = obj.TYPE_CONST
1212 p.From.Offset = frameSize
1213 p.To.Type = obj.TYPE_REG
1215 p.Spadj = -int32(frameSize)
1217 // Unspill arguments.
1218 p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
1221 // save entry point, but skipping the two instructions setting R2 in shared mode and maymorestack
1224 // MOVD g_stackguard(g), R22
1225 p = obj.Appendp(p, c.newprog)
1228 p.From.Type = obj.TYPE_MEM
1230 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
1231 if c.cursym.CFunc() {
1232 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
1234 p.To.Type = obj.TYPE_REG
1237 // Mark the stack bound check and morestack call async nonpreemptible.
1238 // If we get preempted here, when resumed the preemption request is
1239 // cleared, but we'll still call morestack, which will double the stack
1240 // unnecessarily. See issue #35470.
1241 p = c.ctxt.StartUnsafePoint(p, c.newprog)
1244 if framesize <= abi.StackSmall {
1245 // small stack: SP < stackguard
1246 // CMP stackguard, SP
1247 p = obj.Appendp(p, c.newprog)
1250 p.From.Type = obj.TYPE_REG
1251 p.From.Reg = REG_R22
1252 p.To.Type = obj.TYPE_REG
1255 // large stack: SP-framesize < stackguard-StackSmall
1256 offset := int64(framesize) - abi.StackSmall
1257 if framesize > abi.StackBig {
1258 // Such a large stack we need to protect against underflow.
1259 // The runtime guarantees SP > objabi.StackBig, but
1260 // framesize is large enough that SP-framesize may
1261 // underflow, causing a direct comparison with the
1262 // stack guard to incorrectly succeed. We explicitly
1263 // guard against underflow.
1265 // CMPU SP, $(framesize-StackSmall)
1266 // BLT label-of-call-to-morestack
1267 if offset <= 0xffff {
1268 p = obj.Appendp(p, c.newprog)
1270 p.From.Type = obj.TYPE_REG
1272 p.To.Type = obj.TYPE_CONST
1273 p.To.Offset = offset
1275 // Constant is too big for CMPU.
1276 p = obj.Appendp(p, c.newprog)
1278 p.From.Type = obj.TYPE_CONST
1279 p.From.Offset = offset
1280 p.To.Type = obj.TYPE_REG
1283 p = obj.Appendp(p, c.newprog)
1285 p.From.Type = obj.TYPE_REG
1287 p.To.Type = obj.TYPE_REG
1291 p = obj.Appendp(p, c.newprog)
1294 p.To.Type = obj.TYPE_BRANCH
1297 // Check against the stack guard. We've ensured this won't underflow.
1298 // ADD $-(framesize-StackSmall), SP, R4
1299 // CMPU stackguard, R4
1300 p = obj.Appendp(p, c.newprog)
1303 p.From.Type = obj.TYPE_CONST
1304 p.From.Offset = -offset
1306 p.To.Type = obj.TYPE_REG
1309 p = obj.Appendp(p, c.newprog)
1311 p.From.Type = obj.TYPE_REG
1312 p.From.Reg = REG_R22
1313 p.To.Type = obj.TYPE_REG
1318 p = obj.Appendp(p, c.newprog)
1322 p.To.Type = obj.TYPE_BRANCH
1324 p = obj.Appendp(p, c.newprog)
1325 p.As = obj.ANOP // zero-width place holder
1331 // Spill the register args that could be clobbered by the
1334 spill := c.cursym.Func().SpillRegisterArgs(p, c.newprog)
1337 p = obj.Appendp(spill, c.newprog)
1339 p.From.Type = obj.TYPE_REG
1341 p.To.Type = obj.TYPE_REG
1344 p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
1346 var morestacksym *obj.LSym
1347 if c.cursym.CFunc() {
1348 morestacksym = c.ctxt.Lookup("runtime.morestackc")
1349 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
1350 morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt")
1352 morestacksym = c.ctxt.Lookup("runtime.morestack")
1355 if NeedTOCpointer(c.ctxt) {
1356 // In PPC64 PIC code, R2 is used as TOC pointer derived from R12
1357 // which is the address of function entry point when entering
1358 // the function. We need to preserve R2 across call to morestack.
1359 // Fortunately, in shared mode, 8(SP) and 16(SP) are reserved in
1360 // the caller's frame, but not used (0(SP) is caller's saved LR,
1361 // 24(SP) is caller's saved R2). Use 8(SP) to save this function's R2.
1363 p = obj.Appendp(p, c.newprog)
1365 p.From.Type = obj.TYPE_REG
1367 p.To.Type = obj.TYPE_MEM
1372 if c.ctxt.Flag_dynlink {
1373 // Avoid calling morestack via a PLT when dynamically linking. The
1374 // PLT stubs generated by the system linker on ppc64le when "std r2,
1375 // 24(r1)" to save the TOC pointer in their callers stack
1376 // frame. Unfortunately (and necessarily) morestack is called before
1377 // the function that calls it sets up its frame and so the PLT ends
1378 // up smashing the saved TOC pointer for its caller's caller.
1380 // According to the ABI documentation there is a mechanism to avoid
1381 // the TOC save that the PLT stub does (put a R_PPC64_TOCSAVE
1382 // relocation on the nop after the call to morestack) but at the time
1383 // of writing it is not supported at all by gold and my attempt to
1384 // use it with ld.bfd caused an internal linker error. So this hack
1385 // seems preferable.
1387 // MOVD $runtime.morestack(SB), R12
1388 p = obj.Appendp(p, c.newprog)
1390 p.From.Type = obj.TYPE_MEM
1391 p.From.Sym = morestacksym
1392 p.From.Name = obj.NAME_GOTREF
1393 p.To.Type = obj.TYPE_REG
1397 p = obj.Appendp(p, c.newprog)
1399 p.From.Type = obj.TYPE_REG
1400 p.From.Reg = REG_R12
1401 p.To.Type = obj.TYPE_REG
1405 p = obj.Appendp(p, c.newprog)
1407 p.To.Type = obj.TYPE_REG
1410 // BL runtime.morestack(SB)
1411 p = obj.Appendp(p, c.newprog)
1414 p.To.Type = obj.TYPE_BRANCH
1415 p.To.Sym = morestacksym
1418 if NeedTOCpointer(c.ctxt) {
1420 p = obj.Appendp(p, c.newprog)
1422 p.From.Type = obj.TYPE_MEM
1425 p.To.Type = obj.TYPE_REG
1429 // The instructions which unspill regs should be preemptible.
1430 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
1431 unspill := c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
1434 p = obj.Appendp(unspill, c.newprog)
1436 p.To.Type = obj.TYPE_BRANCH
1437 p.To.SetTarget(startPred.Link)
1439 // placeholder for q1's jump target
1440 p = obj.Appendp(p, c.newprog)
1442 p.As = obj.ANOP // zero-width place holder
1448 // MMA accumulator to/from instructions are slightly ambiguous since
1449 // the argument represents both source and destination, specified as
1450 // an accumulator. It is treated as a unary destination to simplify
1451 // the code generation in ppc64map.
1452 var unaryDst = map[obj.As]bool{
1458 var Linkppc64 = obj.LinkArch{
1459 Arch: sys.ArchPPC64,
1461 Preprocess: preprocess,
1465 DWARFRegisters: PPC64DWARFRegisters,
1468 var Linkppc64le = obj.LinkArch{
1469 Arch: sys.ArchPPC64LE,
1471 Preprocess: preprocess,
1475 DWARFRegisters: PPC64DWARFRegisters,