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