github.com/sanprasirt/go@v0.0.0-20170607001320-a027466e4b6d/src/cmd/internal/obj/ppc64/obj9.go (about)

     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/sys"
    36  )
    37  
    38  func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
    39  	p.From.Class = 0
    40  	p.To.Class = 0
    41  
    42  	c := ctxt9{ctxt: ctxt, newprog: newprog}
    43  
    44  	// Rewrite BR/BL to symbol as TYPE_BRANCH.
    45  	switch p.As {
    46  	case ABR,
    47  		ABL,
    48  		obj.ARET,
    49  		obj.ADUFFZERO,
    50  		obj.ADUFFCOPY:
    51  		if p.To.Sym != nil {
    52  			p.To.Type = obj.TYPE_BRANCH
    53  		}
    54  	}
    55  
    56  	// Rewrite float constants to values stored in memory.
    57  	switch p.As {
    58  	case AFMOVS:
    59  		if p.From.Type == obj.TYPE_FCONST {
    60  			f32 := float32(p.From.Val.(float64))
    61  			p.From.Type = obj.TYPE_MEM
    62  			p.From.Sym = ctxt.Float32Sym(f32)
    63  			p.From.Name = obj.NAME_EXTERN
    64  			p.From.Offset = 0
    65  		}
    66  
    67  	case AFMOVD:
    68  		if p.From.Type == obj.TYPE_FCONST {
    69  			f64 := p.From.Val.(float64)
    70  			p.From.Type = obj.TYPE_MEM
    71  			p.From.Sym = ctxt.Float64Sym(f64)
    72  			p.From.Name = obj.NAME_EXTERN
    73  			p.From.Offset = 0
    74  		}
    75  
    76  		// Put >32-bit constants in memory and load them
    77  	case AMOVD:
    78  		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 {
    79  			p.From.Type = obj.TYPE_MEM
    80  			p.From.Sym = ctxt.Int64Sym(p.From.Offset)
    81  			p.From.Name = obj.NAME_EXTERN
    82  			p.From.Offset = 0
    83  		}
    84  	}
    85  
    86  	// Rewrite SUB constants into ADD.
    87  	switch p.As {
    88  	case ASUBC:
    89  		if p.From.Type == obj.TYPE_CONST {
    90  			p.From.Offset = -p.From.Offset
    91  			p.As = AADDC
    92  		}
    93  
    94  	case ASUBCCC:
    95  		if p.From.Type == obj.TYPE_CONST {
    96  			p.From.Offset = -p.From.Offset
    97  			p.As = AADDCCC
    98  		}
    99  
   100  	case ASUB:
   101  		if p.From.Type == obj.TYPE_CONST {
   102  			p.From.Offset = -p.From.Offset
   103  			p.As = AADD
   104  		}
   105  	}
   106  	if c.ctxt.Flag_dynlink {
   107  		c.rewriteToUseGot(p)
   108  	}
   109  }
   110  
   111  // Rewrite p, if necessary, to access global data via the global offset table.
   112  func (c *ctxt9) rewriteToUseGot(p *obj.Prog) {
   113  	if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
   114  		//     ADUFFxxx $offset
   115  		// becomes
   116  		//     MOVD runtime.duffxxx@GOT, R12
   117  		//     ADD $offset, R12
   118  		//     MOVD R12, CTR
   119  		//     BL (CTR)
   120  		var sym *obj.LSym
   121  		if p.As == obj.ADUFFZERO {
   122  			sym = c.ctxt.Lookup("runtime.duffzero")
   123  		} else {
   124  			sym = c.ctxt.Lookup("runtime.duffcopy")
   125  		}
   126  		offset := p.To.Offset
   127  		p.As = AMOVD
   128  		p.From.Type = obj.TYPE_MEM
   129  		p.From.Name = obj.NAME_GOTREF
   130  		p.From.Sym = sym
   131  		p.To.Type = obj.TYPE_REG
   132  		p.To.Reg = REG_R12
   133  		p.To.Name = obj.NAME_NONE
   134  		p.To.Offset = 0
   135  		p.To.Sym = nil
   136  		p1 := obj.Appendp(p, c.newprog)
   137  		p1.As = AADD
   138  		p1.From.Type = obj.TYPE_CONST
   139  		p1.From.Offset = offset
   140  		p1.To.Type = obj.TYPE_REG
   141  		p1.To.Reg = REG_R12
   142  		p2 := obj.Appendp(p1, c.newprog)
   143  		p2.As = AMOVD
   144  		p2.From.Type = obj.TYPE_REG
   145  		p2.From.Reg = REG_R12
   146  		p2.To.Type = obj.TYPE_REG
   147  		p2.To.Reg = REG_CTR
   148  		p3 := obj.Appendp(p2, c.newprog)
   149  		p3.As = obj.ACALL
   150  		p3.From.Type = obj.TYPE_REG
   151  		p3.From.Reg = REG_R12
   152  		p3.To.Type = obj.TYPE_REG
   153  		p3.To.Reg = REG_CTR
   154  	}
   155  
   156  	// We only care about global data: NAME_EXTERN means a global
   157  	// symbol in the Go sense, and p.Sym.Local is true for a few
   158  	// internally defined symbols.
   159  	if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   160  		// MOVD $sym, Rx becomes MOVD sym@GOT, Rx
   161  		// MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx
   162  		if p.As != AMOVD {
   163  			c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
   164  		}
   165  		if p.To.Type != obj.TYPE_REG {
   166  			c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
   167  		}
   168  		p.From.Type = obj.TYPE_MEM
   169  		p.From.Name = obj.NAME_GOTREF
   170  		if p.From.Offset != 0 {
   171  			q := obj.Appendp(p, c.newprog)
   172  			q.As = AADD
   173  			q.From.Type = obj.TYPE_CONST
   174  			q.From.Offset = p.From.Offset
   175  			q.To = p.To
   176  			p.From.Offset = 0
   177  		}
   178  	}
   179  	if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
   180  		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
   181  	}
   182  	var source *obj.Addr
   183  	// MOVx sym, Ry becomes MOVD sym@GOT, REGTMP; MOVx (REGTMP), Ry
   184  	// MOVx Ry, sym becomes MOVD sym@GOT, REGTMP; MOVx Ry, (REGTMP)
   185  	// An addition may be inserted between the two MOVs if there is an offset.
   186  	if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
   187  		if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   188  			c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
   189  		}
   190  		source = &p.From
   191  	} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
   192  		source = &p.To
   193  	} else {
   194  		return
   195  	}
   196  	if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
   197  		return
   198  	}
   199  	if source.Sym.Type == objabi.STLSBSS {
   200  		return
   201  	}
   202  	if source.Type != obj.TYPE_MEM {
   203  		c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
   204  	}
   205  	p1 := obj.Appendp(p, c.newprog)
   206  	p2 := obj.Appendp(p1, c.newprog)
   207  
   208  	p1.As = AMOVD
   209  	p1.From.Type = obj.TYPE_MEM
   210  	p1.From.Sym = source.Sym
   211  	p1.From.Name = obj.NAME_GOTREF
   212  	p1.To.Type = obj.TYPE_REG
   213  	p1.To.Reg = REGTMP
   214  
   215  	p2.As = p.As
   216  	p2.From = p.From
   217  	p2.To = p.To
   218  	if p.From.Name == obj.NAME_EXTERN {
   219  		p2.From.Reg = REGTMP
   220  		p2.From.Name = obj.NAME_NONE
   221  		p2.From.Sym = nil
   222  	} else if p.To.Name == obj.NAME_EXTERN {
   223  		p2.To.Reg = REGTMP
   224  		p2.To.Name = obj.NAME_NONE
   225  		p2.To.Sym = nil
   226  	} else {
   227  		return
   228  	}
   229  	obj.Nopout(p)
   230  }
   231  
   232  func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
   233  	// TODO(minux): add morestack short-cuts with small fixed frame-size.
   234  	if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
   235  		return
   236  	}
   237  
   238  	c := ctxt9{ctxt: ctxt, cursym: cursym, newprog: newprog}
   239  
   240  	p := c.cursym.Func.Text
   241  	textstksiz := p.To.Offset
   242  	if textstksiz == -8 {
   243  		// Compatibility hack.
   244  		p.From.Sym.Set(obj.AttrNoFrame, true)
   245  		textstksiz = 0
   246  	}
   247  	if textstksiz%8 != 0 {
   248  		c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
   249  	}
   250  	if p.From.Sym.NoFrame() {
   251  		if textstksiz != 0 {
   252  			c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
   253  		}
   254  	}
   255  
   256  	c.cursym.Func.Args = p.To.Val.(int32)
   257  	c.cursym.Func.Locals = int32(textstksiz)
   258  
   259  	/*
   260  	 * find leaf subroutines
   261  	 * strip NOPs
   262  	 * expand RET
   263  	 * expand BECOME pseudo
   264  	 */
   265  
   266  	var q *obj.Prog
   267  	var q1 *obj.Prog
   268  	for p := c.cursym.Func.Text; p != nil; p = p.Link {
   269  		switch p.As {
   270  		/* too hard, just leave alone */
   271  		case obj.ATEXT:
   272  			q = p
   273  
   274  			p.Mark |= LABEL | LEAF | SYNC
   275  			if p.Link != nil {
   276  				p.Link.Mark |= LABEL
   277  			}
   278  
   279  		case ANOR:
   280  			q = p
   281  			if p.To.Type == obj.TYPE_REG {
   282  				if p.To.Reg == REGZERO {
   283  					p.Mark |= LABEL | SYNC
   284  				}
   285  			}
   286  
   287  		case ALWAR,
   288  			ALBAR,
   289  			ASTBCCC,
   290  			ASTWCCC,
   291  			AECIWX,
   292  			AECOWX,
   293  			AEIEIO,
   294  			AICBI,
   295  			AISYNC,
   296  			ATLBIE,
   297  			ATLBIEL,
   298  			ASLBIA,
   299  			ASLBIE,
   300  			ASLBMFEE,
   301  			ASLBMFEV,
   302  			ASLBMTE,
   303  			ADCBF,
   304  			ADCBI,
   305  			ADCBST,
   306  			ADCBT,
   307  			ADCBTST,
   308  			ADCBZ,
   309  			ASYNC,
   310  			ATLBSYNC,
   311  			APTESYNC,
   312  			ALWSYNC,
   313  			ATW,
   314  			AWORD,
   315  			ARFI,
   316  			ARFCI,
   317  			ARFID,
   318  			AHRFID:
   319  			q = p
   320  			p.Mark |= LABEL | SYNC
   321  			continue
   322  
   323  		case AMOVW, AMOVWZ, AMOVD:
   324  			q = p
   325  			if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL {
   326  				p.Mark |= LABEL | SYNC
   327  			}
   328  			continue
   329  
   330  		case AFABS,
   331  			AFABSCC,
   332  			AFADD,
   333  			AFADDCC,
   334  			AFCTIW,
   335  			AFCTIWCC,
   336  			AFCTIWZ,
   337  			AFCTIWZCC,
   338  			AFDIV,
   339  			AFDIVCC,
   340  			AFMADD,
   341  			AFMADDCC,
   342  			AFMOVD,
   343  			AFMOVDU,
   344  			/* case AFMOVDS: */
   345  			AFMOVS,
   346  			AFMOVSU,
   347  
   348  			/* case AFMOVSD: */
   349  			AFMSUB,
   350  			AFMSUBCC,
   351  			AFMUL,
   352  			AFMULCC,
   353  			AFNABS,
   354  			AFNABSCC,
   355  			AFNEG,
   356  			AFNEGCC,
   357  			AFNMADD,
   358  			AFNMADDCC,
   359  			AFNMSUB,
   360  			AFNMSUBCC,
   361  			AFRSP,
   362  			AFRSPCC,
   363  			AFSUB,
   364  			AFSUBCC:
   365  			q = p
   366  
   367  			p.Mark |= FLOAT
   368  			continue
   369  
   370  		case ABL,
   371  			ABCL,
   372  			obj.ADUFFZERO,
   373  			obj.ADUFFCOPY:
   374  			c.cursym.Func.Text.Mark &^= LEAF
   375  			fallthrough
   376  
   377  		case ABC,
   378  			ABEQ,
   379  			ABGE,
   380  			ABGT,
   381  			ABLE,
   382  			ABLT,
   383  			ABNE,
   384  			ABR,
   385  			ABVC,
   386  			ABVS:
   387  			p.Mark |= BRANCH
   388  			q = p
   389  			q1 = p.Pcond
   390  			if q1 != nil {
   391  				for q1.As == obj.ANOP {
   392  					q1 = q1.Link
   393  					p.Pcond = q1
   394  				}
   395  
   396  				if q1.Mark&LEAF == 0 {
   397  					q1.Mark |= LABEL
   398  				}
   399  			} else {
   400  				p.Mark |= LABEL
   401  			}
   402  			q1 = p.Link
   403  			if q1 != nil {
   404  				q1.Mark |= LABEL
   405  			}
   406  			continue
   407  
   408  		case AFCMPO, AFCMPU:
   409  			q = p
   410  			p.Mark |= FCMP | FLOAT
   411  			continue
   412  
   413  		case obj.ARET:
   414  			q = p
   415  			if p.Link != nil {
   416  				p.Link.Mark |= LABEL
   417  			}
   418  			continue
   419  
   420  		case obj.ANOP:
   421  			q1 = p.Link
   422  			q.Link = q1 /* q is non-nop */
   423  			q1.Mark |= p.Mark
   424  			continue
   425  
   426  		default:
   427  			q = p
   428  			continue
   429  		}
   430  	}
   431  
   432  	autosize := int32(0)
   433  	var p1 *obj.Prog
   434  	var p2 *obj.Prog
   435  	for p := c.cursym.Func.Text; p != nil; p = p.Link {
   436  		o := p.As
   437  		switch o {
   438  		case obj.ATEXT:
   439  			autosize = int32(textstksiz)
   440  
   441  			if p.Mark&LEAF != 0 && autosize == 0 {
   442  				// A leaf function with no locals has no frame.
   443  				p.From.Sym.Set(obj.AttrNoFrame, true)
   444  			}
   445  
   446  			if !p.From.Sym.NoFrame() {
   447  				// If there is a stack frame at all, it includes
   448  				// space to save the LR.
   449  				autosize += int32(c.ctxt.FixedFrameSize())
   450  			}
   451  
   452  			if p.Mark&LEAF != 0 && autosize < objabi.StackSmall {
   453  				// A leaf function with a small stack can be marked
   454  				// NOSPLIT, avoiding a stack check.
   455  				p.From.Sym.Set(obj.AttrNoSplit, true)
   456  			}
   457  
   458  			p.To.Offset = int64(autosize)
   459  
   460  			q = p
   461  
   462  			if c.ctxt.Flag_shared && c.cursym.Name != "runtime.duffzero" && c.cursym.Name != "runtime.duffcopy" {
   463  				// When compiling Go into PIC, all functions must start
   464  				// with instructions to load the TOC pointer into r2:
   465  				//
   466  				//	addis r2, r12, .TOC.-func@ha
   467  				//	addi r2, r2, .TOC.-func@l+4
   468  				//
   469  				// We could probably skip this prologue in some situations
   470  				// but it's a bit subtle. However, it is both safe and
   471  				// necessary to leave the prologue off duffzero and
   472  				// duffcopy as we rely on being able to jump to a specific
   473  				// instruction offset for them.
   474  				//
   475  				// These are AWORDS because there is no (afaict) way to
   476  				// generate the addis instruction except as part of the
   477  				// load of a large constant, and in that case there is no
   478  				// way to use r12 as the source.
   479  				//
   480  				// Note that the same condition is tested in
   481  				// putelfsym in cmd/link/internal/ld/symtab.go
   482  				// where we set the st_other field to indicate
   483  				// the presence of these instructions.
   484  				q = obj.Appendp(q, c.newprog)
   485  				q.As = AWORD
   486  				q.Pos = p.Pos
   487  				q.From.Type = obj.TYPE_CONST
   488  				q.From.Offset = 0x3c4c0000
   489  				q = obj.Appendp(q, c.newprog)
   490  				q.As = AWORD
   491  				q.Pos = p.Pos
   492  				q.From.Type = obj.TYPE_CONST
   493  				q.From.Offset = 0x38420000
   494  				rel := obj.Addrel(c.cursym)
   495  				rel.Off = 0
   496  				rel.Siz = 8
   497  				rel.Sym = c.ctxt.Lookup(".TOC.")
   498  				rel.Type = objabi.R_ADDRPOWER_PCREL
   499  			}
   500  
   501  			if !c.cursym.Func.Text.From.Sym.NoSplit() {
   502  				q = c.stacksplit(q, autosize) // emit split check
   503  			}
   504  
   505  			if autosize != 0 {
   506  				// Save the link register and update the SP.  MOVDU is used unless
   507  				// the frame size is too large.  The link register must be saved
   508  				// even for non-empty leaf functions so that traceback works.
   509  				if autosize >= -BIG && autosize <= BIG {
   510  					// Use MOVDU to adjust R1 when saving R31, if autosize is small.
   511  					q = obj.Appendp(q, c.newprog)
   512  					q.As = AMOVD
   513  					q.Pos = p.Pos
   514  					q.From.Type = obj.TYPE_REG
   515  					q.From.Reg = REG_LR
   516  					q.To.Type = obj.TYPE_REG
   517  					q.To.Reg = REGTMP
   518  
   519  					q = obj.Appendp(q, c.newprog)
   520  					q.As = AMOVDU
   521  					q.Pos = p.Pos
   522  					q.From.Type = obj.TYPE_REG
   523  					q.From.Reg = REGTMP
   524  					q.To.Type = obj.TYPE_MEM
   525  					q.To.Offset = int64(-autosize)
   526  					q.To.Reg = REGSP
   527  					q.Spadj = int32(autosize)
   528  				} else {
   529  					// Frame size is too large for a MOVDU instruction.
   530  					// Store link register before decrementing SP, so if a signal comes
   531  					// during the execution of the function prologue, the traceback
   532  					// code will not see a half-updated stack frame.
   533  					q = obj.Appendp(q, c.newprog)
   534  					q.As = AMOVD
   535  					q.Pos = p.Pos
   536  					q.From.Type = obj.TYPE_REG
   537  					q.From.Reg = REG_LR
   538  					q.To.Type = obj.TYPE_REG
   539  					q.To.Reg = REG_R29 // REGTMP may be used to synthesize large offset in the next instruction
   540  
   541  					q = obj.Appendp(q, c.newprog)
   542  					q.As = AMOVD
   543  					q.Pos = p.Pos
   544  					q.From.Type = obj.TYPE_REG
   545  					q.From.Reg = REG_R29
   546  					q.To.Type = obj.TYPE_MEM
   547  					q.To.Offset = int64(-autosize)
   548  					q.To.Reg = REGSP
   549  
   550  					q = obj.Appendp(q, c.newprog)
   551  					q.As = AADD
   552  					q.Pos = p.Pos
   553  					q.From.Type = obj.TYPE_CONST
   554  					q.From.Offset = int64(-autosize)
   555  					q.To.Type = obj.TYPE_REG
   556  					q.To.Reg = REGSP
   557  					q.Spadj = +autosize
   558  				}
   559  			} else if c.cursym.Func.Text.Mark&LEAF == 0 {
   560  				// A very few functions that do not return to their caller
   561  				// (e.g. gogo) are not identified as leaves but still have
   562  				// no frame.
   563  				c.cursym.Func.Text.Mark |= LEAF
   564  			}
   565  
   566  			if c.cursym.Func.Text.Mark&LEAF != 0 {
   567  				c.cursym.Set(obj.AttrLeaf, true)
   568  				break
   569  			}
   570  
   571  			if c.ctxt.Flag_shared {
   572  				q = obj.Appendp(q, c.newprog)
   573  				q.As = AMOVD
   574  				q.Pos = p.Pos
   575  				q.From.Type = obj.TYPE_REG
   576  				q.From.Reg = REG_R2
   577  				q.To.Type = obj.TYPE_MEM
   578  				q.To.Reg = REGSP
   579  				q.To.Offset = 24
   580  			}
   581  
   582  			if c.cursym.Func.Text.From.Sym.Wrapper() {
   583  				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
   584  				//
   585  				//	MOVD g_panic(g), R3
   586  				//	CMP R0, R3
   587  				//	BEQ end
   588  				//	MOVD panic_argp(R3), R4
   589  				//	ADD $(autosize+8), R1, R5
   590  				//	CMP R4, R5
   591  				//	BNE end
   592  				//	ADD $8, R1, R6
   593  				//	MOVD R6, panic_argp(R3)
   594  				// end:
   595  				//	NOP
   596  				//
   597  				// The NOP is needed to give the jumps somewhere to land.
   598  				// It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes.
   599  
   600  				q = obj.Appendp(q, c.newprog)
   601  
   602  				q.As = AMOVD
   603  				q.From.Type = obj.TYPE_MEM
   604  				q.From.Reg = REGG
   605  				q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic
   606  				q.To.Type = obj.TYPE_REG
   607  				q.To.Reg = REG_R3
   608  
   609  				q = obj.Appendp(q, c.newprog)
   610  				q.As = ACMP
   611  				q.From.Type = obj.TYPE_REG
   612  				q.From.Reg = REG_R0
   613  				q.To.Type = obj.TYPE_REG
   614  				q.To.Reg = REG_R3
   615  
   616  				q = obj.Appendp(q, c.newprog)
   617  				q.As = ABEQ
   618  				q.To.Type = obj.TYPE_BRANCH
   619  				p1 = q
   620  
   621  				q = obj.Appendp(q, c.newprog)
   622  				q.As = AMOVD
   623  				q.From.Type = obj.TYPE_MEM
   624  				q.From.Reg = REG_R3
   625  				q.From.Offset = 0 // Panic.argp
   626  				q.To.Type = obj.TYPE_REG
   627  				q.To.Reg = REG_R4
   628  
   629  				q = obj.Appendp(q, c.newprog)
   630  				q.As = AADD
   631  				q.From.Type = obj.TYPE_CONST
   632  				q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize()
   633  				q.Reg = REGSP
   634  				q.To.Type = obj.TYPE_REG
   635  				q.To.Reg = REG_R5
   636  
   637  				q = obj.Appendp(q, c.newprog)
   638  				q.As = ACMP
   639  				q.From.Type = obj.TYPE_REG
   640  				q.From.Reg = REG_R4
   641  				q.To.Type = obj.TYPE_REG
   642  				q.To.Reg = REG_R5
   643  
   644  				q = obj.Appendp(q, c.newprog)
   645  				q.As = ABNE
   646  				q.To.Type = obj.TYPE_BRANCH
   647  				p2 = q
   648  
   649  				q = obj.Appendp(q, c.newprog)
   650  				q.As = AADD
   651  				q.From.Type = obj.TYPE_CONST
   652  				q.From.Offset = c.ctxt.FixedFrameSize()
   653  				q.Reg = REGSP
   654  				q.To.Type = obj.TYPE_REG
   655  				q.To.Reg = REG_R6
   656  
   657  				q = obj.Appendp(q, c.newprog)
   658  				q.As = AMOVD
   659  				q.From.Type = obj.TYPE_REG
   660  				q.From.Reg = REG_R6
   661  				q.To.Type = obj.TYPE_MEM
   662  				q.To.Reg = REG_R3
   663  				q.To.Offset = 0 // Panic.argp
   664  
   665  				q = obj.Appendp(q, c.newprog)
   666  
   667  				q.As = obj.ANOP
   668  				p1.Pcond = q
   669  				p2.Pcond = q
   670  			}
   671  
   672  		case obj.ARET:
   673  			if p.From.Type == obj.TYPE_CONST {
   674  				c.ctxt.Diag("using BECOME (%v) is not supported!", p)
   675  				break
   676  			}
   677  
   678  			retTarget := p.To.Sym
   679  
   680  			if c.cursym.Func.Text.Mark&LEAF != 0 {
   681  				if autosize == 0 {
   682  					p.As = ABR
   683  					p.From = obj.Addr{}
   684  					if retTarget == nil {
   685  						p.To.Type = obj.TYPE_REG
   686  						p.To.Reg = REG_LR
   687  					} else {
   688  						p.To.Type = obj.TYPE_BRANCH
   689  						p.To.Sym = retTarget
   690  					}
   691  					p.Mark |= BRANCH
   692  					break
   693  				}
   694  
   695  				p.As = AADD
   696  				p.From.Type = obj.TYPE_CONST
   697  				p.From.Offset = int64(autosize)
   698  				p.To.Type = obj.TYPE_REG
   699  				p.To.Reg = REGSP
   700  				p.Spadj = -autosize
   701  
   702  				q = c.newprog()
   703  				q.As = ABR
   704  				q.Pos = p.Pos
   705  				q.To.Type = obj.TYPE_REG
   706  				q.To.Reg = REG_LR
   707  				q.Mark |= BRANCH
   708  				q.Spadj = +autosize
   709  
   710  				q.Link = p.Link
   711  				p.Link = q
   712  				break
   713  			}
   714  
   715  			p.As = AMOVD
   716  			p.From.Type = obj.TYPE_MEM
   717  			p.From.Offset = 0
   718  			p.From.Reg = REGSP
   719  			p.To.Type = obj.TYPE_REG
   720  			p.To.Reg = REGTMP
   721  
   722  			q = c.newprog()
   723  			q.As = AMOVD
   724  			q.Pos = p.Pos
   725  			q.From.Type = obj.TYPE_REG
   726  			q.From.Reg = REGTMP
   727  			q.To.Type = obj.TYPE_REG
   728  			q.To.Reg = REG_LR
   729  
   730  			q.Link = p.Link
   731  			p.Link = q
   732  			p = q
   733  
   734  			if false {
   735  				// Debug bad returns
   736  				q = c.newprog()
   737  
   738  				q.As = AMOVD
   739  				q.Pos = p.Pos
   740  				q.From.Type = obj.TYPE_MEM
   741  				q.From.Offset = 0
   742  				q.From.Reg = REGTMP
   743  				q.To.Type = obj.TYPE_REG
   744  				q.To.Reg = REGTMP
   745  
   746  				q.Link = p.Link
   747  				p.Link = q
   748  				p = q
   749  			}
   750  
   751  			if autosize != 0 {
   752  				q = c.newprog()
   753  				q.As = AADD
   754  				q.Pos = p.Pos
   755  				q.From.Type = obj.TYPE_CONST
   756  				q.From.Offset = int64(autosize)
   757  				q.To.Type = obj.TYPE_REG
   758  				q.To.Reg = REGSP
   759  				q.Spadj = -autosize
   760  
   761  				q.Link = p.Link
   762  				p.Link = q
   763  			}
   764  
   765  			q1 = c.newprog()
   766  			q1.As = ABR
   767  			q1.Pos = p.Pos
   768  			if retTarget == nil {
   769  				q1.To.Type = obj.TYPE_REG
   770  				q1.To.Reg = REG_LR
   771  			} else {
   772  				q1.To.Type = obj.TYPE_BRANCH
   773  				q1.To.Sym = retTarget
   774  			}
   775  			q1.Mark |= BRANCH
   776  			q1.Spadj = +autosize
   777  
   778  			q1.Link = q.Link
   779  			q.Link = q1
   780  		case AADD:
   781  			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
   782  				p.Spadj = int32(-p.From.Offset)
   783  			}
   784  		}
   785  	}
   786  }
   787  
   788  /*
   789  // instruction scheduling
   790  	if(debug['Q'] == 0)
   791  		return;
   792  
   793  	curtext = nil;
   794  	q = nil;	// p - 1
   795  	q1 = firstp;	// top of block
   796  	o = 0;		// count of instructions
   797  	for(p = firstp; p != nil; p = p1) {
   798  		p1 = p->link;
   799  		o++;
   800  		if(p->mark & NOSCHED){
   801  			if(q1 != p){
   802  				sched(q1, q);
   803  			}
   804  			for(; p != nil; p = p->link){
   805  				if(!(p->mark & NOSCHED))
   806  					break;
   807  				q = p;
   808  			}
   809  			p1 = p;
   810  			q1 = p;
   811  			o = 0;
   812  			continue;
   813  		}
   814  		if(p->mark & (LABEL|SYNC)) {
   815  			if(q1 != p)
   816  				sched(q1, q);
   817  			q1 = p;
   818  			o = 1;
   819  		}
   820  		if(p->mark & (BRANCH|SYNC)) {
   821  			sched(q1, p);
   822  			q1 = p1;
   823  			o = 0;
   824  		}
   825  		if(o >= NSCHED) {
   826  			sched(q1, p);
   827  			q1 = p1;
   828  			o = 0;
   829  		}
   830  		q = p;
   831  	}
   832  */
   833  func (c *ctxt9) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
   834  	p0 := p // save entry point, but skipping the two instructions setting R2 in shared mode
   835  
   836  	// MOVD	g_stackguard(g), R3
   837  	p = obj.Appendp(p, c.newprog)
   838  
   839  	p.As = AMOVD
   840  	p.From.Type = obj.TYPE_MEM
   841  	p.From.Reg = REGG
   842  	p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0
   843  	if c.cursym.CFunc() {
   844  		p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1
   845  	}
   846  	p.To.Type = obj.TYPE_REG
   847  	p.To.Reg = REG_R3
   848  
   849  	var q *obj.Prog
   850  	if framesize <= objabi.StackSmall {
   851  		// small stack: SP < stackguard
   852  		//	CMP	stackguard, SP
   853  		p = obj.Appendp(p, c.newprog)
   854  
   855  		p.As = ACMPU
   856  		p.From.Type = obj.TYPE_REG
   857  		p.From.Reg = REG_R3
   858  		p.To.Type = obj.TYPE_REG
   859  		p.To.Reg = REGSP
   860  	} else if framesize <= objabi.StackBig {
   861  		// large stack: SP-framesize < stackguard-StackSmall
   862  		//	ADD $-(framesize-StackSmall), SP, R4
   863  		//	CMP stackguard, R4
   864  		p = obj.Appendp(p, c.newprog)
   865  
   866  		p.As = AADD
   867  		p.From.Type = obj.TYPE_CONST
   868  		p.From.Offset = -(int64(framesize) - objabi.StackSmall)
   869  		p.Reg = REGSP
   870  		p.To.Type = obj.TYPE_REG
   871  		p.To.Reg = REG_R4
   872  
   873  		p = obj.Appendp(p, c.newprog)
   874  		p.As = ACMPU
   875  		p.From.Type = obj.TYPE_REG
   876  		p.From.Reg = REG_R3
   877  		p.To.Type = obj.TYPE_REG
   878  		p.To.Reg = REG_R4
   879  	} else {
   880  		// Such a large stack we need to protect against wraparound.
   881  		// If SP is close to zero:
   882  		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
   883  		// The +StackGuard on both sides is required to keep the left side positive:
   884  		// SP is allowed to be slightly below stackguard. See stack.h.
   885  		//
   886  		// Preemption sets stackguard to StackPreempt, a very large value.
   887  		// That breaks the math above, so we have to check for that explicitly.
   888  		//	// stackguard is R3
   889  		//	CMP	R3, $StackPreempt
   890  		//	BEQ	label-of-call-to-morestack
   891  		//	ADD	$StackGuard, SP, R4
   892  		//	SUB	R3, R4
   893  		//	MOVD	$(framesize+(StackGuard-StackSmall)), R31
   894  		//	CMPU	R31, R4
   895  		p = obj.Appendp(p, c.newprog)
   896  
   897  		p.As = ACMP
   898  		p.From.Type = obj.TYPE_REG
   899  		p.From.Reg = REG_R3
   900  		p.To.Type = obj.TYPE_CONST
   901  		p.To.Offset = objabi.StackPreempt
   902  
   903  		p = obj.Appendp(p, c.newprog)
   904  		q = p
   905  		p.As = ABEQ
   906  		p.To.Type = obj.TYPE_BRANCH
   907  
   908  		p = obj.Appendp(p, c.newprog)
   909  		p.As = AADD
   910  		p.From.Type = obj.TYPE_CONST
   911  		p.From.Offset = objabi.StackGuard
   912  		p.Reg = REGSP
   913  		p.To.Type = obj.TYPE_REG
   914  		p.To.Reg = REG_R4
   915  
   916  		p = obj.Appendp(p, c.newprog)
   917  		p.As = ASUB
   918  		p.From.Type = obj.TYPE_REG
   919  		p.From.Reg = REG_R3
   920  		p.To.Type = obj.TYPE_REG
   921  		p.To.Reg = REG_R4
   922  
   923  		p = obj.Appendp(p, c.newprog)
   924  		p.As = AMOVD
   925  		p.From.Type = obj.TYPE_CONST
   926  		p.From.Offset = int64(framesize) + objabi.StackGuard - objabi.StackSmall
   927  		p.To.Type = obj.TYPE_REG
   928  		p.To.Reg = REGTMP
   929  
   930  		p = obj.Appendp(p, c.newprog)
   931  		p.As = ACMPU
   932  		p.From.Type = obj.TYPE_REG
   933  		p.From.Reg = REGTMP
   934  		p.To.Type = obj.TYPE_REG
   935  		p.To.Reg = REG_R4
   936  	}
   937  
   938  	// q1: BLT	done
   939  	p = obj.Appendp(p, c.newprog)
   940  	q1 := p
   941  
   942  	p.As = ABLT
   943  	p.To.Type = obj.TYPE_BRANCH
   944  
   945  	// MOVD	LR, R5
   946  	p = obj.Appendp(p, c.newprog)
   947  
   948  	p.As = AMOVD
   949  	p.From.Type = obj.TYPE_REG
   950  	p.From.Reg = REG_LR
   951  	p.To.Type = obj.TYPE_REG
   952  	p.To.Reg = REG_R5
   953  	if q != nil {
   954  		q.Pcond = p
   955  	}
   956  
   957  	var morestacksym *obj.LSym
   958  	if c.cursym.CFunc() {
   959  		morestacksym = c.ctxt.Lookup("runtime.morestackc")
   960  	} else if !c.cursym.Func.Text.From.Sym.NeedCtxt() {
   961  		morestacksym = c.ctxt.Lookup("runtime.morestack_noctxt")
   962  	} else {
   963  		morestacksym = c.ctxt.Lookup("runtime.morestack")
   964  	}
   965  
   966  	if c.ctxt.Flag_shared {
   967  		// In PPC64 PIC code, R2 is used as TOC pointer derived from R12
   968  		// which is the address of function entry point when entering
   969  		// the function. We need to preserve R2 across call to morestack.
   970  		// Fortunately, in shared mode, 8(SP) and 16(SP) are reserved in
   971  		// the caller's frame, but not used (0(SP) is caller's saved LR,
   972  		// 24(SP) is caller's saved R2). Use 8(SP) to save this function's R2.
   973  
   974  		// MOVD R12, 8(SP)
   975  		p = obj.Appendp(p, c.newprog)
   976  		p.As = AMOVD
   977  		p.From.Type = obj.TYPE_REG
   978  		p.From.Reg = REG_R2
   979  		p.To.Type = obj.TYPE_MEM
   980  		p.To.Reg = REGSP
   981  		p.To.Offset = 8
   982  	}
   983  
   984  	if c.ctxt.Flag_dynlink {
   985  		// Avoid calling morestack via a PLT when dynamically linking. The
   986  		// PLT stubs generated by the system linker on ppc64le when "std r2,
   987  		// 24(r1)" to save the TOC pointer in their callers stack
   988  		// frame. Unfortunately (and necessarily) morestack is called before
   989  		// the function that calls it sets up its frame and so the PLT ends
   990  		// up smashing the saved TOC pointer for its caller's caller.
   991  		//
   992  		// According to the ABI documentation there is a mechanism to avoid
   993  		// the TOC save that the PLT stub does (put a R_PPC64_TOCSAVE
   994  		// relocation on the nop after the call to morestack) but at the time
   995  		// of writing it is not supported at all by gold and my attempt to
   996  		// use it with ld.bfd caused an internal linker error. So this hack
   997  		// seems preferable.
   998  
   999  		// MOVD $runtime.morestack(SB), R12
  1000  		p = obj.Appendp(p, c.newprog)
  1001  		p.As = AMOVD
  1002  		p.From.Type = obj.TYPE_MEM
  1003  		p.From.Sym = morestacksym
  1004  		p.From.Name = obj.NAME_GOTREF
  1005  		p.To.Type = obj.TYPE_REG
  1006  		p.To.Reg = REG_R12
  1007  
  1008  		// MOVD R12, CTR
  1009  		p = obj.Appendp(p, c.newprog)
  1010  		p.As = AMOVD
  1011  		p.From.Type = obj.TYPE_REG
  1012  		p.From.Reg = REG_R12
  1013  		p.To.Type = obj.TYPE_REG
  1014  		p.To.Reg = REG_CTR
  1015  
  1016  		// BL CTR
  1017  		p = obj.Appendp(p, c.newprog)
  1018  		p.As = obj.ACALL
  1019  		p.From.Type = obj.TYPE_REG
  1020  		p.From.Reg = REG_R12
  1021  		p.To.Type = obj.TYPE_REG
  1022  		p.To.Reg = REG_CTR
  1023  	} else {
  1024  		// BL	runtime.morestack(SB)
  1025  		p = obj.Appendp(p, c.newprog)
  1026  
  1027  		p.As = ABL
  1028  		p.To.Type = obj.TYPE_BRANCH
  1029  		p.To.Sym = morestacksym
  1030  	}
  1031  
  1032  	if c.ctxt.Flag_shared {
  1033  		// MOVD 8(SP), R2
  1034  		p = obj.Appendp(p, c.newprog)
  1035  		p.As = AMOVD
  1036  		p.From.Type = obj.TYPE_MEM
  1037  		p.From.Reg = REGSP
  1038  		p.From.Offset = 8
  1039  		p.To.Type = obj.TYPE_REG
  1040  		p.To.Reg = REG_R2
  1041  	}
  1042  
  1043  	// BR	start
  1044  	p = obj.Appendp(p, c.newprog)
  1045  	p.As = ABR
  1046  	p.To.Type = obj.TYPE_BRANCH
  1047  	p.Pcond = p0.Link
  1048  
  1049  	// placeholder for q1's jump target
  1050  	p = obj.Appendp(p, c.newprog)
  1051  
  1052  	p.As = obj.ANOP // zero-width place holder
  1053  	q1.Pcond = p
  1054  
  1055  	return p
  1056  }
  1057  
  1058  var Linkppc64 = obj.LinkArch{
  1059  	Arch:       sys.ArchPPC64,
  1060  	Init:       buildop,
  1061  	Preprocess: preprocess,
  1062  	Assemble:   span9,
  1063  	Progedit:   progedit,
  1064  }
  1065  
  1066  var Linkppc64le = obj.LinkArch{
  1067  	Arch:       sys.ArchPPC64LE,
  1068  	Init:       buildop,
  1069  	Preprocess: preprocess,
  1070  	Assemble:   span9,
  1071  	Progedit:   progedit,
  1072  }