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 	"encoding/binary"
     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.Name = obj.NAME_EXTERN
     67 			p.From.Offset = 0
     68 		}
     69 
     70 	case AFMOVD:
     71 		if p.From.Type == obj.TYPE_FCONST {
     72 			i64 := math.Float64bits(p.From.Val.(float64))
     73 			literal := fmt.Sprintf("$f64.%016x", i64)
     74 			s := obj.Linklookup(ctxt, literal, 0)
     75 			s.Size = 8
     76 			p.From.Type = obj.TYPE_MEM
     77 			p.From.Sym = s
     78 			p.From.Name = obj.NAME_EXTERN
     79 			p.From.Offset = 0
     80 		}
     81 
     82 		// Put >32-bit constants in memory and load them
     83 	case AMOVD:
     84 		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 {
     85 			literal := fmt.Sprintf("$i64.%016x", uint64(p.From.Offset))
     86 			s := obj.Linklookup(ctxt, literal, 0)
     87 			s.Size = 8
     88 			p.From.Type = obj.TYPE_MEM
     89 			p.From.Sym = s
     90 			p.From.Name = obj.NAME_EXTERN
     91 			p.From.Offset = 0
     92 		}
     93 	}
     94 
     95 	// Rewrite SUB constants into ADD.
     96 	switch p.As {
     97 	case ASUBC:
     98 		if p.From.Type == obj.TYPE_CONST {
     99 			p.From.Offset = -p.From.Offset
    100 			p.As = AADDC
    101 		}
    102 
    103 	case ASUBCCC:
    104 		if p.From.Type == obj.TYPE_CONST {
    105 			p.From.Offset = -p.From.Offset
    106 			p.As = AADDCCC
    107 		}
    108 
    109 	case ASUB:
    110 		if p.From.Type == obj.TYPE_CONST {
    111 			p.From.Offset = -p.From.Offset
    112 			p.As = AADD
    113 		}
    114 	}
    115 }
    116 
    117 func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
    118 	// TODO(minux): add morestack short-cuts with small fixed frame-size.
    119 	ctxt.Cursym = cursym
    120 
    121 	if cursym.Text == nil || cursym.Text.Link == nil {
    122 		return
    123 	}
    124 
    125 	p := cursym.Text
    126 	textstksiz := p.To.Offset
    127 
    128 	cursym.Args = p.To.Val.(int32)
    129 	cursym.Locals = int32(textstksiz)
    130 
    131 	/*
    132 	 * find leaf subroutines
    133 	 * strip NOPs
    134 	 * expand RET
    135 	 * expand BECOME pseudo
    136 	 */
    137 	if ctxt.Debugvlog != 0 {
    138 		fmt.Fprintf(ctxt.Bso, "%5.2f noops\n", obj.Cputime())
    139 	}
    140 	ctxt.Bso.Flush()
    141 
    142 	var q *obj.Prog
    143 	var q1 *obj.Prog
    144 	for p := cursym.Text; p != nil; p = p.Link {
    145 		switch p.As {
    146 		/* too hard, just leave alone */
    147 		case obj.ATEXT:
    148 			q = p
    149 
    150 			p.Mark |= LABEL | LEAF | SYNC
    151 			if p.Link != nil {
    152 				p.Link.Mark |= LABEL
    153 			}
    154 
    155 		case ANOR:
    156 			q = p
    157 			if p.To.Type == obj.TYPE_REG {
    158 				if p.To.Reg == REGZERO {
    159 					p.Mark |= LABEL | SYNC
    160 				}
    161 			}
    162 
    163 		case ALWAR,
    164 			ASTWCCC,
    165 			AECIWX,
    166 			AECOWX,
    167 			AEIEIO,
    168 			AICBI,
    169 			AISYNC,
    170 			ATLBIE,
    171 			ATLBIEL,
    172 			ASLBIA,
    173 			ASLBIE,
    174 			ASLBMFEE,
    175 			ASLBMFEV,
    176 			ASLBMTE,
    177 			ADCBF,
    178 			ADCBI,
    179 			ADCBST,
    180 			ADCBT,
    181 			ADCBTST,
    182 			ADCBZ,
    183 			ASYNC,
    184 			ATLBSYNC,
    185 			APTESYNC,
    186 			ATW,
    187 			AWORD,
    188 			ARFI,
    189 			ARFCI,
    190 			ARFID,
    191 			AHRFID:
    192 			q = p
    193 			p.Mark |= LABEL | SYNC
    194 			continue
    195 
    196 		case AMOVW, AMOVWZ, AMOVD:
    197 			q = p
    198 			if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL {
    199 				p.Mark |= LABEL | SYNC
    200 			}
    201 			continue
    202 
    203 		case AFABS,
    204 			AFABSCC,
    205 			AFADD,
    206 			AFADDCC,
    207 			AFCTIW,
    208 			AFCTIWCC,
    209 			AFCTIWZ,
    210 			AFCTIWZCC,
    211 			AFDIV,
    212 			AFDIVCC,
    213 			AFMADD,
    214 			AFMADDCC,
    215 			AFMOVD,
    216 			AFMOVDU,
    217 			/* case AFMOVDS: */
    218 			AFMOVS,
    219 			AFMOVSU,
    220 
    221 			/* case AFMOVSD: */
    222 			AFMSUB,
    223 			AFMSUBCC,
    224 			AFMUL,
    225 			AFMULCC,
    226 			AFNABS,
    227 			AFNABSCC,
    228 			AFNEG,
    229 			AFNEGCC,
    230 			AFNMADD,
    231 			AFNMADDCC,
    232 			AFNMSUB,
    233 			AFNMSUBCC,
    234 			AFRSP,
    235 			AFRSPCC,
    236 			AFSUB,
    237 			AFSUBCC:
    238 			q = p
    239 
    240 			p.Mark |= FLOAT
    241 			continue
    242 
    243 		case ABL,
    244 			ABCL,
    245 			obj.ADUFFZERO,
    246 			obj.ADUFFCOPY:
    247 			cursym.Text.Mark &^= LEAF
    248 			fallthrough
    249 
    250 		case ABC,
    251 			ABEQ,
    252 			ABGE,
    253 			ABGT,
    254 			ABLE,
    255 			ABLT,
    256 			ABNE,
    257 			ABR,
    258 			ABVC,
    259 			ABVS:
    260 			p.Mark |= BRANCH
    261 			q = p
    262 			q1 = p.Pcond
    263 			if q1 != nil {
    264 				for q1.As == obj.ANOP {
    265 					q1 = q1.Link
    266 					p.Pcond = q1
    267 				}
    268 
    269 				if q1.Mark&LEAF == 0 {
    270 					q1.Mark |= LABEL
    271 				}
    272 			} else {
    273 				p.Mark |= LABEL
    274 			}
    275 			q1 = p.Link
    276 			if q1 != nil {
    277 				q1.Mark |= LABEL
    278 			}
    279 			continue
    280 
    281 		case AFCMPO, AFCMPU:
    282 			q = p
    283 			p.Mark |= FCMP | FLOAT
    284 			continue
    285 
    286 		case obj.ARET:
    287 			q = p
    288 			if p.Link != nil {
    289 				p.Link.Mark |= LABEL
    290 			}
    291 			continue
    292 
    293 		case obj.ANOP:
    294 			q1 = p.Link
    295 			q.Link = q1 /* q is non-nop */
    296 			q1.Mark |= p.Mark
    297 			continue
    298 
    299 		default:
    300 			q = p
    301 			continue
    302 		}
    303 	}
    304 
    305 	autosize := int32(0)
    306 	var aoffset int
    307 	var mov int
    308 	var o int
    309 	var p1 *obj.Prog
    310 	var p2 *obj.Prog
    311 	for p := cursym.Text; p != nil; p = p.Link {
    312 		o = int(p.As)
    313 		switch o {
    314 		case obj.ATEXT:
    315 			mov = AMOVD
    316 			aoffset = 0
    317 			autosize = int32(textstksiz + 8)
    318 			if (p.Mark&LEAF != 0) && autosize <= 8 {
    319 				autosize = 0
    320 			} else if autosize&4 != 0 {
    321 				autosize += 4
    322 			}
    323 			p.To.Offset = int64(autosize) - 8
    324 
    325 			if p.From3.Offset&obj.NOSPLIT == 0 {
    326 				p = stacksplit(ctxt, p, autosize) // emit split check
    327 			}
    328 
    329 			q = p
    330 
    331 			if autosize != 0 {
    332 				/* use MOVDU to adjust R1 when saving R31, if autosize is small */
    333 				if cursym.Text.Mark&LEAF == 0 && autosize >= -BIG && autosize <= BIG {
    334 					mov = AMOVDU
    335 					aoffset = int(-autosize)
    336 				} else {
    337 					q = obj.Appendp(ctxt, p)
    338 					q.As = AADD
    339 					q.Lineno = p.Lineno
    340 					q.From.Type = obj.TYPE_CONST
    341 					q.From.Offset = int64(-autosize)
    342 					q.To.Type = obj.TYPE_REG
    343 					q.To.Reg = REGSP
    344 					q.Spadj = +autosize
    345 				}
    346 			} else if cursym.Text.Mark&LEAF == 0 {
    347 				if ctxt.Debugvlog != 0 {
    348 					fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name)
    349 					ctxt.Bso.Flush()
    350 				}
    351 
    352 				cursym.Text.Mark |= LEAF
    353 			}
    354 
    355 			if cursym.Text.Mark&LEAF != 0 {
    356 				cursym.Leaf = 1
    357 				break
    358 			}
    359 
    360 			q = obj.Appendp(ctxt, q)
    361 			q.As = AMOVD
    362 			q.Lineno = p.Lineno
    363 			q.From.Type = obj.TYPE_REG
    364 			q.From.Reg = REG_LR
    365 			q.To.Type = obj.TYPE_REG
    366 			q.To.Reg = REGTMP
    367 
    368 			q = obj.Appendp(ctxt, q)
    369 			q.As = int16(mov)
    370 			q.Lineno = p.Lineno
    371 			q.From.Type = obj.TYPE_REG
    372 			q.From.Reg = REGTMP
    373 			q.To.Type = obj.TYPE_MEM
    374 			q.To.Offset = int64(aoffset)
    375 			q.To.Reg = REGSP
    376 			if q.As == AMOVDU {
    377 				q.Spadj = int32(-aoffset)
    378 			}
    379 
    380 			if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
    381 				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
    382 				//
    383 				//	MOVD g_panic(g), R3
    384 				//	CMP R0, R3
    385 				//	BEQ end
    386 				//	MOVD panic_argp(R3), R4
    387 				//	ADD $(autosize+8), R1, R5
    388 				//	CMP R4, R5
    389 				//	BNE end
    390 				//	ADD $8, R1, R6
    391 				//	MOVD R6, panic_argp(R3)
    392 				// end:
    393 				//	NOP
    394 				//
    395 				// The NOP is needed to give the jumps somewhere to land.
    396 				// It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes.
    397 
    398 				q = obj.Appendp(ctxt, q)
    399 
    400 				q.As = AMOVD
    401 				q.From.Type = obj.TYPE_MEM
    402 				q.From.Reg = REGG
    403 				q.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
    404 				q.To.Type = obj.TYPE_REG
    405 				q.To.Reg = REG_R3
    406 
    407 				q = obj.Appendp(ctxt, q)
    408 				q.As = ACMP
    409 				q.From.Type = obj.TYPE_REG
    410 				q.From.Reg = REG_R0
    411 				q.To.Type = obj.TYPE_REG
    412 				q.To.Reg = REG_R3
    413 
    414 				q = obj.Appendp(ctxt, q)
    415 				q.As = ABEQ
    416 				q.To.Type = obj.TYPE_BRANCH
    417 				p1 = q
    418 
    419 				q = obj.Appendp(ctxt, q)
    420 				q.As = AMOVD
    421 				q.From.Type = obj.TYPE_MEM
    422 				q.From.Reg = REG_R3
    423 				q.From.Offset = 0 // Panic.argp
    424 				q.To.Type = obj.TYPE_REG
    425 				q.To.Reg = REG_R4
    426 
    427 				q = obj.Appendp(ctxt, q)
    428 				q.As = AADD
    429 				q.From.Type = obj.TYPE_CONST
    430 				q.From.Offset = int64(autosize) + 8
    431 				q.Reg = REGSP
    432 				q.To.Type = obj.TYPE_REG
    433 				q.To.Reg = REG_R5
    434 
    435 				q = obj.Appendp(ctxt, q)
    436 				q.As = ACMP
    437 				q.From.Type = obj.TYPE_REG
    438 				q.From.Reg = REG_R4
    439 				q.To.Type = obj.TYPE_REG
    440 				q.To.Reg = REG_R5
    441 
    442 				q = obj.Appendp(ctxt, q)
    443 				q.As = ABNE
    444 				q.To.Type = obj.TYPE_BRANCH
    445 				p2 = q
    446 
    447 				q = obj.Appendp(ctxt, q)
    448 				q.As = AADD
    449 				q.From.Type = obj.TYPE_CONST
    450 				q.From.Offset = 8
    451 				q.Reg = REGSP
    452 				q.To.Type = obj.TYPE_REG
    453 				q.To.Reg = REG_R6
    454 
    455 				q = obj.Appendp(ctxt, q)
    456 				q.As = AMOVD
    457 				q.From.Type = obj.TYPE_REG
    458 				q.From.Reg = REG_R6
    459 				q.To.Type = obj.TYPE_MEM
    460 				q.To.Reg = REG_R3
    461 				q.To.Offset = 0 // Panic.argp
    462 
    463 				q = obj.Appendp(ctxt, q)
    464 
    465 				q.As = obj.ANOP
    466 				p1.Pcond = q
    467 				p2.Pcond = q
    468 			}
    469 
    470 		case obj.ARET:
    471 			if p.From.Type == obj.TYPE_CONST {
    472 				ctxt.Diag("using BECOME (%v) is not supported!", p)
    473 				break
    474 			}
    475 
    476 			if p.To.Sym != nil { // retjmp
    477 				p.As = ABR
    478 				p.To.Type = obj.TYPE_BRANCH
    479 				break
    480 			}
    481 
    482 			if cursym.Text.Mark&LEAF != 0 {
    483 				if autosize == 0 {
    484 					p.As = ABR
    485 					p.From = obj.Addr{}
    486 					p.To.Type = obj.TYPE_REG
    487 					p.To.Reg = REG_LR
    488 					p.Mark |= BRANCH
    489 					break
    490 				}
    491 
    492 				p.As = AADD
    493 				p.From.Type = obj.TYPE_CONST
    494 				p.From.Offset = int64(autosize)
    495 				p.To.Type = obj.TYPE_REG
    496 				p.To.Reg = REGSP
    497 				p.Spadj = -autosize
    498 
    499 				q = ctxt.NewProg()
    500 				q.As = ABR
    501 				q.Lineno = p.Lineno
    502 				q.To.Type = obj.TYPE_REG
    503 				q.To.Reg = REG_LR
    504 				q.Mark |= BRANCH
    505 				q.Spadj = +autosize
    506 
    507 				q.Link = p.Link
    508 				p.Link = q
    509 				break
    510 			}
    511 
    512 			p.As = AMOVD
    513 			p.From.Type = obj.TYPE_MEM
    514 			p.From.Offset = 0
    515 			p.From.Reg = REGSP
    516 			p.To.Type = obj.TYPE_REG
    517 			p.To.Reg = REGTMP
    518 
    519 			q = ctxt.NewProg()
    520 			q.As = AMOVD
    521 			q.Lineno = p.Lineno
    522 			q.From.Type = obj.TYPE_REG
    523 			q.From.Reg = REGTMP
    524 			q.To.Type = obj.TYPE_REG
    525 			q.To.Reg = REG_LR
    526 
    527 			q.Link = p.Link
    528 			p.Link = q
    529 			p = q
    530 
    531 			if false {
    532 				// Debug bad returns
    533 				q = ctxt.NewProg()
    534 
    535 				q.As = AMOVD
    536 				q.Lineno = p.Lineno
    537 				q.From.Type = obj.TYPE_MEM
    538 				q.From.Offset = 0
    539 				q.From.Reg = REGTMP
    540 				q.To.Type = obj.TYPE_REG
    541 				q.To.Reg = REGTMP
    542 
    543 				q.Link = p.Link
    544 				p.Link = q
    545 				p = q
    546 			}
    547 
    548 			if autosize != 0 {
    549 				q = ctxt.NewProg()
    550 				q.As = AADD
    551 				q.Lineno = p.Lineno
    552 				q.From.Type = obj.TYPE_CONST
    553 				q.From.Offset = int64(autosize)
    554 				q.To.Type = obj.TYPE_REG
    555 				q.To.Reg = REGSP
    556 				q.Spadj = -autosize
    557 
    558 				q.Link = p.Link
    559 				p.Link = q
    560 			}
    561 
    562 			q1 = ctxt.NewProg()
    563 			q1.As = ABR
    564 			q1.Lineno = p.Lineno
    565 			q1.To.Type = obj.TYPE_REG
    566 			q1.To.Reg = REG_LR
    567 			q1.Mark |= BRANCH
    568 			q1.Spadj = +autosize
    569 
    570 			q1.Link = q.Link
    571 			q.Link = q1
    572 
    573 		case AADD:
    574 			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
    575 				p.Spadj = int32(-p.From.Offset)
    576 			}
    577 		}
    578 	}
    579 }
    580 
    581 /*
    582 // instruction scheduling
    583 	if(debug['Q'] == 0)
    584 		return;
    585 
    586 	curtext = nil;
    587 	q = nil;	// p - 1
    588 	q1 = firstp;	// top of block
    589 	o = 0;		// count of instructions
    590 	for(p = firstp; p != nil; p = p1) {
    591 		p1 = p->link;
    592 		o++;
    593 		if(p->mark & NOSCHED){
    594 			if(q1 != p){
    595 				sched(q1, q);
    596 			}
    597 			for(; p != nil; p = p->link){
    598 				if(!(p->mark & NOSCHED))
    599 					break;
    600 				q = p;
    601 			}
    602 			p1 = p;
    603 			q1 = p;
    604 			o = 0;
    605 			continue;
    606 		}
    607 		if(p->mark & (LABEL|SYNC)) {
    608 			if(q1 != p)
    609 				sched(q1, q);
    610 			q1 = p;
    611 			o = 1;
    612 		}
    613 		if(p->mark & (BRANCH|SYNC)) {
    614 			sched(q1, p);
    615 			q1 = p1;
    616 			o = 0;
    617 		}
    618 		if(o >= NSCHED) {
    619 			sched(q1, p);
    620 			q1 = p1;
    621 			o = 0;
    622 		}
    623 		q = p;
    624 	}
    625 */
    626 func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
    627 	// MOVD	g_stackguard(g), R3
    628 	p = obj.Appendp(ctxt, p)
    629 
    630 	p.As = AMOVD
    631 	p.From.Type = obj.TYPE_MEM
    632 	p.From.Reg = REGG
    633 	p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
    634 	if ctxt.Cursym.Cfunc != 0 {
    635 		p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
    636 	}
    637 	p.To.Type = obj.TYPE_REG
    638 	p.To.Reg = REG_R3
    639 
    640 	var q *obj.Prog
    641 	if framesize <= obj.StackSmall {
    642 		// small stack: SP < stackguard
    643 		//	CMP	stackguard, SP
    644 		p = obj.Appendp(ctxt, p)
    645 
    646 		p.As = ACMPU
    647 		p.From.Type = obj.TYPE_REG
    648 		p.From.Reg = REG_R3
    649 		p.To.Type = obj.TYPE_REG
    650 		p.To.Reg = REGSP
    651 	} else if framesize <= obj.StackBig {
    652 		// large stack: SP-framesize < stackguard-StackSmall
    653 		//	ADD $-framesize, SP, R4
    654 		//	CMP stackguard, R4
    655 		p = obj.Appendp(ctxt, p)
    656 
    657 		p.As = AADD
    658 		p.From.Type = obj.TYPE_CONST
    659 		p.From.Offset = int64(-framesize)
    660 		p.Reg = REGSP
    661 		p.To.Type = obj.TYPE_REG
    662 		p.To.Reg = REG_R4
    663 
    664 		p = obj.Appendp(ctxt, p)
    665 		p.As = ACMPU
    666 		p.From.Type = obj.TYPE_REG
    667 		p.From.Reg = REG_R3
    668 		p.To.Type = obj.TYPE_REG
    669 		p.To.Reg = REG_R4
    670 	} else {
    671 		// Such a large stack we need to protect against wraparound.
    672 		// If SP is close to zero:
    673 		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
    674 		// The +StackGuard on both sides is required to keep the left side positive:
    675 		// SP is allowed to be slightly below stackguard. See stack.h.
    676 		//
    677 		// Preemption sets stackguard to StackPreempt, a very large value.
    678 		// That breaks the math above, so we have to check for that explicitly.
    679 		//	// stackguard is R3
    680 		//	CMP	R3, $StackPreempt
    681 		//	BEQ	label-of-call-to-morestack
    682 		//	ADD	$StackGuard, SP, R4
    683 		//	SUB	R3, R4
    684 		//	MOVD	$(framesize+(StackGuard-StackSmall)), R31
    685 		//	CMPU	R31, R4
    686 		p = obj.Appendp(ctxt, p)
    687 
    688 		p.As = ACMP
    689 		p.From.Type = obj.TYPE_REG
    690 		p.From.Reg = REG_R3
    691 		p.To.Type = obj.TYPE_CONST
    692 		p.To.Offset = obj.StackPreempt
    693 
    694 		p = obj.Appendp(ctxt, p)
    695 		q = p
    696 		p.As = ABEQ
    697 		p.To.Type = obj.TYPE_BRANCH
    698 
    699 		p = obj.Appendp(ctxt, p)
    700 		p.As = AADD
    701 		p.From.Type = obj.TYPE_CONST
    702 		p.From.Offset = obj.StackGuard
    703 		p.Reg = REGSP
    704 		p.To.Type = obj.TYPE_REG
    705 		p.To.Reg = REG_R4
    706 
    707 		p = obj.Appendp(ctxt, p)
    708 		p.As = ASUB
    709 		p.From.Type = obj.TYPE_REG
    710 		p.From.Reg = REG_R3
    711 		p.To.Type = obj.TYPE_REG
    712 		p.To.Reg = REG_R4
    713 
    714 		p = obj.Appendp(ctxt, p)
    715 		p.As = AMOVD
    716 		p.From.Type = obj.TYPE_CONST
    717 		p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall
    718 		p.To.Type = obj.TYPE_REG
    719 		p.To.Reg = REGTMP
    720 
    721 		p = obj.Appendp(ctxt, p)
    722 		p.As = ACMPU
    723 		p.From.Type = obj.TYPE_REG
    724 		p.From.Reg = REGTMP
    725 		p.To.Type = obj.TYPE_REG
    726 		p.To.Reg = REG_R4
    727 	}
    728 
    729 	// q1: BLT	done
    730 	p = obj.Appendp(ctxt, p)
    731 	q1 := p
    732 
    733 	p.As = ABLT
    734 	p.To.Type = obj.TYPE_BRANCH
    735 
    736 	// MOVD	LR, R5
    737 	p = obj.Appendp(ctxt, p)
    738 
    739 	p.As = AMOVD
    740 	p.From.Type = obj.TYPE_REG
    741 	p.From.Reg = REG_LR
    742 	p.To.Type = obj.TYPE_REG
    743 	p.To.Reg = REG_R5
    744 	if q != nil {
    745 		q.Pcond = p
    746 	}
    747 
    748 	// BL	runtime.morestack(SB)
    749 	p = obj.Appendp(ctxt, p)
    750 
    751 	p.As = ABL
    752 	p.To.Type = obj.TYPE_BRANCH
    753 	if ctxt.Cursym.Cfunc != 0 {
    754 		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0)
    755 	} else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 {
    756 		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
    757 	} else {
    758 		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0)
    759 	}
    760 
    761 	// BR	start
    762 	p = obj.Appendp(ctxt, p)
    763 
    764 	p.As = ABR
    765 	p.To.Type = obj.TYPE_BRANCH
    766 	p.Pcond = ctxt.Cursym.Text.Link
    767 
    768 	// placeholder for q1's jump target
    769 	p = obj.Appendp(ctxt, p)
    770 
    771 	p.As = obj.ANOP // zero-width place holder
    772 	q1.Pcond = p
    773 
    774 	return p
    775 }
    776 
    777 func follow(ctxt *obj.Link, s *obj.LSym) {
    778 	ctxt.Cursym = s
    779 
    780 	firstp := ctxt.NewProg()
    781 	lastp := firstp
    782 	xfol(ctxt, s.Text, &lastp)
    783 	lastp.Link = nil
    784 	s.Text = firstp.Link
    785 }
    786 
    787 func relinv(a int) int {
    788 	switch a {
    789 	case ABEQ:
    790 		return ABNE
    791 	case ABNE:
    792 		return ABEQ
    793 
    794 	case ABGE:
    795 		return ABLT
    796 	case ABLT:
    797 		return ABGE
    798 
    799 	case ABGT:
    800 		return ABLE
    801 	case ABLE:
    802 		return ABGT
    803 
    804 	case ABVC:
    805 		return ABVS
    806 	case ABVS:
    807 		return ABVC
    808 	}
    809 
    810 	return 0
    811 }
    812 
    813 func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) {
    814 	var q *obj.Prog
    815 	var r *obj.Prog
    816 	var a int
    817 	var b int
    818 	var i int
    819 
    820 loop:
    821 	if p == nil {
    822 		return
    823 	}
    824 	a = int(p.As)
    825 	if a == ABR {
    826 		q = p.Pcond
    827 		if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) {
    828 			p.Mark |= FOLL
    829 			(*last).Link = p
    830 			*last = p
    831 			p = p.Link
    832 			xfol(ctxt, p, last)
    833 			p = q
    834 			if p != nil && p.Mark&FOLL == 0 {
    835 				goto loop
    836 			}
    837 			return
    838 		}
    839 
    840 		if q != nil {
    841 			p.Mark |= FOLL
    842 			p = q
    843 			if p.Mark&FOLL == 0 {
    844 				goto loop
    845 			}
    846 		}
    847 	}
    848 
    849 	if p.Mark&FOLL != 0 {
    850 		i = 0
    851 		q = p
    852 		for ; i < 4; i, q = i+1, q.Link {
    853 			if q == *last || (q.Mark&NOSCHED != 0) {
    854 				break
    855 			}
    856 			b = 0 /* set */
    857 			a = int(q.As)
    858 			if a == obj.ANOP {
    859 				i--
    860 				continue
    861 			}
    862 
    863 			if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
    864 				goto copy
    865 			}
    866 			if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) {
    867 				continue
    868 			}
    869 			b = relinv(a)
    870 			if b == 0 {
    871 				continue
    872 			}
    873 
    874 		copy:
    875 			for {
    876 				r = ctxt.NewProg()
    877 				*r = *p
    878 				if r.Mark&FOLL == 0 {
    879 					fmt.Printf("cant happen 1\n")
    880 				}
    881 				r.Mark |= FOLL
    882 				if p != q {
    883 					p = p.Link
    884 					(*last).Link = r
    885 					*last = r
    886 					continue
    887 				}
    888 
    889 				(*last).Link = r
    890 				*last = r
    891 				if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
    892 					return
    893 				}
    894 				r.As = int16(b)
    895 				r.Pcond = p.Link
    896 				r.Link = p.Pcond
    897 				if r.Link.Mark&FOLL == 0 {
    898 					xfol(ctxt, r.Link, last)
    899 				}
    900 				if r.Pcond.Mark&FOLL == 0 {
    901 					fmt.Printf("cant happen 2\n")
    902 				}
    903 				return
    904 			}
    905 		}
    906 
    907 		a = ABR
    908 		q = ctxt.NewProg()
    909 		q.As = int16(a)
    910 		q.Lineno = p.Lineno
    911 		q.To.Type = obj.TYPE_BRANCH
    912 		q.To.Offset = p.Pc
    913 		q.Pcond = p
    914 		p = q
    915 	}
    916 
    917 	p.Mark |= FOLL
    918 	(*last).Link = p
    919 	*last = p
    920 	if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
    921 		if p.Mark&NOSCHED != 0 {
    922 			p = p.Link
    923 			goto loop
    924 		}
    925 
    926 		return
    927 	}
    928 
    929 	if p.Pcond != nil {
    930 		if a != ABL && p.Link != nil {
    931 			xfol(ctxt, p.Link, last)
    932 			p = p.Pcond
    933 			if p == nil || (p.Mark&FOLL != 0) {
    934 				return
    935 			}
    936 			goto loop
    937 		}
    938 	}
    939 
    940 	p = p.Link
    941 	goto loop
    942 }
    943 
    944 var Linkppc64 = obj.LinkArch{
    945 	ByteOrder:  binary.BigEndian,
    946 	Name:       "ppc64",
    947 	Thechar:    '9',
    948 	Preprocess: preprocess,
    949 	Assemble:   span9,
    950 	Follow:     follow,
    951 	Progedit:   progedit,
    952 	Minlc:      4,
    953 	Ptrsize:    8,
    954 	Regsize:    8,
    955 }
    956 
    957 var Linkppc64le = obj.LinkArch{
    958 	ByteOrder:  binary.LittleEndian,
    959 	Name:       "ppc64le",
    960 	Thechar:    '9',
    961 	Preprocess: preprocess,
    962 	Assemble:   span9,
    963 	Follow:     follow,
    964 	Progedit:   progedit,
    965 	Minlc:      4,
    966 	Ptrsize:    8,
    967 	Regsize:    8,
    968 }
    969