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