github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/src/cmd/internal/obj/ppc64/obj9.go (about)

     1  // cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
     2  //
     3  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     4  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     5  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     6  //	Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
     7  //	Portions Copyright © 2004,2006 Bruce Ellis
     8  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
     9  //	Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
    10  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    11  //
    12  // Permission is hereby granted, free of charge, to any person obtaining a copy
    13  // of this software and associated documentation files (the "Software"), to deal
    14  // in the Software without restriction, including without limitation the rights
    15  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    16  // copies of the Software, and to permit persons to whom the Software is
    17  // furnished to do so, subject to the following conditions:
    18  //
    19  // The above copyright notice and this permission notice shall be included in
    20  // all copies or substantial portions of the Software.
    21  //
    22  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    23  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    24  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    25  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    26  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    27  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    28  // THE SOFTWARE.
    29  
    30  package ppc64
    31  
    32  import (
    33  	"cmd/internal/obj"
    34  	"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  }