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