github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/src/liblink/obj9.c (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  #include <u.h>
    31  #include <libc.h>
    32  #include <bio.h>
    33  #include <link.h>
    34  #include "../cmd/9l/9.out.h"
    35  #include "../runtime/stack.h"
    36  #include "../runtime/funcdata.h"
    37  
    38  static Prog zprg = {
    39  	.as = AGOK,
    40  	.reg = NREG,
    41  	.from = {
    42  		.name = D_NONE,
    43  		.type = D_NONE,
    44  		.reg = NREG,
    45  	},
    46  	.from3 = {
    47  		.name = D_NONE,
    48  		.type = D_NONE,
    49  		.reg = NREG,
    50  	},
    51  	.to = {
    52  		.name = D_NONE,
    53  		.type = D_NONE,
    54  		.reg = NREG,
    55  	},
    56  };
    57  
    58  static int
    59  symtype(Addr *a)
    60  {
    61  	return a->name;
    62  }
    63  
    64  static int
    65  isdata(Prog *p)
    66  {
    67  	return p->as == ADATA || p->as == AGLOBL;
    68  }
    69  
    70  static int
    71  iscall(Prog *p)
    72  {
    73  	return p->as == ABL;
    74  }
    75  
    76  static int
    77  datasize(Prog *p)
    78  {
    79  	return p->reg;
    80  }
    81  
    82  static int
    83  textflag(Prog *p)
    84  {
    85  	return p->reg;
    86  }
    87  
    88  static void
    89  settextflag(Prog *p, int f)
    90  {
    91  	p->reg = f;
    92  }
    93  
    94  static void
    95  progedit(Link *ctxt, Prog *p)
    96  {
    97  	char literal[64];
    98  	LSym *s;
    99  
   100  	USED(ctxt);
   101  
   102  	p->from.class = 0;
   103  	p->to.class = 0;
   104  
   105  	// Rewrite BR/BL to symbol as D_BRANCH.
   106  	switch(p->as) {
   107  	case ABR:
   108  	case ABL:
   109  	case ARETURN:
   110  	case ADUFFZERO:
   111  	case ADUFFCOPY:
   112  		if(p->to.sym != nil)
   113  			p->to.type = D_BRANCH;
   114  		break;
   115  	}
   116  
   117  	// Rewrite float constants to values stored in memory.
   118  	switch(p->as) {
   119  	case AFMOVS:
   120  		if(p->from.type == D_FCONST) {
   121  			int32 i32;
   122  			float32 f32;
   123  			f32 = p->from.u.dval;
   124  			memmove(&i32, &f32, 4);
   125  			sprint(literal, "$f32.%08ux", (uint32)i32);
   126  			s = linklookup(ctxt, literal, 0);
   127  			s->size = 4;
   128  			p->from.type = D_OREG;
   129  			p->from.sym = s;
   130  			p->from.name = D_EXTERN;
   131  			p->from.offset = 0;
   132  		}
   133  		break;
   134  	case AFMOVD:
   135  		if(p->from.type == D_FCONST) {
   136  			int64 i64;
   137  			memmove(&i64, &p->from.u.dval, 8);
   138  			sprint(literal, "$f64.%016llux", (uvlong)i64);
   139  			s = linklookup(ctxt, literal, 0);
   140  			s->size = 8;
   141  			p->from.type = D_OREG;
   142  			p->from.sym = s;
   143  			p->from.name = D_EXTERN;
   144  			p->from.offset = 0;
   145  		}
   146  		break;
   147  	case AMOVD:
   148  		if(p->from.type == D_CONST && p->from.name == D_NONE && (int64)(uint32)p->from.offset != p->from.offset) {
   149  			sprint(literal, "$i64.%016llux", (uvlong)p->from.offset);
   150  			s = linklookup(ctxt, literal, 0);
   151  			s->size = 8;
   152  			p->from.type = D_OREG;
   153  			p->from.sym = s;
   154  			p->from.name = D_EXTERN;
   155  			p->from.offset = 0;
   156  		}
   157  	}
   158  
   159  	// Rewrite SUB constants into ADD.
   160  	switch(p->as) {
   161  	case ASUBC:
   162  		if(p->from.type == D_CONST) {
   163  			p->from.offset = -p->from.offset;
   164  			p->as = AADDC;
   165  		}
   166  		break;
   167  
   168  	case ASUBCCC:
   169  		if(p->from.type == D_CONST) {
   170  			p->from.offset = -p->from.offset;
   171  			p->as = AADDCCC;
   172  		}
   173  		break;
   174  
   175  	case ASUB:
   176  		if(p->from.type == D_CONST) {
   177  			p->from.offset = -p->from.offset;
   178  			p->as = AADD;
   179  		}
   180  		break;
   181  	}
   182  }
   183  
   184  static Prog*	stacksplit(Link*, Prog*, int32, int);
   185  
   186  static void
   187  parsetextconst(vlong arg, vlong *textstksiz, vlong *textarg)
   188  {
   189  	*textstksiz = arg & 0xffffffffLL;
   190  	if(*textstksiz & 0x80000000LL)
   191  		*textstksiz = -(-*textstksiz & 0xffffffffLL);
   192  
   193  	*textarg = (arg >> 32) & 0xffffffffLL;
   194  	if(*textarg & 0x80000000LL)
   195  		*textarg = 0;
   196  	*textarg = (*textarg+7) & ~7LL;
   197  }
   198  
   199  static void
   200  addstacksplit(Link *ctxt, LSym *cursym)
   201  {
   202  	Prog *p, *q, *p1, *p2, *q1;
   203  	int o, mov, aoffset;
   204  	vlong textstksiz, textarg;
   205  	int32 autosize;
   206  
   207  	if(ctxt->symmorestack[0] == nil) {
   208  		ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
   209  		ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
   210  		// TODO(minux): add morestack short-cuts with small fixed frame-size.
   211  	}
   212  
   213  	ctxt->cursym = cursym;
   214  
   215  	if(cursym->text == nil || cursym->text->link == nil)
   216  		return;				
   217  
   218  	p = cursym->text;
   219  	parsetextconst(p->to.offset, &textstksiz, &textarg);
   220  	
   221  	cursym->args = p->to.offset>>32;
   222  	cursym->locals = textstksiz;
   223  
   224  	/*
   225  	 * find leaf subroutines
   226  	 * strip NOPs
   227  	 * expand RET
   228  	 * expand BECOME pseudo
   229  	 */
   230  
   231  	if(ctxt->debugvlog)
   232  		Bprint(ctxt->bso, "%5.2f noops\n", cputime());
   233  	Bflush(ctxt->bso);
   234  
   235  	q = nil;
   236  	for(p = cursym->text; p != nil; p = p->link) {
   237  		switch(p->as) {
   238  		/* too hard, just leave alone */
   239  		case ATEXT:
   240  			q = p;
   241  			p->mark |= LABEL|LEAF|SYNC;
   242  			if(p->link)
   243  				p->link->mark |= LABEL;
   244  			break;
   245  
   246  		case ANOR:
   247  			q = p;
   248  			if(p->to.type == D_REG)
   249  				if(p->to.reg == REGZERO)
   250  					p->mark |= LABEL|SYNC;
   251  			break;
   252  
   253  		case ALWAR:
   254  		case ASTWCCC:
   255  		case AECIWX:
   256  		case AECOWX:
   257  		case AEIEIO:
   258  		case AICBI:
   259  		case AISYNC:
   260  		case ATLBIE:
   261  		case ATLBIEL:
   262  		case ASLBIA:
   263  		case ASLBIE:
   264  		case ASLBMFEE:
   265  		case ASLBMFEV:
   266  		case ASLBMTE:
   267  		case ADCBF:
   268  		case ADCBI:
   269  		case ADCBST:
   270  		case ADCBT:
   271  		case ADCBTST:
   272  		case ADCBZ:
   273  		case ASYNC:
   274  		case ATLBSYNC:
   275  		case APTESYNC:
   276  		case ATW:
   277  		case AWORD:
   278  		case ARFI:
   279  		case ARFCI:
   280  		case ARFID:
   281  		case AHRFID:
   282  			q = p;
   283  			p->mark |= LABEL|SYNC;
   284  			continue;
   285  
   286  		case AMOVW:
   287  		case AMOVWZ:
   288  		case AMOVD:
   289  			q = p;
   290  			switch(p->from.type) {
   291  			case D_MSR:
   292  			case D_SPR:
   293  			case D_FPSCR:
   294  			case D_CREG:
   295  			case D_DCR:
   296  				p->mark |= LABEL|SYNC;
   297  			}
   298  			switch(p->to.type) {
   299  			case D_MSR:
   300  			case D_SPR:
   301  			case D_FPSCR:
   302  			case D_CREG:
   303  			case D_DCR:
   304  				p->mark |= LABEL|SYNC;
   305  			}
   306  			continue;
   307  
   308  		case AFABS:
   309  		case AFABSCC:
   310  		case AFADD:
   311  		case AFADDCC:
   312  		case AFCTIW:
   313  		case AFCTIWCC:
   314  		case AFCTIWZ:
   315  		case AFCTIWZCC:
   316  		case AFDIV:
   317  		case AFDIVCC:
   318  		case AFMADD:
   319  		case AFMADDCC:
   320  		case AFMOVD:
   321  		case AFMOVDU:
   322  		/* case AFMOVDS: */
   323  		case AFMOVS:
   324  		case AFMOVSU:
   325  		/* case AFMOVSD: */
   326  		case AFMSUB:
   327  		case AFMSUBCC:
   328  		case AFMUL:
   329  		case AFMULCC:
   330  		case AFNABS:
   331  		case AFNABSCC:
   332  		case AFNEG:
   333  		case AFNEGCC:
   334  		case AFNMADD:
   335  		case AFNMADDCC:
   336  		case AFNMSUB:
   337  		case AFNMSUBCC:
   338  		case AFRSP:
   339  		case AFRSPCC:
   340  		case AFSUB:
   341  		case AFSUBCC:
   342  			q = p;
   343  			p->mark |= FLOAT;
   344  			continue;
   345  
   346  		case ABL:
   347  		case ABCL:
   348  		case ADUFFZERO:
   349  		case ADUFFCOPY:
   350  			cursym->text->mark &= ~LEAF;
   351  
   352  		case ABC:
   353  		case ABEQ:
   354  		case ABGE:
   355  		case ABGT:
   356  		case ABLE:
   357  		case ABLT:
   358  		case ABNE:
   359  		case ABR:
   360  		case ABVC:
   361  		case ABVS:
   362  			p->mark |= BRANCH;
   363  			q = p;
   364  			q1 = p->pcond;
   365  			if(q1 != nil) {
   366  				while(q1->as == ANOP) {
   367  					q1 = q1->link;
   368  					p->pcond = q1;
   369  				}
   370  				if(!(q1->mark & LEAF))
   371  					q1->mark |= LABEL;
   372  			} else
   373  				p->mark |= LABEL;
   374  			q1 = p->link;
   375  			if(q1 != nil)
   376  				q1->mark |= LABEL;
   377  			continue;
   378  
   379  		case AFCMPO:
   380  		case AFCMPU:
   381  			q = p;
   382  			p->mark |= FCMP|FLOAT;
   383  			continue;
   384  
   385  		case ARETURN:
   386  			q = p;
   387  			if(p->link != nil)
   388  				p->link->mark |= LABEL;
   389  			continue;
   390  
   391  		case ANOP:
   392  			q1 = p->link;
   393  			q->link = q1;		/* q is non-nop */
   394  			q1->mark |= p->mark;
   395  			continue;
   396  
   397  		default:
   398  			q = p;
   399  			continue;
   400  		}
   401  	}
   402  
   403  	autosize = 0;
   404  	for(p = cursym->text; p != nil; p = p->link) {
   405  		o = p->as;
   406  		switch(o) {
   407  		case ATEXT:
   408  			mov = AMOVD;
   409  			aoffset = 0;
   410  			autosize = textstksiz + 8;
   411  			if((p->mark & LEAF) && autosize <= 8)
   412  				autosize = 0;
   413  			else
   414  				if(autosize & 4)
   415  					autosize += 4;
   416  			p->to.offset = (p->to.offset & (0xffffffffull<<32)) | (uint32)(autosize-8);
   417  
   418  			if(!(p->reg & NOSPLIT))
   419  				p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check
   420  
   421  			q = p;
   422  			if(autosize) {
   423  				/* use MOVDU to adjust R1 when saving R31, if autosize is small */
   424  				if(!(cursym->text->mark & LEAF) && autosize >= -BIG && autosize <= BIG) {
   425  					mov = AMOVDU;
   426  					aoffset = -autosize;
   427  				} else {
   428  					q = appendp(ctxt, p);
   429  					q->as = AADD;
   430  					q->lineno = p->lineno;
   431  					q->from.type = D_CONST;
   432  					q->from.offset = -autosize;
   433  					q->to.type = D_REG;
   434  					q->to.reg = REGSP;
   435  					q->spadj = +autosize;
   436  				}
   437  			} else
   438  			if(!(cursym->text->mark & LEAF)) {
   439  				if(ctxt->debugvlog) {
   440  					Bprint(ctxt->bso, "save suppressed in: %s\n",
   441  						cursym->name);
   442  					Bflush(ctxt->bso);
   443  				}
   444  				cursym->text->mark |= LEAF;
   445  			}
   446  
   447  			if(cursym->text->mark & LEAF) {
   448  				cursym->leaf = 1;
   449  				break;
   450  			}
   451  
   452  			q = appendp(ctxt, q);
   453  			q->as = AMOVD;
   454  			q->lineno = p->lineno;
   455  			q->from.type = D_SPR;
   456  			q->from.offset = D_LR;
   457  			q->to.type = D_REG;
   458  			q->to.reg = REGTMP;
   459  
   460  			q = appendp(ctxt, q);
   461  			q->as = mov;
   462  			q->lineno = p->lineno;
   463  			q->from.type = D_REG;
   464  			q->from.reg = REGTMP;
   465  			q->to.type = D_OREG;
   466  			q->to.offset = aoffset;
   467  			q->to.reg = REGSP;
   468  			if(q->as == AMOVDU)
   469  				q->spadj = -aoffset;
   470  
   471  			if(cursym->text->reg & WRAPPER) {
   472  				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
   473  				//
   474  				//	MOVD g_panic(g), R3
   475  				//	CMP R0, R3
   476  				//	BEQ end
   477  				//	MOVD panic_argp(R3), R4
   478  				//	ADD $(autosize+8), R1, R5
   479  				//	CMP R4, R5
   480  				//	BNE end
   481  				//	ADD $8, R1, R6
   482  				//	MOVD R6, panic_argp(R3)
   483  				// end:
   484  				//	NOP
   485  				//
   486  				// The NOP is needed to give the jumps somewhere to land.
   487  				// It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes.
   488  
   489  
   490  				q = appendp(ctxt, q);
   491  				q->as = AMOVD;
   492  				q->from.type = D_OREG;
   493  				q->from.reg = REGG;
   494  				q->from.offset = 4*ctxt->arch->ptrsize; // G.panic
   495  				q->to.type = D_REG;
   496  				q->to.reg = 3;
   497  
   498  				q = appendp(ctxt, q);
   499  				q->as = ACMP;
   500  				q->from.type = D_REG;
   501  				q->from.reg = 0;
   502  				q->to.type = D_REG;
   503  				q->to.reg = 3;
   504  
   505  				q = appendp(ctxt, q);
   506  				q->as = ABEQ;
   507  				q->to.type = D_BRANCH;
   508  				p1 = q;
   509  
   510  				q = appendp(ctxt, q);
   511  				q->as = AMOVD;
   512  				q->from.type = D_OREG;
   513  				q->from.reg = 3;
   514  				q->from.offset = 0; // Panic.argp
   515  				q->to.type = D_REG;
   516  				q->to.reg = 4;
   517  
   518  				q = appendp(ctxt, q);
   519  				q->as = AADD;
   520  				q->from.type = D_CONST;
   521  				q->from.offset = autosize+8;
   522  				q->reg = REGSP;
   523  				q->to.type = D_REG;
   524  				q->to.reg = 5;
   525  
   526  				q = appendp(ctxt, q);
   527  				q->as = ACMP;
   528  				q->from.type = D_REG;
   529  				q->from.reg = 4;
   530  				q->to.type = D_REG;
   531  				q->to.reg = 5;
   532  
   533  				q = appendp(ctxt, q);
   534  				q->as = ABNE;
   535  				q->to.type = D_BRANCH;
   536  				p2 = q;
   537  
   538  				q = appendp(ctxt, q);
   539  				q->as = AADD;
   540  				q->from.type = D_CONST;
   541  				q->from.offset = 8;
   542  				q->reg = REGSP;
   543  				q->to.type = D_REG;
   544  				q->to.reg = 6;
   545  
   546  				q = appendp(ctxt, q);
   547  				q->as = AMOVD;
   548  				q->from.type = D_REG;
   549  				q->from.reg = 6;
   550  				q->to.type = D_OREG;
   551  				q->to.reg = 3;
   552  				q->to.offset = 0; // Panic.argp
   553  
   554  				q = appendp(ctxt, q);
   555  				q->as = ANOP;
   556  				p1->pcond = q;
   557  				p2->pcond = q;
   558  			}
   559  
   560  			break;
   561  
   562  		case ARETURN:
   563  			if(p->from.type == D_CONST) {
   564  				ctxt->diag("using BECOME (%P) is not supported!", p);
   565  				break;
   566  			}
   567  			if(p->to.sym) { // retjmp
   568  				p->as = ABR;
   569  				p->to.type = D_BRANCH;
   570  				break;
   571  			}
   572  			if(cursym->text->mark & LEAF) {
   573  				if(!autosize) {
   574  					p->as = ABR;
   575  					p->from = zprg.from;
   576  					p->to.type = D_SPR;
   577  					p->to.offset = D_LR;
   578  					p->mark |= BRANCH;
   579  					break;
   580  				}
   581  
   582  				p->as = AADD;
   583  				p->from.type = D_CONST;
   584  				p->from.offset = autosize;
   585  				p->to.type = D_REG;
   586  				p->to.reg = REGSP;
   587  				p->spadj = -autosize;
   588  
   589  				q = ctxt->arch->prg();
   590  				q->as = ABR;
   591  				q->lineno = p->lineno;
   592  				q->to.type = D_SPR;
   593  				q->to.offset = D_LR;
   594  				q->mark |= BRANCH;
   595  				q->spadj = +autosize;
   596  
   597  				q->link = p->link;
   598  				p->link = q;
   599  				break;
   600  			}
   601  
   602  			p->as = AMOVD;
   603  			p->from.type = D_OREG;
   604  			p->from.offset = 0;
   605  			p->from.reg = REGSP;
   606  			p->to.type = D_REG;
   607  			p->to.reg = REGTMP;
   608  
   609  			q = ctxt->arch->prg();
   610  			q->as = AMOVD;
   611  			q->lineno = p->lineno;
   612  			q->from.type = D_REG;
   613  			q->from.reg = REGTMP;
   614  			q->to.type = D_SPR;
   615  			q->to.offset = D_LR;
   616  
   617  			q->link = p->link;
   618  			p->link = q;
   619  			p = q;
   620  
   621  			if(autosize) {
   622  				q = ctxt->arch->prg();
   623  				q->as = AADD;
   624  				q->lineno = p->lineno;
   625  				q->from.type = D_CONST;
   626  				q->from.offset = autosize;
   627  				q->to.type = D_REG;
   628  				q->to.reg = REGSP;
   629  				q->spadj = -autosize;
   630  
   631  				q->link = p->link;
   632  				p->link = q;
   633  			}
   634  
   635  			q1 = ctxt->arch->prg();
   636  			q1->as = ABR;
   637  			q1->lineno = p->lineno;
   638  			q1->to.type = D_SPR;
   639  			q1->to.offset = D_LR;
   640  			q1->mark |= BRANCH;
   641  			q1->spadj = +autosize;
   642  
   643  			q1->link = q->link;
   644  			q->link = q1;
   645  			break;
   646  
   647  		case AADD:
   648  			if(p->to.type == D_REG && p->to.reg == REGSP && p->from.type == D_CONST)
   649  				p->spadj = -p->from.offset;
   650  			break;
   651  		}
   652  	}
   653  
   654  #if 0 // instruction scheduling
   655  	if(debug['Q'] == 0)
   656  		return;
   657  
   658  	curtext = nil;
   659  	q = nil;	/* p - 1 */
   660  	q1 = firstp;	/* top of block */
   661  	o = 0;		/* count of instructions */
   662  	for(p = firstp; p != nil; p = p1) {
   663  		p1 = p->link;
   664  		o++;
   665  		if(p->mark & NOSCHED){
   666  			if(q1 != p){
   667  				sched(q1, q);
   668  			}
   669  			for(; p != nil; p = p->link){
   670  				if(!(p->mark & NOSCHED))
   671  					break;
   672  				q = p;
   673  			}
   674  			p1 = p;
   675  			q1 = p;
   676  			o = 0;
   677  			continue;
   678  		}
   679  		if(p->mark & (LABEL|SYNC)) {
   680  			if(q1 != p)
   681  				sched(q1, q);
   682  			q1 = p;
   683  			o = 1;
   684  		}
   685  		if(p->mark & (BRANCH|SYNC)) {
   686  			sched(q1, p);
   687  			q1 = p1;
   688  			o = 0;
   689  		}
   690  		if(o >= NSCHED) {
   691  			sched(q1, p);
   692  			q1 = p1;
   693  			o = 0;
   694  		}
   695  		q = p;
   696  	}
   697  #endif
   698  }
   699  
   700  static Prog*
   701  stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
   702  {
   703  	Prog *q, *q1;
   704  
   705  	// MOVD	g_stackguard(g), R3
   706  	p = appendp(ctxt, p);
   707  	p->as = AMOVD;
   708  	p->from.type = D_OREG;
   709  	p->from.reg = REGG;
   710  	p->from.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
   711  	if(ctxt->cursym->cfunc)
   712  		p->from.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
   713  	p->to.type = D_REG;
   714  	p->to.reg = 3;
   715  
   716  	q = nil;
   717  	if(framesize <= StackSmall) {
   718  		// small stack: SP < stackguard
   719  		//	CMP	stackguard, SP
   720  		p = appendp(ctxt, p);
   721  		p->as = ACMPU;
   722  		p->from.type = D_REG;
   723  		p->from.reg = 3;
   724  		p->to.type = D_REG;
   725  		p->to.reg = REGSP;
   726  	} else if(framesize <= StackBig) {
   727  		// large stack: SP-framesize < stackguard-StackSmall
   728  		//	ADD $-framesize, SP, R4
   729  		//	CMP stackguard, R4
   730  		p = appendp(ctxt, p);
   731  		p->as = AADD;
   732  		p->from.type = D_CONST;
   733  		p->from.offset = -framesize;
   734  		p->reg = REGSP;
   735  		p->to.type = D_REG;
   736  		p->to.reg = 4;
   737  
   738  		p = appendp(ctxt, p);
   739  		p->as = ACMPU;
   740  		p->from.type = D_REG;
   741  		p->from.reg = 3;
   742  		p->to.type = D_REG;
   743  		p->to.reg = 4;
   744  	} else {
   745  		// Such a large stack we need to protect against wraparound.
   746  		// If SP is close to zero:
   747  		//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
   748  		// The +StackGuard on both sides is required to keep the left side positive:
   749  		// SP is allowed to be slightly below stackguard. See stack.h.
   750  		//
   751  		// Preemption sets stackguard to StackPreempt, a very large value.
   752  		// That breaks the math above, so we have to check for that explicitly.
   753  		//	// stackguard is R3
   754  		//	CMP	R3, $StackPreempt
   755  		//	BEQ	label-of-call-to-morestack
   756  		//	ADD	$StackGuard, SP, R4
   757  		//	SUB	R3, R4
   758  		//	MOVD	$(framesize+(StackGuard-StackSmall)), R31
   759  		//	CMPU	R31, R4
   760  		p = appendp(ctxt, p);
   761  		p->as = ACMP;
   762  		p->from.type = D_REG;
   763  		p->from.reg = 3;
   764  		p->to.type = D_CONST;
   765  		p->to.offset = StackPreempt;
   766  
   767  		q = p = appendp(ctxt, p);
   768  		p->as = ABEQ;
   769  		p->to.type = D_BRANCH;
   770  
   771  		p = appendp(ctxt, p);
   772  		p->as = AADD;
   773  		p->from.type = D_CONST;
   774  		p->from.offset = StackGuard;
   775  		p->reg = REGSP;
   776  		p->to.type = D_REG;
   777  		p->to.reg = 4;
   778  
   779  		p = appendp(ctxt, p);
   780  		p->as = ASUB;
   781  		p->from.type = D_REG;
   782  		p->from.reg = 3;
   783  		p->to.type = D_REG;
   784  		p->to.reg = 4;
   785  
   786  		p = appendp(ctxt, p);
   787  		p->as = AMOVD;
   788  		p->from.type = D_CONST;
   789  		p->from.offset = framesize + StackGuard - StackSmall;
   790  		p->to.type = D_REG;
   791  		p->to.reg = REGTMP;
   792  
   793  		p = appendp(ctxt, p);
   794  		p->as = ACMPU;
   795  		p->from.type = D_REG;
   796  		p->from.reg = REGTMP;
   797  		p->to.type = D_REG;
   798  		p->to.reg = 4;
   799  	}
   800  
   801  	// q1: BLT	done
   802  	q1 = p = appendp(ctxt, p);
   803  	p->as = ABLT;
   804  	p->to.type = D_BRANCH;
   805  
   806  	// MOVD	LR, R5
   807  	p = appendp(ctxt, p);
   808  	p->as = AMOVD;
   809  	p->from.type = D_SPR;
   810  	p->from.offset = D_LR;
   811  	p->to.type = D_REG;
   812  	p->to.reg = 5;
   813  	if(q)
   814  		q->pcond = p;
   815  
   816  	// BL	runtime.morestack(SB)
   817  	p = appendp(ctxt, p);
   818  	p->as = ABL;
   819  	p->to.type = D_BRANCH;
   820  	if(ctxt->cursym->cfunc)
   821  		p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
   822  	else
   823  		p->to.sym = ctxt->symmorestack[noctxt];
   824  
   825  	// BR	start
   826  	p = appendp(ctxt, p);
   827  	p->as = ABR;
   828  	p->to.type = D_BRANCH;
   829  	p->pcond = ctxt->cursym->text->link;
   830  
   831  	// placeholder for q1's jump target
   832  	p = appendp(ctxt, p);
   833  	p->as = ANOP; // zero-width place holder
   834  	q1->pcond = p;
   835  
   836  	return p;
   837  }
   838  
   839  static void xfol(Link*, Prog*, Prog**);
   840  
   841  static void
   842  follow(Link *ctxt, LSym *s)
   843  {
   844  	Prog *firstp, *lastp;
   845  
   846  	ctxt->cursym = s;
   847  
   848  	firstp = ctxt->arch->prg();
   849  	lastp = firstp;
   850  	xfol(ctxt, s->text, &lastp);
   851  	lastp->link = nil;
   852  	s->text = firstp->link;
   853  }
   854  
   855  static int
   856  relinv(int a)
   857  {
   858  
   859  	switch(a) {
   860  	case ABEQ:	return ABNE;
   861  	case ABNE:	return ABEQ;
   862  
   863  	case ABGE:	return ABLT;
   864  	case ABLT:	return ABGE;
   865  
   866  	case ABGT:	return ABLE;
   867  	case ABLE:	return ABGT;
   868  
   869  	case ABVC:	return ABVS;
   870  	case ABVS:	return ABVC;
   871  	}
   872  	return 0;
   873  }
   874  
   875  static void
   876  xfol(Link *ctxt, Prog *p, Prog **last)
   877  {
   878  	Prog *q, *r;
   879  	int a, b, i;
   880  
   881  loop:
   882  	if(p == nil)
   883  		return;
   884  	a = p->as;
   885  	if(a == ABR) {
   886  		q = p->pcond;
   887  		if((p->mark&NOSCHED) || q && (q->mark&NOSCHED)){
   888  			p->mark |= FOLL;
   889  			(*last)->link = p;
   890  			*last = p;
   891  			p = p->link;
   892  			xfol(ctxt, p, last);
   893  			p = q;
   894  			if(p && !(p->mark & FOLL))
   895  				goto loop;
   896  			return;
   897  		}
   898  		if(q != nil) {
   899  			p->mark |= FOLL;
   900  			p = q;
   901  			if(!(p->mark & FOLL))
   902  				goto loop;
   903  		}
   904  	}
   905  	if(p->mark & FOLL) {
   906  		for(i=0,q=p; i<4; i++,q=q->link) {
   907  			if(q == *last || (q->mark&NOSCHED))
   908  				break;
   909  			b = 0;		/* set */
   910  			a = q->as;
   911  			if(a == ANOP) {
   912  				i--;
   913  				continue;
   914  			}
   915  			if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID)
   916  				goto copy;
   917  			if(!q->pcond || (q->pcond->mark&FOLL))
   918  				continue;
   919  			b = relinv(a);
   920  			if(!b)
   921  				continue;
   922  		copy:
   923  			for(;;) {
   924  				r = ctxt->arch->prg();
   925  				*r = *p;
   926  				if(!(r->mark&FOLL))
   927  					print("cant happen 1\n");
   928  				r->mark |= FOLL;
   929  				if(p != q) {
   930  					p = p->link;
   931  					(*last)->link = r;
   932  					*last = r;
   933  					continue;
   934  				}
   935  				(*last)->link = r;
   936  				*last = r;
   937  				if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID)
   938  					return;
   939  				r->as = b;
   940  				r->pcond = p->link;
   941  				r->link = p->pcond;
   942  				if(!(r->link->mark&FOLL))
   943  					xfol(ctxt, r->link, last);
   944  				if(!(r->pcond->mark&FOLL))
   945  					print("cant happen 2\n");
   946  				return;
   947  			}
   948  		}
   949  
   950  		a = ABR;
   951  		q = ctxt->arch->prg();
   952  		q->as = a;
   953  		q->lineno = p->lineno;
   954  		q->to.type = D_BRANCH;
   955  		q->to.offset = p->pc;
   956  		q->pcond = p;
   957  		p = q;
   958  	}
   959  	p->mark |= FOLL;
   960  	(*last)->link = p;
   961  	*last = p;
   962  	if(a == ABR || a == ARETURN || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID){
   963  		if(p->mark & NOSCHED){
   964  			p = p->link;
   965  			goto loop;
   966  		}
   967  		return;
   968  	}
   969  	if(p->pcond != nil)
   970  	if(a != ABL && p->link != nil) {
   971  		xfol(ctxt, p->link, last);
   972  		p = p->pcond;
   973  		if(p == nil || (p->mark&FOLL))
   974  			return;
   975  		goto loop;
   976  	}
   977  	p = p->link;
   978  	goto loop;
   979  }
   980  
   981  static Prog*
   982  prg(void)
   983  {
   984  	Prog *p;
   985  
   986  	p = emallocz(sizeof(*p));
   987  	*p = zprg;
   988  	return p;
   989  }
   990  
   991  LinkArch linkppc64 = {
   992  	.name = "ppc64",
   993  	.thechar = '9',
   994  	.endian = BigEndian,
   995  
   996  	.addstacksplit = addstacksplit,
   997  	.assemble = span9,
   998  	.datasize = datasize,
   999  	.follow = follow,
  1000  	.iscall = iscall,
  1001  	.isdata = isdata,
  1002  	.prg = prg,
  1003  	.progedit = progedit,
  1004  	.settextflag = settextflag,
  1005  	.symtype = symtype,
  1006  	.textflag = textflag,
  1007  
  1008  	.minlc = 4,
  1009  	.ptrsize = 8,
  1010  	.regsize = 8,
  1011  
  1012  	.D_ADDR = D_ADDR,
  1013  	.D_AUTO = D_AUTO,
  1014  	.D_BRANCH = D_BRANCH,
  1015  	.D_CONST = D_CONST,
  1016  	.D_EXTERN = D_EXTERN,
  1017  	.D_FCONST = D_FCONST,
  1018  	.D_NONE = D_NONE,
  1019  	.D_PARAM = D_PARAM,
  1020  	.D_SCONST = D_SCONST,
  1021  	.D_STATIC = D_STATIC,
  1022  	.D_OREG = D_OREG,
  1023  
  1024  	.ACALL = ABL,
  1025  	.ADATA = ADATA,
  1026  	.AEND = AEND,
  1027  	.AFUNCDATA = AFUNCDATA,
  1028  	.AGLOBL = AGLOBL,
  1029  	.AJMP = ABR,
  1030  	.ANOP = ANOP,
  1031  	.APCDATA = APCDATA,
  1032  	.ARET = ARETURN,
  1033  	.ATEXT = ATEXT,
  1034  	.ATYPE = ATYPE,
  1035  	.AUSEFIELD = AUSEFIELD,
  1036  };
  1037  
  1038  LinkArch linkppc64le = {
  1039  	.name = "ppc64le",
  1040  	.thechar = '9',
  1041  	.endian = LittleEndian,
  1042  
  1043  	.addstacksplit = addstacksplit,
  1044  	.assemble = span9,
  1045  	.datasize = datasize,
  1046  	.follow = follow,
  1047  	.iscall = iscall,
  1048  	.isdata = isdata,
  1049  	.prg = prg,
  1050  	.progedit = progedit,
  1051  	.settextflag = settextflag,
  1052  	.symtype = symtype,
  1053  	.textflag = textflag,
  1054  
  1055  	.minlc = 4,
  1056  	.ptrsize = 8,
  1057  	.regsize = 8,
  1058  
  1059  	.D_ADDR = D_ADDR,
  1060  	.D_AUTO = D_AUTO,
  1061  	.D_BRANCH = D_BRANCH,
  1062  	.D_CONST = D_CONST,
  1063  	.D_EXTERN = D_EXTERN,
  1064  	.D_FCONST = D_FCONST,
  1065  	.D_NONE = D_NONE,
  1066  	.D_PARAM = D_PARAM,
  1067  	.D_SCONST = D_SCONST,
  1068  	.D_STATIC = D_STATIC,
  1069  	.D_OREG = D_OREG,
  1070  
  1071  	.ACALL = ABL,
  1072  	.ADATA = ADATA,
  1073  	.AEND = AEND,
  1074  	.AFUNCDATA = AFUNCDATA,
  1075  	.AGLOBL = AGLOBL,
  1076  	.AJMP = ABR,
  1077  	.ANOP = ANOP,
  1078  	.APCDATA = APCDATA,
  1079  	.ARET = ARETURN,
  1080  	.ATEXT = ATEXT,
  1081  	.ATYPE = ATYPE,
  1082  	.AUSEFIELD = AUSEFIELD,
  1083  };