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