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