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