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