github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/cmd/5g/cgen.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  #include <u.h>
     6  #include <libc.h>
     7  #include "gg.h"
     8  
     9  /*
    10   * generate:
    11   *	res = n;
    12   * simplifies and calls gmove.
    13   */
    14  void
    15  cgen(Node *n, Node *res)
    16  {
    17  	Node *nl, *nr, *r;
    18  	Node n1, n2, f0, f1;
    19  	int a, w, rg;
    20  	Prog *p1, *p2, *p3;
    21  	Addr addr;
    22  
    23  	if(debug['g']) {
    24  		dump("\ncgen-n", n);
    25  		dump("cgen-res", res);
    26  	}
    27  	if(n == N || n->type == T)
    28  		goto ret;
    29  
    30  	if(res == N || res->type == T)
    31  		fatal("cgen: res nil");
    32  
    33  	switch(n->op) {
    34  	case OSLICE:
    35  	case OSLICEARR:
    36  	case OSLICESTR:
    37  		if (res->op != ONAME || !res->addable) {
    38  			tempname(&n1, n->type);
    39  			cgen_slice(n, &n1);
    40  			cgen(&n1, res);
    41  		} else
    42  			cgen_slice(n, res);
    43  		return;
    44  	case OEFACE:
    45  		if (res->op != ONAME || !res->addable) {
    46  			tempname(&n1, n->type);
    47  			cgen_eface(n, &n1);
    48  			cgen(&n1, res);
    49  		} else
    50  			cgen_eface(n, res);
    51  		return;
    52  	}
    53  
    54  	while(n->op == OCONVNOP)
    55  		n = n->left;
    56  
    57  	if(n->ullman >= UINF) {
    58  		if(n->op == OINDREG)
    59  			fatal("cgen: this is going to misscompile");
    60  		if(res->ullman >= UINF) {
    61  			tempname(&n1, n->type);
    62  			cgen(n, &n1);
    63  			cgen(&n1, res);
    64  			goto ret;
    65  		}
    66  	}
    67  
    68  	if(isfat(n->type)) {
    69  		if(n->type->width < 0)
    70  			fatal("forgot to compute width for %T", n->type);
    71  		sgen(n, res, n->type->width);
    72  		goto ret;
    73  	}
    74  
    75  
    76  	// update addressability for string, slice
    77  	// can't do in walk because n->left->addable
    78  	// changes if n->left is an escaping local variable.
    79  	switch(n->op) {
    80  	case OLEN:
    81  		if(isslice(n->left->type) || istype(n->left->type, TSTRING))
    82  			n->addable = n->left->addable;
    83  		break;
    84  	case OCAP:
    85  		if(isslice(n->left->type))
    86  			n->addable = n->left->addable;
    87  		break;
    88  	case OITAB:
    89  		n->addable = n->left->addable;
    90  		break;
    91  	}
    92  
    93  	// if both are addressable, move
    94  	if(n->addable && res->addable) {
    95  		if(is64(n->type) || is64(res->type) ||
    96  		   n->op == OREGISTER || res->op == OREGISTER ||
    97  		   iscomplex[n->type->etype] || iscomplex[res->type->etype]) {
    98  			gmove(n, res);
    99  		} else {
   100  			regalloc(&n1, n->type, N);
   101  			gmove(n, &n1);
   102  			cgen(&n1, res);
   103  			regfree(&n1);
   104  		}
   105  		goto ret;
   106  	}
   107  
   108  	// if both are not addressable, use a temporary.
   109  	if(!n->addable && !res->addable) {
   110  		// could use regalloc here sometimes,
   111  		// but have to check for ullman >= UINF.
   112  		tempname(&n1, n->type);
   113  		cgen(n, &n1);
   114  		cgen(&n1, res);
   115  		return;
   116  	}
   117  
   118  	// if result is not addressable directly but n is,
   119  	// compute its address and then store via the address.
   120  	if(!res->addable) {
   121  		igen(res, &n1, N);
   122  		cgen(n, &n1);
   123  		regfree(&n1);
   124  		return;
   125  	}
   126  
   127  	if(complexop(n, res)) {
   128  		complexgen(n, res);
   129  		return;
   130  	}
   131  
   132  	// if n is sudoaddable generate addr and move
   133  	if (!is64(n->type) && !is64(res->type) && !iscomplex[n->type->etype] && !iscomplex[res->type->etype]) {
   134  		a = optoas(OAS, n->type);
   135  		if(sudoaddable(a, n, &addr, &w)) {
   136  			if (res->op != OREGISTER) {
   137  				regalloc(&n2, res->type, N);
   138  				p1 = gins(a, N, &n2);
   139  				p1->from = addr;
   140  				if(debug['g'])
   141  					print("%P [ignore previous line]\n", p1);
   142  				gmove(&n2, res);
   143  				regfree(&n2);
   144  			} else {
   145  				p1 = gins(a, N, res);
   146  				p1->from = addr;
   147  				if(debug['g'])
   148  					print("%P [ignore previous line]\n", p1);
   149  			}
   150  			sudoclean();
   151  			goto ret;
   152  		}
   153  	}
   154  
   155  	// otherwise, the result is addressable but n is not.
   156  	// let's do some computation.
   157  
   158  	nl = n->left;
   159  	nr = n->right;
   160  
   161  	if(nl != N && nl->ullman >= UINF)
   162  	if(nr != N && nr->ullman >= UINF) {
   163  		tempname(&n1, nl->type);
   164  		cgen(nl, &n1);
   165  		n2 = *n;
   166  		n2.left = &n1;
   167  		cgen(&n2, res);
   168  		goto ret;
   169  	}
   170  
   171  	// 64-bit ops are hard on 32-bit machine.
   172  	if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
   173  		switch(n->op) {
   174  		// math goes to cgen64.
   175  		case OMINUS:
   176  		case OCOM:
   177  		case OADD:
   178  		case OSUB:
   179  		case OMUL:
   180  		case OLROT:
   181  		case OLSH:
   182  		case ORSH:
   183  		case OAND:
   184  		case OOR:
   185  		case OXOR:
   186  			cgen64(n, res);
   187  			return;
   188  		}
   189  	}
   190  
   191  	if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype])
   192  		goto flt;
   193  	switch(n->op) {
   194  	default:
   195  		dump("cgen", n);
   196  		fatal("cgen: unknown op %+hN", n);
   197  		break;
   198  
   199  	case OREAL:
   200  	case OIMAG:
   201  	case OCOMPLEX:
   202  		fatal("unexpected complex");
   203  		break;
   204  
   205  	// these call bgen to get a bool value
   206  	case OOROR:
   207  	case OANDAND:
   208  	case OEQ:
   209  	case ONE:
   210  	case OLT:
   211  	case OLE:
   212  	case OGE:
   213  	case OGT:
   214  	case ONOT:
   215  		p1 = gbranch(AB, T, 0);
   216  		p2 = pc;
   217  		gmove(nodbool(1), res);
   218  		p3 = gbranch(AB, T, 0);
   219  		patch(p1, pc);
   220  		bgen(n, 1, 0, p2);
   221  		gmove(nodbool(0), res);
   222  		patch(p3, pc);
   223  		goto ret;
   224  
   225  	case OPLUS:
   226  		cgen(nl, res);
   227  		goto ret;
   228  
   229  	// unary
   230  	case OCOM:
   231  		a = optoas(OXOR, nl->type);
   232  		regalloc(&n1, nl->type, N);
   233  		cgen(nl, &n1);
   234  		nodconst(&n2, nl->type, -1);
   235  		gins(a, &n2, &n1);
   236  		gmove(&n1, res);
   237  		regfree(&n1);
   238  		goto ret;
   239  
   240  	case OMINUS:
   241  		regalloc(&n1, nl->type, N);
   242  		cgen(nl, &n1);
   243  		nodconst(&n2, nl->type, 0);
   244  		gins(optoas(OMINUS, nl->type), &n2, &n1);
   245  		gmove(&n1, res);
   246  		regfree(&n1);
   247  		goto ret;
   248  
   249  	// symmetric binary
   250  	case OAND:
   251  	case OOR:
   252  	case OXOR:
   253  	case OADD:
   254  	case OMUL:
   255  		a = optoas(n->op, nl->type);
   256  		goto sbop;
   257  
   258  	// asymmetric binary
   259  	case OSUB:
   260  		a = optoas(n->op, nl->type);
   261  		goto abop;
   262  
   263  	case OHMUL:
   264  		cgen_hmul(nl, nr, res);
   265  		break;
   266  
   267  	case OLROT:
   268  	case OLSH:
   269  	case ORSH:
   270  		cgen_shift(n->op, n->bounded, nl, nr, res);
   271  		break;
   272  
   273  	case OCONV:
   274  		if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
   275  			cgen(nl, res);
   276  			break;
   277  		}
   278  		if(nl->addable && !is64(nl->type)) {
   279  			regalloc(&n1, nl->type, res);
   280  			gmove(nl, &n1);
   281  		} else {
   282  			if(n->type->width > widthptr || is64(nl->type) || isfloat[nl->type->etype])
   283  				tempname(&n1, nl->type);
   284  			else
   285  				regalloc(&n1, nl->type, res);
   286  			cgen(nl, &n1);
   287  		}
   288  		if(n->type->width > widthptr || is64(n->type) || isfloat[n->type->etype])
   289  			tempname(&n2, n->type);
   290  		else
   291  			regalloc(&n2, n->type, N);
   292  		gmove(&n1, &n2);
   293  		gmove(&n2, res);
   294  		if(n1.op == OREGISTER)
   295  			regfree(&n1);
   296  		if(n2.op == OREGISTER)
   297  			regfree(&n2);
   298  		break;
   299  
   300  	case ODOT:
   301  	case ODOTPTR:
   302  	case OINDEX:
   303  	case OIND:
   304  	case ONAME:	// PHEAP or PPARAMREF var
   305  		igen(n, &n1, res);
   306  		gmove(&n1, res);
   307  		regfree(&n1);
   308  		break;
   309  
   310  	case OITAB:
   311  		// interface table is first word of interface value
   312  		igen(nl, &n1, res);
   313  		n1.type = n->type;
   314  		gmove(&n1, res);
   315  		regfree(&n1);
   316  		break;
   317  
   318  	case OLEN:
   319  		if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
   320  			// map has len in the first 32-bit word.
   321  			// a zero pointer means zero length
   322  			regalloc(&n1, types[tptr], res);
   323  			cgen(nl, &n1);
   324  
   325  			nodconst(&n2, types[tptr], 0);
   326  			gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
   327  			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
   328  
   329  			n2 = n1;
   330  			n2.op = OINDREG;
   331  			n2.type = types[TINT32];
   332  			gmove(&n2, &n1);
   333  
   334  			patch(p1, pc);
   335  
   336  			gmove(&n1, res);
   337  			regfree(&n1);
   338  			break;
   339  		}
   340  		if(istype(nl->type, TSTRING) || isslice(nl->type)) {
   341  			// both slice and string have len one pointer into the struct.
   342  			igen(nl, &n1, res);
   343  			n1.type = types[TUINT32];
   344  			n1.xoffset += Array_nel;
   345  			gmove(&n1, res);
   346  			regfree(&n1);
   347  			break;
   348  		}
   349  		fatal("cgen: OLEN: unknown type %lT", nl->type);
   350  		break;
   351  
   352  	case OCAP:
   353  		if(istype(nl->type, TCHAN)) {
   354  			// chan has cap in the second 32-bit word.
   355  			// a zero pointer means zero length
   356  			regalloc(&n1, types[tptr], res);
   357  			cgen(nl, &n1);
   358  
   359  			nodconst(&n2, types[tptr], 0);
   360  			gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
   361  			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
   362  
   363  			n2 = n1;
   364  			n2.op = OINDREG;
   365  			n2.xoffset = 4;
   366  			n2.type = types[TINT32];
   367  			gmove(&n2, &n1);
   368  
   369  			patch(p1, pc);
   370  
   371  			gmove(&n1, res);
   372  			regfree(&n1);
   373  			break;
   374  		}
   375  		if(isslice(nl->type)) {
   376  			igen(nl, &n1, res);
   377  			n1.type = types[TUINT32];
   378  			n1.xoffset += Array_cap;
   379  			gmove(&n1, res);
   380  			regfree(&n1);
   381  			break;
   382  		}
   383  		fatal("cgen: OCAP: unknown type %lT", nl->type);
   384  		break;
   385  
   386  	case OADDR:
   387  		agen(nl, res);
   388  		break;
   389  
   390  	case OCALLMETH:
   391  	case OCALLFUNC:
   392  		// Release res so that it is available for cgen_call.
   393  		// Pick it up again after the call.
   394  		rg = -1;
   395  		if(n->ullman >= UINF) {
   396  			if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
   397  				rg = res->val.u.reg;
   398  				reg[rg]--;
   399  			}
   400  		}
   401  		if(n->op == OCALLMETH)
   402  			cgen_callmeth(n, 0);
   403  		else
   404  			cgen_call(n, 0);
   405  		if(rg >= 0)
   406  			reg[rg]++;
   407  		cgen_callret(n, res);
   408  		break;
   409  
   410  	case OCALLINTER:
   411  		cgen_callinter(n, res, 0);
   412  		cgen_callret(n, res);
   413  		break;
   414  
   415  	case OMOD:
   416  	case ODIV:
   417  		a = optoas(n->op, nl->type);
   418  		goto abop;
   419  	}
   420  	goto ret;
   421  
   422  sbop:	// symmetric binary
   423  	if(nl->ullman < nr->ullman) {
   424  		r = nl;
   425  		nl = nr;
   426  		nr = r;
   427  	}
   428  
   429  abop:	// asymmetric binary
   430  	// TODO(kaib): use fewer registers here.
   431  	if(nl->ullman >= nr->ullman) {
   432  		regalloc(&n1, nl->type, res);
   433  		cgen(nl, &n1);
   434  		switch(n->op) {
   435  		case OADD:
   436  		case OSUB:
   437  		case OAND:
   438  		case OOR:
   439  		case OXOR:
   440  			if(smallintconst(nr)) {
   441  				n2 = *nr;
   442  				break;
   443  			}
   444  		default:
   445  			regalloc(&n2, nr->type, N);
   446  			cgen(nr, &n2);
   447  		}
   448  	} else {
   449  		switch(n->op) {
   450  		case OADD:
   451  		case OSUB:
   452  		case OAND:
   453  		case OOR:
   454  		case OXOR:
   455  			if(smallintconst(nr)) {
   456  				n2 = *nr;
   457  				break;
   458  			}
   459  		default:
   460  			regalloc(&n2, nr->type, res);
   461  			cgen(nr, &n2);
   462  		}
   463  		regalloc(&n1, nl->type, N);
   464  		cgen(nl, &n1);
   465  	}
   466  	gins(a, &n2, &n1);
   467  	gmove(&n1, res);
   468  	regfree(&n1);
   469  	if(n2.op != OLITERAL)
   470  		regfree(&n2);
   471  	goto ret;
   472  
   473  flt:	// floating-point.
   474  	regalloc(&f0, nl->type, res);
   475  	if(nr != N)
   476  		goto flt2;
   477  
   478  	if(n->op == OMINUS) {
   479  		nr = nodintconst(-1);
   480  		convlit(&nr, n->type);
   481  		n->op = OMUL;
   482  		goto flt2;
   483  	}
   484  
   485  	// unary
   486  	cgen(nl, &f0);
   487  	if(n->op != OCONV && n->op != OPLUS)
   488  		gins(optoas(n->op, n->type), &f0, &f0);
   489  	gmove(&f0, res);
   490  	regfree(&f0);
   491  	goto ret;
   492  
   493  flt2:	// binary
   494  	if(nl->ullman >= nr->ullman) {
   495  		cgen(nl, &f0);
   496  		regalloc(&f1, n->type, N);
   497  		gmove(&f0, &f1);
   498  		cgen(nr, &f0);
   499  		gins(optoas(n->op, n->type), &f0, &f1);
   500  	} else {
   501  		cgen(nr, &f0);
   502  		regalloc(&f1, n->type, N);
   503  		cgen(nl, &f1);
   504  		gins(optoas(n->op, n->type), &f0, &f1);
   505  	}
   506  	gmove(&f1, res);
   507  	regfree(&f0);
   508  	regfree(&f1);
   509  	goto ret;
   510  
   511  ret:
   512  	;
   513  }
   514  
   515  /*
   516   * generate array index into res.
   517   * n might be any size; res is 32-bit.
   518   * returns Prog* to patch to panic call.
   519   */
   520  Prog*
   521  cgenindex(Node *n, Node *res, int bounded)
   522  {
   523  	Node tmp, lo, hi, zero, n1, n2;
   524  
   525  	if(!is64(n->type)) {
   526  		cgen(n, res);
   527  		return nil;
   528  	}
   529  
   530  	tempname(&tmp, types[TINT64]);
   531  	cgen(n, &tmp);
   532  	split64(&tmp, &lo, &hi);
   533  	gmove(&lo, res);
   534  	if(bounded) {
   535  		splitclean();
   536  		return nil;
   537  	}
   538  	regalloc(&n1, types[TINT32], N);
   539  	regalloc(&n2, types[TINT32], N);
   540  	nodconst(&zero, types[TINT32], 0);
   541  	gmove(&hi, &n1);
   542  	gmove(&zero, &n2);
   543  	gcmp(ACMP, &n1, &n2);
   544  	regfree(&n2);
   545  	regfree(&n1);
   546  	splitclean();
   547  	return gbranch(ABNE, T, -1);
   548  }
   549  
   550  /*
   551   * generate:
   552   *	res = &n;
   553   */
   554  void
   555  agen(Node *n, Node *res)
   556  {
   557  	Node *nl;
   558  	Node n1, n2, n3;
   559  	int r;
   560  
   561  	if(debug['g']) {
   562  		dump("\nagen-res", res);
   563  		dump("agen-r", n);
   564  	}
   565  	if(n == N || n->type == T || res == N || res->type == T)
   566  		fatal("agen");
   567  
   568  	while(n->op == OCONVNOP)
   569  		n = n->left;
   570  
   571  	if(isconst(n, CTNIL) && n->type->width > widthptr) {
   572  		// Use of a nil interface or nil slice.
   573  		// Create a temporary we can take the address of and read.
   574  		// The generated code is just going to panic, so it need not
   575  		// be terribly efficient. See issue 3670.
   576  		tempname(&n1, n->type);
   577  		clearfat(&n1);
   578  		regalloc(&n2, types[tptr], res);
   579  		gins(AMOVW, &n1, &n2);
   580  		gmove(&n2, res);
   581  		regfree(&n2);
   582  		goto ret;
   583  	}
   584  		
   585  
   586  	if(n->addable) {
   587  		memset(&n1, 0, sizeof n1);
   588  		n1.op = OADDR;
   589  		n1.left = n;
   590  		regalloc(&n2, types[tptr], res);
   591  		gins(AMOVW, &n1, &n2);
   592  		gmove(&n2, res);
   593  		regfree(&n2);
   594  		goto ret;
   595  	}
   596  
   597  	nl = n->left;
   598  
   599  	switch(n->op) {
   600  	default:
   601  		fatal("agen: unknown op %+hN", n);
   602  		break;
   603  
   604  	case OCALLMETH:
   605  	case OCALLFUNC:
   606  		// Release res so that it is available for cgen_call.
   607  		// Pick it up again after the call.
   608  		r = -1;
   609  		if(n->ullman >= UINF) {
   610  			if(res->op == OREGISTER || res->op == OINDREG) {
   611  				r = res->val.u.reg;
   612  				reg[r]--;
   613  			}
   614  		}
   615  		if(n->op == OCALLMETH)
   616  			cgen_callmeth(n, 0);
   617  		else
   618  			cgen_call(n, 0);
   619  		if(r >= 0)
   620  			reg[r]++;
   621  		cgen_aret(n, res);
   622  		break;
   623  
   624  	case OCALLINTER:
   625  		cgen_callinter(n, res, 0);
   626  		cgen_aret(n, res);
   627  		break;
   628  
   629  	case OSLICE:
   630  	case OSLICEARR:
   631  	case OSLICESTR:
   632  		tempname(&n1, n->type);
   633  		cgen_slice(n, &n1);
   634  		agen(&n1, res);
   635  		break;
   636  
   637  	case OEFACE:
   638  		tempname(&n1, n->type);
   639  		cgen_eface(n, &n1);
   640  		agen(&n1, res);
   641  		break;
   642  
   643  	case OINDEX:
   644  		agenr(n, &n1, res);
   645  		gmove(&n1, res);
   646  		regfree(&n1);
   647  		break;
   648  
   649  	case ONAME:
   650  		// should only get here with names in this func.
   651  		if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
   652  			dump("bad agen", n);
   653  			fatal("agen: bad ONAME funcdepth %d != %d",
   654  				n->funcdepth, funcdepth);
   655  		}
   656  
   657  		// should only get here for heap vars or paramref
   658  		if(!(n->class & PHEAP) && n->class != PPARAMREF) {
   659  			dump("bad agen", n);
   660  			fatal("agen: bad ONAME class %#x", n->class);
   661  		}
   662  		cgen(n->heapaddr, res);
   663  		if(n->xoffset != 0) {
   664  			nodconst(&n1, types[TINT32], n->xoffset);
   665  			regalloc(&n2, n1.type, N);
   666  			regalloc(&n3, types[TINT32], N);
   667  			gmove(&n1, &n2);
   668  			gmove(res, &n3);
   669  			gins(optoas(OADD, types[tptr]), &n2, &n3);
   670  			gmove(&n3, res);
   671  			regfree(&n2);
   672  			regfree(&n3);
   673  		}
   674  		break;
   675  
   676  	case OIND:
   677  		cgen(nl, res);
   678  		break;
   679  
   680  	case ODOT:
   681  		agen(nl, res);
   682  		// explicit check for nil if struct is large enough
   683  		// that we might derive too big a pointer.  If the left node
   684  		// was ODOT we have already done the nil check.
   685  		if(nl->op != ODOT)
   686  		if(nl->type->width >= unmappedzero) {
   687  			regalloc(&n1, types[tptr], N);
   688  			gmove(res, &n1);
   689  			regalloc(&n2, types[TUINT8], &n1);
   690  			n1.op = OINDREG;
   691  			n1.type = types[TUINT8];
   692  			n1.xoffset = 0;
   693  			gmove(&n1, &n2);
   694  			regfree(&n1);
   695  			regfree(&n2);
   696  		}
   697  		if(n->xoffset != 0) {
   698  			nodconst(&n1, types[TINT32], n->xoffset);
   699  			regalloc(&n2, n1.type, N);
   700  			regalloc(&n3, types[TINT32], N);
   701  			gmove(&n1, &n2);
   702  			gmove(res, &n3);
   703  			gins(optoas(OADD, types[tptr]), &n2, &n3);
   704  			gmove(&n3, res);
   705  			regfree(&n2);
   706  			regfree(&n3);
   707  		}
   708  		break;
   709  
   710  	case ODOTPTR:
   711  		cgen(nl, res);
   712  		// explicit check for nil if struct is large enough
   713  		// that we might derive too big a pointer.
   714  		if(nl->type->type->width >= unmappedzero) {
   715  			regalloc(&n1, types[tptr], N);
   716  			gmove(res, &n1);
   717  			regalloc(&n2, types[TUINT8], &n1);
   718  			n1.op = OINDREG;
   719  			n1.type = types[TUINT8];
   720  			n1.xoffset = 0;
   721  			gmove(&n1, &n2);
   722  			regfree(&n1);
   723  			regfree(&n2);
   724  		}
   725  		if(n->xoffset != 0) {
   726  			nodconst(&n1, types[TINT32], n->xoffset);
   727  			regalloc(&n2, n1.type, N);
   728  			regalloc(&n3, types[tptr], N);
   729  			gmove(&n1, &n2);
   730  			gmove(res, &n3);
   731  			gins(optoas(OADD, types[tptr]), &n2, &n3);
   732  			gmove(&n3, res);
   733  			regfree(&n2);
   734  			regfree(&n3);
   735  		}
   736  		break;
   737  	}
   738  
   739  ret:
   740  	;
   741  }
   742  
   743  /*
   744   * generate:
   745   *	newreg = &n;
   746   *	res = newreg
   747   *
   748   * on exit, a has been changed to be *newreg.
   749   * caller must regfree(a).
   750   */
   751  void
   752  igen(Node *n, Node *a, Node *res)
   753  {
   754  	Node n1, n2;
   755  	int r;
   756  
   757  	if(debug['g']) {
   758  		dump("\nigen-n", n);
   759  	}
   760  	switch(n->op) {
   761  	case ONAME:
   762  		if((n->class&PHEAP) || n->class == PPARAMREF)
   763  			break;
   764  		*a = *n;
   765  		return;
   766  
   767  	case OINDREG:
   768  		// Increase the refcount of the register so that igen's caller
   769  		// has to call regfree.
   770  		if(n->val.u.reg != REGSP)
   771  			reg[n->val.u.reg]++;
   772  		*a = *n;
   773  		return;
   774  
   775  	case ODOT:
   776  		igen(n->left, a, res);
   777  		a->xoffset += n->xoffset;
   778  		a->type = n->type;
   779  		return;
   780  
   781  	case ODOTPTR:
   782  		if(n->left->addable
   783  			|| n->left->op == OCALLFUNC
   784  			|| n->left->op == OCALLMETH
   785  			|| n->left->op == OCALLINTER) {
   786  			// igen-able nodes.
   787  			igen(n->left, &n1, res);
   788  			regalloc(a, types[tptr], &n1);
   789  			gmove(&n1, a);
   790  			regfree(&n1);
   791  		} else {
   792  			regalloc(a, types[tptr], res);
   793  			cgen(n->left, a);
   794  		}
   795  		// explicit check for nil if struct is large enough
   796  		// that we might derive too big a pointer.
   797  		if(n->left->type->type->width >= unmappedzero) {
   798  			regalloc(&n1, types[tptr], N);
   799  			gmove(a, &n1);
   800  			regalloc(&n2, types[TUINT8], &n1);
   801  			n1.op = OINDREG;
   802  			n1.type = types[TUINT8];
   803  			n1.xoffset = 0;
   804  			gmove(&n1, &n2);
   805  			regfree(&n1);
   806  			regfree(&n2);
   807  		}
   808  		a->op = OINDREG;
   809  		a->xoffset = n->xoffset;
   810  		a->type = n->type;
   811  		return;
   812  
   813  	case OCALLMETH:
   814  	case OCALLFUNC:
   815  	case OCALLINTER:
   816  		// Release res so that it is available for cgen_call.
   817  		// Pick it up again after the call.
   818  		r = -1;
   819  		if(n->ullman >= UINF) {
   820  			if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
   821  				r = res->val.u.reg;
   822  				reg[r]--;
   823  			}
   824  		}
   825  		switch(n->op) {
   826  		case OCALLMETH:
   827  			cgen_callmeth(n, 0);
   828  			break;
   829  		case OCALLFUNC:
   830  			cgen_call(n, 0);
   831  			break;
   832  		case OCALLINTER:
   833  			cgen_callinter(n, N, 0);
   834  			break;
   835  		}
   836  		if(r >= 0)
   837  			reg[r]++;
   838  		regalloc(a, types[tptr], res);
   839  		cgen_aret(n, a);
   840  		a->op = OINDREG;
   841  		a->type = n->type;
   842  		return;
   843  	}
   844  
   845  	agenr(n, a, res);
   846  	a->op = OINDREG;
   847  	a->type = n->type;
   848  }
   849  
   850  /*
   851   * allocate a register in res and generate
   852   *  newreg = &n
   853   * The caller must call regfree(a).
   854   */
   855  void
   856  cgenr(Node *n, Node *a, Node *res)
   857  {
   858  	Node n1;
   859  
   860  	if(debug['g'])
   861  		dump("cgenr-n", n);
   862  
   863  	if(isfat(n->type))
   864  		fatal("cgenr on fat node");
   865  
   866  	if(n->addable) {
   867  		regalloc(a, types[tptr], res);
   868  		gmove(n, a);
   869  		return;
   870  	}
   871  
   872  	switch(n->op) {
   873  	case ONAME:
   874  	case ODOT:
   875  	case ODOTPTR:
   876  	case OINDEX:
   877  	case OCALLFUNC:
   878  	case OCALLMETH:
   879  	case OCALLINTER:
   880  		igen(n, &n1, res);
   881  		regalloc(a, types[tptr], &n1);
   882  		gmove(&n1, a);
   883  		regfree(&n1);
   884  		break;
   885  	default:
   886  		regalloc(a, n->type, res);
   887  		cgen(n, a);
   888  		break;
   889  	}
   890  }
   891  
   892  /*
   893   * generate:
   894   *	newreg = &n;
   895   *
   896   * caller must regfree(a).
   897   */
   898  void
   899  agenr(Node *n, Node *a, Node *res)
   900  {
   901  	Node *nl, *nr;
   902  	Node n1, n2, n3, n4, tmp;
   903  	Prog *p1, *p2;
   904  	uint32 w;
   905  	uint64 v;
   906  	int bounded;
   907  
   908  	if(debug['g'])
   909  		dump("agenr-n", n);
   910  
   911  	nl = n->left;
   912  	nr = n->right;
   913  
   914  	switch(n->op) {
   915  	case ODOT:
   916  	case ODOTPTR:
   917  	case OCALLFUNC:
   918  	case OCALLMETH:
   919  	case OCALLINTER:
   920  		igen(n, &n1, res);
   921  		regalloc(a, types[tptr], &n1);
   922  		agen(&n1, a);
   923  		regfree(&n1);
   924  		break;
   925  
   926  	case OIND:
   927  		cgenr(n->left, a, res);
   928  		break;
   929  
   930  	case OINDEX:
   931  		p2 = nil;  // to be patched to panicindex.
   932  		w = n->type->width;
   933  		bounded = debug['B'] || n->bounded;
   934  		if(nr->addable) {
   935  			if(!isconst(nr, CTINT))
   936  				tempname(&tmp, types[TINT32]);
   937  			if(!isconst(nl, CTSTR))
   938  				agenr(nl, &n3, res);
   939  			if(!isconst(nr, CTINT)) {
   940  				p2 = cgenindex(nr, &tmp, bounded);
   941  				regalloc(&n1, tmp.type, N);
   942  				gmove(&tmp, &n1);
   943  			}
   944  		} else
   945  		if(nl->addable) {
   946  			if(!isconst(nr, CTINT)) {
   947  				tempname(&tmp, types[TINT32]);
   948  				p2 = cgenindex(nr, &tmp, bounded);
   949  				regalloc(&n1, tmp.type, N);
   950  				gmove(&tmp, &n1);
   951  			}
   952  			if(!isconst(nl, CTSTR)) {
   953  				agenr(nl, &n3, res);
   954  			}
   955  		} else {
   956  			tempname(&tmp, types[TINT32]);
   957  			p2 = cgenindex(nr, &tmp, bounded);
   958  			nr = &tmp;
   959  			if(!isconst(nl, CTSTR))
   960  				agenr(nl, &n3, res);
   961  			regalloc(&n1, tmp.type, N);
   962  			gins(optoas(OAS, tmp.type), &tmp, &n1);
   963  		}
   964  
   965  		// &a is in &n3 (allocated in res)
   966  		// i is in &n1 (if not constant)
   967  		// w is width
   968  
   969  		// explicit check for nil if array is large enough
   970  		// that we might derive too big a pointer.
   971  		if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) {
   972  			regalloc(&n4, types[tptr], N);
   973  			gmove(&n3, &n4);
   974  			regalloc(&tmp, types[TUINT8], &n4);
   975  			n4.op = OINDREG;
   976  			n4.type = types[TUINT8];
   977  			n4.xoffset = 0;
   978  			gmove(&n4, &tmp);
   979  			regfree(&n4);
   980  			regfree(&tmp);
   981  		}
   982  
   983  		// constant index
   984  		if(isconst(nr, CTINT)) {
   985  			if(isconst(nl, CTSTR))
   986  				fatal("constant string constant index");
   987  			v = mpgetfix(nr->val.u.xval);
   988  			if(isslice(nl->type) || nl->type->etype == TSTRING) {
   989  				if(!debug['B'] && !n->bounded) {
   990  					n1 = n3;
   991  					n1.op = OINDREG;
   992  					n1.type = types[tptr];
   993  					n1.xoffset = Array_nel;
   994  					regalloc(&n4, n1.type, N);
   995  					gmove(&n1, &n4);
   996  					nodconst(&n2, types[TUINT32], v);
   997  					gcmp(optoas(OCMP, types[TUINT32]), &n4, &n2);
   998  					regfree(&n4);
   999  					p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
  1000  					ginscall(panicindex, 0);
  1001  					patch(p1, pc);
  1002  				}
  1003  
  1004  				n1 = n3;
  1005  				n1.op = OINDREG;
  1006  				n1.type = types[tptr];
  1007  				n1.xoffset = Array_array;
  1008  				gmove(&n1, &n3);
  1009  			}
  1010  
  1011  			nodconst(&n2, types[tptr], v*w);
  1012  			gins(optoas(OADD, types[tptr]), &n2, &n3);
  1013  			*a = n3;
  1014  			break;
  1015  		}
  1016  
  1017  		regalloc(&n2, types[TINT32], &n1);			// i
  1018  		gmove(&n1, &n2);
  1019  		regfree(&n1);
  1020  
  1021  		if(!debug['B'] && !n->bounded) {
  1022  			// check bounds
  1023  			if(isconst(nl, CTSTR)) {
  1024  				nodconst(&n4, types[TUINT32], nl->val.u.sval->len);
  1025  			} else if(isslice(nl->type) || nl->type->etype == TSTRING) {
  1026  				n1 = n3;
  1027  				n1.op = OINDREG;
  1028  				n1.type = types[tptr];
  1029  				n1.xoffset = Array_nel;
  1030  				regalloc(&n4, types[TUINT32], N);
  1031  				gmove(&n1, &n4);
  1032  			} else {
  1033  				nodconst(&n4, types[TUINT32], nl->type->bound);
  1034  			}
  1035  			gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
  1036  			if(n4.op == OREGISTER)
  1037  				regfree(&n4);
  1038  			p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
  1039  			if(p2)
  1040  				patch(p2, pc);
  1041  			ginscall(panicindex, 0);
  1042  			patch(p1, pc);
  1043  		}
  1044  		
  1045  		if(isconst(nl, CTSTR)) {
  1046  			regalloc(&n3, types[tptr], res);
  1047  			p1 = gins(AMOVW, N, &n3);
  1048  			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
  1049  			p1->from.type = D_CONST;
  1050  		} else
  1051  		if(isslice(nl->type) || nl->type->etype == TSTRING) {
  1052  			n1 = n3;
  1053  			n1.op = OINDREG;
  1054  			n1.type = types[tptr];
  1055  			n1.xoffset = Array_array;
  1056  			gmove(&n1, &n3);
  1057  		}
  1058  
  1059  		if(w == 0) {
  1060  			// nothing to do
  1061  		} else if(w == 1 || w == 2 || w == 4 || w == 8) {
  1062  			memset(&n4, 0, sizeof n4);
  1063  			n4.op = OADDR;
  1064  			n4.left = &n2;
  1065  			cgen(&n4, &n3);
  1066  			if (w == 1)
  1067  				gins(AADD, &n2, &n3);
  1068  			else if(w == 2)
  1069  				gshift(AADD, &n2, SHIFT_LL, 1, &n3);
  1070  			else if(w == 4)
  1071  				gshift(AADD, &n2, SHIFT_LL, 2, &n3);
  1072  			else if(w == 8)
  1073  				gshift(AADD, &n2, SHIFT_LL, 3, &n3);
  1074  		} else {
  1075  			regalloc(&n4, types[TUINT32], N);
  1076  			nodconst(&n1, types[TUINT32], w);
  1077  			gmove(&n1, &n4);
  1078  			gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
  1079  			gins(optoas(OADD, types[tptr]), &n2, &n3);
  1080  			regfree(&n4);
  1081  		}
  1082  
  1083  		*a = n3;
  1084  		regfree(&n2);
  1085  		break;
  1086  
  1087  	default:
  1088  		regalloc(a, types[tptr], res);
  1089  		agen(n, a);
  1090  		break;
  1091  	}
  1092  }
  1093  
  1094  void
  1095  gencmp0(Node *n, Type *t, int o, int likely, Prog *to)
  1096  {
  1097  	Node n1, n2, n3;
  1098  	int a;
  1099  
  1100  	regalloc(&n1, t, N);
  1101  	cgen(n, &n1);
  1102  	a = optoas(OCMP, t);
  1103  	if(a != ACMP) {
  1104  		nodconst(&n2, t, 0);
  1105  		regalloc(&n3, t, N);
  1106  		gmove(&n2, &n3);
  1107  		gcmp(a, &n1, &n3);
  1108  		regfree(&n3);
  1109  	} else
  1110  		gins(ATST, &n1, N);
  1111  	a = optoas(o, t);
  1112  	patch(gbranch(a, t, likely), to);
  1113  	regfree(&n1);
  1114  }
  1115  
  1116  /*
  1117   * generate:
  1118   *	if(n == true) goto to;
  1119   */
  1120  void
  1121  bgen(Node *n, int true, int likely, Prog *to)
  1122  {
  1123  	int et, a;
  1124  	Node *nl, *nr, *r;
  1125  	Node n1, n2, n3, n4, tmp;
  1126  	NodeList *ll;
  1127  	Prog *p1, *p2;
  1128  
  1129  	USED(n4);			// in unreachable code below
  1130  	if(debug['g']) {
  1131  		dump("\nbgen", n);
  1132  	}
  1133  
  1134  	if(n == N)
  1135  		n = nodbool(1);
  1136  
  1137  	if(n->ninit != nil)
  1138  		genlist(n->ninit);
  1139  
  1140  	if(n->type == T) {
  1141  		convlit(&n, types[TBOOL]);
  1142  		if(n->type == T)
  1143  			goto ret;
  1144  	}
  1145  
  1146  	et = n->type->etype;
  1147  	if(et != TBOOL) {
  1148  		yyerror("cgen: bad type %T for %O", n->type, n->op);
  1149  		patch(gins(AEND, N, N), to);
  1150  		goto ret;
  1151  	}
  1152  	nr = N;
  1153  
  1154  	switch(n->op) {
  1155  	default:
  1156  		a = ONE;
  1157  		if(!true)
  1158  			a = OEQ;
  1159  		gencmp0(n, n->type, a, likely, to);
  1160  		goto ret;
  1161  
  1162  	case OLITERAL:
  1163  		// need to ask if it is bool?
  1164  		if(!true == !n->val.u.bval)
  1165  			patch(gbranch(AB, T, 0), to);
  1166  		goto ret;
  1167  
  1168  	case OANDAND:
  1169  		if(!true)
  1170  			goto caseor;
  1171  
  1172  	caseand:
  1173  		p1 = gbranch(AB, T, 0);
  1174  		p2 = gbranch(AB, T, 0);
  1175  		patch(p1, pc);
  1176  		bgen(n->left, !true, -likely, p2);
  1177  		bgen(n->right, !true, -likely, p2);
  1178  		p1 = gbranch(AB, T, 0);
  1179  		patch(p1, to);
  1180  		patch(p2, pc);
  1181  		goto ret;
  1182  
  1183  	case OOROR:
  1184  		if(!true)
  1185  			goto caseand;
  1186  
  1187  	caseor:
  1188  		bgen(n->left, true, likely, to);
  1189  		bgen(n->right, true, likely, to);
  1190  		goto ret;
  1191  
  1192  	case OEQ:
  1193  	case ONE:
  1194  	case OLT:
  1195  	case OGT:
  1196  	case OLE:
  1197  	case OGE:
  1198  		nr = n->right;
  1199  		if(nr == N || nr->type == T)
  1200  			goto ret;
  1201  
  1202  	case ONOT:	// unary
  1203  		nl = n->left;
  1204  		if(nl == N || nl->type == T)
  1205  			goto ret;
  1206  	}
  1207  
  1208  	switch(n->op) {
  1209  
  1210  	case ONOT:
  1211  		bgen(nl, !true, likely, to);
  1212  		goto ret;
  1213  
  1214  	case OEQ:
  1215  	case ONE:
  1216  	case OLT:
  1217  	case OGT:
  1218  	case OLE:
  1219  	case OGE:
  1220  		a = n->op;
  1221  		if(!true) {
  1222  			if(isfloat[nl->type->etype]) {
  1223  				// brcom is not valid on floats when NaN is involved.
  1224  				p1 = gbranch(AB, T, 0);
  1225  				p2 = gbranch(AB, T, 0);
  1226  				patch(p1, pc);
  1227  				ll = n->ninit;
  1228  				n->ninit = nil;
  1229  				bgen(n, 1, -likely, p2);
  1230  				n->ninit = ll;
  1231  				patch(gbranch(AB, T, 0), to);
  1232  				patch(p2, pc);
  1233  				goto ret;
  1234  			}				
  1235  			a = brcom(a);
  1236  			true = !true;
  1237  		}
  1238  
  1239  		// make simplest on right
  1240  		if(nl->op == OLITERAL || (nl->ullman < UINF && nl->ullman < nr->ullman)) {
  1241  			a = brrev(a);
  1242  			r = nl;
  1243  			nl = nr;
  1244  			nr = r;
  1245  		}
  1246  
  1247  		if(isslice(nl->type)) {
  1248  			// only valid to cmp darray to literal nil
  1249  			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
  1250  				yyerror("illegal array comparison");
  1251  				break;
  1252  			}
  1253  
  1254  			igen(nl, &n1, N);
  1255  			n1.xoffset += Array_array;
  1256  			n1.type = types[tptr];
  1257  			gencmp0(&n1, types[tptr], a, likely, to);
  1258  			regfree(&n1);
  1259  			break;
  1260  		}
  1261  
  1262  		if(isinter(nl->type)) {
  1263  			// front end shold only leave cmp to literal nil
  1264  			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
  1265  				yyerror("illegal interface comparison");
  1266  				break;
  1267  			}
  1268  
  1269  			igen(nl, &n1, N);
  1270  			n1.type = types[tptr];
  1271  			n1.xoffset += 0;
  1272  			gencmp0(&n1, types[tptr], a, likely, to);
  1273  			regfree(&n1);
  1274  			break;
  1275  		}
  1276  
  1277  		if(iscomplex[nl->type->etype]) {
  1278  			complexbool(a, nl, nr, true, likely, to);
  1279  			break;
  1280  		}
  1281  
  1282  		if(is64(nr->type)) {
  1283  			if(!nl->addable) {
  1284  				tempname(&n1, nl->type);
  1285  				cgen(nl, &n1);
  1286  				nl = &n1;
  1287  			}
  1288  			if(!nr->addable) {
  1289  				tempname(&n2, nr->type);
  1290  				cgen(nr, &n2);
  1291  				nr = &n2;
  1292  			}
  1293  			cmp64(nl, nr, a, likely, to);
  1294  			break;
  1295  		}
  1296  
  1297  		if(nr->op == OLITERAL) {
  1298  			if(isconst(nr, CTINT) &&  mpgetfix(nr->val.u.xval) == 0) {
  1299  				gencmp0(nl, nl->type, a, likely, to);
  1300  				break;
  1301  			}
  1302  			if(nr->val.ctype == CTNIL) {
  1303  				gencmp0(nl, nl->type, a, likely, to);
  1304  				break;
  1305  			}
  1306  		}
  1307  
  1308  		a = optoas(a, nr->type);
  1309  
  1310  		if(nr->ullman >= UINF) {
  1311  			regalloc(&n1, nl->type, N);
  1312  			cgen(nl, &n1);
  1313  
  1314  			tempname(&tmp, nl->type);
  1315  			gmove(&n1, &tmp);
  1316  			regfree(&n1);
  1317  
  1318  			regalloc(&n2, nr->type, N);
  1319  			cgen(nr, &n2);
  1320  
  1321  			regalloc(&n1, nl->type, N);
  1322  			cgen(&tmp, &n1);
  1323  
  1324  			gcmp(optoas(OCMP, nr->type), &n1, &n2);
  1325  			patch(gbranch(a, nr->type, likely), to);
  1326  
  1327  			regfree(&n1);
  1328  			regfree(&n2);
  1329  			break;
  1330  		}
  1331  
  1332  		tempname(&n3, nl->type);
  1333  		cgen(nl, &n3);
  1334  
  1335  		tempname(&tmp, nr->type);
  1336  		cgen(nr, &tmp);
  1337  
  1338  		regalloc(&n1, nl->type, N);
  1339  		gmove(&n3, &n1);
  1340  
  1341  		regalloc(&n2, nr->type, N);
  1342  		gmove(&tmp, &n2);
  1343  
  1344  		gcmp(optoas(OCMP, nr->type), &n1, &n2);
  1345  		if(isfloat[nl->type->etype]) {
  1346  			if(n->op == ONE) {
  1347  				p1 = gbranch(ABVS, nr->type, likely);
  1348  				patch(gbranch(a, nr->type, likely), to);
  1349  				patch(p1, to);
  1350  			} else {
  1351  				p1 = gbranch(ABVS, nr->type, -likely);
  1352  				patch(gbranch(a, nr->type, likely), to);
  1353  				patch(p1, pc);
  1354  			}
  1355  		} else {
  1356  			patch(gbranch(a, nr->type, likely), to);
  1357  		}
  1358  		regfree(&n1);
  1359  		regfree(&n2);
  1360  		break;
  1361  	}
  1362  	goto ret;
  1363  
  1364  ret:
  1365  	;
  1366  }
  1367  
  1368  /*
  1369   * n is on stack, either local variable
  1370   * or return value from function call.
  1371   * return n's offset from SP.
  1372   */
  1373  int32
  1374  stkof(Node *n)
  1375  {
  1376  	Type *t;
  1377  	Iter flist;
  1378  	int32 off;
  1379  
  1380  	switch(n->op) {
  1381  	case OINDREG:
  1382  		return n->xoffset;
  1383  
  1384  	case ODOT:
  1385  		t = n->left->type;
  1386  		if(isptr[t->etype])
  1387  			break;
  1388  		off = stkof(n->left);
  1389  		if(off == -1000 || off == 1000)
  1390  			return off;
  1391  		return off + n->xoffset;
  1392  
  1393  	case OINDEX:
  1394  		t = n->left->type;
  1395  		if(!isfixedarray(t))
  1396  			break;
  1397  		off = stkof(n->left);
  1398  		if(off == -1000 || off == 1000)
  1399  			return off;
  1400  		if(isconst(n->right, CTINT))
  1401  			return off + t->type->width * mpgetfix(n->right->val.u.xval);
  1402  		return 1000;
  1403  		
  1404  	case OCALLMETH:
  1405  	case OCALLINTER:
  1406  	case OCALLFUNC:
  1407  		t = n->left->type;
  1408  		if(isptr[t->etype])
  1409  			t = t->type;
  1410  
  1411  		t = structfirst(&flist, getoutarg(t));
  1412  		if(t != T)
  1413  			return t->width + 4;	// correct for LR
  1414  		break;
  1415  	}
  1416  
  1417  	// botch - probably failing to recognize address
  1418  	// arithmetic on the above. eg INDEX and DOT
  1419  	return -1000;
  1420  }
  1421  
  1422  /*
  1423   * block copy:
  1424   *	memmove(&res, &n, w);
  1425   * NB: character copy assumed little endian architecture
  1426   */
  1427  void
  1428  sgen(Node *n, Node *res, int64 w)
  1429  {
  1430  	Node dst, src, tmp, nend;
  1431  	int32 c, odst, osrc;
  1432  	int dir, align, op;
  1433  	Prog *p, *ploop;
  1434  
  1435  	if(debug['g']) {
  1436  		print("\nsgen w=%lld\n", w);
  1437  		dump("r", n);
  1438  		dump("res", res);
  1439  	}
  1440  
  1441  	if(n->ullman >= UINF && res->ullman >= UINF)
  1442  		fatal("sgen UINF");
  1443  
  1444  	if(w < 0 || (int32)w != w)
  1445  		fatal("sgen copy %lld", w);
  1446  
  1447  	if(n->type == T)
  1448  		fatal("sgen: missing type");
  1449  
  1450  	if(w == 0) {
  1451  		// evaluate side effects only.
  1452  		regalloc(&dst, types[tptr], N);
  1453  		agen(res, &dst);
  1454  		agen(n, &dst);
  1455  		regfree(&dst);
  1456  		return;
  1457  	}
  1458  
  1459  	// Avoid taking the address for simple enough types.
  1460  	if(componentgen(n, res))
  1461  		return;
  1462  	
  1463  	// determine alignment.
  1464  	// want to avoid unaligned access, so have to use
  1465  	// smaller operations for less aligned types.
  1466  	// for example moving [4]byte must use 4 MOVB not 1 MOVW.
  1467  	align = n->type->align;
  1468  	switch(align) {
  1469  	default:
  1470  		fatal("sgen: invalid alignment %d for %T", align, n->type);
  1471  	case 1:
  1472  		op = AMOVB;
  1473  		break;
  1474  	case 2:
  1475  		op = AMOVH;
  1476  		break;
  1477  	case 4:
  1478  		op = AMOVW;
  1479  		break;
  1480  	}
  1481  	if(w%align)
  1482  		fatal("sgen: unaligned size %lld (align=%d) for %T", w, align, n->type);
  1483  	c = w / align;
  1484  
  1485  	// offset on the stack
  1486  	osrc = stkof(n);
  1487  	odst = stkof(res);
  1488  	if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
  1489  		// osrc and odst both on stack, and at least one is in
  1490  		// an unknown position.  Could generate code to test
  1491  		// for forward/backward copy, but instead just copy
  1492  		// to a temporary location first.
  1493  		tempname(&tmp, n->type);
  1494  		sgen(n, &tmp, w);
  1495  		sgen(&tmp, res, w);
  1496  		return;
  1497  	}
  1498  	if(osrc%align != 0 || odst%align != 0)
  1499  		fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align);
  1500  	// if we are copying forward on the stack and
  1501  	// the src and dst overlap, then reverse direction
  1502  	dir = align;
  1503  	if(osrc < odst && odst < osrc+w)
  1504  		dir = -dir;
  1505  
  1506  	if(n->ullman >= res->ullman) {
  1507  		agenr(n, &dst, res);	// temporarily use dst
  1508  		regalloc(&src, types[tptr], N);
  1509  		gins(AMOVW, &dst, &src);
  1510  		agen(res, &dst);
  1511  	} else {
  1512  		agenr(res, &dst, res);
  1513  		agenr(n, &src, N);
  1514  	}
  1515  
  1516  	regalloc(&tmp, types[TUINT32], N);
  1517  
  1518  	// set up end marker
  1519  	memset(&nend, 0, sizeof nend);
  1520  	if(c >= 4) {
  1521  		regalloc(&nend, types[TUINT32], N);
  1522  
  1523  		p = gins(AMOVW, &src, &nend);
  1524  		p->from.type = D_CONST;
  1525  		if(dir < 0)
  1526  			p->from.offset = dir;
  1527  		else
  1528  			p->from.offset = w;
  1529  	}
  1530  
  1531  	// move src and dest to the end of block if necessary
  1532  	if(dir < 0) {
  1533  		p = gins(AMOVW, &src, &src);
  1534  		p->from.type = D_CONST;
  1535  		p->from.offset = w + dir;
  1536  
  1537  		p = gins(AMOVW, &dst, &dst);
  1538  		p->from.type = D_CONST;
  1539  		p->from.offset = w + dir;
  1540  	}
  1541  	
  1542  	// move
  1543  	if(c >= 4) {
  1544  		p = gins(op, &src, &tmp);
  1545  		p->from.type = D_OREG;
  1546  		p->from.offset = dir;
  1547  		p->scond |= C_PBIT;
  1548  		ploop = p;
  1549  
  1550  		p = gins(op, &tmp, &dst);
  1551  		p->to.type = D_OREG;
  1552  		p->to.offset = dir;
  1553  		p->scond |= C_PBIT;
  1554  
  1555  		p = gins(ACMP, &src, N);
  1556  		raddr(&nend, p);
  1557  
  1558  		patch(gbranch(ABNE, T, 0), ploop);
  1559   		regfree(&nend);
  1560  	} else {
  1561  		while(c-- > 0) {
  1562  			p = gins(op, &src, &tmp);
  1563  			p->from.type = D_OREG;
  1564  			p->from.offset = dir;
  1565  			p->scond |= C_PBIT;
  1566  	
  1567  			p = gins(op, &tmp, &dst);
  1568  			p->to.type = D_OREG;
  1569  			p->to.offset = dir;
  1570  			p->scond |= C_PBIT;
  1571  		}
  1572  	}
  1573  
  1574  	regfree(&dst);
  1575  	regfree(&src);
  1576  	regfree(&tmp);
  1577  }
  1578  
  1579  static int
  1580  cadable(Node *n)
  1581  {
  1582  	if(!n->addable) {
  1583  		// dont know how it happens,
  1584  		// but it does
  1585  		return 0;
  1586  	}
  1587  
  1588  	switch(n->op) {
  1589  	case ONAME:
  1590  		return 1;
  1591  	}
  1592  	return 0;
  1593  }
  1594  
  1595  /*
  1596   * copy a composite value by moving its individual components.
  1597   * Slices, strings and interfaces are supported.
  1598   * nr is N when assigning a zero value.
  1599   * return 1 if can do, 0 if cant.
  1600   */
  1601  int
  1602  componentgen(Node *nr, Node *nl)
  1603  {
  1604  	Node nodl, nodr, tmp;
  1605  	int freel, freer;
  1606  
  1607  	freel = 0;
  1608  	freer = 0;
  1609  
  1610  	switch(nl->type->etype) {
  1611  	default:
  1612  		goto no;
  1613  
  1614  	case TARRAY:
  1615  		if(!isslice(nl->type))
  1616  			goto no;
  1617  	case TSTRING:
  1618  	case TINTER:
  1619  		break;
  1620  	}
  1621  
  1622  	nodl = *nl;
  1623  	if(!cadable(nl)) {
  1624  		if(nr == N || !cadable(nr))
  1625  			goto no;
  1626  		igen(nl, &nodl, N);
  1627  		freel = 1;
  1628  	}
  1629  
  1630  	if(nr != N) {
  1631  		nodr = *nr;
  1632  		if(!cadable(nr)) {
  1633  			igen(nr, &nodr, N);
  1634  			freer = 1;
  1635  		}
  1636  	} else {
  1637  		// When zeroing, prepare a register containing zero.
  1638  		nodconst(&tmp, nl->type, 0);
  1639  		regalloc(&nodr, types[TUINT], N);
  1640  		gmove(&tmp, &nodr);
  1641  		freer = 1;
  1642  	}
  1643  
  1644  	switch(nl->type->etype) {
  1645  	case TARRAY:
  1646  		nodl.xoffset += Array_array;
  1647  		nodl.type = ptrto(nl->type->type);
  1648  
  1649  		if(nr != N) {
  1650  			nodr.xoffset += Array_array;
  1651  			nodr.type = nodl.type;
  1652  		}
  1653  		gmove(&nodr, &nodl);
  1654  
  1655  		nodl.xoffset += Array_nel-Array_array;
  1656  		nodl.type = types[simtype[TUINT]];
  1657  
  1658  		if(nr != N) {
  1659  			nodr.xoffset += Array_nel-Array_array;
  1660  			nodr.type = nodl.type;
  1661  		}
  1662  		gmove(&nodr, &nodl);
  1663  
  1664  		nodl.xoffset += Array_cap-Array_nel;
  1665  		nodl.type = types[simtype[TUINT]];
  1666  
  1667  		if(nr != N) {
  1668  			nodr.xoffset += Array_cap-Array_nel;
  1669  			nodr.type = nodl.type;
  1670  		}
  1671  		gmove(&nodr, &nodl);
  1672  
  1673  		goto yes;
  1674  
  1675  	case TSTRING:
  1676  		nodl.xoffset += Array_array;
  1677  		nodl.type = ptrto(types[TUINT8]);
  1678  
  1679  		if(nr != N) {
  1680  			nodr.xoffset += Array_array;
  1681  			nodr.type = nodl.type;
  1682  		}
  1683  		gmove(&nodr, &nodl);
  1684  
  1685  		nodl.xoffset += Array_nel-Array_array;
  1686  		nodl.type = types[simtype[TUINT]];
  1687  
  1688  		if(nr != N) {
  1689  			nodr.xoffset += Array_nel-Array_array;
  1690  			nodr.type = nodl.type;
  1691  		}
  1692  		gmove(&nodr, &nodl);
  1693  
  1694  		goto yes;
  1695  
  1696  	case TINTER:
  1697  		nodl.xoffset += Array_array;
  1698  		nodl.type = ptrto(types[TUINT8]);
  1699  
  1700  		if(nr != N) {
  1701  			nodr.xoffset += Array_array;
  1702  			nodr.type = nodl.type;
  1703  		}
  1704  		gmove(&nodr, &nodl);
  1705  
  1706  		nodl.xoffset += Array_nel-Array_array;
  1707  		nodl.type = ptrto(types[TUINT8]);
  1708  
  1709  		if(nr != N) {
  1710  			nodr.xoffset += Array_nel-Array_array;
  1711  			nodr.type = nodl.type;
  1712  		}
  1713  		gmove(&nodr, &nodl);
  1714  
  1715  		goto yes;
  1716  	}
  1717  
  1718  no:
  1719  	if(freer)
  1720  		regfree(&nodr);
  1721  	if(freel)
  1722  		regfree(&nodl);
  1723  	return 0;
  1724  
  1725  yes:
  1726  	if(freer)
  1727  		regfree(&nodr);
  1728  	if(freel)
  1729  		regfree(&nodl);
  1730  	return 1;
  1731  }