github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/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  			retTarget := p.To.Sym
   477  
   478  			if cursym.Text.Mark&LEAF != 0 {
   479  				if autosize == 0 {
   480  					p.As = ABR
   481  					p.From = obj.Addr{}
   482  					if retTarget == nil {
   483  						p.To.Type = obj.TYPE_REG
   484  						p.To.Reg = REG_LR
   485  					} else {
   486  						p.To.Type = obj.TYPE_BRANCH
   487  						p.To.Sym = retTarget
   488  					}
   489  					p.Mark |= BRANCH
   490  					break
   491  				}
   492  
   493  				p.As = AADD
   494  				p.From.Type = obj.TYPE_CONST
   495  				p.From.Offset = int64(autosize)
   496  				p.To.Type = obj.TYPE_REG
   497  				p.To.Reg = REGSP
   498  				p.Spadj = -autosize
   499  
   500  				q = ctxt.NewProg()
   501  				q.As = ABR
   502  				q.Lineno = p.Lineno
   503  				q.To.Type = obj.TYPE_REG
   504  				q.To.Reg = REG_LR
   505  				q.Mark |= BRANCH
   506  				q.Spadj = +autosize
   507  
   508  				q.Link = p.Link
   509  				p.Link = q
   510  				break
   511  			}
   512  
   513  			p.As = AMOVD
   514  			p.From.Type = obj.TYPE_MEM
   515  			p.From.Offset = 0
   516  			p.From.Reg = REGSP
   517  			p.To.Type = obj.TYPE_REG
   518  			p.To.Reg = REGTMP
   519  
   520  			q = ctxt.NewProg()
   521  			q.As = AMOVD
   522  			q.Lineno = p.Lineno
   523  			q.From.Type = obj.TYPE_REG
   524  			q.From.Reg = REGTMP
   525  			q.To.Type = obj.TYPE_REG
   526  			q.To.Reg = REG_LR
   527  
   528  			q.Link = p.Link
   529  			p.Link = q
   530  			p = q
   531  
   532  			if false {
   533  				// Debug bad returns
   534  				q = ctxt.NewProg()
   535  
   536  				q.As = AMOVD
   537  				q.Lineno = p.Lineno
   538  				q.From.Type = obj.TYPE_MEM
   539  				q.From.Offset = 0
   540  				q.From.Reg = REGTMP
   541  				q.To.Type = obj.TYPE_REG
   542  				q.To.Reg = REGTMP
   543  
   544  				q.Link = p.Link
   545  				p.Link = q
   546  				p = q
   547  			}
   548  
   549  			if autosize != 0 {
   550  				q = ctxt.NewProg()
   551  				q.As = AADD
   552  				q.Lineno = p.Lineno
   553  				q.From.Type = obj.TYPE_CONST
   554  				q.From.Offset = int64(autosize)
   555  				q.To.Type = obj.TYPE_REG
   556  				q.To.Reg = REGSP
   557  				q.Spadj = -autosize
   558  
   559  				q.Link = p.Link
   560  				p.Link = q
   561  			}
   562  
   563  			q1 = ctxt.NewProg()
   564  			q1.As = ABR
   565  			q1.Lineno = p.Lineno
   566  			if retTarget == nil {
   567  				q1.To.Type = obj.TYPE_REG
   568  				q1.To.Reg = REG_LR
   569  			} else {
   570  				q1.To.Type = obj.TYPE_BRANCH
   571  				q1.To.Sym = retTarget
   572  			}
   573  			q1.Mark |= BRANCH
   574  			q1.Spadj = +autosize
   575  
   576  			q1.Link = q.Link
   577  			q.Link = q1
   578  		case AADD:
   579  			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
   580  				p.Spadj = int32(-p.From.Offset)
   581  			}
   582  		}
   583  	}
   584  }
   585  
   586  /*
   587  // instruction scheduling
   588  	if(debug['Q'] == 0)
   589  		return;
   590  
   591  	curtext = nil;
   592  	q = nil;	// p - 1
   593  	q1 = firstp;	// top of block
   594  	o = 0;		// count of instructions
   595  	for(p = firstp; p != nil; p = p1) {
   596  		p1 = p->link;
   597  		o++;
   598  		if(p->mark & NOSCHED){
   599  			if(q1 != p){
   600  				sched(q1, q);
   601  			}
   602  			for(; p != nil; p = p->link){
   603  				if(!(p->mark & NOSCHED))
   604  					break;
   605  				q = p;
   606  			}
   607  			p1 = p;
   608  			q1 = p;
   609  			o = 0;
   610  			continue;
   611  		}
   612  		if(p->mark & (LABEL|SYNC)) {
   613  			if(q1 != p)
   614  				sched(q1, q);
   615  			q1 = p;
   616  			o = 1;
   617  		}
   618  		if(p->mark & (BRANCH|SYNC)) {
   619  			sched(q1, p);
   620  			q1 = p1;
   621  			o = 0;
   622  		}
   623  		if(o >= NSCHED) {
   624  			sched(q1, p);
   625  			q1 = p1;
   626  			o = 0;
   627  		}
   628  		q = p;
   629  	}
   630  */
   631  func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
   632  	// MOVD	g_stackguard(g), R3
   633  	p = obj.Appendp(ctxt, p)
   634  
   635  	p.As = AMOVD
   636  	p.From.Type = obj.TYPE_MEM
   637  	p.From.Reg = REGG
   638  	p.From.Offset = 2 * int64(ctxt.Arch.Ptrsize) // G.stackguard0
   639  	if ctxt.Cursym.Cfunc != 0 {
   640  		p.From.Offset = 3 * int64(ctxt.Arch.Ptrsize) // G.stackguard1
   641  	}
   642  	p.To.Type = obj.TYPE_REG
   643  	p.To.Reg = REG_R3
   644  
   645  	var q *obj.Prog
   646  	if framesize <= obj.StackSmall {
   647  		// small stack: SP < stackguard
   648  		//	CMP	stackguard, SP
   649  		p = obj.Appendp(ctxt, p)
   650  
   651  		p.As = ACMPU
   652  		p.From.Type = obj.TYPE_REG
   653  		p.From.Reg = REG_R3
   654  		p.To.Type = obj.TYPE_REG
   655  		p.To.Reg = REGSP
   656  	} else if framesize <= obj.StackBig {
   657  		// large stack: SP-framesize < stackguard-StackSmall
   658  		//	ADD $-framesize, SP, R4
   659  		//	CMP stackguard, R4
   660  		p = obj.Appendp(ctxt, p)
   661  
   662  		p.As = AADD
   663  		p.From.Type = obj.TYPE_CONST
   664  		p.From.Offset = int64(-framesize)
   665  		p.Reg = REGSP
   666  		p.To.Type = obj.TYPE_REG
   667  		p.To.Reg = REG_R4
   668  
   669  		p = obj.Appendp(ctxt, p)
   670  		p.As = ACMPU
   671  		p.From.Type = obj.TYPE_REG
   672  		p.From.Reg = REG_R3
   673  		p.To.Type = obj.TYPE_REG
   674  		p.To.Reg = REG_R4
   675  	} else {
   676  		// Such a large stack we need to protect against wraparound.
   677  		// If SP is close to zero:
   678  		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
   679  		// The +StackGuard on both sides is required to keep the left side positive:
   680  		// SP is allowed to be slightly below stackguard. See stack.h.
   681  		//
   682  		// Preemption sets stackguard to StackPreempt, a very large value.
   683  		// That breaks the math above, so we have to check for that explicitly.
   684  		//	// stackguard is R3
   685  		//	CMP	R3, $StackPreempt
   686  		//	BEQ	label-of-call-to-morestack
   687  		//	ADD	$StackGuard, SP, R4
   688  		//	SUB	R3, R4
   689  		//	MOVD	$(framesize+(StackGuard-StackSmall)), R31
   690  		//	CMPU	R31, R4
   691  		p = obj.Appendp(ctxt, p)
   692  
   693  		p.As = ACMP
   694  		p.From.Type = obj.TYPE_REG
   695  		p.From.Reg = REG_R3
   696  		p.To.Type = obj.TYPE_CONST
   697  		p.To.Offset = obj.StackPreempt
   698  
   699  		p = obj.Appendp(ctxt, p)
   700  		q = p
   701  		p.As = ABEQ
   702  		p.To.Type = obj.TYPE_BRANCH
   703  
   704  		p = obj.Appendp(ctxt, p)
   705  		p.As = AADD
   706  		p.From.Type = obj.TYPE_CONST
   707  		p.From.Offset = obj.StackGuard
   708  		p.Reg = REGSP
   709  		p.To.Type = obj.TYPE_REG
   710  		p.To.Reg = REG_R4
   711  
   712  		p = obj.Appendp(ctxt, p)
   713  		p.As = ASUB
   714  		p.From.Type = obj.TYPE_REG
   715  		p.From.Reg = REG_R3
   716  		p.To.Type = obj.TYPE_REG
   717  		p.To.Reg = REG_R4
   718  
   719  		p = obj.Appendp(ctxt, p)
   720  		p.As = AMOVD
   721  		p.From.Type = obj.TYPE_CONST
   722  		p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall
   723  		p.To.Type = obj.TYPE_REG
   724  		p.To.Reg = REGTMP
   725  
   726  		p = obj.Appendp(ctxt, p)
   727  		p.As = ACMPU
   728  		p.From.Type = obj.TYPE_REG
   729  		p.From.Reg = REGTMP
   730  		p.To.Type = obj.TYPE_REG
   731  		p.To.Reg = REG_R4
   732  	}
   733  
   734  	// q1: BLT	done
   735  	p = obj.Appendp(ctxt, p)
   736  	q1 := p
   737  
   738  	p.As = ABLT
   739  	p.To.Type = obj.TYPE_BRANCH
   740  
   741  	// MOVD	LR, R5
   742  	p = obj.Appendp(ctxt, p)
   743  
   744  	p.As = AMOVD
   745  	p.From.Type = obj.TYPE_REG
   746  	p.From.Reg = REG_LR
   747  	p.To.Type = obj.TYPE_REG
   748  	p.To.Reg = REG_R5
   749  	if q != nil {
   750  		q.Pcond = p
   751  	}
   752  
   753  	// BL	runtime.morestack(SB)
   754  	p = obj.Appendp(ctxt, p)
   755  
   756  	p.As = ABL
   757  	p.To.Type = obj.TYPE_BRANCH
   758  	if ctxt.Cursym.Cfunc != 0 {
   759  		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestackc", 0)
   760  	} else if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 {
   761  		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
   762  	} else {
   763  		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0)
   764  	}
   765  
   766  	// BR	start
   767  	p = obj.Appendp(ctxt, p)
   768  
   769  	p.As = ABR
   770  	p.To.Type = obj.TYPE_BRANCH
   771  	p.Pcond = ctxt.Cursym.Text.Link
   772  
   773  	// placeholder for q1's jump target
   774  	p = obj.Appendp(ctxt, p)
   775  
   776  	p.As = obj.ANOP // zero-width place holder
   777  	q1.Pcond = p
   778  
   779  	return p
   780  }
   781  
   782  func follow(ctxt *obj.Link, s *obj.LSym) {
   783  	ctxt.Cursym = s
   784  
   785  	firstp := ctxt.NewProg()
   786  	lastp := firstp
   787  	xfol(ctxt, s.Text, &lastp)
   788  	lastp.Link = nil
   789  	s.Text = firstp.Link
   790  }
   791  
   792  func relinv(a int) int {
   793  	switch a {
   794  	case ABEQ:
   795  		return ABNE
   796  	case ABNE:
   797  		return ABEQ
   798  
   799  	case ABGE:
   800  		return ABLT
   801  	case ABLT:
   802  		return ABGE
   803  
   804  	case ABGT:
   805  		return ABLE
   806  	case ABLE:
   807  		return ABGT
   808  
   809  	case ABVC:
   810  		return ABVS
   811  	case ABVS:
   812  		return ABVC
   813  	}
   814  
   815  	return 0
   816  }
   817  
   818  func xfol(ctxt *obj.Link, p *obj.Prog, last **obj.Prog) {
   819  	var q *obj.Prog
   820  	var r *obj.Prog
   821  	var a int
   822  	var b int
   823  	var i int
   824  
   825  loop:
   826  	if p == nil {
   827  		return
   828  	}
   829  	a = int(p.As)
   830  	if a == ABR {
   831  		q = p.Pcond
   832  		if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) {
   833  			p.Mark |= FOLL
   834  			(*last).Link = p
   835  			*last = p
   836  			p = p.Link
   837  			xfol(ctxt, p, last)
   838  			p = q
   839  			if p != nil && p.Mark&FOLL == 0 {
   840  				goto loop
   841  			}
   842  			return
   843  		}
   844  
   845  		if q != nil {
   846  			p.Mark |= FOLL
   847  			p = q
   848  			if p.Mark&FOLL == 0 {
   849  				goto loop
   850  			}
   851  		}
   852  	}
   853  
   854  	if p.Mark&FOLL != 0 {
   855  		i = 0
   856  		q = p
   857  		for ; i < 4; i, q = i+1, q.Link {
   858  			if q == *last || (q.Mark&NOSCHED != 0) {
   859  				break
   860  			}
   861  			b = 0 /* set */
   862  			a = int(q.As)
   863  			if a == obj.ANOP {
   864  				i--
   865  				continue
   866  			}
   867  
   868  			if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
   869  				goto copy
   870  			}
   871  			if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) {
   872  				continue
   873  			}
   874  			b = relinv(a)
   875  			if b == 0 {
   876  				continue
   877  			}
   878  
   879  		copy:
   880  			for {
   881  				r = ctxt.NewProg()
   882  				*r = *p
   883  				if r.Mark&FOLL == 0 {
   884  					fmt.Printf("cant happen 1\n")
   885  				}
   886  				r.Mark |= FOLL
   887  				if p != q {
   888  					p = p.Link
   889  					(*last).Link = r
   890  					*last = r
   891  					continue
   892  				}
   893  
   894  				(*last).Link = r
   895  				*last = r
   896  				if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
   897  					return
   898  				}
   899  				r.As = int16(b)
   900  				r.Pcond = p.Link
   901  				r.Link = p.Pcond
   902  				if r.Link.Mark&FOLL == 0 {
   903  					xfol(ctxt, r.Link, last)
   904  				}
   905  				if r.Pcond.Mark&FOLL == 0 {
   906  					fmt.Printf("cant happen 2\n")
   907  				}
   908  				return
   909  			}
   910  		}
   911  
   912  		a = ABR
   913  		q = ctxt.NewProg()
   914  		q.As = int16(a)
   915  		q.Lineno = p.Lineno
   916  		q.To.Type = obj.TYPE_BRANCH
   917  		q.To.Offset = p.Pc
   918  		q.Pcond = p
   919  		p = q
   920  	}
   921  
   922  	p.Mark |= FOLL
   923  	(*last).Link = p
   924  	*last = p
   925  	if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
   926  		if p.Mark&NOSCHED != 0 {
   927  			p = p.Link
   928  			goto loop
   929  		}
   930  
   931  		return
   932  	}
   933  
   934  	if p.Pcond != nil {
   935  		if a != ABL && p.Link != nil {
   936  			xfol(ctxt, p.Link, last)
   937  			p = p.Pcond
   938  			if p == nil || (p.Mark&FOLL != 0) {
   939  				return
   940  			}
   941  			goto loop
   942  		}
   943  	}
   944  
   945  	p = p.Link
   946  	goto loop
   947  }
   948  
   949  var Linkppc64 = obj.LinkArch{
   950  	ByteOrder:  binary.BigEndian,
   951  	Name:       "ppc64",
   952  	Thechar:    '9',
   953  	Preprocess: preprocess,
   954  	Assemble:   span9,
   955  	Follow:     follow,
   956  	Progedit:   progedit,
   957  	Minlc:      4,
   958  	Ptrsize:    8,
   959  	Regsize:    8,
   960  }
   961  
   962  var Linkppc64le = obj.LinkArch{
   963  	ByteOrder:  binary.LittleEndian,
   964  	Name:       "ppc64le",
   965  	Thechar:    '9',
   966  	Preprocess: preprocess,
   967  	Assemble:   span9,
   968  	Follow:     follow,
   969  	Progedit:   progedit,
   970  	Minlc:      4,
   971  	Ptrsize:    8,
   972  	Regsize:    8,
   973  }