Source file 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  	"log"
    38  )
    39  
    40  func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
    41  	p.From.Class = 0
    42  	p.To.Class = 0
    43  
    44  	c := ctxt9{ctxt: ctxt, newprog: newprog}
    45  
    46  	// Rewrite BR/BL to symbol as TYPE_BRANCH.
    47  	switch p.As {
    48  	case ABR,
    49  		ABL,
    50  		obj.ARET,
    51  		obj.ADUFFZERO,
    52  		obj.ADUFFCOPY:
    53  		if p.To.Sym != nil {
    54  			p.To.Type = obj.TYPE_BRANCH
    55  		}
    56  	}
    57  
    58  	// Rewrite float constants to values stored in memory.
    59  	switch p.As {
    60  	case AFMOVS:
    61  		if p.From.Type == obj.TYPE_FCONST {
    62  			f32 := float32(p.From.Val.(float64))
    63  			p.From.Type = obj.TYPE_MEM
    64  			p.From.Sym = ctxt.Float32Sym(f32)
    65  			p.From.Name = obj.NAME_EXTERN
    66  			p.From.Offset = 0
    67  		}
    68  
    69  	case AFMOVD:
    70  		if p.From.Type == obj.TYPE_FCONST {
    71  			f64 := p.From.Val.(float64)
    72  			// Constant not needed in memory for float +/- 0
    73  			if f64 != 0 {
    74  				p.From.Type = obj.TYPE_MEM
    75  				p.From.Sym = ctxt.Float64Sym(f64)
    76  				p.From.Name = obj.NAME_EXTERN
    77  				p.From.Offset = 0
    78  			}
    79  		}
    80  
    81  		// Put >32-bit constants in memory and load them
    82  	case AMOVD:
    83  		if p.From.Type == obj.TYPE_CONST && p.From.Name == obj.NAME_NONE && p.From.Reg == 0 && int64(int32(p.From.Offset)) != p.From.Offset {
    84  			p.From.Type = obj.TYPE_MEM
    85  			p.From.Sym = ctxt.Int64Sym(p.From.Offset)
    86  			p.From.Name = obj.NAME_EXTERN
    87  			p.From.Offset = 0
    88  		}
    89  	}
    90  
    91  	// Rewrite SUB constants into ADD.
    92  	switch p.As {
    93  	case ASUBC:
    94  		if p.From.Type == obj.TYPE_CONST {
    95  			p.From.Offset = -p.From.Offset
    96  			p.As = AADDC
    97  		}
    98  
    99  	case ASUBCCC:
   100  		if p.From.Type == obj.TYPE_CONST {
   101  			p.From.Offset = -p.From.Offset
   102  			p.As = AADDCCC
   103  		}
   104  
   105  	case ASUB:
   106  		if p.From.Type == obj.TYPE_CONST {
   107  			p.From.Offset = -p.From.Offset
   108  			p.As = AADD
   109  		}
   110  	}
   111  	if c.ctxt.Headtype == objabi.Haix {
   112  		c.rewriteToUseTOC(p)
   113  	} else if c.ctxt.Flag_dynlink {
   114  		c.rewriteToUseGot(p)
   115  	}
   116  }
   117  
   118  // Rewrite p, if necessary, to access a symbol using its TOC anchor.
   119  // This code is for AIX only.
   120  func (c *ctxt9) rewriteToUseTOC(p *obj.Prog) {
   121  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
   122  		return
   123  	}
   124  
   125  	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
   126  		// ADUFFZERO/ADUFFCOPY is considered as an ABL except in dynamic
   127  		// link where it should be an indirect call.
   128  		if !c.ctxt.Flag_dynlink {
   129  			return
   130  		}
   131  		//     ADUFFxxx $offset
   132  		// becomes
   133  		//     MOVD runtime.duffxxx@TOC, R12
   134  		//     ADD $offset, R12
   135  		//     MOVD R12, LR
   136  		//     BL (LR)
   137  		var sym *obj.LSym
   138  		if p.As == obj.ADUFFZERO {
   139  			sym = c.ctxt.Lookup("runtime.duffzero")
   140  		} else {
   141  			sym = c.ctxt.Lookup("runtime.duffcopy")
   142  		}
   143  		// Retrieve or create the TOC anchor.
   144  		symtoc := c.ctxt.LookupInit("TOC."+sym.Name, func(s *obj.LSym) {
   145  			s.Type = objabi.SDATA
   146  			s.Set(obj.AttrDuplicateOK, true)
   147  			s.Set(obj.AttrStatic, true)
   148  			c.ctxt.Data = append(c.ctxt.Data, s)
   149  			s.WriteAddr(c.ctxt, 0, 8, sym, 0)
   150  		})
   151  
   152  		offset := p.To.Offset
   153  		p.As = AMOVD
   154  		p.From.Type = obj.TYPE_MEM
   155  		p.From.Name = obj.NAME_TOCREF
   156  		p.From.Sym = symtoc
   157  		p.To.Type = obj.TYPE_REG
   158  		p.To.Reg = REG_R12
   159  		p.To.Name = obj.NAME_NONE
   160  		p.To.Offset = 0
   161  		p.To.Sym = nil
   162  		p1 := obj.Appendp(p, c.newprog)
   163  		p1.As = AADD
   164  		p1.From.Type = obj.TYPE_CONST
   165  		p1.From.Offset = offset
   166  		p1.To.Type = obj.TYPE_REG
   167  		p1.To.Reg = REG_R12
   168  		p2 := obj.Appendp(p1, c.newprog)
   169  		p2.As = AMOVD
   170  		p2.From.Type = obj.TYPE_REG
   171  		p2.From.Reg = REG_R12
   172  		p2.To.Type = obj.TYPE_REG
   173  		p2.To.Reg = REG_LR
   174  		p3 := obj.Appendp(p2, c.newprog)
   175  		p3.As = obj.ACALL
   176  		p3.To.Type = obj.TYPE_REG
   177  		p3.To.Reg = REG_LR
   178  	}
   179  
   180  	var source *obj.Addr
   181  	if p.From.Name == obj.NAME_EXTERN || p.From.Name == obj.NAME_STATIC {
   182  		if p.From.Type == obj.TYPE_ADDR {
   183  			if p.As == ADWORD {
   184  				// ADWORD $sym doesn't need TOC anchor
   185  				return
   186  			}
   187  			if p.As != AMOVD {
   188  				c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v", p)
   189  				return
   190  			}
   191  			if p.To.Type != obj.TYPE_REG {
   192  				c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v", p)
   193  				return
   194  			}
   195  		} else if p.From.Type != obj.TYPE_MEM {
   196  			c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
   197  			return
   198  		}
   199  		source = &p.From
   200  
   201  	} else if p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC {
   202  		if p.To.Type != obj.TYPE_MEM {
   203  			c.ctxt.Diag("do not know how to handle %v without TYPE_MEM", p)
   204  			return
   205  		}
   206  		if source != nil {
   207  			c.ctxt.Diag("cannot handle symbols on both sides in %v", p)
   208  			return
   209  		}
   210  		source = &p.To
   211  	} else {
   212  		return
   213  
   214  	}
   215  
   216  	if source.Sym == nil {
   217  		c.ctxt.Diag("do not know how to handle nil symbol in %v", p)
   218  		return
   219  	}
   220  
   221  	if source.Sym.Type == objabi.STLSBSS {
   222  		return
   223  	}
   224  
   225  	// Retrieve or create the TOC anchor.
   226  	symtoc := c.ctxt.LookupInit("TOC."+source.Sym.Name, func(s *obj.LSym) {
   227  		s.Type = objabi.SDATA
   228  		s.Set(obj.AttrDuplicateOK, true)
   229  		s.Set(obj.AttrStatic, true)
   230  		c.ctxt.Data = append(c.ctxt.Data, s)
   231  		s.WriteAddr(c.ctxt, 0, 8, source.Sym, 0)
   232  	})
   233  
   234  	if source.Type == obj.TYPE_ADDR {
   235  		// MOVD $sym, Rx becomes MOVD symtoc, Rx
   236  		// MOVD $sym+<off>, Rx becomes MOVD symtoc, Rx; ADD <off>, Rx
   237  		p.From.Type = obj.TYPE_MEM
   238  		p.From.Sym = symtoc
   239  		p.From.Name = obj.NAME_TOCREF
   240  
   241  		if p.From.Offset != 0 {
   242  			q := obj.Appendp(p, c.newprog)
   243  			q.As = AADD
   244  			q.From.Type = obj.TYPE_CONST
   245  			q.From.Offset = p.From.Offset
   246  			p.From.Offset = 0
   247  			q.To = p.To
   248  		}
   249  		return
   250  
   251  	}
   252  
   253  	// MOVx sym, Ry becomes MOVD symtoc, REGTMP; MOVx (REGTMP), Ry
   254  	// MOVx Ry, sym becomes MOVD symtoc, REGTMP; MOVx Ry, (REGTMP)
   255  	// An addition may be inserted between the two MOVs if there is an offset.
   256  
   257  	q := obj.Appendp(p, c.newprog)
   258  	q.As = AMOVD
   259  	q.From.Type = obj.TYPE_MEM
   260  	q.From.Sym = symtoc
   261  	q.From.Name = obj.NAME_TOCREF
   262  	q.To.Type = obj.TYPE_REG
   263  	q.To.Reg = REGTMP
   264  
   265  	q = obj.Appendp(q, c.newprog)
   266  	q.As = p.As
   267  	q.From = p.From
   268  	q.To = p.To
   269  	if p.From.Name != obj.NAME_NONE {
   270  		q.From.Type = obj.TYPE_MEM
   271  		q.From.Reg = REGTMP
   272  		q.From.Name = obj.NAME_NONE
   273  		q.From.Sym = nil
   274  	} else if p.To.Name != obj.NAME_NONE {
   275  		q.To.Type = obj.TYPE_MEM
   276  		q.To.Reg = REGTMP
   277  		q.To.Name = obj.NAME_NONE
   278  		q.To.Sym = nil
   279  	} else {
   280  		c.ctxt.Diag("unreachable case in rewriteToUseTOC with %v", p)
   281  	}
   282  
   283  	obj.Nopout(p)
   284  }
   285  
   286  // Rewrite p, if necessary, to access global data via the global offset table.
   287  func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
   288  	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
   289  		//     ADUFFxxx $offset
   290  		// becomes
   291  		//     MOVD runtime.duffxxx@GOT, R12
   292  		//     ADD $offset, R12
   293  		//     MOVD R12, LR
   294  		//     BL (LR)
   295  		var sym *obj.LSym
   296  		if p.As == obj.ADUFFZERO {
   297  			sym = c.ctxt.LookupABI("runtime.duffzero", obj.ABIInternal)
   298  		} else {
   299  			sym = c.ctxt.LookupABI("runtime.duffcopy", obj.ABIInternal)
   300  		}
   301  		offset := p.To.Offset
   302  		p.As = AMOVD
   303  		p.From.Type = obj.TYPE_MEM
   304  		p.From.Name = obj.NAME_GOTREF
   305  		p.From.Sym = sym
   306  		p.To.Type = obj.TYPE_REG
   307  		p.To.Reg = REG_R12
   308  		p.To.Name = obj.NAME_NONE
   309  		p.To.Offset = 0
   310  		p.To.Sym = nil
   311  		p1 := obj.Appendp(p, c.newprog)
   312  		p1.As = AADD
   313  		p1.From.Type = obj.TYPE_CONST
   314  		p1.From.Offset = offset
   315  		p1.To.Type = obj.TYPE_REG
   316  		p1.To.Reg = REG_R12
   317  		p2 := obj.Appendp(p1, c.newprog)
   318  		p2.As = AMOVD
   319  		p2.From.Type = obj.TYPE_REG
   320  		p2.From.Reg = REG_R12
   321  		p2.To.Type = obj.TYPE_REG
   322  		p2.To.Reg = REG_LR
   323  		p3 := obj.Appendp(p2, c.newprog)
   324  		p3.As = obj.ACALL
   325  		p3.To.Type = obj.TYPE_REG
   326  		p3.To.Reg = REG_LR
   327  	}
   328  
   329  	// We only care about global data: NAME_EXTERN means a global
   330  	// symbol in the Go sense, and p.Sym.Local is true for a few
   331  	// internally defined symbols.
   332  	if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   333  		// MOVD $sym, Rx becomes MOVD sym@GOT, Rx
   334  		// MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx
   335  		if p.As != AMOVD {
   336  			c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
   337  		}
   338  		if p.To.Type != obj.TYPE_REG {
   339  			c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
   340  		}
   341  		p.From.Type = obj.TYPE_MEM
   342  		p.From.Name = obj.NAME_GOTREF
   343  		if p.From.Offset != 0 {
   344  			q := obj.Appendp(p, c.newprog)
   345  			q.As = AADD
   346  			q.From.Type = obj.TYPE_CONST
   347  			q.From.Offset = p.From.Offset
   348  			q.To = p.To
   349  			p.From.Offset = 0
   350  		}
   351  	}
   352  	if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
   353  		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
   354  	}
   355  	var source *obj.Addr
   356  	// MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry
   357  	// MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVx Ry, (REGTMP)
   358  	// An addition may be inserted between the two MOVs if there is an offset.
   359  	if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   360  		if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   361  			c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
   362  		}
   363  		source = &p.From
   364  	} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   365  		source = &p.To
   366  	} else {
   367  		return
   368  	}
   369  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
   370  		return
   371  	}
   372  	if source.Sym.Type == objabi.STLSBSS {
   373  		return
   374  	}
   375  	if source.Type != obj.TYPE_MEM {
   376  		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
   377  	}
   378  	p1 := obj.Appendp(p, c.newprog)
   379  	p2 := obj.Appendp(p1, c.newprog)
   380  
   381  	p1.As = AMOVD
   382  	p1.From.Type = obj.TYPE_MEM
   383  	p1.From.Sym = source.Sym
   384  	p1.From.Name = obj.NAME_GOTREF
   385  	p1.To.Type = obj.TYPE_REG
   386  	p1.To.Reg = REGTMP
   387  
   388  	p2.As = p.As
   389  	p2.From = p.From
   390  	p2.To = p.To
   391  	if p.From.Name == obj.NAME_EXTERN {
   392  		p2.From.Reg = REGTMP
   393  		p2.From.Name = obj.NAME_NONE
   394  		p2.From.Sym = nil
   395  	} else if p.To.Name == obj.NAME_EXTERN {
   396  		p2.To.Reg = REGTMP
   397  		p2.To.Name = obj.NAME_NONE
   398  		p2.To.Sym = nil
   399  	} else {
   400  		return
   401  	}
   402  	obj.Nopout(p)
   403  }
   404  
   405  func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
   406  	// TODO(minux): add morestack short-cuts with small fixed frame-size.
   407  	if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
   408  		return
   409  	}
   410  
   411  	c := ctxt9{ctxt: ctxt, cursym: cursym, newprog: newprog}
   412  
   413  	p := c.cursym.Func().Text
   414  	textstksiz := p.To.Offset
   415  	if textstksiz == -8 {
   416  		// Compatibility hack.
   417  		p.From.Sym.Set(obj.AttrNoFrame, true)
   418  		textstksiz = 0
   419  	}
   420  	if textstksiz%8 != 0 {
   421  		c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
   422  	}
   423  	if p.From.Sym.NoFrame() {
   424  		if textstksiz != 0 {
   425  			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
   426  		}
   427  	}
   428  
   429  	c.cursym.Func().Args = p.To.Val.(int32)
   430  	c.cursym.Func().Locals = int32(textstksiz)
   431  
   432  	/*
   433  	 * find leaf subroutines
   434  	 * expand RET
   435  	 * expand BECOME pseudo
   436  	 */
   437  
   438  	var q *obj.Prog
   439  	var q1 *obj.Prog
   440  	for p := c.cursym.Func().Text; p != nil; p = p.Link {
   441  		switch p.As {
   442  		/* too hard, just leave alone */
   443  		case obj.ATEXT:
   444  			q = p
   445  
   446  			p.Mark |= LABEL | LEAF | SYNC
   447  			if p.Link != nil {
   448  				p.Link.Mark |= LABEL
   449  			}
   450  
   451  		case ANOR:
   452  			q = p
   453  			if p.To.Type == obj.TYPE_REG {
   454  				if p.To.Reg == REGZERO {
   455  					p.Mark |= LABEL | SYNC
   456  				}
   457  			}
   458  
   459  		case ALWAR,
   460  			ALBAR,
   461  			ASTBCCC,
   462  			ASTWCCC,
   463  			AECIWX,
   464  			AECOWX,
   465  			AEIEIO,
   466  			AICBI,
   467  			AISYNC,
   468  			ATLBIE,
   469  			ATLBIEL,
   470  			ASLBIA,
   471  			ASLBIE,
   472  			ASLBMFEE,
   473  			ASLBMFEV,
   474  			ASLBMTE,
   475  			ADCBF,
   476  			ADCBI,
   477  			ADCBST,
   478  			ADCBT,
   479  			ADCBTST,
   480  			ADCBZ,
   481  			ASYNC,
   482  			ATLBSYNC,
   483  			APTESYNC,
   484  			ALWSYNC,
   485  			ATW,
   486  			AWORD,
   487  			ARFI,
   488  			ARFCI,
   489  			ARFID,
   490  			AHRFID:
   491  			q = p
   492  			p.Mark |= LABEL | SYNC
   493  			continue
   494  
   495  		case AMOVW, AMOVWZ, AMOVD:
   496  			q = p
   497  			if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL {
   498  				p.Mark |= LABEL | SYNC
   499  			}
   500  			continue
   501  
   502  		case AFABS,
   503  			AFABSCC,
   504  			AFADD,
   505  			AFADDCC,
   506  			AFCTIW,
   507  			AFCTIWCC,
   508  			AFCTIWZ,
   509  			AFCTIWZCC,
   510  			AFDIV,
   511  			AFDIVCC,
   512  			AFMADD,
   513  			AFMADDCC,
   514  			AFMOVD,
   515  			AFMOVDU,
   516  			/* case AFMOVDS: */
   517  			AFMOVS,
   518  			AFMOVSU,
   519  
   520  			/* case AFMOVSD: */
   521  			AFMSUB,
   522  			AFMSUBCC,
   523  			AFMUL,
   524  			AFMULCC,
   525  			AFNABS,
   526  			AFNABSCC,
   527  			AFNEG,
   528  			AFNEGCC,
   529  			AFNMADD,
   530  			AFNMADDCC,
   531  			AFNMSUB,
   532  			AFNMSUBCC,
   533  			AFRSP,
   534  			AFRSPCC,
   535  			AFSUB,
   536  			AFSUBCC:
   537  			q = p
   538  
   539  			p.Mark |= FLOAT
   540  			continue
   541  
   542  		case ABL,
   543  			ABCL,
   544  			obj.ADUFFZERO,
   545  			obj.ADUFFCOPY:
   546  			c.cursym.Func().Text.Mark &^= LEAF
   547  			fallthrough
   548  
   549  		case ABC,
   550  			ABEQ,
   551  			ABGE,
   552  			ABGT,
   553  			ABLE,
   554  			ABLT,
   555  			ABNE,
   556  			ABR,
   557  			ABVC,
   558  			ABVS:
   559  			p.Mark |= BRANCH
   560  			q = p
   561  			q1 = p.To.Target()
   562  			if q1 != nil {
   563  				// NOPs are not removed due to #40689.
   564  
   565  				if q1.Mark&LEAF == 0 {
   566  					q1.Mark |= LABEL
   567  				}
   568  			} else {
   569  				p.Mark |= LABEL
   570  			}
   571  			q1 = p.Link
   572  			if q1 != nil {
   573  				q1.Mark |= LABEL
   574  			}
   575  			continue
   576  
   577  		case AFCMPO, AFCMPU:
   578  			q = p
   579  			p.Mark |= FCMP | FLOAT
   580  			continue
   581  
   582  		case obj.ARET:
   583  			q = p
   584  			if p.Link != nil {
   585  				p.Link.Mark |= LABEL
   586  			}
   587  			continue
   588  
   589  		case obj.ANOP:
   590  			// NOPs are not removed due to
   591  			// #40689
   592  			continue
   593  
   594  		default:
   595  			q = p
   596  			continue
   597  		}
   598  	}
   599  
   600  	autosize := int32(0)
   601  	var p1 *obj.Prog
   602  	var p2 *obj.Prog
   603  	for p := c.cursym.Func().Text; p != nil; p = p.Link {
   604  		o := p.As
   605  		switch o {
   606  		case obj.ATEXT:
   607  			autosize = int32(textstksiz)
   608  
   609  			if p.Mark&LEAF != 0 && autosize == 0 {
   610  				// A leaf function with no locals has no frame.
   611  				p.From.Sym.Set(obj.AttrNoFrame, true)
   612  			}
   613  
   614  			if !p.From.Sym.NoFrame() {
   615  				// If there is a stack frame at all, it includes
   616  				// space to save the LR.
   617  				autosize += int32(c.ctxt.FixedFrameSize())
   618  			}
   619  
   620  			if p.Mark&LEAF != 0 && autosize < objabi.StackSmall {
   621  				// A leaf function with a small stack can be marked
   622  				// NOSPLIT, avoiding a stack check.
   623  				p.From.Sym.Set(obj.AttrNoSplit, true)
   624  			}
   625  
   626  			p.To.Offset = int64(autosize)
   627  
   628  			q = p
   629  
   630  			if c.ctxt.Flag_shared && c.cursym.Name != "runtime.duffzero" && c.cursym.Name != "runtime.duffcopy" {
   631  				// When compiling Go into PIC, all functions must start
   632  				// with instructions to load the TOC pointer into r2:
   633  				//
   634  				//	addis r2, r12, .TOC.-func@ha
   635  				//	addi r2, r2, .TOC.-func@l+4
   636  				//
   637  				// We could probably skip this prologue in some situations
   638  				// but it's a bit subtle. However, it is both safe and
   639  				// necessary to leave the prologue off duffzero and
   640  				// duffcopy as we rely on being able to jump to a specific
   641  				// instruction offset for them.
   642  				//
   643  				// These are AWORDS because there is no (afaict) way to
   644  				// generate the addis instruction except as part of the
   645  				// load of a large constant, and in that case there is no
   646  				// way to use r12 as the source.
   647  				//
   648  				// Note that the same condition is tested in
   649  				// putelfsym in cmd/link/internal/ld/symtab.go
   650  				// where we set the st_other field to indicate
   651  				// the presence of these instructions.
   652  				q = obj.Appendp(q, c.newprog)
   653  				q.As = AWORD
   654  				q.Pos = p.Pos
   655  				q.From.Type = obj.TYPE_CONST
   656  				q.From.Offset = 0x3c4c0000
   657  				q = obj.Appendp(q, c.newprog)
   658  				q.As = AWORD
   659  				q.Pos = p.Pos
   660  				q.From.Type = obj.TYPE_CONST
   661  				q.From.Offset = 0x38420000
   662  				rel := obj.Addrel(c.cursym)
   663  				rel.Off = 0
   664  				rel.Siz = 8
   665  				rel.Sym = c.ctxt.Lookup(".TOC.")
   666  				rel.Type = objabi.R_ADDRPOWER_PCREL
   667  			}
   668  
   669  			if !c.cursym.Func().Text.From.Sym.NoSplit() {
   670  				q = c.stacksplit(q, autosize) // emit split check
   671  			}
   672  
   673  			// Special handling of the racecall thunk. Assume that its asm code will
   674  			// save the link register and update the stack, since that code is
   675  			// called directly from C/C++ and can't clobber REGTMP (R31).
   676  			if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" {
   677  				var prologueEnd *obj.Prog
   678  				// Save the link register and update the SP.  MOVDU is used unless
   679  				// the frame size is too large.  The link register must be saved
   680  				// even for non-empty leaf functions so that traceback works.
   681  				if autosize >= -BIG && autosize <= BIG {
   682  					// Use MOVDU to adjust R1 when saving R31, if autosize is small.
   683  					q = obj.Appendp(q, c.newprog)
   684  					q.As = AMOVD
   685  					q.Pos = p.Pos
   686  					q.From.Type = obj.TYPE_REG
   687  					q.From.Reg = REG_LR
   688  					q.To.Type = obj.TYPE_REG
   689  					q.To.Reg = REGTMP
   690  					prologueEnd = q
   691  
   692  					q = obj.Appendp(q, c.newprog)
   693  					q.As = AMOVDU
   694  					q.Pos = p.Pos
   695  					q.From.Type = obj.TYPE_REG
   696  					q.From.Reg = REGTMP
   697  					q.To.Type = obj.TYPE_MEM
   698  					q.To.Offset = int64(-autosize)
   699  					q.To.Reg = REGSP
   700  					q.Spadj = autosize
   701  				} else {
   702  					// Frame size is too large for a MOVDU instruction.
   703  					// Store link register before decrementing SP, so if a signal comes
   704  					// during the execution of the function prologue, the traceback
   705  					// code will not see a half-updated stack frame.
   706  					// This sequence is not async preemptible, as if we open a frame
   707  					// at the current SP, it will clobber the saved LR.
   708  					q = obj.Appendp(q, c.newprog)
   709  					q.As = AMOVD
   710  					q.Pos = p.Pos
   711  					q.From.Type = obj.TYPE_REG
   712  					q.From.Reg = REG_LR
   713  					q.To.Type = obj.TYPE_REG
   714  					q.To.Reg = REG_R29 // REGTMP may be used to synthesize large offset in the next instruction
   715  
   716  					q = c.ctxt.StartUnsafePoint(q, c.newprog)
   717  
   718  					q = obj.Appendp(q, c.newprog)
   719  					q.As = AMOVD
   720  					q.Pos = p.Pos
   721  					q.From.Type = obj.TYPE_REG
   722  					q.From.Reg = REG_R29
   723  					q.To.Type = obj.TYPE_MEM
   724  					q.To.Offset = int64(-autosize)
   725  					q.To.Reg = REGSP
   726  
   727  					prologueEnd = q
   728  
   729  					q = obj.Appendp(q, c.newprog)
   730  					q.As = AADD
   731  					q.Pos = p.Pos
   732  					q.From.Type = obj.TYPE_CONST
   733  					q.From.Offset = int64(-autosize)
   734  					q.To.Type = obj.TYPE_REG
   735  					q.To.Reg = REGSP
   736  					q.Spadj = +autosize
   737  
   738  					q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
   739  				}
   740  				prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
   741  			} else if c.cursym.Func().Text.Mark&LEAF == 0 {
   742  				// A very few functions that do not return to their caller
   743  				// (e.g. gogo) are not identified as leaves but still have
   744  				// no frame.
   745  				c.cursym.Func().Text.Mark |= LEAF
   746  			}
   747  
   748  			if c.cursym.Func().Text.Mark&LEAF != 0 {
   749  				c.cursym.Set(obj.AttrLeaf, true)
   750  				break
   751  			}
   752  
   753  			if c.ctxt.Flag_shared {
   754  				q = obj.Appendp(q, c.newprog)
   755  				q.As = AMOVD
   756  				q.Pos = p.Pos
   757  				q.From.Type = obj.TYPE_REG
   758  				q.From.Reg = REG_R2
   759  				q.To.Type = obj.TYPE_MEM
   760  				q.To.Reg = REGSP
   761  				q.To.Offset = 24
   762  			}
   763  
   764  			if c.cursym.Func().Text.From.Sym.Wrapper() {
   765  				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
   766  				//
   767  				//	MOVD g_panic(g), R3
   768  				//	CMP R0, R3
   769  				//	BEQ end
   770  				//	MOVD panic_argp(R3), R4
   771  				//	ADD $(autosize+8), R1, R5
   772  				//	CMP R4, R5
   773  				//	BNE end
   774  				//	ADD $8, R1, R6
   775  				//	MOVD R6, panic_argp(R3)
   776  				// end:
   777  				//	NOP
   778  				//
   779  				// The NOP is needed to give the jumps somewhere to land.
   780  				// It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes.
   781  
   782  				q = obj.Appendp(q, c.newprog)
   783  
   784  				q.As = AMOVD
   785  				q.From.Type = obj.TYPE_MEM
   786  				q.From.Reg = REGG
   787  				q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
   788  				q.To.Type = obj.TYPE_REG
   789  				q.To.Reg = REG_R22
   790  
   791  				q = obj.Appendp(q, c.newprog)
   792  				q.As = ACMP
   793  				q.From.Type = obj.TYPE_REG
   794  				q.From.Reg = REG_R0
   795  				q.To.Type = obj.TYPE_REG
   796  				q.To.Reg = REG_R22
   797  
   798  				q = obj.Appendp(q, c.newprog)
   799  				q.As = ABEQ
   800  				q.To.Type = obj.TYPE_BRANCH
   801  				p1 = q
   802  
   803  				q = obj.Appendp(q, c.newprog)
   804  				q.As = AMOVD
   805  				q.From.Type = obj.TYPE_MEM
   806  				q.From.Reg = REG_R22
   807  				q.From.Offset = 0 // Panic.argp
   808  				q.To.Type = obj.TYPE_REG
   809  				q.To.Reg = REG_R23
   810  
   811  				q = obj.Appendp(q, c.newprog)
   812  				q.As = AADD
   813  				q.From.Type = obj.TYPE_CONST
   814  				q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize()
   815  				q.Reg = REGSP
   816  				q.To.Type = obj.TYPE_REG
   817  				q.To.Reg = REG_R24
   818  
   819  				q = obj.Appendp(q, c.newprog)
   820  				q.As = ACMP
   821  				q.From.Type = obj.TYPE_REG
   822  				q.From.Reg = REG_R23
   823  				q.To.Type = obj.TYPE_REG
   824  				q.To.Reg = REG_R24
   825  
   826  				q = obj.Appendp(q, c.newprog)
   827  				q.As = ABNE
   828  				q.To.Type = obj.TYPE_BRANCH
   829  				p2 = q
   830  
   831  				q = obj.Appendp(q, c.newprog)
   832  				q.As = AADD
   833  				q.From.Type = obj.TYPE_CONST
   834  				q.From.Offset = c.ctxt.FixedFrameSize()
   835  				q.Reg = REGSP
   836  				q.To.Type = obj.TYPE_REG
   837  				q.To.Reg = REG_R25
   838  
   839  				q = obj.Appendp(q, c.newprog)
   840  				q.As = AMOVD
   841  				q.From.Type = obj.TYPE_REG
   842  				q.From.Reg = REG_R25
   843  				q.To.Type = obj.TYPE_MEM
   844  				q.To.Reg = REG_R22
   845  				q.To.Offset = 0 // Panic.argp
   846  
   847  				q = obj.Appendp(q, c.newprog)
   848  
   849  				q.As = obj.ANOP
   850  				p1.To.SetTarget(q)
   851  				p2.To.SetTarget(q)
   852  			}
   853  
   854  		case obj.ARET:
   855  			if p.From.Type == obj.TYPE_CONST {
   856  				c.ctxt.Diag("using BECOME (%v) is not supported!", p)
   857  				break
   858  			}
   859  
   860  			retTarget := p.To.Sym
   861  
   862  			if c.cursym.Func().Text.Mark&LEAF != 0 {
   863  				if autosize == 0 || c.cursym.Name == "runtime.racecallbackthunk" {
   864  					p.As = ABR
   865  					p.From = obj.Addr{}
   866  					if retTarget == nil {
   867  						p.To.Type = obj.TYPE_REG
   868  						p.To.Reg = REG_LR
   869  					} else {
   870  						p.To.Type = obj.TYPE_BRANCH
   871  						p.To.Sym = retTarget
   872  					}
   873  					p.Mark |= BRANCH
   874  					break
   875  				}
   876  
   877  				p.As = AADD
   878  				p.From.Type = obj.TYPE_CONST
   879  				p.From.Offset = int64(autosize)
   880  				p.To.Type = obj.TYPE_REG
   881  				p.To.Reg = REGSP
   882  				p.Spadj = -autosize
   883  
   884  				q = c.newprog()
   885  				q.As = ABR
   886  				q.Pos = p.Pos
   887  				if retTarget == nil {
   888  					q.To.Type = obj.TYPE_REG
   889  					q.To.Reg = REG_LR
   890  				} else {
   891  					q.To.Type = obj.TYPE_BRANCH
   892  					q.To.Sym = retTarget
   893  				}
   894  				q.Mark |= BRANCH
   895  				q.Spadj = +autosize
   896  
   897  				q.Link = p.Link
   898  				p.Link = q
   899  				break
   900  			}
   901  
   902  			p.As = AMOVD
   903  			p.From.Type = obj.TYPE_MEM
   904  			p.From.Offset = 0
   905  			p.From.Reg = REGSP
   906  			p.To.Type = obj.TYPE_REG
   907  			p.To.Reg = REGTMP
   908  
   909  			q = c.newprog()
   910  			q.As = AMOVD
   911  			q.Pos = p.Pos
   912  			q.From.Type = obj.TYPE_REG
   913  			q.From.Reg = REGTMP
   914  			q.To.Type = obj.TYPE_REG
   915  			q.To.Reg = REG_LR
   916  
   917  			q.Link = p.Link
   918  			p.Link = q
   919  			p = q
   920  
   921  			if false {
   922  				// Debug bad returns
   923  				q = c.newprog()
   924  
   925  				q.As = AMOVD
   926  				q.Pos = p.Pos
   927  				q.From.Type = obj.TYPE_MEM
   928  				q.From.Offset = 0
   929  				q.From.Reg = REGTMP
   930  				q.To.Type = obj.TYPE_REG
   931  				q.To.Reg = REGTMP
   932  
   933  				q.Link = p.Link
   934  				p.Link = q
   935  				p = q
   936  			}
   937  			prev := p
   938  			if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" {
   939  				q = c.newprog()
   940  				q.As = AADD
   941  				q.Pos = p.Pos
   942  				q.From.Type = obj.TYPE_CONST
   943  				q.From.Offset = int64(autosize)
   944  				q.To.Type = obj.TYPE_REG
   945  				q.To.Reg = REGSP
   946  				q.Spadj = -autosize
   947  
   948  				q.Link = p.Link
   949  				prev.Link = q
   950  				prev = q
   951  			}
   952  
   953  			q1 = c.newprog()
   954  			q1.As = ABR
   955  			q1.Pos = p.Pos
   956  			if retTarget == nil {
   957  				q1.To.Type = obj.TYPE_REG
   958  				q1.To.Reg = REG_LR
   959  			} else {
   960  				q1.To.Type = obj.TYPE_BRANCH
   961  				q1.To.Sym = retTarget
   962  			}
   963  			q1.Mark |= BRANCH
   964  			q1.Spadj = +autosize
   965  
   966  			q1.Link = q.Link
   967  			prev.Link = q1
   968  		case AADD:
   969  			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
   970  				p.Spadj = int32(-p.From.Offset)
   971  			}
   972  		case AMOVDU:
   973  			if p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
   974  				p.Spadj = int32(-p.To.Offset)
   975  			}
   976  			if p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP {
   977  				p.Spadj = int32(-p.From.Offset)
   978  			}
   979  		case obj.AGETCALLERPC:
   980  			if cursym.Leaf() {
   981  				/* MOVD LR, Rd */
   982  				p.As = AMOVD
   983  				p.From.Type = obj.TYPE_REG
   984  				p.From.Reg = REG_LR
   985  			} else {
   986  				/* MOVD (RSP), Rd */
   987  				p.As = AMOVD
   988  				p.From.Type = obj.TYPE_MEM
   989  				p.From.Reg = REGSP
   990  			}
   991  		}
   992  
   993  		if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 && p.As != ACMPU {
   994  			f := c.cursym.Func()
   995  			if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
   996  				c.cursym.Func().FuncFlag |= objabi.FuncFlag_SPWRITE
   997  				if ctxt.Debugvlog || !ctxt.IsAsm {
   998  					ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
   999  					if !ctxt.IsAsm {
  1000  						ctxt.Diag("invalid auto-SPWRITE in non-assembly")
  1001  						ctxt.DiagFlush()
  1002  						log.Fatalf("bad SPWRITE")
  1003  					}
  1004  				}
  1005  			}
  1006  		}
  1007  	}
  1008  }
  1009  
  1010  /*
  1011  // instruction scheduling
  1012  	if(debug['Q'] == 0)
  1013  		return;
  1014  
  1015  	curtext = nil;
  1016  	q = nil;	// p - 1
  1017  	q1 = firstp;	// top of block
  1018  	o = 0;		// count of instructions
  1019  	for(p = firstp; p != nil; p = p1) {
  1020  		p1 = p->link;
  1021  		o++;
  1022  		if(p->mark & NOSCHED){
  1023  			if(q1 != p){
  1024  				sched(q1, q);
  1025  			}
  1026  			for(; p != nil; p = p->link){
  1027  				if(!(p->mark & NOSCHED))
  1028  					break;
  1029  				q = p;
  1030  			}
  1031  			p1 = p;
  1032  			q1 = p;
  1033  			o = 0;
  1034  			continue;
  1035  		}
  1036  		if(p->mark & (LABEL|SYNC)) {
  1037  			if(q1 != p)
  1038  				sched(q1, q);
  1039  			q1 = p;
  1040  			o = 1;
  1041  		}
  1042  		if(p->mark & (BRANCH|SYNC)) {
  1043  			sched(q1, p);
  1044  			q1 = p1;
  1045  			o = 0;
  1046  		}
  1047  		if(o >= NSCHED) {
  1048  			sched(q1, p);
  1049  			q1 = p1;
  1050  			o = 0;
  1051  		}
  1052  		q = p;
  1053  	}
  1054  */
  1055  func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
  1056  	if c.ctxt.Flag_maymorestack != "" {
  1057  		if c.ctxt.Flag_shared || c.ctxt.Flag_dynlink {
  1058  			// See the call to morestack for why these are
  1059  			// complicated to support.
  1060  			c.ctxt.Diag("maymorestack with -shared or -dynlink is not supported")
  1061  		}
  1062  
  1063  		// Spill arguments. This has to happen before we open
  1064  		// any more frame space.
  1065  		p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
  1066  
  1067  		// Save LR and REGCTXT
  1068  		frameSize := 8 + c.ctxt.FixedFrameSize()
  1069  
  1070  		// MOVD LR, REGTMP
  1071  		p = obj.Appendp(p, c.newprog)
  1072  		p.As = AMOVD
  1073  		p.From.Type = obj.TYPE_REG
  1074  		p.From.Reg = REG_LR
  1075  		p.To.Type = obj.TYPE_REG
  1076  		p.To.Reg = REGTMP
  1077  		// MOVDU REGTMP, -16(SP)
  1078  		p = obj.Appendp(p, c.newprog)
  1079  		p.As = AMOVDU
  1080  		p.From.Type = obj.TYPE_REG
  1081  		p.From.Reg = REGTMP
  1082  		p.To.Type = obj.TYPE_MEM
  1083  		p.To.Offset = -frameSize
  1084  		p.To.Reg = REGSP
  1085  		p.Spadj = int32(frameSize)
  1086  
  1087  		// MOVD REGCTXT, 8(SP)
  1088  		p = obj.Appendp(p, c.newprog)
  1089  		p.As = AMOVD
  1090  		p.From.Type = obj.TYPE_REG
  1091  		p.From.Reg = REGCTXT
  1092  		p.To.Type = obj.TYPE_MEM
  1093  		p.To.Offset = 8
  1094  		p.To.Reg = REGSP
  1095  
  1096  		// BL maymorestack
  1097  		p = obj.Appendp(p, c.newprog)
  1098  		p.As = ABL
  1099  		p.To.Type = obj.TYPE_BRANCH
  1100  		// See ../x86/obj6.go
  1101  		p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
  1102  
  1103  		// Restore LR and REGCTXT
  1104  
  1105  		// MOVD 8(SP), REGCTXT
  1106  		p = obj.Appendp(p, c.newprog)
  1107  		p.As = AMOVD
  1108  		p.From.Type = obj.TYPE_MEM
  1109  		p.From.Offset = 8
  1110  		p.From.Reg = REGSP
  1111  		p.To.Type = obj.TYPE_REG
  1112  		p.To.Reg = REGCTXT
  1113  
  1114  		// MOVD 0(SP), REGTMP
  1115  		p = obj.Appendp(p, c.newprog)
  1116  		p.As = AMOVD
  1117  		p.From.Type = obj.TYPE_MEM
  1118  		p.From.Offset = 0
  1119  		p.From.Reg = REGSP
  1120  		p.To.Type = obj.TYPE_REG
  1121  		p.To.Reg = REGTMP
  1122  
  1123  		// MOVD REGTMP, LR
  1124  		p = obj.Appendp(p, c.newprog)
  1125  		p.As = AMOVD
  1126  		p.From.Type = obj.TYPE_REG
  1127  		p.From.Reg = REGTMP
  1128  		p.To.Type = obj.TYPE_REG
  1129  		p.To.Reg = REG_LR
  1130  
  1131  		// ADD $16, SP
  1132  		p = obj.Appendp(p, c.newprog)
  1133  		p.As = AADD
  1134  		p.From.Type = obj.TYPE_CONST
  1135  		p.From.Offset = frameSize
  1136  		p.To.Type = obj.TYPE_REG
  1137  		p.To.Reg = REGSP
  1138  		p.Spadj = -int32(frameSize)
  1139  
  1140  		// Unspill arguments.
  1141  		p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
  1142  	}
  1143  
  1144  	// save entry point, but skipping the two instructions setting R2 in shared mode and maymorestack
  1145  	startPred := p
  1146  
  1147  	// MOVD	g_stackguard(g), R22
  1148  	p = obj.Appendp(p, c.newprog)
  1149  
  1150  	p.As = AMOVD
  1151  	p.From.Type = obj.TYPE_MEM
  1152  	p.From.Reg = REGG
  1153  	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
  1154  	if c.cursym.CFunc() {
  1155  		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
  1156  	}
  1157  	p.To.Type = obj.TYPE_REG
  1158  	p.To.Reg = REG_R22
  1159  
  1160  	// Mark the stack bound check and morestack call async nonpreemptible.
  1161  	// If we get preempted here, when resumed the preemption request is
  1162  	// cleared, but we'll still call morestack, which will double the stack
  1163  	// unnecessarily. See issue #35470.
  1164  	p = c.ctxt.StartUnsafePoint(p, c.newprog)
  1165  
  1166  	var q *obj.Prog
  1167  	if framesize <= objabi.StackSmall {
  1168  		// small stack: SP < stackguard
  1169  		//	CMP	stackguard, SP
  1170  		p = obj.Appendp(p, c.newprog)
  1171  
  1172  		p.As = ACMPU
  1173  		p.From.Type = obj.TYPE_REG
  1174  		p.From.Reg = REG_R22
  1175  		p.To.Type = obj.TYPE_REG
  1176  		p.To.Reg = REGSP
  1177  	} else {
  1178  		// large stack: SP-framesize < stackguard-StackSmall
  1179  		offset := int64(framesize) - objabi.StackSmall
  1180  		if framesize > objabi.StackBig {
  1181  			// Such a large stack we need to protect against underflow.
  1182  			// The runtime guarantees SP > objabi.StackBig, but
  1183  			// framesize is large enough that SP-framesize may
  1184  			// underflow, causing a direct comparison with the
  1185  			// stack guard to incorrectly succeed. We explicitly
  1186  			// guard against underflow.
  1187  			//
  1188  			//	CMPU	SP, $(framesize-StackSmall)
  1189  			//	BLT	label-of-call-to-morestack
  1190  			if offset <= 0xffff {
  1191  				p = obj.Appendp(p, c.newprog)
  1192  				p.As = ACMPU
  1193  				p.From.Type = obj.TYPE_REG
  1194  				p.From.Reg = REGSP
  1195  				p.To.Type = obj.TYPE_CONST
  1196  				p.To.Offset = offset
  1197  			} else {
  1198  				// Constant is too big for CMPU.
  1199  				p = obj.Appendp(p, c.newprog)
  1200  				p.As = AMOVD
  1201  				p.From.Type = obj.TYPE_CONST
  1202  				p.From.Offset = offset
  1203  				p.To.Type = obj.TYPE_REG
  1204  				p.To.Reg = REG_R23
  1205  
  1206  				p = obj.Appendp(p, c.newprog)
  1207  				p.As = ACMPU
  1208  				p.From.Type = obj.TYPE_REG
  1209  				p.From.Reg = REGSP
  1210  				p.To.Type = obj.TYPE_REG
  1211  				p.To.Reg = REG_R23
  1212  			}
  1213  
  1214  			p = obj.Appendp(p, c.newprog)
  1215  			q = p
  1216  			p.As = ABLT
  1217  			p.To.Type = obj.TYPE_BRANCH
  1218  		}
  1219  
  1220  		// Check against the stack guard. We've ensured this won't underflow.
  1221  		//	ADD  $-(framesize-StackSmall), SP, R4
  1222  		//	CMPU stackguard, R4
  1223  		p = obj.Appendp(p, c.newprog)
  1224  
  1225  		p.As = AADD
  1226  		p.From.Type = obj.TYPE_CONST
  1227  		p.From.Offset = -offset
  1228  		p.Reg = REGSP
  1229  		p.To.Type = obj.TYPE_REG
  1230  		p.To.Reg = REG_R23
  1231  
  1232  		p = obj.Appendp(p, c.newprog)
  1233  		p.As = ACMPU
  1234  		p.From.Type = obj.TYPE_REG
  1235  		p.From.Reg = REG_R22
  1236  		p.To.Type = obj.TYPE_REG
  1237  		p.To.Reg = REG_R23
  1238  	}
  1239  
  1240  	// q1: BLT	done
  1241  	p = obj.Appendp(p, c.newprog)
  1242  	q1 := p
  1243  
  1244  	p.As = ABLT
  1245  	p.To.Type = obj.TYPE_BRANCH
  1246  
  1247  	p = obj.Appendp(p, c.newprog)
  1248  	p.As = obj.ANOP // zero-width place holder
  1249  
  1250  	if q != nil {
  1251  		q.To.SetTarget(p)
  1252  	}
  1253  
  1254  	// Spill the register args that could be clobbered by the
  1255  	// morestack code.
  1256  
  1257  	spill := c.cursym.Func().SpillRegisterArgs(p, c.newprog)
  1258  
  1259  	// MOVD LR, R5
  1260  	p = obj.Appendp(spill, c.newprog)
  1261  	p.As = AMOVD
  1262  	p.From.Type = obj.TYPE_REG
  1263  	p.From.Reg = REG_LR
  1264  	p.To.Type = obj.TYPE_REG
  1265  	p.To.Reg = REG_R5
  1266  
  1267  	p = c.ctxt.EmitEntryStackMap(c.cursym, p, c.newprog)
  1268  
  1269  	var morestacksym *obj.LSym
  1270  	if c.cursym.CFunc() {
  1271  		morestacksym = c.ctxt.Lookup("runtime.morestackc")
  1272  	} else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
  1273  		morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt")
  1274  	} else {
  1275  		morestacksym = c.ctxt.Lookup("runtime.morestack")
  1276  	}
  1277  
  1278  	if c.ctxt.Flag_shared {
  1279  		// In PPC64 PIC code, R2 is used as TOC pointer derived from R12
  1280  		// which is the address of function entry point when entering
  1281  		// the function. We need to preserve R2 across call to morestack.
  1282  		// Fortunately, in shared mode, 8(SP) and 16(SP) are reserved in
  1283  		// the caller's frame, but not used (0(SP) is caller's saved LR,
  1284  		// 24(SP) is caller's saved R2). Use 8(SP) to save this function's R2.
  1285  		// MOVD R2, 8(SP)
  1286  		p = obj.Appendp(p, c.newprog)
  1287  		p.As = AMOVD
  1288  		p.From.Type = obj.TYPE_REG
  1289  		p.From.Reg = REG_R2
  1290  		p.To.Type = obj.TYPE_MEM
  1291  		p.To.Reg = REGSP
  1292  		p.To.Offset = 8
  1293  	}
  1294  
  1295  	if c.ctxt.Flag_dynlink {
  1296  		// Avoid calling morestack via a PLT when dynamically linking. The
  1297  		// PLT stubs generated by the system linker on ppc64le when "std r2,
  1298  		// 24(r1)" to save the TOC pointer in their callers stack
  1299  		// frame. Unfortunately (and necessarily) morestack is called before
  1300  		// the function that calls it sets up its frame and so the PLT ends
  1301  		// up smashing the saved TOC pointer for its caller's caller.
  1302  		//
  1303  		// According to the ABI documentation there is a mechanism to avoid
  1304  		// the TOC save that the PLT stub does (put a R_PPC64_TOCSAVE
  1305  		// relocation on the nop after the call to morestack) but at the time
  1306  		// of writing it is not supported at all by gold and my attempt to
  1307  		// use it with ld.bfd caused an internal linker error. So this hack
  1308  		// seems preferable.
  1309  
  1310  		// MOVD $runtime.morestack(SB), R12
  1311  		p = obj.Appendp(p, c.newprog)
  1312  		p.As = AMOVD
  1313  		p.From.Type = obj.TYPE_MEM
  1314  		p.From.Sym = morestacksym
  1315  		p.From.Name = obj.NAME_GOTREF
  1316  		p.To.Type = obj.TYPE_REG
  1317  		p.To.Reg = REG_R12
  1318  
  1319  		// MOVD R12, LR
  1320  		p = obj.Appendp(p, c.newprog)
  1321  		p.As = AMOVD
  1322  		p.From.Type = obj.TYPE_REG
  1323  		p.From.Reg = REG_R12
  1324  		p.To.Type = obj.TYPE_REG
  1325  		p.To.Reg = REG_LR
  1326  
  1327  		// BL LR
  1328  		p = obj.Appendp(p, c.newprog)
  1329  		p.As = obj.ACALL
  1330  		p.To.Type = obj.TYPE_REG
  1331  		p.To.Reg = REG_LR
  1332  	} else {
  1333  		// BL	runtime.morestack(SB)
  1334  		p = obj.Appendp(p, c.newprog)
  1335  
  1336  		p.As = ABL
  1337  		p.To.Type = obj.TYPE_BRANCH
  1338  		p.To.Sym = morestacksym
  1339  	}
  1340  
  1341  	if c.ctxt.Flag_shared {
  1342  		// MOVD 8(SP), R2
  1343  		p = obj.Appendp(p, c.newprog)
  1344  		p.As = AMOVD
  1345  		p.From.Type = obj.TYPE_MEM
  1346  		p.From.Reg = REGSP
  1347  		p.From.Offset = 8
  1348  		p.To.Type = obj.TYPE_REG
  1349  		p.To.Reg = REG_R2
  1350  	}
  1351  
  1352  	unspill := c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
  1353  	p = c.ctxt.EndUnsafePoint(unspill, c.newprog, -1)
  1354  
  1355  	// BR	start
  1356  	p = obj.Appendp(p, c.newprog)
  1357  	p.As = ABR
  1358  	p.To.Type = obj.TYPE_BRANCH
  1359  	p.To.SetTarget(startPred.Link)
  1360  
  1361  	// placeholder for q1's jump target
  1362  	p = obj.Appendp(p, c.newprog)
  1363  
  1364  	p.As = obj.ANOP // zero-width place holder
  1365  	q1.To.SetTarget(p)
  1366  
  1367  	return p
  1368  }
  1369  
  1370  var Linkppc64 = obj.LinkArch{
  1371  	Arch:           sys.ArchPPC64,
  1372  	Init:           buildop,
  1373  	Preprocess:     preprocess,
  1374  	Assemble:       span9,
  1375  	Progedit:       progedit,
  1376  	DWARFRegisters: PPC64DWARFRegisters,
  1377  }
  1378  
  1379  var Linkppc64le = obj.LinkArch{
  1380  	Arch:           sys.ArchPPC64LE,
  1381  	Init:           buildop,
  1382  	Preprocess:     preprocess,
  1383  	Assemble:       span9,
  1384  	Progedit:       progedit,
  1385  	DWARFRegisters: PPC64DWARFRegisters,
  1386  }
  1387  

View as plain text