github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/5g/ggen.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #undef	EXTERN
     6  #define	EXTERN
     7  #include <u.h>
     8  #include <libc.h>
     9  #include "gg.h"
    10  #include "opt.h"
    11  
    12  void
    13  defframe(Prog *ptxt)
    14  {
    15  	// fill in argument size
    16  	ptxt->to.type = D_CONST2;
    17  	ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
    18  
    19  	// fill in final stack size
    20  	if(stksize > maxstksize)
    21  		maxstksize = stksize;
    22  	ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
    23  	maxstksize = 0;
    24  }
    25  
    26  // Sweep the prog list to mark any used nodes.
    27  void
    28  markautoused(Prog* p)
    29  {
    30  	for (; p; p = p->link) {
    31  		if (p->as == ATYPE)
    32  			continue;
    33  
    34  		if (p->from.name == D_AUTO && p->from.node)
    35  			p->from.node->used = 1;
    36  
    37  		if (p->to.name == D_AUTO && p->to.node)
    38  			p->to.node->used = 1;
    39  	}
    40  }
    41  
    42  // Fixup instructions after compactframe has moved all autos around.
    43  void
    44  fixautoused(Prog* p)
    45  {
    46  	Prog **lp;
    47  
    48  	for (lp=&p; (p=*lp) != P; ) {
    49  		if (p->as == ATYPE && p->from.node && p->from.name == D_AUTO && !p->from.node->used) {
    50  			*lp = p->link;
    51  			continue;
    52  		}
    53  
    54  		if (p->from.name == D_AUTO && p->from.node)
    55  			p->from.offset += p->from.node->stkdelta;
    56  
    57  		if (p->to.name == D_AUTO && p->to.node)
    58  			p->to.offset += p->to.node->stkdelta;
    59  
    60  		lp = &p->link;
    61  	}
    62  }
    63  
    64  /*
    65   * generate:
    66   *	call f
    67   *	proc=-1	normal call but no return
    68   *	proc=0	normal call
    69   *	proc=1	goroutine run in new proc
    70   *	proc=2	defer call save away stack
    71    *	proc=3	normal call to C pointer (not Go func value)
    72   */
    73  void
    74  ginscall(Node *f, int proc)
    75  {
    76  	Prog *p;
    77  	Node n1, r, r1, con;
    78  
    79  	switch(proc) {
    80  	default:
    81  		fatal("ginscall: bad proc %d", proc);
    82  		break;
    83  
    84  	case 0:	// normal call
    85  	case -1:	// normal call but no return
    86  		if(f->op == ONAME && f->class == PFUNC) {
    87  			p = gins(ABL, N, f);
    88  			afunclit(&p->to, f);
    89  			if(proc == -1 || noreturn(p))
    90  				gins(AUNDEF, N, N);
    91  			break;
    92  		}
    93  		nodreg(&r, types[tptr], 7);
    94  		nodreg(&r1, types[tptr], 1);
    95  		gmove(f, &r);
    96  		r.op = OINDREG;
    97  		gmove(&r, &r1);
    98  		r.op = OREGISTER;
    99  		r1.op = OINDREG;
   100  		gins(ABL, &r, &r1);
   101  		break;
   102  
   103  	case 3:	// normal call of c function pointer
   104  		gins(ABL, N, f);
   105  		break;
   106  
   107  	case 1:	// call in new proc (go)
   108  	case 2:	// deferred call (defer)
   109  		regalloc(&r, types[tptr], N);
   110  		p = gins(AMOVW, N, &r);
   111  		p->from.type = D_OREG;
   112  		p->from.reg = REGSP;
   113  		
   114  		p = gins(AMOVW, &r, N);
   115  		p->to.type = D_OREG;
   116  		p->to.reg = REGSP;
   117  		p->to.offset = -12;
   118  		p->scond |= C_WBIT;
   119  
   120  		memset(&n1, 0, sizeof n1);
   121  		n1.op = OADDR;
   122  		n1.left = f;
   123  		gins(AMOVW, &n1, &r);
   124  
   125  		p = gins(AMOVW, &r, N);
   126  		p->to.type = D_OREG;
   127  		p->to.reg = REGSP;
   128  		p->to.offset = 8;
   129  
   130  		nodconst(&con, types[TINT32], argsize(f->type));
   131  		gins(AMOVW, &con, &r);
   132  		p = gins(AMOVW, &r, N);
   133  		p->to.type = D_OREG;
   134  		p->to.reg = REGSP;
   135  		p->to.offset = 4;
   136  		regfree(&r);
   137  
   138  		if(proc == 1)
   139  			ginscall(newproc, 0);
   140  		else
   141  			ginscall(deferproc, 0);
   142  
   143  		nodreg(&r, types[tptr], 1);
   144  		p = gins(AMOVW, N, N);
   145  		p->from.type = D_CONST;
   146  		p->from.reg = REGSP;
   147  		p->from.offset = 12;
   148  		p->to.reg = REGSP;
   149  		p->to.type = D_REG;
   150  
   151  		if(proc == 2) {
   152  			nodconst(&con, types[TINT32], 0);
   153  			p = gins(ACMP, &con, N);
   154  			p->reg = 0;
   155  			patch(gbranch(ABNE, T, -1), retpc);
   156  		}
   157  		break;
   158  	}
   159  }
   160  
   161  /*
   162   * n is call to interface method.
   163   * generate res = n.
   164   */
   165  void
   166  cgen_callinter(Node *n, Node *res, int proc)
   167  {
   168  	int r;
   169  	Node *i, *f;
   170  	Node tmpi, nodo, nodr, nodsp;
   171  	Prog *p;
   172  
   173  	i = n->left;
   174  	if(i->op != ODOTINTER)
   175  		fatal("cgen_callinter: not ODOTINTER %O", i->op);
   176  
   177  	f = i->right;		// field
   178  	if(f->op != ONAME)
   179  		fatal("cgen_callinter: not ONAME %O", f->op);
   180  
   181  	i = i->left;		// interface
   182  
   183  	// Release res register during genlist and cgen,
   184  	// which might have their own function calls.
   185  	r = -1;
   186  	if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
   187  		r = res->val.u.reg;
   188  		reg[r]--;
   189  	}
   190  
   191  	if(!i->addable) {
   192  		tempname(&tmpi, i->type);
   193  		cgen(i, &tmpi);
   194  		i = &tmpi;
   195  	}
   196  
   197  	genlist(n->list);			// args
   198  	if(r >= 0)
   199  		reg[r]++;
   200  
   201  	regalloc(&nodr, types[tptr], res);
   202  	regalloc(&nodo, types[tptr], &nodr);
   203  	nodo.op = OINDREG;
   204  
   205  	agen(i, &nodr);		// REG = &inter
   206  
   207  	nodindreg(&nodsp, types[tptr], REGSP);
   208  	nodsp.xoffset = 4;
   209  	nodo.xoffset += widthptr;
   210  	cgen(&nodo, &nodsp);	// 4(SP) = 4(REG) -- i.data
   211  
   212  	nodo.xoffset -= widthptr;
   213  	cgen(&nodo, &nodr);	// REG = 0(REG) -- i.tab
   214  
   215  	nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
   216  	
   217  	if(proc == 0) {
   218  		// plain call: use direct c function pointer - more efficient
   219  		cgen(&nodo, &nodr);	// REG = 20+offset(REG) -- i.tab->fun[f]
   220  		nodr.op = OINDREG;
   221  		proc = 3;
   222  	} else {
   223  		// go/defer. generate go func value.
   224  		p = gins(AMOVW, &nodo, &nodr);
   225  		p->from.type = D_CONST;	// REG = &(20+offset(REG)) -- i.tab->fun[f]
   226  	}
   227  
   228  	// BOTCH nodr.type = fntype;
   229  	nodr.type = n->left->type;
   230  	ginscall(&nodr, proc);
   231  
   232  	regfree(&nodr);
   233  	regfree(&nodo);
   234  
   235  	setmaxarg(n->left->type);
   236  }
   237  
   238  /*
   239   * generate function call;
   240   *	proc=0	normal call
   241   *	proc=1	goroutine run in new proc
   242   *	proc=2	defer call save away stack
   243   */
   244  void
   245  cgen_call(Node *n, int proc)
   246  {
   247  	Type *t;
   248  	Node nod, afun;
   249  
   250  	if(n == N)
   251  		return;
   252  
   253  	if(n->left->ullman >= UINF) {
   254  		// if name involves a fn call
   255  		// precompute the address of the fn
   256  		tempname(&afun, types[tptr]);
   257  		cgen(n->left, &afun);
   258  	}
   259  
   260  	genlist(n->list);		// assign the args
   261  	t = n->left->type;
   262  
   263  	setmaxarg(t);
   264  
   265  	// call tempname pointer
   266  	if(n->left->ullman >= UINF) {
   267  		regalloc(&nod, types[tptr], N);
   268  		cgen_as(&nod, &afun);
   269  		nod.type = t;
   270  		ginscall(&nod, proc);
   271  		regfree(&nod);
   272  		goto ret;
   273  	}
   274  
   275  	// call pointer
   276  	if(n->left->op != ONAME || n->left->class != PFUNC) {
   277  		regalloc(&nod, types[tptr], N);
   278  		cgen_as(&nod, n->left);
   279  		nod.type = t;
   280  		ginscall(&nod, proc);
   281  		regfree(&nod);
   282  		goto ret;
   283  	}
   284  
   285  	// call direct
   286  	n->left->method = 1;
   287  	ginscall(n->left, proc);
   288  
   289  
   290  ret:
   291  	;
   292  }
   293  
   294  /*
   295   * call to n has already been generated.
   296   * generate:
   297   *	res = return value from call.
   298   */
   299  void
   300  cgen_callret(Node *n, Node *res)
   301  {
   302  	Node nod;
   303  	Type *fp, *t;
   304  	Iter flist;
   305  
   306  	t = n->left->type;
   307  	if(t->etype == TPTR32 || t->etype == TPTR64)
   308  		t = t->type;
   309  
   310  	fp = structfirst(&flist, getoutarg(t));
   311  	if(fp == T)
   312  		fatal("cgen_callret: nil");
   313  
   314  	memset(&nod, 0, sizeof(nod));
   315  	nod.op = OINDREG;
   316  	nod.val.u.reg = REGSP;
   317  	nod.addable = 1;
   318  
   319  	nod.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
   320  	nod.type = fp->type;
   321  	cgen_as(res, &nod);
   322  }
   323  
   324  /*
   325   * call to n has already been generated.
   326   * generate:
   327   *	res = &return value from call.
   328   */
   329  void
   330  cgen_aret(Node *n, Node *res)
   331  {
   332  	Node nod1, nod2;
   333  	Type *fp, *t;
   334  	Iter flist;
   335  
   336  	t = n->left->type;
   337  	if(isptr[t->etype])
   338  		t = t->type;
   339  
   340  	fp = structfirst(&flist, getoutarg(t));
   341  	if(fp == T)
   342  		fatal("cgen_aret: nil");
   343  
   344  	memset(&nod1, 0, sizeof(nod1));
   345  	nod1.op = OINDREG;
   346  	nod1.val.u.reg = REGSP;
   347  	nod1.addable = 1;
   348  
   349  	nod1.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
   350  	nod1.type = fp->type;
   351  
   352  	if(res->op != OREGISTER) {
   353  		regalloc(&nod2, types[tptr], res);
   354  		agen(&nod1, &nod2);
   355  		gins(AMOVW, &nod2, res);
   356  		regfree(&nod2);
   357  	} else
   358  		agen(&nod1, res);
   359  }
   360  
   361  /*
   362   * generate return.
   363   * n->left is assignments to return values.
   364   */
   365  void
   366  cgen_ret(Node *n)
   367  {
   368  	genlist(n->list);		// copy out args
   369  	if(hasdefer || curfn->exit)
   370  		gjmp(retpc);
   371  	else
   372  		gins(ARET, N, N);
   373  }
   374  
   375  /*
   376   * generate += *= etc.
   377   */
   378  void
   379  cgen_asop(Node *n)
   380  {
   381  	Node n1, n2, n3, n4;
   382  	Node *nl, *nr;
   383  	Prog *p1;
   384  	Addr addr;
   385  	int a, w;
   386  
   387  	nl = n->left;
   388  	nr = n->right;
   389  
   390  	if(nr->ullman >= UINF && nl->ullman >= UINF) {
   391  		tempname(&n1, nr->type);
   392  		cgen(nr, &n1);
   393  		n2 = *n;
   394  		n2.right = &n1;
   395  		cgen_asop(&n2);
   396  		goto ret;
   397  	}
   398  
   399  	if(!isint[nl->type->etype])
   400  		goto hard;
   401  	if(!isint[nr->type->etype])
   402  		goto hard;
   403  	if(is64(nl->type) || is64(nr->type))
   404  		goto hard64;
   405  
   406  	switch(n->etype) {
   407  	case OADD:
   408  	case OSUB:
   409  	case OXOR:
   410  	case OAND:
   411  	case OOR:
   412  		a = optoas(n->etype, nl->type);
   413  		if(nl->addable) {
   414  			if(smallintconst(nr))
   415  				n3 = *nr;
   416  			else {
   417  				regalloc(&n3, nr->type, N);
   418  				cgen(nr, &n3);
   419  			}
   420  			regalloc(&n2, nl->type, N);
   421  			cgen(nl, &n2);
   422  			gins(a, &n3, &n2);
   423  			cgen(&n2, nl);
   424  			regfree(&n2);
   425  			if(n3.op != OLITERAL)
   426  				regfree(&n3);
   427  			goto ret;
   428  		}
   429  		if(nr->ullman < UINF)
   430  		if(sudoaddable(a, nl, &addr, &w)) {
   431  			w = optoas(OAS, nl->type);
   432  			regalloc(&n2, nl->type, N);
   433  			p1 = gins(w, N, &n2);
   434  			p1->from = addr;
   435  			regalloc(&n3, nr->type, N);
   436  			cgen(nr, &n3);
   437  			gins(a, &n3, &n2);
   438  			p1 = gins(w, &n2, N);
   439  			p1->to = addr;
   440  			regfree(&n2);
   441  			regfree(&n3);
   442  			sudoclean();
   443  			goto ret;
   444  		}
   445  	}
   446  
   447  hard:
   448  	n2.op = 0;
   449  	n1.op = 0;
   450  	if(nr->op == OLITERAL) {
   451  		// don't allocate a register for literals.
   452  	} else if(nr->ullman >= nl->ullman || nl->addable) {
   453  		regalloc(&n2, nr->type, N);
   454  		cgen(nr, &n2);
   455  		nr = &n2;
   456  	} else {
   457  		tempname(&n2, nr->type);
   458  		cgen(nr, &n2);
   459  		nr = &n2;
   460  	}
   461  	if(!nl->addable) {
   462  		igen(nl, &n1, N);
   463  		nl = &n1;
   464  	}
   465  
   466  	n3 = *n;
   467  	n3.left = nl;
   468  	n3.right = nr;
   469  	n3.op = n->etype;
   470  
   471  	regalloc(&n4, nl->type, N);
   472  	cgen(&n3, &n4);
   473  	gmove(&n4, nl);
   474  
   475  	if(n1.op)
   476  		regfree(&n1);
   477  	if(n2.op == OREGISTER)
   478  		regfree(&n2);
   479  	regfree(&n4);
   480  	goto ret;
   481  
   482  hard64:
   483  	if(nr->ullman > nl->ullman) {
   484  		tempname(&n2, nr->type);
   485  		cgen(nr, &n2);
   486  		igen(nl, &n1, N);
   487  	} else {
   488  		igen(nl, &n1, N);
   489  		tempname(&n2, nr->type);
   490  		cgen(nr, &n2);
   491  	}
   492  
   493  	n3 = *n;
   494  	n3.left = &n1;
   495  	n3.right = &n2;
   496  	n3.op = n->etype;
   497  
   498  	cgen(&n3, &n1);
   499  
   500  ret:
   501  	;
   502  }
   503  
   504  int
   505  samereg(Node *a, Node *b)
   506  {
   507  	if(a->op != OREGISTER)
   508  		return 0;
   509  	if(b->op != OREGISTER)
   510  		return 0;
   511  	if(a->val.u.reg != b->val.u.reg)
   512  		return 0;
   513  	return 1;
   514  }
   515  
   516  /*
   517   * generate high multiply
   518   *  res = (nl * nr) >> wordsize
   519   */
   520  void
   521  cgen_hmul(Node *nl, Node *nr, Node *res)
   522  {
   523  	int w;
   524  	Node n1, n2, *tmp;
   525  	Type *t;
   526  	Prog *p;
   527  
   528  	if(nl->ullman < nr->ullman) {
   529  		tmp = nl;
   530  		nl = nr;
   531  		nr = tmp;
   532  	}
   533  	t = nl->type;
   534  	w = t->width * 8;
   535  	regalloc(&n1, t, res);
   536  	cgen(nl, &n1);
   537  	regalloc(&n2, t, N);
   538  	cgen(nr, &n2);
   539  	switch(simtype[t->etype]) {
   540  	case TINT8:
   541  	case TINT16:
   542  		gins(optoas(OMUL, t), &n2, &n1);
   543  		gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
   544  		break;
   545  	case TUINT8:
   546  	case TUINT16:
   547  		gins(optoas(OMUL, t), &n2, &n1);
   548  		gshift(AMOVW, &n1, SHIFT_LR, w, &n1);
   549  		break;
   550  	case TINT32:
   551  	case TUINT32:
   552  		// perform a long multiplication.
   553  		if(issigned[t->etype])
   554  			p = gins(AMULL, &n2, N);
   555  		else
   556  			p = gins(AMULLU, &n2, N);
   557  		// n2 * n1 -> (n1 n2)
   558  		p->reg = n1.val.u.reg;
   559  		p->to.type = D_REGREG;
   560  		p->to.reg = n1.val.u.reg;
   561  		p->to.offset = n2.val.u.reg;
   562  		break;
   563  	default:
   564  		fatal("cgen_hmul %T", t);
   565  		break;
   566  	}
   567  	cgen(&n1, res);
   568  	regfree(&n1);
   569  	regfree(&n2);
   570  }
   571  
   572  /*
   573   * generate shift according to op, one of:
   574   *	res = nl << nr
   575   *	res = nl >> nr
   576   */
   577  void
   578  cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
   579  {
   580  	Node n1, n2, n3, nt, t, lo, hi;
   581  	int w, v;
   582  	Prog *p1, *p2, *p3;
   583  	Type *tr;
   584  	uvlong sc;
   585  
   586  	USED(bounded);
   587  	if(nl->type->width > 4)
   588  		fatal("cgen_shift %T", nl->type);
   589  
   590  	w = nl->type->width * 8;
   591  
   592  	if(op == OLROT) {
   593  		v = mpgetfix(nr->val.u.xval);
   594  		regalloc(&n1, nl->type, res);
   595  		if(w == 32) {
   596  			cgen(nl, &n1);
   597  			gshift(AMOVW, &n1, SHIFT_RR, w-v, &n1);
   598  		} else {
   599  			regalloc(&n2, nl->type, N);
   600  			cgen(nl, &n2);
   601  			gshift(AMOVW, &n2, SHIFT_LL, v, &n1);
   602  			gshift(AORR, &n2, SHIFT_LR, w-v, &n1);
   603  			regfree(&n2);
   604  		}
   605  		gmove(&n1, res);
   606  		regfree(&n1);
   607  		return;
   608  	}
   609  
   610  	if(nr->op == OLITERAL) {
   611  		regalloc(&n1, nl->type, res);
   612  		cgen(nl, &n1);
   613  		sc = mpgetfix(nr->val.u.xval);
   614  		if(sc == 0) {
   615  			// nothing to do
   616  		} else if(sc >= nl->type->width*8) {
   617  			if(op == ORSH && issigned[nl->type->etype])
   618  				gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
   619  			else
   620  				gins(AEOR, &n1, &n1);
   621  		} else {
   622  			if(op == ORSH && issigned[nl->type->etype])
   623  				gshift(AMOVW, &n1, SHIFT_AR, sc, &n1);
   624  			else if(op == ORSH)
   625  				gshift(AMOVW, &n1, SHIFT_LR, sc, &n1);
   626  			else // OLSH
   627  				gshift(AMOVW, &n1, SHIFT_LL, sc, &n1);
   628  		}
   629  		gmove(&n1, res);
   630  		regfree(&n1);
   631  		return;
   632  	}
   633  
   634  	tr = nr->type;
   635  	if(tr->width > 4) {
   636  		tempname(&nt, nr->type);
   637  		if(nl->ullman >= nr->ullman) {
   638  			regalloc(&n2, nl->type, res);
   639  			cgen(nl, &n2);
   640  			cgen(nr, &nt);
   641  			n1 = nt;
   642  		} else {
   643  			cgen(nr, &nt);
   644  			regalloc(&n2, nl->type, res);
   645  			cgen(nl, &n2);
   646  		}
   647  		split64(&nt, &lo, &hi);
   648  		regalloc(&n1, types[TUINT32], N);
   649  		regalloc(&n3, types[TUINT32], N);
   650  		gmove(&lo, &n1);
   651  		gmove(&hi, &n3);
   652  		splitclean();
   653  		gins(ATST, &n3, N);
   654  		nodconst(&t, types[TUINT32], w);
   655  		p1 = gins(AMOVW, &t, &n1);
   656  		p1->scond = C_SCOND_NE;
   657  		tr = types[TUINT32];
   658  		regfree(&n3);
   659  	} else {
   660  		if(nl->ullman >= nr->ullman) {
   661  			regalloc(&n2, nl->type, res);
   662  			cgen(nl, &n2);
   663  			regalloc(&n1, nr->type, N);
   664  			cgen(nr, &n1);
   665  		} else {
   666  			regalloc(&n1, nr->type, N);
   667  			cgen(nr, &n1);
   668  			regalloc(&n2, nl->type, res);
   669  			cgen(nl, &n2);
   670  		}
   671  	}
   672  
   673  	// test for shift being 0
   674  	gins(ATST, &n1, N);
   675  	p3 = gbranch(ABEQ, T, -1);
   676  
   677  	// test and fix up large shifts
   678  	// TODO: if(!bounded), don't emit some of this.
   679  	regalloc(&n3, tr, N);
   680  	nodconst(&t, types[TUINT32], w);
   681  	gmove(&t, &n3);
   682  	gcmp(ACMP, &n1, &n3);
   683  	if(op == ORSH) {
   684  		if(issigned[nl->type->etype]) {
   685  			p1 = gshift(AMOVW, &n2, SHIFT_AR, w-1, &n2);
   686  			p2 = gregshift(AMOVW, &n2, SHIFT_AR, &n1, &n2);
   687  		} else {
   688  			p1 = gins(AEOR, &n2, &n2);
   689  			p2 = gregshift(AMOVW, &n2, SHIFT_LR, &n1, &n2);
   690  		}
   691  		p1->scond = C_SCOND_HS;
   692  		p2->scond = C_SCOND_LO;
   693  	} else {
   694  		p1 = gins(AEOR, &n2, &n2);
   695  		p2 = gregshift(AMOVW, &n2, SHIFT_LL, &n1, &n2);
   696  		p1->scond = C_SCOND_HS;
   697  		p2->scond = C_SCOND_LO;
   698  	}
   699  	regfree(&n3);
   700  
   701  	patch(p3, pc);
   702  	gmove(&n2, res);
   703  
   704  	regfree(&n1);
   705  	regfree(&n2);
   706  }
   707  
   708  void
   709  clearfat(Node *nl)
   710  {
   711  	uint32 w, c, q;
   712  	Node dst, nc, nz, end;
   713  	Prog *p, *pl;
   714  
   715  	/* clear a fat object */
   716  	if(debug['g'])
   717  		dump("\nclearfat", nl);
   718  
   719  
   720  	w = nl->type->width;
   721  	// Avoid taking the address for simple enough types.
   722  	if(componentgen(N, nl))
   723  		return;
   724  
   725  	c = w % 4;	// bytes
   726  	q = w / 4;	// quads
   727  
   728  	regalloc(&dst, types[tptr], N);
   729  	agen(nl, &dst);
   730  	nodconst(&nc, types[TUINT32], 0);
   731  	regalloc(&nz, types[TUINT32], 0);
   732  	cgen(&nc, &nz);
   733  
   734  	if(q >= 4) {
   735  		regalloc(&end, types[tptr], N);
   736  		p = gins(AMOVW, &dst, &end);
   737  		p->from.type = D_CONST;
   738  		p->from.offset = q*4;
   739  
   740  		p = gins(AMOVW, &nz, &dst);
   741  		p->to.type = D_OREG;
   742  		p->to.offset = 4;
   743  		p->scond |= C_PBIT;
   744  		pl = p;
   745  
   746  		p = gins(ACMP, &dst, N);
   747  		raddr(&end, p);
   748  		patch(gbranch(ABNE, T, 0), pl);
   749  
   750  		regfree(&end);
   751  	} else
   752  	while(q > 0) {
   753  		p = gins(AMOVW, &nz, &dst);
   754  		p->to.type = D_OREG;
   755  		p->to.offset = 4;
   756   		p->scond |= C_PBIT;
   757  //print("1. %P\n", p);
   758  		q--;
   759  	}
   760  
   761  	while(c > 0) {
   762  		p = gins(AMOVBU, &nz, &dst);
   763  		p->to.type = D_OREG;
   764  		p->to.offset = 1;
   765   		p->scond |= C_PBIT;
   766  //print("2. %P\n", p);
   767  		c--;
   768  	}
   769  	regfree(&dst);
   770  	regfree(&nz);
   771  }