github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/cc/pgen.c (about)

     1  // Inferno utils/6c/sgen.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.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  #include "gc.h"
    32  #include "../../pkg/runtime/funcdata.h"
    33  
    34  enum { BitsPerPointer = 2 };
    35  
    36  static void dumpgcargs(Type *fn, Sym *sym);
    37  
    38  static Sym*
    39  makefuncdatasym(char *namefmt, int64 funcdatakind)
    40  {
    41  	Node nod;
    42  	Sym *sym;
    43  	static int32 nsym;
    44  	static char namebuf[40];
    45  
    46  	snprint(namebuf, sizeof(namebuf), namefmt, nsym++);
    47  	sym = slookup(namebuf);
    48  	sym->class = CSTATIC;
    49  	memset(&nod, 0, sizeof nod);
    50  	nod.op = ONAME;
    51  	nod.sym = sym;
    52  	nod.class = CSTATIC;
    53  	gins(AFUNCDATA, nodconst(funcdatakind), &nod);
    54  	linksym(sym)->type = SRODATA;
    55  	return sym;
    56  }
    57  
    58  int
    59  hasdotdotdot(void)
    60  {
    61  	Type *t;
    62  
    63  	for(t=thisfn->down; t!=T; t=t->down)
    64  		if(t->etype == TDOT)
    65  			return 1;
    66  	return 0;
    67  }
    68  
    69  vlong
    70  argsize(void)
    71  {
    72  	Type *t;
    73  	int32 s;
    74  
    75  //print("t=%T\n", thisfn);
    76  	s = align(0, thisfn->link, Aarg0, nil);
    77  	for(t=thisfn->down; t!=T; t=t->down) {
    78  		switch(t->etype) {
    79  		case TVOID:
    80  			break;
    81  		case TDOT:
    82  			if((textflag & NOSPLIT) == 0)
    83  				yyerror("function takes ... without textflag NOSPLIT");
    84  			return ArgsSizeUnknown;
    85  		default:
    86  			s = align(s, t, Aarg1, nil);
    87  			s = align(s, t, Aarg2, nil);
    88  			break;
    89  		}
    90  //print("	%d %T\n", s, t);
    91  	}
    92  	if(thechar == '6')
    93  		s = (s+7) & ~7;
    94  	else
    95  		s = (s+3) & ~3;
    96  	return s;
    97  }
    98  
    99  void
   100  codgen(Node *n, Node *nn)
   101  {
   102  	Prog *sp;
   103  	Node *n1, nod, nod1;
   104  	Sym *gcargs;
   105  	Sym *gclocals;
   106  	int isvarargs;
   107  
   108  	cursafe = 0;
   109  	curarg = 0;
   110  	maxargsafe = 0;
   111  
   112  	/*
   113  	 * isolate name
   114  	 */
   115  	for(n1 = nn;; n1 = n1->left) {
   116  		if(n1 == Z) {
   117  			diag(nn, "can't find function name");
   118  			return;
   119  		}
   120  		if(n1->op == ONAME)
   121  			break;
   122  	}
   123  	nearln = nn->lineno;
   124  
   125  	p = gtext(n1->sym, stkoff);
   126  	sp = p;
   127  
   128  	/*
   129  	 * generate funcdata symbol for this function.
   130  	 * data is filled in at the end of codgen().
   131  	 */
   132  	isvarargs = hasdotdotdot();
   133  	gcargs = nil;
   134  	if(!isvarargs)
   135  		gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
   136  	gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
   137  
   138  	/*
   139  	 * isolate first argument
   140  	 */
   141  	if(REGARG >= 0) {
   142  		if(typesuv[thisfn->link->etype]) {
   143  			nod1 = *nodret->left;
   144  			nodreg(&nod, &nod1, REGARG);
   145  			gmove(&nod, &nod1);
   146  		} else
   147  		if(firstarg && typechlp[firstargtype->etype]) {
   148  			nod1 = *nodret->left;
   149  			nod1.sym = firstarg;
   150  			nod1.type = firstargtype;
   151  			nod1.xoffset = align(0, firstargtype, Aarg1, nil);
   152  			nod1.etype = firstargtype->etype;
   153  			nodreg(&nod, &nod1, REGARG);
   154  			gmove(&nod, &nod1);
   155  		}
   156  	}
   157  
   158  	retok = 0;
   159  
   160  	canreach = 1;
   161  	warnreach = 1;
   162  	gen(n);
   163  	if(canreach && thisfn->link->etype != TVOID)
   164  		diag(Z, "no return at end of function: %s", n1->sym->name);
   165  	noretval(3);
   166  	gbranch(ORETURN);
   167  
   168  	if(!debug['N'] || debug['R'] || debug['P'])
   169  		regopt(sp);
   170  
   171  	if(thechar=='6' || thechar=='7')	/* [sic] */
   172  		maxargsafe = xround(maxargsafe, 8);
   173  	sp->to.offset += maxargsafe;
   174  
   175  	if(!isvarargs)
   176  		dumpgcargs(thisfn, gcargs);
   177  
   178  	// TODO(rsc): "stkoff" is not right. It does not account for
   179  	// the possibility of data stored in .safe variables.
   180  	// Unfortunately those move up and down just like
   181  	// the argument frame (and in fact dovetail with it)
   182  	// so the number we need is not available or even
   183  	// well-defined. Probably we need to make the safe
   184  	// area its own section.
   185  	// That said, we've been using stkoff for months
   186  	// and nothing too terrible has happened.
   187  	gextern(gclocals, nodconst(-stkoff), 0, 4); // locals
   188  	gclocals->type = typ(0, T);
   189  	gclocals->type->width = 4;
   190  }
   191  
   192  void
   193  supgen(Node *n)
   194  {
   195  	int owarn;
   196  	long spc;
   197  	Prog *sp;
   198  
   199  	if(n == Z)
   200  		return;
   201  	suppress++;
   202  	owarn = warnreach;
   203  	warnreach = 0;
   204  	spc = pc;
   205  	sp = lastp;
   206  	gen(n);
   207  	lastp = sp;
   208  	pc = spc;
   209  	sp->link = nil;
   210  	suppress--;
   211  	warnreach = owarn;
   212  }
   213  
   214  void
   215  gen(Node *n)
   216  {
   217  	Node *l, nod;
   218  	Prog *sp, *spc, *spb;
   219  	Case *cn;
   220  	long sbc, scc;
   221  	int snbreak, sncontin;
   222  	int f, o, oldreach;
   223  
   224  loop:
   225  	if(n == Z)
   226  		return;
   227  	nearln = n->lineno;
   228  	o = n->op;
   229  	if(debug['G'])
   230  		if(o != OLIST)
   231  			print("%L %O\n", nearln, o);
   232  
   233  	if(!canreach) {
   234  		switch(o) {
   235  		case OLABEL:
   236  		case OCASE:
   237  		case OLIST:
   238  		case OBREAK:
   239  		case OFOR:
   240  		case OWHILE:
   241  		case ODWHILE:
   242  			/* all handled specially - see switch body below */
   243  			break;
   244  		default:
   245  			if(warnreach) {
   246  				warn(n, "unreachable code %O", o);
   247  				warnreach = 0;
   248  			}
   249  		}
   250  	}
   251  
   252  	switch(o) {
   253  
   254  	default:
   255  		complex(n);
   256  		cgen(n, Z);
   257  		break;
   258  
   259  	case OLIST:
   260  		gen(n->left);
   261  
   262  	rloop:
   263  		n = n->right;
   264  		goto loop;
   265  
   266  	case ORETURN:
   267  		canreach = 0;
   268  		warnreach = !suppress;
   269  		complex(n);
   270  		if(n->type == T)
   271  			break;
   272  		l = n->left;
   273  		if(l == Z) {
   274  			noretval(3);
   275  			gbranch(ORETURN);
   276  			break;
   277  		}
   278  		if(typecmplx[n->type->etype]) {
   279  			sugen(l, nodret, n->type->width);
   280  			noretval(3);
   281  			gbranch(ORETURN);
   282  			break;
   283  		}
   284  		regret(&nod, n);
   285  		cgen(l, &nod);
   286  		regfree(&nod);
   287  		if(typefd[n->type->etype])
   288  			noretval(1);
   289  		else
   290  			noretval(2);
   291  		gbranch(ORETURN);
   292  		break;
   293  
   294  	case OLABEL:
   295  		canreach = 1;
   296  		l = n->left;
   297  		if(l) {
   298  			l->pc = pc;
   299  			if(l->label)
   300  				patch(l->label, pc);
   301  		}
   302  		gbranch(OGOTO);	/* prevent self reference in reg */
   303  		patch(p, pc);
   304  		goto rloop;
   305  
   306  	case OGOTO:
   307  		canreach = 0;
   308  		warnreach = !suppress;
   309  		n = n->left;
   310  		if(n == Z)
   311  			return;
   312  		if(n->complex == 0) {
   313  			diag(Z, "label undefined: %s", n->sym->name);
   314  			return;
   315  		}
   316  		if(suppress)
   317  			return;
   318  		gbranch(OGOTO);
   319  		if(n->pc) {
   320  			patch(p, n->pc);
   321  			return;
   322  		}
   323  		if(n->label)
   324  			patch(n->label, pc-1);
   325  		n->label = p;
   326  		return;
   327  
   328  	case OCASE:
   329  		canreach = 1;
   330  		l = n->left;
   331  		if(cases == C)
   332  			diag(n, "case/default outside a switch");
   333  		if(l == Z) {
   334  			newcase();
   335  			cases->val = 0;
   336  			cases->def = 1;
   337  			cases->label = pc;
   338  			cases->isv = 0;
   339  			goto rloop;
   340  		}
   341  		complex(l);
   342  		if(l->type == T)
   343  			goto rloop;
   344  		if(l->op == OCONST)
   345  		if(typeword[l->type->etype] && l->type->etype != TIND) {
   346  			newcase();
   347  			cases->val = l->vconst;
   348  			cases->def = 0;
   349  			cases->label = pc;
   350  			cases->isv = typev[l->type->etype];
   351  			goto rloop;
   352  		}
   353  		diag(n, "case expression must be integer constant");
   354  		goto rloop;
   355  
   356  	case OSWITCH:
   357  		l = n->left;
   358  		complex(l);
   359  		if(l->type == T)
   360  			break;
   361  		if(!typechlvp[l->type->etype] || l->type->etype == TIND) {
   362  			diag(n, "switch expression must be integer");
   363  			break;
   364  		}
   365  
   366  		gbranch(OGOTO);		/* entry */
   367  		sp = p;
   368  
   369  		cn = cases;
   370  		cases = C;
   371  		newcase();
   372  
   373  		sbc = breakpc;
   374  		breakpc = pc;
   375  		snbreak = nbreak;
   376  		nbreak = 0;
   377  		gbranch(OGOTO);
   378  		spb = p;
   379  
   380  		gen(n->right);		/* body */
   381  		if(canreach){
   382  			gbranch(OGOTO);
   383  			patch(p, breakpc);
   384  			nbreak++;
   385  		}
   386  
   387  		patch(sp, pc);
   388  		doswit(l);
   389  		patch(spb, pc);
   390  
   391  		cases = cn;
   392  		breakpc = sbc;
   393  		canreach = nbreak!=0;
   394  		if(canreach == 0)
   395  			warnreach = !suppress;
   396  		nbreak = snbreak;
   397  		break;
   398  
   399  	case OWHILE:
   400  	case ODWHILE:
   401  		l = n->left;
   402  		gbranch(OGOTO);		/* entry */
   403  		sp = p;
   404  
   405  		scc = continpc;
   406  		continpc = pc;
   407  		gbranch(OGOTO);
   408  		spc = p;
   409  
   410  		sbc = breakpc;
   411  		breakpc = pc;
   412  		snbreak = nbreak;
   413  		nbreak = 0;
   414  		gbranch(OGOTO);
   415  		spb = p;
   416  
   417  		patch(spc, pc);
   418  		if(n->op == OWHILE)
   419  			patch(sp, pc);
   420  		bcomplex(l, Z);		/* test */
   421  		patch(p, breakpc);
   422  		if(l->op != OCONST || vconst(l) == 0)
   423  			nbreak++;
   424  
   425  		if(n->op == ODWHILE)
   426  			patch(sp, pc);
   427  		gen(n->right);		/* body */
   428  		gbranch(OGOTO);
   429  		patch(p, continpc);
   430  
   431  		patch(spb, pc);
   432  		continpc = scc;
   433  		breakpc = sbc;
   434  		canreach = nbreak!=0;
   435  		if(canreach == 0)
   436  			warnreach = !suppress;
   437  		nbreak = snbreak;
   438  		break;
   439  
   440  	case OFOR:
   441  		l = n->left;
   442  		if(!canreach && l->right->left && warnreach) {
   443  			warn(n, "unreachable code FOR");
   444  			warnreach = 0;
   445  		}
   446  		gen(l->right->left);	/* init */
   447  		gbranch(OGOTO);		/* entry */
   448  		sp = p;
   449  
   450  		/*
   451  		 * if there are no incoming labels in the
   452  		 * body and the top's not reachable, warn
   453  		 */
   454  		if(!canreach && warnreach && deadheads(n)) {
   455  			warn(n, "unreachable code %O", o);
   456  			warnreach = 0;
   457  		}
   458  
   459  		scc = continpc;
   460  		continpc = pc;
   461  		gbranch(OGOTO);
   462  		spc = p;
   463  
   464  		sbc = breakpc;
   465  		breakpc = pc;
   466  		snbreak = nbreak;
   467  		nbreak = 0;
   468  		sncontin = ncontin;
   469  		ncontin = 0;
   470  		gbranch(OGOTO);
   471  		spb = p;
   472  
   473  		patch(spc, pc);
   474  		gen(l->right->right);	/* inc */
   475  		patch(sp, pc);
   476  		if(l->left != Z) {	/* test */
   477  			bcomplex(l->left, Z);
   478  			patch(p, breakpc);
   479  			if(l->left->op != OCONST || vconst(l->left) == 0)
   480  				nbreak++;
   481  		}
   482  		canreach = 1;
   483  		gen(n->right);		/* body */
   484  		if(canreach){
   485  			gbranch(OGOTO);
   486  			patch(p, continpc);
   487  			ncontin++;
   488  		}
   489  		if(!ncontin && l->right->right && warnreach) {
   490  			warn(l->right->right, "unreachable FOR inc");
   491  			warnreach = 0;
   492  		}
   493  
   494  		patch(spb, pc);
   495  		continpc = scc;
   496  		breakpc = sbc;
   497  		canreach = nbreak!=0;
   498  		if(canreach == 0)
   499  			warnreach = !suppress;
   500  		nbreak = snbreak;
   501  		ncontin = sncontin;
   502  		break;
   503  
   504  	case OCONTINUE:
   505  		if(continpc < 0) {
   506  			diag(n, "continue not in a loop");
   507  			break;
   508  		}
   509  		gbranch(OGOTO);
   510  		patch(p, continpc);
   511  		ncontin++;
   512  		canreach = 0;
   513  		warnreach = !suppress;
   514  		break;
   515  
   516  	case OBREAK:
   517  		if(breakpc < 0) {
   518  			diag(n, "break not in a loop");
   519  			break;
   520  		}
   521  		/*
   522  		 * Don't complain about unreachable break statements.
   523  		 * There are breaks hidden in yacc's output and some people
   524  		 * write return; break; in their switch statements out of habit.
   525  		 * However, don't confuse the analysis by inserting an
   526  		 * unreachable reference to breakpc either.
   527  		 */
   528  		if(!canreach)
   529  			break;
   530  		gbranch(OGOTO);
   531  		patch(p, breakpc);
   532  		nbreak++;
   533  		canreach = 0;
   534  		warnreach = !suppress;
   535  		break;
   536  
   537  	case OIF:
   538  		l = n->left;
   539  		if(bcomplex(l, n->right)) {
   540  			if(typefd[l->type->etype])
   541  				f = !l->fconst;
   542  			else
   543  				f = !l->vconst;
   544  			if(debug['c'])
   545  				print("%L const if %s\n", nearln, f ? "false" : "true");
   546  			if(f) {
   547  				canreach = 1;
   548  				supgen(n->right->left);
   549  				oldreach = canreach;
   550  				canreach = 1;
   551  				gen(n->right->right);
   552  				/*
   553  				 * treat constant ifs as regular ifs for
   554  				 * reachability warnings.
   555  				 */
   556  				if(!canreach && oldreach && debug['w'] < 2)
   557  					warnreach = 0;
   558  			}
   559  			else {
   560  				canreach = 1;
   561  				gen(n->right->left);
   562  				oldreach = canreach;
   563  				canreach = 1;
   564  				supgen(n->right->right);
   565  				/*
   566  				 * treat constant ifs as regular ifs for
   567  				 * reachability warnings.
   568  				 */
   569  				if(!oldreach && canreach && debug['w'] < 2)
   570  					warnreach = 0;
   571  				canreach = oldreach;
   572  			}
   573  		}
   574  		else {
   575  			sp = p;
   576  			canreach = 1;
   577  			if(n->right->left != Z)
   578  				gen(n->right->left);
   579  			oldreach = canreach;
   580  			canreach = 1;
   581  			if(n->right->right != Z) {
   582  				gbranch(OGOTO);
   583  				patch(sp, pc);
   584  				sp = p;
   585  				gen(n->right->right);
   586  			}
   587  			patch(sp, pc);
   588  			canreach = canreach || oldreach;
   589  			if(canreach == 0)
   590  				warnreach = !suppress;
   591  		}
   592  		break;
   593  
   594  	case OSET:
   595  	case OUSED:
   596  	case OPREFETCH:
   597  		usedset(n->left, o);
   598  		break;
   599  	}
   600  }
   601  
   602  void
   603  usedset(Node *n, int o)
   604  {
   605  	if(n->op == OLIST) {
   606  		usedset(n->left, o);
   607  		usedset(n->right, o);
   608  		return;
   609  	}
   610  	complex(n);
   611  	if(o == OPREFETCH) {
   612  		gprefetch(n);
   613  		return;
   614  	}
   615  	switch(n->op) {
   616  	case OADDR:	/* volatile */
   617  		gins(ANOP, n, Z);
   618  		break;
   619  	case ONAME:
   620  		if(o == OSET)
   621  			gins(ANOP, Z, n);
   622  		else
   623  			gins(ANOP, n, Z);
   624  		break;
   625  	}
   626  }
   627  
   628  int
   629  bcomplex(Node *n, Node *c)
   630  {
   631  	Node *b, nod;
   632  
   633  	complex(n);
   634  	if(n->type != T)
   635  	if(tcompat(n, T, n->type, tnot))
   636  		n->type = T;
   637  	if(n->type == T) {
   638  		gbranch(OGOTO);
   639  		return 0;
   640  	}
   641  	if(c != Z && n->op == OCONST && deadheads(c))
   642  		return 1;
   643  	if(typev[n->type->etype] && machcap(Z)) {
   644  		b = &nod;
   645  		b->op = ONE;
   646  		b->left = n;
   647  		b->right = new(0, Z, Z);
   648  		*b->right = *nodconst(0);
   649  		b->right->type = n->type;
   650  		b->type = types[TLONG];
   651  		n = b;
   652  	}
   653  	bool64(n);
   654  	boolgen(n, 1, Z);
   655  	return 0;
   656  }
   657  
   658  // Updates the bitvector with a set bit for each pointer containing
   659  // value in the type description starting at offset.
   660  static void
   661  walktype1(Type *t, int32 offset, Bvec *bv, int param)
   662  {
   663  	Type *t1;
   664  	int32 o;
   665  	int32 widthptr;
   666  
   667  	widthptr = ewidth[TIND];
   668  	switch(t->etype) {
   669  	case TCHAR:
   670  	case TUCHAR:
   671  	case TSHORT:
   672  	case TUSHORT:
   673  	case TINT:
   674  	case TUINT:
   675  	case TLONG:
   676  	case TULONG:
   677  	case TVLONG:
   678  	case TUVLONG:
   679  	case TFLOAT:
   680  	case TDOUBLE:
   681  		// non-pointer types
   682  		for(o = 0; o < t->width; o++)
   683  			bvset(bv, ((offset + t->offset + o) / widthptr) * BitsPerPointer); // 1 = live scalar
   684  		break;
   685  
   686  	case TIND:
   687  	pointer:
   688  		// pointer types
   689  		if((offset + t->offset) % widthptr != 0)
   690  			yyerror("unaligned pointer");
   691  		bvset(bv, ((offset + t->offset) / widthptr)*BitsPerPointer + 1); // 2 = live ptr
   692  		break;
   693  
   694  	case TARRAY:
   695  		if(param)	// unlike Go, C passes arrays by reference
   696  			goto pointer;
   697  		// array in struct or union is an actual array
   698  		for(o = 0; o < t->width; o += t->link->width)
   699  			walktype1(t->link, offset+o, bv, 0);
   700  		break;
   701  
   702  	case TSTRUCT:
   703  		// build map recursively
   704  		for(t1 = t->link; t1 != T; t1 = t1->down)
   705  			walktype1(t1, offset, bv, 0);
   706  		break;
   707  
   708  	case TUNION:
   709  		walktype1(t->link, offset, bv, 0);
   710  		break;
   711  
   712  	default:
   713  		yyerror("can't handle arg type %s\n", tnames[t->etype]);
   714  	}
   715  }
   716  
   717  // Compute a bit vector to describe the pointer containing locations
   718  // in the argument list.  Adds the data to gcsym and returns the offset
   719  // of end of the bit vector.
   720  static void
   721  dumpgcargs(Type *fn, Sym *sym)
   722  {
   723  	Bvec *bv;
   724  	Type *t;
   725  	int32 i;
   726  	int32 argbytes;
   727  	int32 symoffset, argoffset;
   728  
   729  	// Dump the length of the bitmap array.  This value is always one for
   730  	// functions written in C.
   731  	symoffset = 0;
   732  	gextern(sym, nodconst(1), symoffset, 4);
   733  	symoffset += 4;
   734  	argbytes = (argsize() + ewidth[TIND] - 1);
   735  	bv = bvalloc((argbytes  / ewidth[TIND]) * BitsPerPointer);
   736  	argoffset = align(0, fn->link, Aarg0, nil);
   737  	if(argoffset > 0) {
   738  		// The C calling convention returns structs by copying them to a
   739  		// location pointed to by a hidden first argument.  This first
   740  		// argument is a pointer.
   741  		if(argoffset != ewidth[TIND])
   742  			yyerror("passbyptr arg not the right size");
   743  		bvset(bv, 1); // 2 = live ptr
   744  	}
   745  	for(t = fn->down; t != T; t = t->down) {
   746  		if(t->etype == TVOID)
   747  			continue;
   748  		argoffset = align(argoffset, t, Aarg1, nil);
   749  		walktype1(t, argoffset, bv, 1);
   750  		argoffset = align(argoffset, t, Aarg2, nil);
   751  	}
   752  	// Dump the length of the bitmap.
   753  	gextern(sym, nodconst(bv->n), symoffset, 4);
   754  	symoffset += 4;
   755  	// Dump the words of the bitmap.
   756  	for(i = 0; i < bv->n; i += 32) {
   757  		gextern(sym, nodconst(bv->b[i/32]), symoffset, 4);
   758  		symoffset += 4;
   759  	}
   760  	free(bv);
   761  	// Finalize the gc symbol.
   762  	sym->type = typ(0, T);
   763  	sym->type->width = symoffset;
   764  }