github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/cmd/6l/pass.c (about)

     1  // Inferno utils/6l/pass.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  // Code and data passes.
    32  
    33  #include	"l.h"
    34  #include	"../ld/lib.h"
    35  #include "../../pkg/runtime/stack.h"
    36  
    37  static void xfol(Prog*, Prog**);
    38  
    39  Prog*
    40  brchain(Prog *p)
    41  {
    42  	int i;
    43  
    44  	for(i=0; i<20; i++) {
    45  		if(p == P || p->as != AJMP)
    46  			return p;
    47  		p = p->pcond;
    48  	}
    49  	return P;
    50  }
    51  
    52  void
    53  follow(void)
    54  {
    55  	Prog *firstp, *lastp;
    56  
    57  	if(debug['v'])
    58  		Bprint(&bso, "%5.2f follow\n", cputime());
    59  	Bflush(&bso);
    60  	
    61  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
    62  		firstp = prg();
    63  		lastp = firstp;
    64  		xfol(cursym->text, &lastp);
    65  		lastp->link = nil;
    66  		cursym->text = firstp->link;
    67  	}
    68  }
    69  
    70  static int
    71  nofollow(int a)
    72  {
    73  	switch(a) {
    74  	case AJMP:
    75  	case ARET:
    76  	case AIRETL:
    77  	case AIRETQ:
    78  	case AIRETW:
    79  	case ARETFL:
    80  	case ARETFQ:
    81  	case ARETFW:
    82  	case AUNDEF:
    83  		return 1;
    84  	}
    85  	return 0;
    86  }
    87  
    88  static int
    89  pushpop(int a)
    90  {
    91  	switch(a) {
    92  	case APUSHL:
    93  	case APUSHFL:
    94  	case APUSHQ:
    95  	case APUSHFQ:
    96  	case APUSHW:
    97  	case APUSHFW:
    98  	case APOPL:
    99  	case APOPFL:
   100  	case APOPQ:
   101  	case APOPFQ:
   102  	case APOPW:
   103  	case APOPFW:
   104  		return 1;
   105  	}
   106  	return 0;
   107  }
   108  
   109  static void
   110  xfol(Prog *p, Prog **last)
   111  {
   112  	Prog *q;
   113  	int i;
   114  	enum as a;
   115  
   116  loop:
   117  	if(p == P)
   118  		return;
   119  	if(p->as == AJMP)
   120  	if((q = p->pcond) != P && q->as != ATEXT) {
   121  		/* mark instruction as done and continue layout at target of jump */
   122  		p->mark = 1;
   123  		p = q;
   124  		if(p->mark == 0)
   125  			goto loop;
   126  	}
   127  	if(p->mark) {
   128  		/* 
   129  		 * p goes here, but already used it elsewhere.
   130  		 * copy up to 4 instructions or else branch to other copy.
   131  		 */
   132  		for(i=0,q=p; i<4; i++,q=q->link) {
   133  			if(q == P)
   134  				break;
   135  			if(q == *last)
   136  				break;
   137  			a = q->as;
   138  			if(a == ANOP) {
   139  				i--;
   140  				continue;
   141  			}
   142  			if(nofollow(a) || pushpop(a))	
   143  				break;	// NOTE(rsc): arm does goto copy
   144  			if(q->pcond == P || q->pcond->mark)
   145  				continue;
   146  			if(a == ACALL || a == ALOOP)
   147  				continue;
   148  			for(;;) {
   149  				if(p->as == ANOP) {
   150  					p = p->link;
   151  					continue;
   152  				}
   153  				q = copyp(p);
   154  				p = p->link;
   155  				q->mark = 1;
   156  				(*last)->link = q;
   157  				*last = q;
   158  				if(q->as != a || q->pcond == P || q->pcond->mark)
   159  					continue;
   160  
   161  				q->as = relinv(q->as);
   162  				p = q->pcond;
   163  				q->pcond = q->link;
   164  				q->link = p;
   165  				xfol(q->link, last);
   166  				p = q->link;
   167  				if(p->mark)
   168  					return;
   169  				goto loop;
   170  			}
   171  		} /* */
   172  		q = prg();
   173  		q->as = AJMP;
   174  		q->line = p->line;
   175  		q->to.type = D_BRANCH;
   176  		q->to.offset = p->pc;
   177  		q->pcond = p;
   178  		p = q;
   179  	}
   180  	
   181  	/* emit p */
   182  	p->mark = 1;
   183  	(*last)->link = p;
   184  	*last = p;
   185  	a = p->as;
   186  
   187  	/* continue loop with what comes after p */
   188  	if(nofollow(a))
   189  		return;
   190  	if(p->pcond != P && a != ACALL) {
   191  		/*
   192  		 * some kind of conditional branch.
   193  		 * recurse to follow one path.
   194  		 * continue loop on the other.
   195  		 */
   196  		if((q = brchain(p->pcond)) != P)
   197  			p->pcond = q;
   198  		if((q = brchain(p->link)) != P)
   199  			p->link = q;
   200  		if(p->from.type == D_CONST) {
   201  			if(p->from.offset == 1) {
   202  				/*
   203  				 * expect conditional jump to be taken.
   204  				 * rewrite so that's the fall-through case.
   205  				 */
   206  				p->as = relinv(a);
   207  				q = p->link;
   208  				p->link = p->pcond;
   209  				p->pcond = q;
   210  			}
   211  		} else {			
   212  			q = p->link;
   213  			if(q->mark)
   214  			if(a != ALOOP) {
   215  				p->as = relinv(a);
   216  				p->link = p->pcond;
   217  				p->pcond = q;
   218  			}
   219  		}
   220  		xfol(p->link, last);
   221  		if(p->pcond->mark)
   222  			return;
   223  		p = p->pcond;
   224  		goto loop;
   225  	}
   226  	p = p->link;
   227  	goto loop;
   228  }
   229  
   230  Prog*
   231  byteq(int v)
   232  {
   233  	Prog *p;
   234  
   235  	p = prg();
   236  	p->as = ABYTE;
   237  	p->from.type = D_CONST;
   238  	p->from.offset = v&0xff;
   239  	return p;
   240  }
   241  
   242  int
   243  relinv(int a)
   244  {
   245  
   246  	switch(a) {
   247  	case AJEQ:	return AJNE;
   248  	case AJNE:	return AJEQ;
   249  	case AJLE:	return AJGT;
   250  	case AJLS:	return AJHI;
   251  	case AJLT:	return AJGE;
   252  	case AJMI:	return AJPL;
   253  	case AJGE:	return AJLT;
   254  	case AJPL:	return AJMI;
   255  	case AJGT:	return AJLE;
   256  	case AJHI:	return AJLS;
   257  	case AJCS:	return AJCC;
   258  	case AJCC:	return AJCS;
   259  	case AJPS:	return AJPC;
   260  	case AJPC:	return AJPS;
   261  	case AJOS:	return AJOC;
   262  	case AJOC:	return AJOS;
   263  	}
   264  	diag("unknown relation: %s in %s", anames[a], TNAME);
   265  	errorexit();
   266  	return a;
   267  }
   268  
   269  void
   270  patch(void)
   271  {
   272  	int32 c;
   273  	Prog *p, *q;
   274  	Sym *s, *gmsym;
   275  	int32 vexit;
   276  
   277  	if(debug['v'])
   278  		Bprint(&bso, "%5.2f mkfwd\n", cputime());
   279  	Bflush(&bso);
   280  	mkfwd();
   281  	if(debug['v'])
   282  		Bprint(&bso, "%5.2f patch\n", cputime());
   283  	Bflush(&bso);
   284  
   285  	if(flag_shared) {
   286  		s = lookup("init_array", 0);
   287  		s->type = SINITARR;
   288  		s->reachable = 1;
   289  		s->hide = 1;
   290  		addaddr(s, lookup(INITENTRY, 0));
   291  	}
   292  
   293  	gmsym = lookup("runtime.tlsgm", 0);
   294  	if(linkmode != LinkExternal)
   295  		gmsym->reachable = 0;
   296  	s = lookup("exit", 0);
   297  	vexit = s->value;
   298  	for(cursym = textp; cursym != nil; cursym = cursym->next)
   299  	for(p = cursym->text; p != P; p = p->link) {
   300  		if(HEADTYPE == Hwindows) { 
   301  			// Windows
   302  			// Convert
   303  			//   op	  n(GS), reg
   304  			// to
   305  			//   MOVL 0x28(GS), reg
   306  			//   op	  n(reg), reg
   307  			// The purpose of this patch is to fix some accesses
   308  			// to extern register variables (TLS) on Windows, as
   309  			// a different method is used to access them.
   310  			if(p->from.type == D_INDIR+D_GS
   311  			&& p->to.type >= D_AX && p->to.type <= D_DI 
   312  			&& p->from.offset <= 8) {
   313  				q = appendp(p);
   314  				q->from = p->from;
   315  				q->from.type = D_INDIR + p->to.type;
   316  				q->to = p->to;
   317  				q->as = p->as;
   318  				p->as = AMOVQ;
   319  				p->from.type = D_INDIR+D_GS;
   320  				p->from.offset = 0x28;
   321  			}
   322  		}
   323  		if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
   324  		|| HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
   325  		|| HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) {
   326  			// ELF uses FS instead of GS.
   327  			if(p->from.type == D_INDIR+D_GS)
   328  				p->from.type = D_INDIR+D_FS;
   329  			if(p->to.type == D_INDIR+D_GS)
   330  				p->to.type = D_INDIR+D_FS;
   331  			if(p->from.index == D_GS)
   332  				p->from.index = D_FS;
   333  			if(p->to.index == D_GS)
   334  				p->to.index = D_FS;
   335  		}
   336  		if(!flag_shared) {
   337  			// Convert g() or m() accesses of the form
   338  			//   op n(reg)(GS*1), reg
   339  			// to
   340  			//   op n(GS*1), reg
   341  			if(p->from.index == D_FS || p->from.index == D_GS) {
   342  				p->from.type = D_INDIR + p->from.index;
   343  				p->from.index = D_NONE;
   344  			}
   345  			// Convert g() or m() accesses of the form
   346  			//   op reg, n(reg)(GS*1)
   347  			// to
   348  			//   op reg, n(GS*1)
   349  			if(p->to.index == D_FS || p->to.index == D_GS) {
   350  				p->to.type = D_INDIR + p->to.index;
   351  				p->to.index = D_NONE;
   352  			}
   353  			// Convert get_tls access of the form
   354  			//   op runtime.tlsgm(SB), reg
   355  			// to
   356  			//   NOP
   357  			if(gmsym != S && p->from.sym == gmsym) {
   358  				p->as = ANOP;
   359  				p->from.type = D_NONE;
   360  				p->to.type = D_NONE;
   361  				p->from.sym = nil;
   362  				p->to.sym = nil;
   363  				continue;
   364  			}
   365  		} else {
   366  			// Convert TLS reads of the form
   367  			//   op n(GS), reg
   368  			// to
   369  			//   MOVQ $runtime.tlsgm(SB), reg
   370  			//   op n(reg)(GS*1), reg
   371  			if((p->from.type == D_INDIR+D_FS || p->from.type == D_INDIR + D_GS) && p->to.type >= D_AX && p->to.type <= D_DI) {
   372  				q = appendp(p);
   373  				q->to = p->to;
   374  				q->as = p->as;
   375  				q->from.type = D_INDIR+p->to.type;
   376  				q->from.index = p->from.type - D_INDIR;
   377  				q->from.scale = 1;
   378  				q->from.offset = p->from.offset;
   379  				p->as = AMOVQ;
   380  				p->from.type = D_EXTERN;
   381  				p->from.sym = gmsym;
   382  				p->from.offset = 0;
   383  			}
   384  		}
   385  		if(p->as == ACALL || (p->as == AJMP && p->to.type != D_BRANCH) || (p->as == ARET && p->to.sym != nil)) {
   386  			s = p->to.sym;
   387  			if(s) {
   388  				if(debug['c'])
   389  					Bprint(&bso, "%s calls %s\n", TNAME, s->name);
   390  				if((s->type&SMASK) != STEXT) {
   391  					/* diag prints TNAME first */
   392  					diag("undefined: %s", s->name);
   393  					s->type = STEXT;
   394  					s->value = vexit;
   395  					continue;	// avoid more error messages
   396  				}
   397  				if(s->text == nil)
   398  					continue;
   399  				p->to.type = D_BRANCH;
   400  				p->to.offset = s->text->pc;
   401  				p->pcond = s->text;
   402  				continue;
   403  			}
   404  		}
   405  		if(p->to.type != D_BRANCH)
   406  			continue;
   407  		c = p->to.offset;
   408  		for(q = cursym->text; q != P;) {
   409  			if(c == q->pc)
   410  				break;
   411  			if(q->forwd != P && c >= q->forwd->pc)
   412  				q = q->forwd;
   413  			else
   414  				q = q->link;
   415  		}
   416  		if(q == P) {
   417  			diag("branch out of range in %s (%#ux)\n%P [%s]",
   418  				TNAME, c, p, p->to.sym ? p->to.sym->name : "<nil>");
   419  			p->to.type = D_NONE;
   420  		}
   421  		p->pcond = q;
   422  	}
   423  
   424  	for(cursym = textp; cursym != nil; cursym = cursym->next)
   425  	for(p = cursym->text; p != P; p = p->link) {
   426  		p->mark = 0;	/* initialization for follow */
   427  		if(p->pcond != P) {
   428  			p->pcond = brloop(p->pcond);
   429  			if(p->pcond != P)
   430  			if(p->to.type == D_BRANCH)
   431  				p->to.offset = p->pcond->pc;
   432  		}
   433  	}
   434  }
   435  
   436  Prog*
   437  brloop(Prog *p)
   438  {
   439  	int c;
   440  	Prog *q;
   441  
   442  	c = 0;
   443  	for(q = p; q != P; q = q->pcond) {
   444  		if(q->as != AJMP)
   445  			break;
   446  		c++;
   447  		if(c >= 5000)
   448  			return P;
   449  	}
   450  	return q;
   451  }
   452  
   453  static char*
   454  morename[] =
   455  {
   456  	"runtime.morestack00",
   457  	"runtime.morestack10",
   458  	"runtime.morestack01",
   459  	"runtime.morestack11",
   460  
   461  	"runtime.morestack8",
   462  	"runtime.morestack16",
   463  	"runtime.morestack24",
   464  	"runtime.morestack32",
   465  	"runtime.morestack40",
   466  	"runtime.morestack48",
   467  };
   468  Prog*	pmorestack[nelem(morename)];
   469  Sym*	symmorestack[nelem(morename)];
   470  
   471  void
   472  dostkoff(void)
   473  {
   474  	Prog *p, *q, *q1;
   475  	int32 autoffset, deltasp;
   476  	int a, pcsize;
   477  	uint32 moreconst1, moreconst2, i;
   478  	Sym *gmsym;
   479  
   480  
   481  	gmsym = lookup("runtime.tlsgm", 0);
   482  	for(i=0; i<nelem(morename); i++) {
   483  		symmorestack[i] = lookup(morename[i], 0);
   484  		if(symmorestack[i]->type != STEXT)
   485  			diag("morestack trampoline not defined - %s", morename[i]);
   486  		pmorestack[i] = symmorestack[i]->text;
   487  	}
   488  
   489  	for(cursym = textp; cursym != nil; cursym = cursym->next) {
   490  		if(cursym->text == nil || cursym->text->link == nil)
   491  			continue;				
   492  
   493  		p = cursym->text;
   494  		parsetextconst(p->to.offset);
   495  		autoffset = textstksiz;
   496  		if(autoffset < 0)
   497  			autoffset = 0;
   498  
   499  		if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) {
   500  			for(q = p; q != P; q = q->link)
   501  				if(q->as == ACALL)
   502  					goto noleaf;
   503  			p->from.scale |= NOSPLIT;
   504  		noleaf:;
   505  		}
   506  
   507  		q = P;
   508  		q1 = P;
   509  		if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
   510  			diag("nosplit func likely to overflow stack");
   511  
   512  		if(!(p->from.scale & NOSPLIT)) {
   513  			if(flag_shared) {
   514  				// Load TLS offset with MOVQ $runtime.tlsgm(SB), CX
   515  				p = appendp(p);
   516  				p->as = AMOVQ;
   517  				p->from.type = D_EXTERN;
   518  				p->from.sym = gmsym;
   519  				p->to.type = D_CX;
   520  			}
   521  			p = appendp(p);	// load g into CX
   522  			p->as = AMOVQ;
   523  			if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd
   524  			|| HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd
   525  			|| HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly)
   526  				// ELF uses FS
   527  				p->from.type = D_INDIR+D_FS;
   528  			else
   529  				p->from.type = D_INDIR+D_GS;
   530  			if(flag_shared) {
   531  				// Add TLS offset stored in CX
   532  				p->from.index = p->from.type - D_INDIR;
   533  				p->from.type = D_INDIR + D_CX;
   534  			}
   535  			p->from.offset = tlsoffset+0;
   536  			p->to.type = D_CX;
   537  			if(HEADTYPE == Hwindows) {
   538  				// movq %gs:0x28, %rcx
   539  				// movq (%rcx), %rcx
   540  				p->as = AMOVQ;
   541  				p->from.type = D_INDIR+D_GS;
   542  				p->from.offset = 0x28;
   543  				p->to.type = D_CX;
   544  
   545  			
   546  				p = appendp(p);
   547  				p->as = AMOVQ;
   548  				p->from.type = D_INDIR+D_CX;
   549  				p->from.offset = 0;
   550  				p->to.type = D_CX;
   551  			}
   552  
   553  			if(debug['K']) {
   554  				// 6l -K means check not only for stack
   555  				// overflow but stack underflow.
   556  				// On underflow, INT 3 (breakpoint).
   557  				// Underflow itself is rare but this also
   558  				// catches out-of-sync stack guard info
   559  
   560  				p = appendp(p);
   561  				p->as = ACMPQ;
   562  				p->from.type = D_INDIR+D_CX;
   563  				p->from.offset = 8;
   564  				p->to.type = D_SP;
   565  
   566  				p = appendp(p);
   567  				p->as = AJHI;
   568  				p->to.type = D_BRANCH;
   569  				p->to.offset = 4;
   570  				q1 = p;
   571  
   572  				p = appendp(p);
   573  				p->as = AINT;
   574  				p->from.type = D_CONST;
   575  				p->from.offset = 3;
   576  
   577  				p = appendp(p);
   578  				p->as = ANOP;
   579  				q1->pcond = p;
   580  			}
   581  
   582  			q1 = P;
   583  			if(autoffset <= StackSmall) {
   584  				// small stack: SP <= stackguard
   585  				//	CMPQ SP, stackguard
   586  				p = appendp(p);
   587  				p->as = ACMPQ;
   588  				p->from.type = D_SP;
   589  				p->to.type = D_INDIR+D_CX;
   590  			} else if(autoffset <= StackBig) {
   591  				// large stack: SP-framesize <= stackguard-StackSmall
   592  				//	LEAQ -xxx(SP), AX
   593  				//	CMPQ AX, stackguard
   594  				p = appendp(p);
   595  				p->as = ALEAQ;
   596  				p->from.type = D_INDIR+D_SP;
   597  				p->from.offset = -(autoffset-StackSmall);
   598  				p->to.type = D_AX;
   599  
   600  				p = appendp(p);
   601  				p->as = ACMPQ;
   602  				p->from.type = D_AX;
   603  				p->to.type = D_INDIR+D_CX;
   604  			} else {
   605  				// Such a large stack we need to protect against wraparound.
   606  				// If SP is close to zero:
   607  				//	SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall)
   608  				// The +StackGuard on both sides is required to keep the left side positive:
   609  				// SP is allowed to be slightly below stackguard. See stack.h.
   610  				//
   611  				// Preemption sets stackguard to StackPreempt, a very large value.
   612  				// That breaks the math above, so we have to check for that explicitly.
   613  				//	MOVQ	stackguard, CX
   614  				//	CMPQ	CX, $StackPreempt
   615  				//	JEQ	label-of-call-to-morestack
   616  				//	LEAQ	StackGuard(SP), AX
   617  				//	SUBQ	CX, AX
   618  				//	CMPQ	AX, $(autoffset+(StackGuard-StackSmall))
   619  
   620  				p = appendp(p);
   621  				p->as = AMOVQ;
   622  				p->from.type = D_INDIR+D_CX;
   623  				p->from.offset = 0;
   624  				p->to.type = D_SI;
   625  
   626  				p = appendp(p);
   627  				p->as = ACMPQ;
   628  				p->from.type = D_SI;
   629  				p->to.type = D_CONST;
   630  				p->to.offset = StackPreempt;
   631  
   632  				p = appendp(p);
   633  				p->as = AJEQ;
   634  				p->to.type = D_BRANCH;
   635  				q1 = p;
   636  
   637  				p = appendp(p);
   638  				p->as = ALEAQ;
   639  				p->from.type = D_INDIR+D_SP;
   640  				p->from.offset = StackGuard;
   641  				p->to.type = D_AX;
   642  				
   643  				p = appendp(p);
   644  				p->as = ASUBQ;
   645  				p->from.type = D_SI;
   646  				p->to.type = D_AX;
   647  				
   648  				p = appendp(p);
   649  				p->as = ACMPQ;
   650  				p->from.type = D_AX;
   651  				p->to.type = D_CONST;
   652  				p->to.offset = autoffset+(StackGuard-StackSmall);
   653  			}					
   654  
   655  			// common
   656  			p = appendp(p);
   657  			p->as = AJHI;
   658  			p->to.type = D_BRANCH;
   659  			q = p;
   660  
   661  			// If we ask for more stack, we'll get a minimum of StackMin bytes.
   662  			// We need a stack frame large enough to hold the top-of-stack data,
   663  			// the function arguments+results, our caller's PC, our frame,
   664  			// a word for the return PC of the next call, and then the StackLimit bytes
   665  			// that must be available on entry to any function called from a function
   666  			// that did a stack check.  If StackMin is enough, don't ask for a specific
   667  			// amount: then we can use the custom functions and save a few
   668  			// instructions.
   669  			moreconst1 = 0;
   670  			if(StackTop + textarg + PtrSize + autoffset + PtrSize + StackLimit >= StackMin)
   671  				moreconst1 = autoffset;
   672  			moreconst2 = textarg;
   673  			if(moreconst2 == 1) // special marker
   674  				moreconst2 = 0;
   675  			if((moreconst2&7) != 0)
   676  				diag("misaligned argument size in stack split");
   677  			// 4 varieties varieties (const1==0 cross const2==0)
   678  			// and 6 subvarieties of (const1==0 and const2!=0)
   679  			p = appendp(p);
   680  			if(moreconst1 == 0 && moreconst2 == 0) {
   681  				p->as = ACALL;
   682  				p->to.type = D_BRANCH;
   683  				p->pcond = pmorestack[0];
   684  				p->to.sym = symmorestack[0];
   685  			} else
   686  			if(moreconst1 != 0 && moreconst2 == 0) {
   687  				p->as = AMOVL;
   688  				p->from.type = D_CONST;
   689  				p->from.offset = moreconst1;
   690  				p->to.type = D_AX;
   691  
   692  				p = appendp(p);
   693  				p->as = ACALL;
   694  				p->to.type = D_BRANCH;
   695  				p->pcond = pmorestack[1];
   696  				p->to.sym = symmorestack[1];
   697  			} else
   698  			if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) {
   699  				i = moreconst2/8 + 3;
   700  				p->as = ACALL;
   701  				p->to.type = D_BRANCH;
   702  				p->pcond = pmorestack[i];
   703  				p->to.sym = symmorestack[i];
   704  			} else
   705  			if(moreconst1 == 0 && moreconst2 != 0) {
   706  				p->as = AMOVL;
   707  				p->from.type = D_CONST;
   708  				p->from.offset = moreconst2;
   709  				p->to.type = D_AX;
   710  
   711  				p = appendp(p);
   712  				p->as = ACALL;
   713  				p->to.type = D_BRANCH;
   714  				p->pcond = pmorestack[2];
   715  				p->to.sym = symmorestack[2];
   716  			} else {
   717  				p->as = AMOVQ;
   718  				p->from.type = D_CONST;
   719  				p->from.offset = (uint64)moreconst2 << 32;
   720  				p->from.offset |= moreconst1;
   721  				p->to.type = D_AX;
   722  
   723  				p = appendp(p);
   724  				p->as = ACALL;
   725  				p->to.type = D_BRANCH;
   726  				p->pcond = pmorestack[3];
   727  				p->to.sym = symmorestack[3];
   728  			}
   729  			
   730  			p = appendp(p);
   731  			p->as = AJMP;
   732  			p->to.type = D_BRANCH;
   733  			p->pcond = cursym->text->link;
   734  		}
   735  
   736  		if(q != P)
   737  			q->pcond = p->link;
   738  		if(q1 != P)
   739  			q1->pcond = q->link;
   740  
   741  		if(autoffset) {
   742  			p = appendp(p);
   743  			p->as = AADJSP;
   744  			p->from.type = D_CONST;
   745  			p->from.offset = autoffset;
   746  			p->spadj = autoffset;
   747  			if(q != P)
   748  				q->pcond = p;
   749  		} else {
   750  			// zero-byte stack adjustment.
   751  			// Insert a fake non-zero adjustment so that stkcheck can
   752  			// recognize the end of the stack-splitting prolog.
   753  			p = appendp(p);
   754  			p->as = ANOP;
   755  			p->spadj = -PtrSize;
   756  			p = appendp(p);
   757  			p->as = ANOP;
   758  			p->spadj = PtrSize;
   759  		}
   760  		deltasp = autoffset;
   761  
   762  		if(debug['K'] > 1 && autoffset) {
   763  			// 6l -KK means double-check for stack overflow
   764  			// even after calling morestack and even if the
   765  			// function is marked as nosplit.
   766  			p = appendp(p);
   767  			p->as = AMOVQ;
   768  			p->from.type = D_INDIR+D_CX;
   769  			p->from.offset = 0;
   770  			p->to.type = D_BX;
   771  
   772  			p = appendp(p);
   773  			p->as = ASUBQ;
   774  			p->from.type = D_CONST;
   775  			p->from.offset = StackSmall+32;
   776  			p->to.type = D_BX;
   777  
   778  			p = appendp(p);
   779  			p->as = ACMPQ;
   780  			p->from.type = D_SP;
   781  			p->to.type = D_BX;
   782  
   783  			p = appendp(p);
   784  			p->as = AJHI;
   785  			p->to.type = D_BRANCH;
   786  			q1 = p;
   787  
   788  			p = appendp(p);
   789  			p->as = AINT;
   790  			p->from.type = D_CONST;
   791  			p->from.offset = 3;
   792  
   793  			p = appendp(p);
   794  			p->as = ANOP;
   795  			q1->pcond = p;
   796  		}
   797  		
   798  		if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
   799  			// 6l -Z means zero the stack frame on entry.
   800  			// This slows down function calls but can help avoid
   801  			// false positives in garbage collection.
   802  			p = appendp(p);
   803  			p->as = AMOVQ;
   804  			p->from.type = D_SP;
   805  			p->to.type = D_DI;
   806  			
   807  			p = appendp(p);
   808  			p->as = AMOVQ;
   809  			p->from.type = D_CONST;
   810  			p->from.offset = autoffset/8;
   811  			p->to.type = D_CX;
   812  			
   813  			p = appendp(p);
   814  			p->as = AMOVQ;
   815  			p->from.type = D_CONST;
   816  			p->from.offset = 0;
   817  			p->to.type = D_AX;
   818  			
   819  			p = appendp(p);
   820  			p->as = AREP;
   821  			
   822  			p = appendp(p);
   823  			p->as = ASTOSQ;
   824  		}
   825  		
   826  		for(; p != P; p = p->link) {
   827  			pcsize = p->mode/8;
   828  			a = p->from.type;
   829  			if(a == D_AUTO)
   830  				p->from.offset += deltasp;
   831  			if(a == D_PARAM)
   832  				p->from.offset += deltasp + pcsize;
   833  			a = p->to.type;
   834  			if(a == D_AUTO)
   835  				p->to.offset += deltasp;
   836  			if(a == D_PARAM)
   837  				p->to.offset += deltasp + pcsize;
   838  	
   839  			switch(p->as) {
   840  			default:
   841  				continue;
   842  			case APUSHL:
   843  			case APUSHFL:
   844  				deltasp += 4;
   845  				p->spadj = 4;
   846  				continue;
   847  			case APUSHQ:
   848  			case APUSHFQ:
   849  				deltasp += 8;
   850  				p->spadj = 8;
   851  				continue;
   852  			case APUSHW:
   853  			case APUSHFW:
   854  				deltasp += 2;
   855  				p->spadj = 2;
   856  				continue;
   857  			case APOPL:
   858  			case APOPFL:
   859  				deltasp -= 4;
   860  				p->spadj = -4;
   861  				continue;
   862  			case APOPQ:
   863  			case APOPFQ:
   864  				deltasp -= 8;
   865  				p->spadj = -8;
   866  				continue;
   867  			case APOPW:
   868  			case APOPFW:
   869  				deltasp -= 2;
   870  				p->spadj = -2;
   871  				continue;
   872  			case ARET:
   873  				break;
   874  			}
   875  	
   876  			if(autoffset != deltasp)
   877  				diag("unbalanced PUSH/POP");
   878  	
   879  			if(autoffset) {
   880  				p->as = AADJSP;
   881  				p->from.type = D_CONST;
   882  				p->from.offset = -autoffset;
   883  				p->spadj = -autoffset;
   884  				p = appendp(p);
   885  				p->as = ARET;
   886  				// If there are instructions following
   887  				// this ARET, they come from a branch
   888  				// with the same stackframe, so undo
   889  				// the cleanup.
   890  				p->spadj = +autoffset;
   891  			}
   892  			if(p->to.sym) // retjmp
   893  				p->as = AJMP;
   894  		}
   895  	}
   896  }
   897  
   898  vlong
   899  atolwhex(char *s)
   900  {
   901  	vlong n;
   902  	int f;
   903  
   904  	n = 0;
   905  	f = 0;
   906  	while(*s == ' ' || *s == '\t')
   907  		s++;
   908  	if(*s == '-' || *s == '+') {
   909  		if(*s++ == '-')
   910  			f = 1;
   911  		while(*s == ' ' || *s == '\t')
   912  			s++;
   913  	}
   914  	if(s[0]=='0' && s[1]){
   915  		if(s[1]=='x' || s[1]=='X'){
   916  			s += 2;
   917  			for(;;){
   918  				if(*s >= '0' && *s <= '9')
   919  					n = n*16 + *s++ - '0';
   920  				else if(*s >= 'a' && *s <= 'f')
   921  					n = n*16 + *s++ - 'a' + 10;
   922  				else if(*s >= 'A' && *s <= 'F')
   923  					n = n*16 + *s++ - 'A' + 10;
   924  				else
   925  					break;
   926  			}
   927  		} else
   928  			while(*s >= '0' && *s <= '7')
   929  				n = n*8 + *s++ - '0';
   930  	} else
   931  		while(*s >= '0' && *s <= '9')
   932  			n = n*10 + *s++ - '0';
   933  	if(f)
   934  		n = -n;
   935  	return n;
   936  }