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