github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/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  static Prog* appendp(Prog*, int, int, int, int32, int, int, int32);
    13  
    14  void
    15  defframe(Prog *ptxt, Bvec *bv)
    16  {
    17  	int i, j, first;
    18  	uint32 frame;
    19  	Prog *p, *p1;
    20  	
    21  	// fill in argument size
    22  	ptxt->to.type = D_CONST2;
    23  	ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
    24  
    25  	// fill in final stack size
    26  	if(stksize > maxstksize)
    27  		maxstksize = stksize;
    28  	frame = rnd(maxstksize+maxarg, widthptr);
    29  	ptxt->to.offset = frame;
    30  	maxstksize = 0;
    31  
    32  	// insert code to clear pointered part of the frame,
    33  	// so that garbage collector only sees initialized values
    34  	// when it looks for pointers.
    35  	p = ptxt;
    36  	while(p->link->as == AFUNCDATA || p->link->as == APCDATA || p->link->as == ATYPE)
    37  		p = p->link;
    38  	if(stkzerosize >= 8*widthptr) {
    39  		p = appendp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0);
    40  		p = appendp(p, AADD, D_CONST, NREG, 4+frame-stkzerosize, D_REG, 1, 0);
    41  		p->reg = REGSP;
    42  		p = appendp(p, AADD, D_CONST, NREG, stkzerosize, D_REG, 2, 0);
    43  		p->reg = 1;
    44  		p1 = p = appendp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4);
    45  		p->scond |= C_PBIT;
    46  		p = appendp(p, ACMP, D_REG, 1, 0, D_NONE, 0, 0);
    47  		p->reg = 2;
    48  		p = appendp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0);
    49  		patch(p, p1);
    50  	} else {
    51  		first = 1;
    52  		for(i=0, j=(stkptrsize-stkzerosize)/widthptr*2; i<stkzerosize; i+=widthptr, j+=2) {
    53  			if(bvget(bv, j) || bvget(bv, j+1)) {
    54  				if(first) {
    55  					p = appendp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0);
    56  					first = 0;
    57  				}
    58  				p = appendp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame-stkzerosize+i);
    59  			}
    60  		}
    61  	}
    62  }
    63  
    64  static Prog*
    65  appendp(Prog *p, int as, int ftype, int freg, int32 foffset, int ttype, int treg, int32 toffset)
    66  {
    67  	Prog *q;
    68  	
    69  	q = mal(sizeof(*q));
    70  	clearp(q);
    71  	q->as = as;
    72  	q->lineno = p->lineno;
    73  	q->from.type = ftype;
    74  	q->from.reg = freg;
    75  	q->from.offset = foffset;
    76  	q->to.type = ttype;
    77  	q->to.reg = treg;
    78  	q->to.offset = toffset;
    79  	q->link = p->link;
    80  	p->link = q;
    81  	return q;
    82  }
    83  
    84  // Sweep the prog list to mark any used nodes.
    85  void
    86  markautoused(Prog* p)
    87  {
    88  	for (; p; p = p->link) {
    89  		if (p->as == ATYPE)
    90  			continue;
    91  
    92  		if (p->from.name == D_AUTO && p->from.node)
    93  			p->from.node->used = 1;
    94  
    95  		if (p->to.name == D_AUTO && p->to.node)
    96  			p->to.node->used = 1;
    97  	}
    98  }
    99  
   100  // Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
   101  void
   102  fixautoused(Prog* p)
   103  {
   104  	Prog **lp;
   105  
   106  	for (lp=&p; (p=*lp) != P; ) {
   107  		if (p->as == ATYPE && p->from.node && p->from.name == D_AUTO && !p->from.node->used) {
   108  			*lp = p->link;
   109  			continue;
   110  		}
   111  
   112  		if (p->from.name == D_AUTO && p->from.node)
   113  			p->from.offset += p->from.node->stkdelta;
   114  
   115  		if (p->to.name == D_AUTO && p->to.node)
   116  			p->to.offset += p->to.node->stkdelta;
   117  
   118  		lp = &p->link;
   119  	}
   120  }
   121  
   122  /*
   123   * generate:
   124   *	call f
   125   *	proc=-1	normal call but no return
   126   *	proc=0	normal call
   127   *	proc=1	goroutine run in new proc
   128   *	proc=2	defer call save away stack
   129    *	proc=3	normal call to C pointer (not Go func value)
   130   */
   131  void
   132  ginscall(Node *f, int proc)
   133  {
   134  	int32 arg;
   135  	Prog *p;
   136  	Node n1, r, r1, con;
   137  
   138  	if(f->type != T)
   139  		setmaxarg(f->type);
   140  
   141  	arg = -1;
   142  	// Most functions have a fixed-size argument block, so traceback uses that during unwind.
   143  	// Not all, though: there are some variadic functions in package runtime,
   144  	// and for those we emit call-specific metadata recorded by caller.
   145  	// Reflect generates functions with variable argsize (see reflect.methodValueCall/makeFuncStub),
   146  	// so we do this for all indirect calls as well.
   147  	if(f->type != T && (f->sym == S || (f->sym != S && f->sym->pkg == runtimepkg) || proc == 1 || proc == 2)) {
   148  		arg = f->type->argwid;
   149  		if(proc == 1 || proc == 2)
   150  			arg += 3*widthptr;
   151  	}
   152  
   153  	if(arg != -1)
   154  		gargsize(arg);
   155  
   156  	switch(proc) {
   157  	default:
   158  		fatal("ginscall: bad proc %d", proc);
   159  		break;
   160  
   161  	case 0:	// normal call
   162  	case -1:	// normal call but no return
   163  		if(f->op == ONAME && f->class == PFUNC) {
   164  			if(f == deferreturn) {
   165  				// Deferred calls will appear to be returning to
   166  				// the BL deferreturn(SB) that we are about to emit.
   167  				// However, the stack trace code will show the line
   168  				// of the instruction before that return PC. 
   169  				// To avoid that instruction being an unrelated instruction,
   170  				// insert a NOP so that we will have the right line number.
   171  				// ARM NOP 0x00000000 is really AND.EQ R0, R0, R0.
   172  				// Use the latter form because the NOP pseudo-instruction
   173  				// would be removed by the linker.
   174  				nodreg(&r, types[TINT], 0);
   175  				p = gins(AAND, &r, &r);
   176  				p->scond = C_SCOND_EQ;
   177  			}
   178  			p = gins(ABL, N, f);
   179  			afunclit(&p->to, f);
   180  			if(proc == -1 || noreturn(p))
   181  				gins(AUNDEF, N, N);
   182  			break;
   183  		}
   184  		nodreg(&r, types[tptr], 7);
   185  		nodreg(&r1, types[tptr], 1);
   186  		gmove(f, &r);
   187  		r.op = OINDREG;
   188  		gmove(&r, &r1);
   189  		r.op = OREGISTER;
   190  		r1.op = OINDREG;
   191  		gins(ABL, &r, &r1);
   192  		break;
   193  
   194  	case 3:	// normal call of c function pointer
   195  		gins(ABL, N, f);
   196  		break;
   197  
   198  	case 1:	// call in new proc (go)
   199  	case 2:	// deferred call (defer)
   200  		regalloc(&r, types[tptr], N);
   201  		p = gins(AMOVW, N, &r);
   202  		p->from.type = D_OREG;
   203  		p->from.reg = REGSP;
   204  		
   205  		p = gins(AMOVW, &r, N);
   206  		p->to.type = D_OREG;
   207  		p->to.reg = REGSP;
   208  		p->to.offset = -12;
   209  		p->scond |= C_WBIT;
   210  
   211  		memset(&n1, 0, sizeof n1);
   212  		n1.op = OADDR;
   213  		n1.left = f;
   214  		gins(AMOVW, &n1, &r);
   215  
   216  		p = gins(AMOVW, &r, N);
   217  		p->to.type = D_OREG;
   218  		p->to.reg = REGSP;
   219  		p->to.offset = 8;
   220  
   221  		nodconst(&con, types[TINT32], argsize(f->type));
   222  		gins(AMOVW, &con, &r);
   223  		p = gins(AMOVW, &r, N);
   224  		p->to.type = D_OREG;
   225  		p->to.reg = REGSP;
   226  		p->to.offset = 4;
   227  		regfree(&r);
   228  
   229  		if(proc == 1)
   230  			ginscall(newproc, 0);
   231  		else
   232  			ginscall(deferproc, 0);
   233  
   234  		nodreg(&r, types[tptr], 1);
   235  		p = gins(AMOVW, N, N);
   236  		p->from.type = D_CONST;
   237  		p->from.reg = REGSP;
   238  		p->from.offset = 12;
   239  		p->to.reg = REGSP;
   240  		p->to.type = D_REG;
   241  
   242  		if(proc == 2) {
   243  			nodconst(&con, types[TINT32], 0);
   244  			p = gins(ACMP, &con, N);
   245  			p->reg = 0;
   246  			patch(gbranch(ABNE, T, -1), retpc);
   247  		}
   248  		break;
   249  	}
   250  	
   251  	if(arg != -1)
   252  		gargsize(-1);
   253  }
   254  
   255  /*
   256   * n is call to interface method.
   257   * generate res = n.
   258   */
   259  void
   260  cgen_callinter(Node *n, Node *res, int proc)
   261  {
   262  	int r;
   263  	Node *i, *f;
   264  	Node tmpi, nodo, nodr, nodsp;
   265  	Prog *p;
   266  
   267  	i = n->left;
   268  	if(i->op != ODOTINTER)
   269  		fatal("cgen_callinter: not ODOTINTER %O", i->op);
   270  
   271  	f = i->right;		// field
   272  	if(f->op != ONAME)
   273  		fatal("cgen_callinter: not ONAME %O", f->op);
   274  
   275  	i = i->left;		// interface
   276  
   277  	// Release res register during genlist and cgen,
   278  	// which might have their own function calls.
   279  	r = -1;
   280  	if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
   281  		r = res->val.u.reg;
   282  		reg[r]--;
   283  	}
   284  
   285  	if(!i->addable) {
   286  		tempname(&tmpi, i->type);
   287  		cgen(i, &tmpi);
   288  		i = &tmpi;
   289  	}
   290  
   291  	genlist(n->list);			// args
   292  	if(r >= 0)
   293  		reg[r]++;
   294  
   295  	regalloc(&nodr, types[tptr], res);
   296  	regalloc(&nodo, types[tptr], &nodr);
   297  	nodo.op = OINDREG;
   298  
   299  	agen(i, &nodr);		// REG = &inter
   300  
   301  	nodindreg(&nodsp, types[tptr], REGSP);
   302  	nodsp.xoffset = 4;
   303  	nodo.xoffset += widthptr;
   304  	cgen(&nodo, &nodsp);	// 4(SP) = 4(REG) -- i.data
   305  
   306  	nodo.xoffset -= widthptr;
   307  	cgen(&nodo, &nodr);	// REG = 0(REG) -- i.tab
   308  	cgen_checknil(&nodr); // in case offset is huge
   309  
   310  	nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
   311  	
   312  	if(proc == 0) {
   313  		// plain call: use direct c function pointer - more efficient
   314  		cgen(&nodo, &nodr);	// REG = 20+offset(REG) -- i.tab->fun[f]
   315  		nodr.op = OINDREG;
   316  		proc = 3;
   317  	} else {
   318  		// go/defer. generate go func value.
   319  		p = gins(AMOVW, &nodo, &nodr);
   320  		p->from.type = D_CONST;	// REG = &(20+offset(REG)) -- i.tab->fun[f]
   321  	}
   322  
   323  	nodr.type = n->left->type;
   324  	ginscall(&nodr, proc);
   325  
   326  	regfree(&nodr);
   327  	regfree(&nodo);
   328  }
   329  
   330  /*
   331   * generate function call;
   332   *	proc=0	normal call
   333   *	proc=1	goroutine run in new proc
   334   *	proc=2	defer call save away stack
   335   */
   336  void
   337  cgen_call(Node *n, int proc)
   338  {
   339  	Type *t;
   340  	Node nod, afun;
   341  
   342  	if(n == N)
   343  		return;
   344  
   345  	if(n->left->ullman >= UINF) {
   346  		// if name involves a fn call
   347  		// precompute the address of the fn
   348  		tempname(&afun, types[tptr]);
   349  		cgen(n->left, &afun);
   350  	}
   351  
   352  	genlist(n->list);		// assign the args
   353  	t = n->left->type;
   354  
   355  	// call tempname pointer
   356  	if(n->left->ullman >= UINF) {
   357  		regalloc(&nod, types[tptr], N);
   358  		cgen_as(&nod, &afun);
   359  		nod.type = t;
   360  		ginscall(&nod, proc);
   361  		regfree(&nod);
   362  		goto ret;
   363  	}
   364  
   365  	// call pointer
   366  	if(n->left->op != ONAME || n->left->class != PFUNC) {
   367  		regalloc(&nod, types[tptr], N);
   368  		cgen_as(&nod, n->left);
   369  		nod.type = t;
   370  		ginscall(&nod, proc);
   371  		regfree(&nod);
   372  		goto ret;
   373  	}
   374  
   375  	// call direct
   376  	n->left->method = 1;
   377  	ginscall(n->left, proc);
   378  
   379  
   380  ret:
   381  	;
   382  }
   383  
   384  /*
   385   * call to n has already been generated.
   386   * generate:
   387   *	res = return value from call.
   388   */
   389  void
   390  cgen_callret(Node *n, Node *res)
   391  {
   392  	Node nod;
   393  	Type *fp, *t;
   394  	Iter flist;
   395  
   396  	t = n->left->type;
   397  	if(t->etype == TPTR32 || t->etype == TPTR64)
   398  		t = t->type;
   399  
   400  	fp = structfirst(&flist, getoutarg(t));
   401  	if(fp == T)
   402  		fatal("cgen_callret: nil");
   403  
   404  	memset(&nod, 0, sizeof(nod));
   405  	nod.op = OINDREG;
   406  	nod.val.u.reg = REGSP;
   407  	nod.addable = 1;
   408  
   409  	nod.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
   410  	nod.type = fp->type;
   411  	cgen_as(res, &nod);
   412  }
   413  
   414  /*
   415   * call to n has already been generated.
   416   * generate:
   417   *	res = &return value from call.
   418   */
   419  void
   420  cgen_aret(Node *n, Node *res)
   421  {
   422  	Node nod1, nod2;
   423  	Type *fp, *t;
   424  	Iter flist;
   425  
   426  	t = n->left->type;
   427  	if(isptr[t->etype])
   428  		t = t->type;
   429  
   430  	fp = structfirst(&flist, getoutarg(t));
   431  	if(fp == T)
   432  		fatal("cgen_aret: nil");
   433  
   434  	memset(&nod1, 0, sizeof(nod1));
   435  	nod1.op = OINDREG;
   436  	nod1.val.u.reg = REGSP;
   437  	nod1.addable = 1;
   438  
   439  	nod1.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
   440  	nod1.type = fp->type;
   441  
   442  	if(res->op != OREGISTER) {
   443  		regalloc(&nod2, types[tptr], res);
   444  		agen(&nod1, &nod2);
   445  		gins(AMOVW, &nod2, res);
   446  		regfree(&nod2);
   447  	} else
   448  		agen(&nod1, res);
   449  }
   450  
   451  /*
   452   * generate return.
   453   * n->left is assignments to return values.
   454   */
   455  void
   456  cgen_ret(Node *n)
   457  {
   458  	Prog *p;
   459  
   460  	genlist(n->list);		// copy out args
   461  	if(hasdefer || curfn->exit) {
   462  		gjmp(retpc);
   463  		return;
   464  	}
   465  	p = gins(ARET, N, N);
   466  	if(n->op == ORETJMP) {
   467  		p->to.name = D_EXTERN;
   468  		p->to.type = D_CONST;
   469  		p->to.sym = n->left->sym;
   470  	}
   471  }
   472  
   473  /*
   474   * generate += *= etc.
   475   */
   476  void
   477  cgen_asop(Node *n)
   478  {
   479  	Node n1, n2, n3, n4;
   480  	Node *nl, *nr;
   481  	Prog *p1;
   482  	Addr addr;
   483  	int a, w;
   484  
   485  	nl = n->left;
   486  	nr = n->right;
   487  
   488  	if(nr->ullman >= UINF && nl->ullman >= UINF) {
   489  		tempname(&n1, nr->type);
   490  		cgen(nr, &n1);
   491  		n2 = *n;
   492  		n2.right = &n1;
   493  		cgen_asop(&n2);
   494  		goto ret;
   495  	}
   496  
   497  	if(!isint[nl->type->etype])
   498  		goto hard;
   499  	if(!isint[nr->type->etype])
   500  		goto hard;
   501  	if(is64(nl->type) || is64(nr->type))
   502  		goto hard64;
   503  
   504  	switch(n->etype) {
   505  	case OADD:
   506  	case OSUB:
   507  	case OXOR:
   508  	case OAND:
   509  	case OOR:
   510  		a = optoas(n->etype, nl->type);
   511  		if(nl->addable) {
   512  			if(smallintconst(nr))
   513  				n3 = *nr;
   514  			else {
   515  				regalloc(&n3, nr->type, N);
   516  				cgen(nr, &n3);
   517  			}
   518  			regalloc(&n2, nl->type, N);
   519  			cgen(nl, &n2);
   520  			gins(a, &n3, &n2);
   521  			cgen(&n2, nl);
   522  			regfree(&n2);
   523  			if(n3.op != OLITERAL)
   524  				regfree(&n3);
   525  			goto ret;
   526  		}
   527  		if(nr->ullman < UINF)
   528  		if(sudoaddable(a, nl, &addr, &w)) {
   529  			w = optoas(OAS, nl->type);
   530  			regalloc(&n2, nl->type, N);
   531  			p1 = gins(w, N, &n2);
   532  			p1->from = addr;
   533  			regalloc(&n3, nr->type, N);
   534  			cgen(nr, &n3);
   535  			gins(a, &n3, &n2);
   536  			p1 = gins(w, &n2, N);
   537  			p1->to = addr;
   538  			regfree(&n2);
   539  			regfree(&n3);
   540  			sudoclean();
   541  			goto ret;
   542  		}
   543  	}
   544  
   545  hard:
   546  	n2.op = 0;
   547  	n1.op = 0;
   548  	if(nr->op == OLITERAL) {
   549  		// don't allocate a register for literals.
   550  	} else if(nr->ullman >= nl->ullman || nl->addable) {
   551  		regalloc(&n2, nr->type, N);
   552  		cgen(nr, &n2);
   553  		nr = &n2;
   554  	} else {
   555  		tempname(&n2, nr->type);
   556  		cgen(nr, &n2);
   557  		nr = &n2;
   558  	}
   559  	if(!nl->addable) {
   560  		igen(nl, &n1, N);
   561  		nl = &n1;
   562  	}
   563  
   564  	n3 = *n;
   565  	n3.left = nl;
   566  	n3.right = nr;
   567  	n3.op = n->etype;
   568  
   569  	regalloc(&n4, nl->type, N);
   570  	cgen(&n3, &n4);
   571  	gmove(&n4, nl);
   572  
   573  	if(n1.op)
   574  		regfree(&n1);
   575  	if(n2.op == OREGISTER)
   576  		regfree(&n2);
   577  	regfree(&n4);
   578  	goto ret;
   579  
   580  hard64:
   581  	if(nr->ullman > nl->ullman) {
   582  		tempname(&n2, nr->type);
   583  		cgen(nr, &n2);
   584  		igen(nl, &n1, N);
   585  	} else {
   586  		igen(nl, &n1, N);
   587  		tempname(&n2, nr->type);
   588  		cgen(nr, &n2);
   589  	}
   590  
   591  	n3 = *n;
   592  	n3.left = &n1;
   593  	n3.right = &n2;
   594  	n3.op = n->etype;
   595  
   596  	cgen(&n3, &n1);
   597  
   598  ret:
   599  	;
   600  }
   601  
   602  int
   603  samereg(Node *a, Node *b)
   604  {
   605  	if(a->op != OREGISTER)
   606  		return 0;
   607  	if(b->op != OREGISTER)
   608  		return 0;
   609  	if(a->val.u.reg != b->val.u.reg)
   610  		return 0;
   611  	return 1;
   612  }
   613  
   614  /*
   615   * generate high multiply
   616   *  res = (nl * nr) >> wordsize
   617   */
   618  void
   619  cgen_hmul(Node *nl, Node *nr, Node *res)
   620  {
   621  	int w;
   622  	Node n1, n2, *tmp;
   623  	Type *t;
   624  	Prog *p;
   625  
   626  	if(nl->ullman < nr->ullman) {
   627  		tmp = nl;
   628  		nl = nr;
   629  		nr = tmp;
   630  	}
   631  	t = nl->type;
   632  	w = t->width * 8;
   633  	regalloc(&n1, t, res);
   634  	cgen(nl, &n1);
   635  	regalloc(&n2, t, N);
   636  	cgen(nr, &n2);
   637  	switch(simtype[t->etype]) {
   638  	case TINT8:
   639  	case TINT16:
   640  		gins(optoas(OMUL, t), &n2, &n1);
   641  		gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
   642  		break;
   643  	case TUINT8:
   644  	case TUINT16:
   645  		gins(optoas(OMUL, t), &n2, &n1);
   646  		gshift(AMOVW, &n1, SHIFT_LR, w, &n1);
   647  		break;
   648  	case TINT32:
   649  	case TUINT32:
   650  		// perform a long multiplication.
   651  		if(issigned[t->etype])
   652  			p = gins(AMULL, &n2, N);
   653  		else
   654  			p = gins(AMULLU, &n2, N);
   655  		// n2 * n1 -> (n1 n2)
   656  		p->reg = n1.val.u.reg;
   657  		p->to.type = D_REGREG;
   658  		p->to.reg = n1.val.u.reg;
   659  		p->to.offset = n2.val.u.reg;
   660  		break;
   661  	default:
   662  		fatal("cgen_hmul %T", t);
   663  		break;
   664  	}
   665  	cgen(&n1, res);
   666  	regfree(&n1);
   667  	regfree(&n2);
   668  }
   669  
   670  /*
   671   * generate shift according to op, one of:
   672   *	res = nl << nr
   673   *	res = nl >> nr
   674   */
   675  void
   676  cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
   677  {
   678  	Node n1, n2, n3, nt, t, lo, hi;
   679  	int w, v;
   680  	Prog *p1, *p2, *p3;
   681  	Type *tr;
   682  	uvlong sc;
   683  
   684  	USED(bounded);
   685  	if(nl->type->width > 4)
   686  		fatal("cgen_shift %T", nl->type);
   687  
   688  	w = nl->type->width * 8;
   689  
   690  	if(op == OLROT) {
   691  		v = mpgetfix(nr->val.u.xval);
   692  		regalloc(&n1, nl->type, res);
   693  		if(w == 32) {
   694  			cgen(nl, &n1);
   695  			gshift(AMOVW, &n1, SHIFT_RR, w-v, &n1);
   696  		} else {
   697  			regalloc(&n2, nl->type, N);
   698  			cgen(nl, &n2);
   699  			gshift(AMOVW, &n2, SHIFT_LL, v, &n1);
   700  			gshift(AORR, &n2, SHIFT_LR, w-v, &n1);
   701  			regfree(&n2);
   702  			// Ensure sign/zero-extended result.
   703  			gins(optoas(OAS, nl->type), &n1, &n1);
   704  		}
   705  		gmove(&n1, res);
   706  		regfree(&n1);
   707  		return;
   708  	}
   709  
   710  	if(nr->op == OLITERAL) {
   711  		regalloc(&n1, nl->type, res);
   712  		cgen(nl, &n1);
   713  		sc = mpgetfix(nr->val.u.xval);
   714  		if(sc == 0) {
   715  			// nothing to do
   716  		} else if(sc >= nl->type->width*8) {
   717  			if(op == ORSH && issigned[nl->type->etype])
   718  				gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
   719  			else
   720  				gins(AEOR, &n1, &n1);
   721  		} else {
   722  			if(op == ORSH && issigned[nl->type->etype])
   723  				gshift(AMOVW, &n1, SHIFT_AR, sc, &n1);
   724  			else if(op == ORSH)
   725  				gshift(AMOVW, &n1, SHIFT_LR, sc, &n1);
   726  			else // OLSH
   727  				gshift(AMOVW, &n1, SHIFT_LL, sc, &n1);
   728  		}
   729  		if(w < 32 && op == OLSH)
   730  			gins(optoas(OAS, nl->type), &n1, &n1);
   731  		gmove(&n1, res);
   732  		regfree(&n1);
   733  		return;
   734  	}
   735  
   736  	tr = nr->type;
   737  	if(tr->width > 4) {
   738  		tempname(&nt, nr->type);
   739  		if(nl->ullman >= nr->ullman) {
   740  			regalloc(&n2, nl->type, res);
   741  			cgen(nl, &n2);
   742  			cgen(nr, &nt);
   743  			n1 = nt;
   744  		} else {
   745  			cgen(nr, &nt);
   746  			regalloc(&n2, nl->type, res);
   747  			cgen(nl, &n2);
   748  		}
   749  		split64(&nt, &lo, &hi);
   750  		regalloc(&n1, types[TUINT32], N);
   751  		regalloc(&n3, types[TUINT32], N);
   752  		gmove(&lo, &n1);
   753  		gmove(&hi, &n3);
   754  		splitclean();
   755  		gins(ATST, &n3, N);
   756  		nodconst(&t, types[TUINT32], w);
   757  		p1 = gins(AMOVW, &t, &n1);
   758  		p1->scond = C_SCOND_NE;
   759  		tr = types[TUINT32];
   760  		regfree(&n3);
   761  	} else {
   762  		if(nl->ullman >= nr->ullman) {
   763  			regalloc(&n2, nl->type, res);
   764  			cgen(nl, &n2);
   765  			regalloc(&n1, nr->type, N);
   766  			cgen(nr, &n1);
   767  		} else {
   768  			regalloc(&n1, nr->type, N);
   769  			cgen(nr, &n1);
   770  			regalloc(&n2, nl->type, res);
   771  			cgen(nl, &n2);
   772  		}
   773  	}
   774  
   775  	// test for shift being 0
   776  	gins(ATST, &n1, N);
   777  	p3 = gbranch(ABEQ, T, -1);
   778  
   779  	// test and fix up large shifts
   780  	// TODO: if(!bounded), don't emit some of this.
   781  	regalloc(&n3, tr, N);
   782  	nodconst(&t, types[TUINT32], w);
   783  	gmove(&t, &n3);
   784  	gcmp(ACMP, &n1, &n3);
   785  	if(op == ORSH) {
   786  		if(issigned[nl->type->etype]) {
   787  			p1 = gshift(AMOVW, &n2, SHIFT_AR, w-1, &n2);
   788  			p2 = gregshift(AMOVW, &n2, SHIFT_AR, &n1, &n2);
   789  		} else {
   790  			p1 = gins(AEOR, &n2, &n2);
   791  			p2 = gregshift(AMOVW, &n2, SHIFT_LR, &n1, &n2);
   792  		}
   793  		p1->scond = C_SCOND_HS;
   794  		p2->scond = C_SCOND_LO;
   795  	} else {
   796  		p1 = gins(AEOR, &n2, &n2);
   797  		p2 = gregshift(AMOVW, &n2, SHIFT_LL, &n1, &n2);
   798  		p1->scond = C_SCOND_HS;
   799  		p2->scond = C_SCOND_LO;
   800  	}
   801  	regfree(&n3);
   802  
   803  	patch(p3, pc);
   804  	// Left-shift of smaller word must be sign/zero-extended.
   805  	if(w < 32 && op == OLSH)
   806  		gins(optoas(OAS, nl->type), &n2, &n2);
   807  	gmove(&n2, res);
   808  
   809  	regfree(&n1);
   810  	regfree(&n2);
   811  }
   812  
   813  void
   814  clearfat(Node *nl)
   815  {
   816  	uint32 w, c, q;
   817  	Node dst, nc, nz, end;
   818  	Prog *p, *pl;
   819  
   820  	/* clear a fat object */
   821  	if(debug['g'])
   822  		dump("\nclearfat", nl);
   823  
   824  
   825  	w = nl->type->width;
   826  	// Avoid taking the address for simple enough types.
   827  	if(componentgen(N, nl))
   828  		return;
   829  
   830  	c = w % 4;	// bytes
   831  	q = w / 4;	// quads
   832  
   833  	regalloc(&dst, types[tptr], N);
   834  	agen(nl, &dst);
   835  	nodconst(&nc, types[TUINT32], 0);
   836  	regalloc(&nz, types[TUINT32], 0);
   837  	cgen(&nc, &nz);
   838  
   839  	if(q >= 4) {
   840  		regalloc(&end, types[tptr], N);
   841  		p = gins(AMOVW, &dst, &end);
   842  		p->from.type = D_CONST;
   843  		p->from.offset = q*4;
   844  
   845  		p = gins(AMOVW, &nz, &dst);
   846  		p->to.type = D_OREG;
   847  		p->to.offset = 4;
   848  		p->scond |= C_PBIT;
   849  		pl = p;
   850  
   851  		p = gins(ACMP, &dst, N);
   852  		raddr(&end, p);
   853  		patch(gbranch(ABNE, T, 0), pl);
   854  
   855  		regfree(&end);
   856  	} else
   857  	while(q > 0) {
   858  		p = gins(AMOVW, &nz, &dst);
   859  		p->to.type = D_OREG;
   860  		p->to.offset = 4;
   861   		p->scond |= C_PBIT;
   862  //print("1. %P\n", p);
   863  		q--;
   864  	}
   865  
   866  	while(c > 0) {
   867  		p = gins(AMOVB, &nz, &dst);
   868  		p->to.type = D_OREG;
   869  		p->to.offset = 1;
   870   		p->scond |= C_PBIT;
   871  //print("2. %P\n", p);
   872  		c--;
   873  	}
   874  	regfree(&dst);
   875  	regfree(&nz);
   876  }
   877  
   878  // Called after regopt and peep have run.
   879  // Expand CHECKNIL pseudo-op into actual nil pointer check.
   880  void
   881  expandchecks(Prog *firstp)
   882  {
   883  	int reg;
   884  	Prog *p, *p1;
   885  
   886  	for(p = firstp; p != P; p = p->link) {
   887  		if(p->as != ACHECKNIL)
   888  			continue;
   889  		if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
   890  			warnl(p->lineno, "nil check %D", &p->from);
   891  		if(p->from.type != D_REG)
   892  			fatal("invalid nil check %P", p);
   893  		reg = p->from.reg;
   894  		// check is
   895  		//	CMP arg, $0
   896  		//	MOV.EQ arg, 0(arg)
   897  		p1 = mal(sizeof *p1);
   898  		clearp(p1);
   899  		p1->link = p->link;
   900  		p->link = p1;
   901  		p1->lineno = p->lineno;
   902  		p1->loc = 9999;
   903  		p1->as = AMOVW;
   904  		p1->from.type = D_REG;
   905  		p1->from.reg = reg;
   906  		p1->to.type = D_OREG;
   907  		p1->to.reg = reg;
   908  		p1->to.offset = 0;
   909  		p1->scond = C_SCOND_EQ;
   910  		p->as = ACMP;
   911  		p->from.type = D_CONST;
   912  		p->from.reg = NREG;
   913  		p->from.offset = 0;
   914  		p->reg = reg;
   915  	}
   916  }