]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/internal/obj/ppc64/obj9.go
ab397892c2d89f86ff890d38403452dbf846dbb9
[gostls13.git] / src / cmd / internal / obj / ppc64 / obj9.go
1 // cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
2 //
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.
11 //
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:
18 //
19 // The above copyright notice and this permission notice shall be included in
20 // all copies or substantial portions of the Software.
21 //
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
28 // THE SOFTWARE.
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         "log"
39         "math/bits"
40 )
41
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.
49         v := uint64(v64)
50         vp := (v & -v) + v
51         // Likewise, for the wrapping case.
52         vn := ^v
53         vpn := (vn & -vn) + vn
54         return (v&vp == 0 || vn&vpn == 0) && v != 0
55 }
56
57 // Encode a doubleword rotate mask into mb (mask begin) and
58 // me (mask end, inclusive). Note, POWER ISA labels bits in
59 // big endian order.
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
69                 mb, me = men, mbn
70         }
71         // Note, me is inclusive.
72         return mb, me - 1
73 }
74
75 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
76         p.From.Class = 0
77         p.To.Class = 0
78
79         c := ctxt9{ctxt: ctxt, newprog: newprog}
80
81         // Rewrite BR/BL to symbol as TYPE_BRANCH.
82         switch p.As {
83         case ABR,
84                 ABL,
85                 obj.ARET,
86                 obj.ADUFFZERO,
87                 obj.ADUFFCOPY:
88                 if p.To.Sym != nil {
89                         p.To.Type = obj.TYPE_BRANCH
90                 }
91         }
92
93         // Rewrite float constants to values stored in memory.
94         switch p.As {
95         case AFMOVS:
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
101                         p.From.Offset = 0
102                 }
103
104         case AFMOVD:
105                 if p.From.Type == obj.TYPE_FCONST {
106                         f64 := p.From.Val.(float64)
107                         // Constant not needed in memory for float +/- 0
108                         if f64 != 0 {
109                                 p.From.Type = obj.TYPE_MEM
110                                 p.From.Sym = ctxt.Float64Sym(f64)
111                                 p.From.Name = obj.NAME_EXTERN
112                                 p.From.Offset = 0
113                         }
114                 }
115
116         case AMOVD:
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)
120
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 {
124
125                         // Is this a shifted 16b constant? If so, rewrite it to avoid a creating and loading a constant.
126                         val := p.From.Offset
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)
132                                 q.As = ASLD
133                                 q.From.SetConst(int64(shift))
134                                 q.To = p.To
135                                 p.From.Offset >>= shift
136                                 p = q
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)
141                                 q.As = ARLDC
142                                 q.AddRestSourceConst((^int64(me)) & 0x3F)
143                                 q.AddRestSourceConst(int64(mb))
144                                 q.From = p.To
145                                 q.To = p.To
146                                 p.From.Offset = -1
147                                 p = q
148                         } else {
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
153                                 p.From.Offset = 0
154                         }
155                 }
156         }
157
158         switch p.As {
159         // Rewrite SUB constants into ADD.
160         case ASUBC:
161                 if p.From.Type == obj.TYPE_CONST {
162                         p.From.Offset = -p.From.Offset
163                         p.As = AADDC
164                 }
165
166         case ASUBCCC:
167                 if p.From.Type == obj.TYPE_CONST {
168                         p.From.Offset = -p.From.Offset
169                         p.As = AADDCCC
170                 }
171
172         case ASUB:
173                 if p.From.Type == obj.TYPE_CONST {
174                         p.From.Offset = -p.From.Offset
175                         p.As = AADD
176                 }
177
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
181         // instructions.
182         //
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]
189                 }
190         }
191
192         if c.ctxt.Headtype == objabi.Haix {
193                 c.rewriteToUseTOC(p)
194         } else if c.ctxt.Flag_dynlink {
195                 c.rewriteToUseGot(p)
196         }
197 }
198
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 {
203                 return
204         }
205
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 {
210                         return
211                 }
212                 //     ADUFFxxx $offset
213                 // becomes
214                 //     MOVD runtime.duffxxx@TOC, R12
215                 //     ADD $offset, R12
216                 //     MOVD R12, LR
217                 //     BL (LR)
218                 var sym *obj.LSym
219                 if p.As == obj.ADUFFZERO {
220                         sym = c.ctxt.Lookup("runtime.duffzero")
221                 } else {
222                         sym = c.ctxt.Lookup("runtime.duffcopy")
223                 }
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)
231                 })
232
233                 offset := p.To.Offset
234                 p.As = AMOVD
235                 p.From.Type = obj.TYPE_MEM
236                 p.From.Name = obj.NAME_TOCREF
237                 p.From.Sym = symtoc
238                 p.To.Type = obj.TYPE_REG
239                 p.To.Reg = REG_R12
240                 p.To.Name = obj.NAME_NONE
241                 p.To.Offset = 0
242                 p.To.Sym = nil
243                 p1 := obj.Appendp(p, c.newprog)
244                 p1.As = AADD
245                 p1.From.Type = obj.TYPE_CONST
246                 p1.From.Offset = offset
247                 p1.To.Type = obj.TYPE_REG
248                 p1.To.Reg = REG_R12
249                 p2 := obj.Appendp(p1, c.newprog)
250                 p2.As = AMOVD
251                 p2.From.Type = obj.TYPE_REG
252                 p2.From.Reg = REG_R12
253                 p2.To.Type = obj.TYPE_REG
254                 p2.To.Reg = REG_LR
255                 p3 := obj.Appendp(p2, c.newprog)
256                 p3.As = obj.ACALL
257                 p3.To.Type = obj.TYPE_REG
258                 p3.To.Reg = REG_LR
259         }
260
261         var source *obj.Addr
262         if p.From.Name == obj.NAME_EXTERN || p.From.Name == obj.NAME_STATIC {
263                 if p.From.Type == obj.TYPE_ADDR {
264                         if p.As == ADWORD {
265                                 // ADWORD $sym doesn't need TOC anchor
266                                 return
267                         }
268                         if p.As != AMOVD {
269                                 c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v", p)
270                                 return
271                         }
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)
274                                 return
275                         }
276                 } else if p.From.Type != obj.TYPE_MEM {
277                         c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
278                         return
279                 }
280                 source = &p.From
281
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)
285                         return
286                 }
287                 if source != nil {
288                         c.ctxt.Diag("cannot handle symbols on both sides in %v", p)
289                         return
290                 }
291                 source = &p.To
292         } else {
293                 return
294
295         }
296
297         if source.Sym == nil {
298                 c.ctxt.Diag("do not know how to handle nil symbol in %v", p)
299                 return
300         }
301
302         if source.Sym.Type == objabi.STLSBSS {
303                 return
304         }
305
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)
313         })
314
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
319                 p.From.Sym = symtoc
320                 p.From.Name = obj.NAME_TOCREF
321
322                 if p.From.Offset != 0 {
323                         q := obj.Appendp(p, c.newprog)
324                         q.As = AADD
325                         q.From.Type = obj.TYPE_CONST
326                         q.From.Offset = p.From.Offset
327                         p.From.Offset = 0
328                         q.To = p.To
329                 }
330                 return
331
332         }
333
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.
337
338         q := obj.Appendp(p, c.newprog)
339         q.As = AMOVD
340         q.From.Type = obj.TYPE_MEM
341         q.From.Sym = symtoc
342         q.From.Name = obj.NAME_TOCREF
343         q.To.Type = obj.TYPE_REG
344         q.To.Reg = REGTMP
345
346         q = obj.Appendp(q, c.newprog)
347         q.As = p.As
348         q.From = p.From
349         q.To = p.To
350         if p.From.Name != obj.NAME_NONE {
351                 q.From.Type = obj.TYPE_MEM
352                 q.From.Reg = REGTMP
353                 q.From.Name = obj.NAME_NONE
354                 q.From.Sym = nil
355         } else if p.To.Name != obj.NAME_NONE {
356                 q.To.Type = obj.TYPE_MEM
357                 q.To.Reg = REGTMP
358                 q.To.Name = obj.NAME_NONE
359                 q.To.Sym = nil
360         } else {
361                 c.ctxt.Diag("unreachable case in rewriteToUseTOC with %v", p)
362         }
363
364         obj.Nopout(p)
365 }
366
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 {
370                 //     ADUFFxxx $offset
371                 // becomes
372                 //     MOVD runtime.duffxxx@GOT, R12
373                 //     ADD $offset, R12
374                 //     MOVD R12, LR
375                 //     BL (LR)
376                 var sym *obj.LSym
377                 if p.As == obj.ADUFFZERO {
378                         sym = c.ctxt.LookupABI("runtime.duffzero", obj.ABIInternal)
379                 } else {
380                         sym = c.ctxt.LookupABI("runtime.duffcopy", obj.ABIInternal)
381                 }
382                 offset := p.To.Offset
383                 p.As = AMOVD
384                 p.From.Type = obj.TYPE_MEM
385                 p.From.Name = obj.NAME_GOTREF
386                 p.From.Sym = sym
387                 p.To.Type = obj.TYPE_REG
388                 p.To.Reg = REG_R12
389                 p.To.Name = obj.NAME_NONE
390                 p.To.Offset = 0
391                 p.To.Sym = nil
392                 p1 := obj.Appendp(p, c.newprog)
393                 p1.As = AADD
394                 p1.From.Type = obj.TYPE_CONST
395                 p1.From.Offset = offset
396                 p1.To.Type = obj.TYPE_REG
397                 p1.To.Reg = REG_R12
398                 p2 := obj.Appendp(p1, c.newprog)
399                 p2.As = AMOVD
400                 p2.From.Type = obj.TYPE_REG
401                 p2.From.Reg = REG_R12
402                 p2.To.Type = obj.TYPE_REG
403                 p2.To.Reg = REG_LR
404                 p3 := obj.Appendp(p2, c.newprog)
405                 p3.As = obj.ACALL
406                 p3.To.Type = obj.TYPE_REG
407                 p3.To.Reg = REG_LR
408         }
409
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
416                 if p.As != AMOVD {
417                         c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
418                 }
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)
421                 }
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)
426                         q.As = AADD
427                         q.From.Type = obj.TYPE_CONST
428                         q.From.Offset = p.From.Offset
429                         q.To = p.To
430                         p.From.Offset = 0
431                 }
432         }
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)
435         }
436         var source *obj.Addr
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)
443                 }
444                 source = &p.From
445         } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
446                 source = &p.To
447         } else {
448                 return
449         }
450         if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
451                 return
452         }
453         if source.Sym.Type == objabi.STLSBSS {
454                 return
455         }
456         if source.Type != obj.TYPE_MEM {
457                 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
458         }
459         p1 := obj.Appendp(p, c.newprog)
460         p2 := obj.Appendp(p1, c.newprog)
461
462         p1.As = AMOVD
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
467         p1.To.Reg = REGTMP
468
469         p2.As = p.As
470         p2.From = p.From
471         p2.To = p.To
472         if p.From.Name == obj.NAME_EXTERN {
473                 p2.From.Reg = REGTMP
474                 p2.From.Name = obj.NAME_NONE
475                 p2.From.Sym = nil
476         } else if p.To.Name == obj.NAME_EXTERN {
477                 p2.To.Reg = REGTMP
478                 p2.To.Name = obj.NAME_NONE
479                 p2.To.Sym = nil
480         } else {
481                 return
482         }
483         obj.Nopout(p)
484 }
485
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 {
489                 return
490         }
491
492         c := ctxt9{ctxt: ctxt, cursym: cursym, newprog: newprog}
493
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)
499                 textstksiz = 0
500         }
501         if textstksiz%8 != 0 {
502                 c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
503         }
504         if p.From.Sym.NoFrame() {
505                 if textstksiz != 0 {
506                         c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
507                 }
508         }
509
510         c.cursym.Func().Args = p.To.Val.(int32)
511         c.cursym.Func().Locals = int32(textstksiz)
512
513         /*
514          * find leaf subroutines
515          * expand RET
516          * expand BECOME pseudo
517          */
518
519         var q *obj.Prog
520         var q1 *obj.Prog
521         for p := c.cursym.Func().Text; p != nil; p = p.Link {
522                 switch p.As {
523                 /* too hard, just leave alone */
524                 case obj.ATEXT:
525                         q = p
526
527                         p.Mark |= LABEL | LEAF | SYNC
528                         if p.Link != nil {
529                                 p.Link.Mark |= LABEL
530                         }
531
532                 case ANOR:
533                         q = p
534                         if p.To.Type == obj.TYPE_REG {
535                                 if p.To.Reg == REGZERO {
536                                         p.Mark |= LABEL | SYNC
537                                 }
538                         }
539
540                 case ALWAR,
541                         ALBAR,
542                         ASTBCCC,
543                         ASTWCCC,
544                         AEIEIO,
545                         AICBI,
546                         AISYNC,
547                         ATLBIE,
548                         ATLBIEL,
549                         ASLBIA,
550                         ASLBIE,
551                         ASLBMFEE,
552                         ASLBMFEV,
553                         ASLBMTE,
554                         ADCBF,
555                         ADCBI,
556                         ADCBST,
557                         ADCBT,
558                         ADCBTST,
559                         ADCBZ,
560                         ASYNC,
561                         ATLBSYNC,
562                         APTESYNC,
563                         ALWSYNC,
564                         ATW,
565                         AWORD,
566                         ARFI,
567                         ARFCI,
568                         ARFID,
569                         AHRFID:
570                         q = p
571                         p.Mark |= LABEL | SYNC
572                         continue
573
574                 case AMOVW, AMOVWZ, AMOVD:
575                         q = p
576                         if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL {
577                                 p.Mark |= LABEL | SYNC
578                         }
579                         continue
580
581                 case AFABS,
582                         AFABSCC,
583                         AFADD,
584                         AFADDCC,
585                         AFCTIW,
586                         AFCTIWCC,
587                         AFCTIWZ,
588                         AFCTIWZCC,
589                         AFDIV,
590                         AFDIVCC,
591                         AFMADD,
592                         AFMADDCC,
593                         AFMOVD,
594                         AFMOVDU,
595                         /* case AFMOVDS: */
596                         AFMOVS,
597                         AFMOVSU,
598
599                         /* case AFMOVSD: */
600                         AFMSUB,
601                         AFMSUBCC,
602                         AFMUL,
603                         AFMULCC,
604                         AFNABS,
605                         AFNABSCC,
606                         AFNEG,
607                         AFNEGCC,
608                         AFNMADD,
609                         AFNMADDCC,
610                         AFNMSUB,
611                         AFNMSUBCC,
612                         AFRSP,
613                         AFRSPCC,
614                         AFSUB,
615                         AFSUBCC:
616                         q = p
617
618                         p.Mark |= FLOAT
619                         continue
620
621                 case ABL,
622                         ABCL,
623                         obj.ADUFFZERO,
624                         obj.ADUFFCOPY:
625                         c.cursym.Func().Text.Mark &^= LEAF
626                         fallthrough
627
628                 case ABC,
629                         ABEQ,
630                         ABGE,
631                         ABGT,
632                         ABLE,
633                         ABLT,
634                         ABNE,
635                         ABR,
636                         ABVC,
637                         ABVS:
638                         p.Mark |= BRANCH
639                         q = p
640                         q1 = p.To.Target()
641                         if q1 != nil {
642                                 // NOPs are not removed due to #40689.
643
644                                 if q1.Mark&LEAF == 0 {
645                                         q1.Mark |= LABEL
646                                 }
647                         } else {
648                                 p.Mark |= LABEL
649                         }
650                         q1 = p.Link
651                         if q1 != nil {
652                                 q1.Mark |= LABEL
653                         }
654                         continue
655
656                 case AFCMPO, AFCMPU:
657                         q = p
658                         p.Mark |= FCMP | FLOAT
659                         continue
660
661                 case obj.ARET:
662                         q = p
663                         if p.Link != nil {
664                                 p.Link.Mark |= LABEL
665                         }
666                         continue
667
668                 case obj.ANOP:
669                         // NOPs are not removed due to
670                         // #40689
671                         continue
672
673                 default:
674                         q = p
675                         continue
676                 }
677         }
678
679         autosize := int32(0)
680         var p1 *obj.Prog
681         var p2 *obj.Prog
682         for p := c.cursym.Func().Text; p != nil; p = p.Link {
683                 o := p.As
684                 switch o {
685                 case obj.ATEXT:
686                         autosize = int32(textstksiz)
687
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)
691                         }
692
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)
697                         }
698
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)
703                         }
704
705                         p.To.Offset = int64(autosize)
706
707                         q = p
708
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:
712                                 //
713                                 //      addis r2, r12, .TOC.-func@ha
714                                 //      addi r2, r2, .TOC.-func@l+4
715                                 //
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.
721                                 //
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.
726                                 //
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)
732                                 q.As = AWORD
733                                 q.Pos = p.Pos
734                                 q.From.Type = obj.TYPE_CONST
735                                 q.From.Offset = 0x3c4c0000
736                                 q = obj.Appendp(q, c.newprog)
737                                 q.As = AWORD
738                                 q.Pos = p.Pos
739                                 q.From.Type = obj.TYPE_CONST
740                                 q.From.Offset = 0x38420000
741                                 rel := obj.Addrel(c.cursym)
742                                 rel.Off = 0
743                                 rel.Siz = 8
744                                 rel.Sym = c.ctxt.Lookup(".TOC.")
745                                 rel.Type = objabi.R_ADDRPOWER_PCREL
746                         }
747
748                         if !c.cursym.Func().Text.From.Sym.NoSplit() {
749                                 q = c.stacksplit(q, autosize) // emit split check
750                         }
751
752                         if autosize != 0 {
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)
760                                         q.As = AMOVD
761                                         q.Pos = p.Pos
762                                         q.From.Type = obj.TYPE_REG
763                                         q.From.Reg = REG_LR
764                                         q.To.Type = obj.TYPE_REG
765                                         q.To.Reg = REGTMP
766                                         prologueEnd = q
767
768                                         q = obj.Appendp(q, c.newprog)
769                                         q.As = AMOVDU
770                                         q.Pos = p.Pos
771                                         q.From.Type = obj.TYPE_REG
772                                         q.From.Reg = REGTMP
773                                         q.To.Type = obj.TYPE_MEM
774                                         q.To.Offset = int64(-autosize)
775                                         q.To.Reg = REGSP
776                                         q.Spadj = autosize
777                                 } else {
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)
785                                         q.As = AMOVD
786                                         q.Pos = p.Pos
787                                         q.From.Type = obj.TYPE_REG
788                                         q.From.Reg = REG_LR
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
791
792                                         q = c.ctxt.StartUnsafePoint(q, c.newprog)
793
794                                         q = obj.Appendp(q, c.newprog)
795                                         q.As = AMOVD
796                                         q.Pos = p.Pos
797                                         q.From.Type = obj.TYPE_REG
798                                         q.From.Reg = REG_R29
799                                         q.To.Type = obj.TYPE_MEM
800                                         q.To.Offset = int64(-autosize)
801                                         q.To.Reg = REGSP
802
803                                         prologueEnd = q
804
805                                         q = obj.Appendp(q, c.newprog)
806                                         q.As = AADD
807                                         q.Pos = p.Pos
808                                         q.From.Type = obj.TYPE_CONST
809                                         q.From.Offset = int64(-autosize)
810                                         q.To.Type = obj.TYPE_REG
811                                         q.To.Reg = REGSP
812                                         q.Spadj = +autosize
813
814                                         q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
815                                 }
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
820                                 // no frame.
821                                 c.cursym.Func().Text.Mark |= LEAF
822                         }
823
824                         if c.cursym.Func().Text.Mark&LEAF != 0 {
825                                 c.cursym.Set(obj.AttrLeaf, true)
826                                 break
827                         }
828
829                         if NeedTOCpointer(c.ctxt) {
830                                 q = obj.Appendp(q, c.newprog)
831                                 q.As = AMOVD
832                                 q.Pos = p.Pos
833                                 q.From.Type = obj.TYPE_REG
834                                 q.From.Reg = REG_R2
835                                 q.To.Type = obj.TYPE_MEM
836                                 q.To.Reg = REGSP
837                                 q.To.Offset = 24
838                         }
839
840                         if c.cursym.Func().Text.From.Sym.Wrapper() {
841                                 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
842                                 //
843                                 //      MOVD g_panic(g), R3
844                                 //      CMP R0, R3
845                                 //      BEQ end
846                                 //      MOVD panic_argp(R3), R4
847                                 //      ADD $(autosize+8), R1, R5
848                                 //      CMP R4, R5
849                                 //      BNE end
850                                 //      ADD $8, R1, R6
851                                 //      MOVD R6, panic_argp(R3)
852                                 // end:
853                                 //      NOP
854                                 //
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.
857
858                                 q = obj.Appendp(q, c.newprog)
859
860                                 q.As = AMOVD
861                                 q.From.Type = obj.TYPE_MEM
862                                 q.From.Reg = REGG
863                                 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
864                                 q.To.Type = obj.TYPE_REG
865                                 q.To.Reg = REG_R22
866
867                                 q = obj.Appendp(q, c.newprog)
868                                 q.As = ACMP
869                                 q.From.Type = obj.TYPE_REG
870                                 q.From.Reg = REG_R0
871                                 q.To.Type = obj.TYPE_REG
872                                 q.To.Reg = REG_R22
873
874                                 q = obj.Appendp(q, c.newprog)
875                                 q.As = ABEQ
876                                 q.To.Type = obj.TYPE_BRANCH
877                                 p1 = q
878
879                                 q = obj.Appendp(q, c.newprog)
880                                 q.As = AMOVD
881                                 q.From.Type = obj.TYPE_MEM
882                                 q.From.Reg = REG_R22
883                                 q.From.Offset = 0 // Panic.argp
884                                 q.To.Type = obj.TYPE_REG
885                                 q.To.Reg = REG_R23
886
887                                 q = obj.Appendp(q, c.newprog)
888                                 q.As = AADD
889                                 q.From.Type = obj.TYPE_CONST
890                                 q.From.Offset = int64(autosize) + c.ctxt.Arch.FixedFrameSize
891                                 q.Reg = REGSP
892                                 q.To.Type = obj.TYPE_REG
893                                 q.To.Reg = REG_R24
894
895                                 q = obj.Appendp(q, c.newprog)
896                                 q.As = ACMP
897                                 q.From.Type = obj.TYPE_REG
898                                 q.From.Reg = REG_R23
899                                 q.To.Type = obj.TYPE_REG
900                                 q.To.Reg = REG_R24
901
902                                 q = obj.Appendp(q, c.newprog)
903                                 q.As = ABNE
904                                 q.To.Type = obj.TYPE_BRANCH
905                                 p2 = q
906
907                                 q = obj.Appendp(q, c.newprog)
908                                 q.As = AADD
909                                 q.From.Type = obj.TYPE_CONST
910                                 q.From.Offset = c.ctxt.Arch.FixedFrameSize
911                                 q.Reg = REGSP
912                                 q.To.Type = obj.TYPE_REG
913                                 q.To.Reg = REG_R25
914
915                                 q = obj.Appendp(q, c.newprog)
916                                 q.As = AMOVD
917                                 q.From.Type = obj.TYPE_REG
918                                 q.From.Reg = REG_R25
919                                 q.To.Type = obj.TYPE_MEM
920                                 q.To.Reg = REG_R22
921                                 q.To.Offset = 0 // Panic.argp
922
923                                 q = obj.Appendp(q, c.newprog)
924
925                                 q.As = obj.ANOP
926                                 p1.To.SetTarget(q)
927                                 p2.To.SetTarget(q)
928                         }
929
930                 case obj.ARET:
931                         if p.From.Type == obj.TYPE_CONST {
932                                 c.ctxt.Diag("using BECOME (%v) is not supported!", p)
933                                 break
934                         }
935
936                         retTarget := p.To.Sym
937
938                         if c.cursym.Func().Text.Mark&LEAF != 0 {
939                                 if autosize == 0 {
940                                         p.As = ABR
941                                         p.From = obj.Addr{}
942                                         if retTarget == nil {
943                                                 p.To.Type = obj.TYPE_REG
944                                                 p.To.Reg = REG_LR
945                                         } else {
946                                                 p.To.Type = obj.TYPE_BRANCH
947                                                 p.To.Sym = retTarget
948                                         }
949                                         p.Mark |= BRANCH
950                                         break
951                                 }
952
953                                 p.As = AADD
954                                 p.From.Type = obj.TYPE_CONST
955                                 p.From.Offset = int64(autosize)
956                                 p.To.Type = obj.TYPE_REG
957                                 p.To.Reg = REGSP
958                                 p.Spadj = -autosize
959
960                                 q = c.newprog()
961                                 q.As = ABR
962                                 q.Pos = p.Pos
963                                 if retTarget == nil {
964                                         q.To.Type = obj.TYPE_REG
965                                         q.To.Reg = REG_LR
966                                 } else {
967                                         q.To.Type = obj.TYPE_BRANCH
968                                         q.To.Sym = retTarget
969                                 }
970                                 q.Mark |= BRANCH
971                                 q.Spadj = +autosize
972
973                                 q.Link = p.Link
974                                 p.Link = q
975                                 break
976                         }
977
978                         p.As = AMOVD
979                         p.From.Type = obj.TYPE_MEM
980                         p.From.Offset = 0
981                         p.From.Reg = REGSP
982                         p.To.Type = obj.TYPE_REG
983                         p.To.Reg = REGTMP
984
985                         q = c.newprog()
986                         q.As = AMOVD
987                         q.Pos = p.Pos
988                         q.From.Type = obj.TYPE_REG
989                         q.From.Reg = REGTMP
990                         q.To.Type = obj.TYPE_REG
991                         q.To.Reg = REG_LR
992
993                         q.Link = p.Link
994                         p.Link = q
995                         p = q
996
997                         if false {
998                                 // Debug bad returns
999                                 q = c.newprog()
1000
1001                                 q.As = AMOVD
1002                                 q.Pos = p.Pos
1003                                 q.From.Type = obj.TYPE_MEM
1004                                 q.From.Offset = 0
1005                                 q.From.Reg = REGTMP
1006                                 q.To.Type = obj.TYPE_REG
1007                                 q.To.Reg = REGTMP
1008
1009                                 q.Link = p.Link
1010                                 p.Link = q
1011                                 p = q
1012                         }
1013                         prev := p
1014                         if autosize != 0 {
1015                                 q = c.newprog()
1016                                 q.As = AADD
1017                                 q.Pos = p.Pos
1018                                 q.From.Type = obj.TYPE_CONST
1019                                 q.From.Offset = int64(autosize)
1020                                 q.To.Type = obj.TYPE_REG
1021                                 q.To.Reg = REGSP
1022                                 q.Spadj = -autosize
1023
1024                                 q.Link = p.Link
1025                                 prev.Link = q
1026                                 prev = q
1027                         }
1028
1029                         q1 = c.newprog()
1030                         q1.As = ABR
1031                         q1.Pos = p.Pos
1032                         if retTarget == nil {
1033                                 q1.To.Type = obj.TYPE_REG
1034                                 q1.To.Reg = REG_LR
1035                         } else {
1036                                 q1.To.Type = obj.TYPE_BRANCH
1037                                 q1.To.Sym = retTarget
1038                         }
1039                         q1.Mark |= BRANCH
1040                         q1.Spadj = +autosize
1041
1042                         q1.Link = q.Link
1043                         prev.Link = q1
1044                 case AADD:
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)
1047                         }
1048                 case AMOVDU:
1049                         if p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
1050                                 p.Spadj = int32(-p.To.Offset)
1051                         }
1052                         if p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP {
1053                                 p.Spadj = int32(-p.From.Offset)
1054                         }
1055                 case obj.AGETCALLERPC:
1056                         if cursym.Leaf() {
1057                                 /* MOVD LR, Rd */
1058                                 p.As = AMOVD
1059                                 p.From.Type = obj.TYPE_REG
1060                                 p.From.Reg = REG_LR
1061                         } else {
1062                                 /* MOVD (RSP), Rd */
1063                                 p.As = AMOVD
1064                                 p.From.Type = obj.TYPE_MEM
1065                                 p.From.Reg = REGSP
1066                         }
1067                 }
1068
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)
1075                                         if !ctxt.IsAsm {
1076                                                 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
1077                                                 ctxt.DiagFlush()
1078                                                 log.Fatalf("bad SPWRITE")
1079                                         }
1080                                 }
1081                         }
1082                 }
1083         }
1084 }
1085
1086 /*
1087 // instruction scheduling
1088
1089         if(debug['Q'] == 0)
1090                 return;
1091
1092         curtext = nil;
1093         q = nil;        // p - 1
1094         q1 = firstp;    // top of block
1095         o = 0;          // count of instructions
1096         for(p = firstp; p != nil; p = p1) {
1097                 p1 = p->link;
1098                 o++;
1099                 if(p->mark & NOSCHED){
1100                         if(q1 != p){
1101                                 sched(q1, q);
1102                         }
1103                         for(; p != nil; p = p->link){
1104                                 if(!(p->mark & NOSCHED))
1105                                         break;
1106                                 q = p;
1107                         }
1108                         p1 = p;
1109                         q1 = p;
1110                         o = 0;
1111                         continue;
1112                 }
1113                 if(p->mark & (LABEL|SYNC)) {
1114                         if(q1 != p)
1115                                 sched(q1, q);
1116                         q1 = p;
1117                         o = 1;
1118                 }
1119                 if(p->mark & (BRANCH|SYNC)) {
1120                         sched(q1, p);
1121                         q1 = p1;
1122                         o = 0;
1123                 }
1124                 if(o >= NSCHED) {
1125                         sched(q1, p);
1126                         q1 = p1;
1127                         o = 0;
1128                 }
1129                 q = p;
1130         }
1131 */
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")
1138                 }
1139
1140                 // Spill arguments. This has to happen before we open
1141                 // any more frame space.
1142                 p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
1143
1144                 // Save LR and REGCTXT
1145                 frameSize := 8 + c.ctxt.Arch.FixedFrameSize
1146
1147                 // MOVD LR, REGTMP
1148                 p = obj.Appendp(p, c.newprog)
1149                 p.As = AMOVD
1150                 p.From.Type = obj.TYPE_REG
1151                 p.From.Reg = REG_LR
1152                 p.To.Type = obj.TYPE_REG
1153                 p.To.Reg = REGTMP
1154                 // MOVDU REGTMP, -16(SP)
1155                 p = obj.Appendp(p, c.newprog)
1156                 p.As = AMOVDU
1157                 p.From.Type = obj.TYPE_REG
1158                 p.From.Reg = REGTMP
1159                 p.To.Type = obj.TYPE_MEM
1160                 p.To.Offset = -frameSize
1161                 p.To.Reg = REGSP
1162                 p.Spadj = int32(frameSize)
1163
1164                 // MOVD REGCTXT, 8(SP)
1165                 p = obj.Appendp(p, c.newprog)
1166                 p.As = AMOVD
1167                 p.From.Type = obj.TYPE_REG
1168                 p.From.Reg = REGCTXT
1169                 p.To.Type = obj.TYPE_MEM
1170                 p.To.Offset = 8
1171                 p.To.Reg = REGSP
1172
1173                 // BL maymorestack
1174                 p = obj.Appendp(p, c.newprog)
1175                 p.As = ABL
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())
1179
1180                 // Restore LR and REGCTXT
1181
1182                 // MOVD 8(SP), REGCTXT
1183                 p = obj.Appendp(p, c.newprog)
1184                 p.As = AMOVD
1185                 p.From.Type = obj.TYPE_MEM
1186                 p.From.Offset = 8
1187                 p.From.Reg = REGSP
1188                 p.To.Type = obj.TYPE_REG
1189                 p.To.Reg = REGCTXT
1190
1191                 // MOVD 0(SP), REGTMP
1192                 p = obj.Appendp(p, c.newprog)
1193                 p.As = AMOVD
1194                 p.From.Type = obj.TYPE_MEM
1195                 p.From.Offset = 0
1196                 p.From.Reg = REGSP
1197                 p.To.Type = obj.TYPE_REG
1198                 p.To.Reg = REGTMP
1199
1200                 // MOVD REGTMP, LR
1201                 p = obj.Appendp(p, c.newprog)
1202                 p.As = AMOVD
1203                 p.From.Type = obj.TYPE_REG
1204                 p.From.Reg = REGTMP
1205                 p.To.Type = obj.TYPE_REG
1206                 p.To.Reg = REG_LR
1207
1208                 // ADD $16, SP
1209                 p = obj.Appendp(p, c.newprog)
1210                 p.As = AADD
1211                 p.From.Type = obj.TYPE_CONST
1212                 p.From.Offset = frameSize
1213                 p.To.Type = obj.TYPE_REG
1214                 p.To.Reg = REGSP
1215                 p.Spadj = -int32(frameSize)
1216
1217                 // Unspill arguments.
1218                 p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
1219         }
1220
1221         // save entry point, but skipping the two instructions setting R2 in shared mode and maymorestack
1222         startPred := p
1223
1224         // MOVD g_stackguard(g), R22
1225         p = obj.Appendp(p, c.newprog)
1226
1227         p.As = AMOVD
1228         p.From.Type = obj.TYPE_MEM
1229         p.From.Reg = REGG
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
1233         }
1234         p.To.Type = obj.TYPE_REG
1235         p.To.Reg = REG_R22
1236
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)
1242
1243         var q *obj.Prog
1244         if framesize <= abi.StackSmall {
1245                 // small stack: SP < stackguard
1246                 //      CMP     stackguard, SP
1247                 p = obj.Appendp(p, c.newprog)
1248
1249                 p.As = ACMPU
1250                 p.From.Type = obj.TYPE_REG
1251                 p.From.Reg = REG_R22
1252                 p.To.Type = obj.TYPE_REG
1253                 p.To.Reg = REGSP
1254         } else {
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.
1264                         //
1265                         //      CMPU    SP, $(framesize-StackSmall)
1266                         //      BLT     label-of-call-to-morestack
1267                         if offset <= 0xffff {
1268                                 p = obj.Appendp(p, c.newprog)
1269                                 p.As = ACMPU
1270                                 p.From.Type = obj.TYPE_REG
1271                                 p.From.Reg = REGSP
1272                                 p.To.Type = obj.TYPE_CONST
1273                                 p.To.Offset = offset
1274                         } else {
1275                                 // Constant is too big for CMPU.
1276                                 p = obj.Appendp(p, c.newprog)
1277                                 p.As = AMOVD
1278                                 p.From.Type = obj.TYPE_CONST
1279                                 p.From.Offset = offset
1280                                 p.To.Type = obj.TYPE_REG
1281                                 p.To.Reg = REG_R23
1282
1283                                 p = obj.Appendp(p, c.newprog)
1284                                 p.As = ACMPU
1285                                 p.From.Type = obj.TYPE_REG
1286                                 p.From.Reg = REGSP
1287                                 p.To.Type = obj.TYPE_REG
1288                                 p.To.Reg = REG_R23
1289                         }
1290
1291                         p = obj.Appendp(p, c.newprog)
1292                         q = p
1293                         p.As = ABLT
1294                         p.To.Type = obj.TYPE_BRANCH
1295                 }
1296
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)
1301
1302                 p.As = AADD
1303                 p.From.Type = obj.TYPE_CONST
1304                 p.From.Offset = -offset
1305                 p.Reg = REGSP
1306                 p.To.Type = obj.TYPE_REG
1307                 p.To.Reg = REG_R23
1308
1309                 p = obj.Appendp(p, c.newprog)
1310                 p.As = ACMPU
1311                 p.From.Type = obj.TYPE_REG
1312                 p.From.Reg = REG_R22
1313                 p.To.Type = obj.TYPE_REG
1314                 p.To.Reg = REG_R23
1315         }
1316
1317         // q1: BLT      done
1318         p = obj.Appendp(p, c.newprog)
1319         q1 := p
1320
1321         p.As = ABLT
1322         p.To.Type = obj.TYPE_BRANCH
1323
1324         p = obj.Appendp(p, c.newprog)
1325         p.As = obj.ANOP // zero-width place holder
1326
1327         if q != nil {
1328                 q.To.SetTarget(p)
1329         }
1330
1331         // Spill the register args that could be clobbered by the
1332         // morestack code.
1333
1334         spill := c.cursym.Func().SpillRegisterArgs(p, c.newprog)
1335
1336         // MOVD LR, R5
1337         p = obj.Appendp(spill, c.newprog)
1338         p.As = AMOVD
1339         p.From.Type = obj.TYPE_REG
1340         p.From.Reg = REG_LR
1341         p.To.Type = obj.TYPE_REG
1342         p.To.Reg = REG_R5
1343
1344         p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
1345
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")
1351         } else {
1352                 morestacksym = c.ctxt.Lookup("runtime.morestack")
1353         }
1354
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.
1362                 // MOVD R2, 8(SP)
1363                 p = obj.Appendp(p, c.newprog)
1364                 p.As = AMOVD
1365                 p.From.Type = obj.TYPE_REG
1366                 p.From.Reg = REG_R2
1367                 p.To.Type = obj.TYPE_MEM
1368                 p.To.Reg = REGSP
1369                 p.To.Offset = 8
1370         }
1371
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.
1379                 //
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.
1386
1387                 // MOVD $runtime.morestack(SB), R12
1388                 p = obj.Appendp(p, c.newprog)
1389                 p.As = AMOVD
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
1394                 p.To.Reg = REG_R12
1395
1396                 // MOVD R12, LR
1397                 p = obj.Appendp(p, c.newprog)
1398                 p.As = AMOVD
1399                 p.From.Type = obj.TYPE_REG
1400                 p.From.Reg = REG_R12
1401                 p.To.Type = obj.TYPE_REG
1402                 p.To.Reg = REG_LR
1403
1404                 // BL LR
1405                 p = obj.Appendp(p, c.newprog)
1406                 p.As = obj.ACALL
1407                 p.To.Type = obj.TYPE_REG
1408                 p.To.Reg = REG_LR
1409         } else {
1410                 // BL   runtime.morestack(SB)
1411                 p = obj.Appendp(p, c.newprog)
1412
1413                 p.As = ABL
1414                 p.To.Type = obj.TYPE_BRANCH
1415                 p.To.Sym = morestacksym
1416         }
1417
1418         if NeedTOCpointer(c.ctxt) {
1419                 // MOVD 8(SP), R2
1420                 p = obj.Appendp(p, c.newprog)
1421                 p.As = AMOVD
1422                 p.From.Type = obj.TYPE_MEM
1423                 p.From.Reg = REGSP
1424                 p.From.Offset = 8
1425                 p.To.Type = obj.TYPE_REG
1426                 p.To.Reg = REG_R2
1427         }
1428
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)
1432
1433         // BR   start
1434         p = obj.Appendp(unspill, c.newprog)
1435         p.As = ABR
1436         p.To.Type = obj.TYPE_BRANCH
1437         p.To.SetTarget(startPred.Link)
1438
1439         // placeholder for q1's jump target
1440         p = obj.Appendp(p, c.newprog)
1441
1442         p.As = obj.ANOP // zero-width place holder
1443         q1.To.SetTarget(p)
1444
1445         return p
1446 }
1447
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{
1453         AXXSETACCZ: true,
1454         AXXMTACC:   true,
1455         AXXMFACC:   true,
1456 }
1457
1458 var Linkppc64 = obj.LinkArch{
1459         Arch:           sys.ArchPPC64,
1460         Init:           buildop,
1461         Preprocess:     preprocess,
1462         Assemble:       span9,
1463         Progedit:       progedit,
1464         UnaryDst:       unaryDst,
1465         DWARFRegisters: PPC64DWARFRegisters,
1466 }
1467
1468 var Linkppc64le = obj.LinkArch{
1469         Arch:           sys.ArchPPC64LE,
1470         Init:           buildop,
1471         Preprocess:     preprocess,
1472         Assemble:       span9,
1473         Progedit:       progedit,
1474         UnaryDst:       unaryDst,
1475         DWARFRegisters: PPC64DWARFRegisters,
1476 }