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