Home | History | Annotate | Download | only in ppc64
      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 (a] 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 (a] 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.GetFrom3() != nil && p.GetFrom3().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 }
   1073