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