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