github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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  			if(flag_largemodel) {
   755  				gins(AADDQ, &n2, &n3);
   756  			} else {
   757  				p1->from.scale = 1;
   758  				p1->from.index = n2.val.u.reg;
   759  			}
   760  			goto indexdone;
   761  		}
   762  
   763  		if(w == 0) {
   764  			// nothing to do
   765  		} else if(w == 1 || w == 2 || w == 4 || w == 8) {
   766  			p1 = gins(ALEAQ, &n2, &n3);
   767  			p1->from.scale = w;
   768  			p1->from.index = p1->from.type;
   769  			p1->from.type = p1->to.type + D_INDIR;
   770  		} else {
   771  			ginscon(optoas(OMUL, t), w, &n2);
   772  			gins(optoas(OADD, types[tptr]), &n2, &n3);
   773  		}
   774  
   775  	indexdone:
   776  		*a = n3;
   777  		regfree(&n2);
   778  		if(freelen)
   779  			regfree(&nlen);
   780  		break;
   781  
   782  	default:
   783  		regalloc(a, types[tptr], res);
   784  		agen(n, a);
   785  		break;
   786  	}
   787  }
   788  
   789  /*
   790   * generate:
   791   *	res = &n;
   792   * The generated code checks that the result is not nil.
   793   */
   794  void
   795  agen(Node *n, Node *res)
   796  {
   797  	Node *nl, *nr;
   798  	Node n1, n2;
   799  
   800  	if(debug['g']) {
   801  		dump("\nagen-res", res);
   802  		dump("agen-r", n);
   803  	}
   804  	if(n == N || n->type == T)
   805  		return;
   806  
   807  	while(n->op == OCONVNOP)
   808  		n = n->left;
   809  
   810  	if(isconst(n, CTNIL) && n->type->width > widthptr) {
   811  		// Use of a nil interface or nil slice.
   812  		// Create a temporary we can take the address of and read.
   813  		// The generated code is just going to panic, so it need not
   814  		// be terribly efficient. See issue 3670.
   815  		tempname(&n1, n->type);
   816  		clearfat(&n1);
   817  		regalloc(&n2, types[tptr], res);
   818  		gins(ALEAQ, &n1, &n2);
   819  		gmove(&n2, res);
   820  		regfree(&n2);
   821  		goto ret;
   822  	}
   823  		
   824  	if(n->addable) {
   825  		regalloc(&n1, types[tptr], res);
   826  		gins(ALEAQ, n, &n1);
   827  		gmove(&n1, res);
   828  		regfree(&n1);
   829  		goto ret;
   830  	}
   831  
   832  	nl = n->left;
   833  	nr = n->right;
   834  	USED(nr);
   835  
   836  	switch(n->op) {
   837  	default:
   838  		fatal("agen: unknown op %+hN", n);
   839  		break;
   840  
   841  	case OCALLMETH:
   842  		cgen_callmeth(n, 0);
   843  		cgen_aret(n, res);
   844  		break;
   845  
   846  	case OCALLINTER:
   847  		cgen_callinter(n, res, 0);
   848  		cgen_aret(n, res);
   849  		break;
   850  
   851  	case OCALLFUNC:
   852  		cgen_call(n, 0);
   853  		cgen_aret(n, res);
   854  		break;
   855  
   856  	case OSLICE:
   857  	case OSLICEARR:
   858  	case OSLICESTR:
   859  	case OSLICE3:
   860  	case OSLICE3ARR:
   861  		tempname(&n1, n->type);
   862  		cgen_slice(n, &n1);
   863  		agen(&n1, res);
   864  		break;
   865  
   866  	case OEFACE:
   867  		tempname(&n1, n->type);
   868  		cgen_eface(n, &n1);
   869  		agen(&n1, res);
   870  		break;
   871  
   872  	case OINDEX:
   873  		agenr(n, &n1, res);
   874  		gmove(&n1, res);
   875  		regfree(&n1);
   876  		break;
   877  
   878  	case ONAME:
   879  		// should only get here with names in this func.
   880  		if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
   881  			dump("bad agen", n);
   882  			fatal("agen: bad ONAME funcdepth %d != %d",
   883  				n->funcdepth, funcdepth);
   884  		}
   885  
   886  		// should only get here for heap vars or paramref
   887  		if(!(n->class & PHEAP) && n->class != PPARAMREF) {
   888  			dump("bad agen", n);
   889  			fatal("agen: bad ONAME class %#x", n->class);
   890  		}
   891  		cgen(n->heapaddr, res);
   892  		if(n->xoffset != 0)
   893  			ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
   894  		break;
   895  
   896  	case OIND:
   897  		cgen(nl, res);
   898  		cgen_checknil(res);
   899  		break;
   900  
   901  	case ODOT:
   902  		agen(nl, res);
   903  		if(n->xoffset != 0)
   904  			ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
   905  		break;
   906  
   907  	case ODOTPTR:
   908  		cgen(nl, res);
   909  		cgen_checknil(res);
   910  		if(n->xoffset != 0)
   911  			ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
   912  		break;
   913  	}
   914  
   915  ret:
   916  	;
   917  }
   918  
   919  /*
   920   * generate:
   921   *	newreg = &n;
   922   *	res = newreg
   923   *
   924   * on exit, a has been changed to be *newreg.
   925   * caller must regfree(a).
   926   * The generated code checks that the result is not *nil.
   927   */
   928  void
   929  igen(Node *n, Node *a, Node *res)
   930  {
   931  	Type *fp;
   932  	Iter flist;
   933  	Node n1;
   934  
   935  	if(debug['g']) {
   936  		dump("\nigen-n", n);
   937  	}
   938  	switch(n->op) {
   939  	case ONAME:
   940  		if((n->class&PHEAP) || n->class == PPARAMREF)
   941  			break;
   942  		*a = *n;
   943  		return;
   944  
   945  	case OINDREG:
   946  		// Increase the refcount of the register so that igen's caller
   947  		// has to call regfree.
   948  		if(n->val.u.reg != D_SP)
   949  			reg[n->val.u.reg]++;
   950  		*a = *n;
   951  		return;
   952  
   953  	case ODOT:
   954  		igen(n->left, a, res);
   955  		a->xoffset += n->xoffset;
   956  		a->type = n->type;
   957  		fixlargeoffset(a);
   958  		return;
   959  
   960  	case ODOTPTR:
   961  		cgenr(n->left, a, res);
   962  		cgen_checknil(a);
   963  		a->op = OINDREG;
   964  		a->xoffset += n->xoffset;
   965  		a->type = n->type;
   966  		fixlargeoffset(a);
   967  		return;
   968  
   969  	case OCALLFUNC:
   970  	case OCALLMETH:
   971  	case OCALLINTER:
   972  		switch(n->op) {
   973  		case OCALLFUNC:
   974  			cgen_call(n, 0);
   975  			break;
   976  		case OCALLMETH:
   977  			cgen_callmeth(n, 0);
   978  			break;
   979  		case OCALLINTER:
   980  			cgen_callinter(n, N, 0);
   981  			break;
   982  		}
   983  		fp = structfirst(&flist, getoutarg(n->left->type));
   984  		memset(a, 0, sizeof *a);
   985  		a->op = OINDREG;
   986  		a->val.u.reg = D_SP;
   987  		a->addable = 1;
   988  		a->xoffset = fp->width;
   989  		a->type = n->type;
   990  		return;
   991  
   992  	case OINDEX:
   993  		// Index of fixed-size array by constant can
   994  		// put the offset in the addressing.
   995  		// Could do the same for slice except that we need
   996  		// to use the real index for the bounds checking.
   997  		if(isfixedarray(n->left->type) ||
   998  		   (isptr[n->left->type->etype] && isfixedarray(n->left->left->type)))
   999  		if(isconst(n->right, CTINT)) {
  1000  			// Compute &a.
  1001  			if(!isptr[n->left->type->etype])
  1002  				igen(n->left, a, res);
  1003  			else {
  1004  				igen(n->left, &n1, res);
  1005  				cgen_checknil(&n1);
  1006  				regalloc(a, types[tptr], res);
  1007  				gmove(&n1, a);
  1008  				regfree(&n1);
  1009  				a->op = OINDREG;
  1010  			}
  1011  
  1012  			// Compute &a[i] as &a + i*width.
  1013  			a->type = n->type;
  1014  			a->xoffset += mpgetfix(n->right->val.u.xval)*n->type->width;
  1015  			fixlargeoffset(a);
  1016  			return;
  1017  		}
  1018  		break;
  1019  	}
  1020  
  1021  	agenr(n, a, res);
  1022  	a->op = OINDREG;
  1023  	a->type = n->type;
  1024  }
  1025  
  1026  /*
  1027   * generate:
  1028   *	if(n == true) goto to;
  1029   */
  1030  void
  1031  bgen(Node *n, int true, int likely, Prog *to)
  1032  {
  1033  	int et, a;
  1034  	Node *nl, *nr, *l, *r;
  1035  	Node n1, n2, tmp;
  1036  	NodeList *ll;
  1037  	Prog *p1, *p2;
  1038  
  1039  	if(debug['g']) {
  1040  		dump("\nbgen", n);
  1041  	}
  1042  
  1043  	if(n == N)
  1044  		n = nodbool(1);
  1045  
  1046  	if(n->ninit != nil)
  1047  		genlist(n->ninit);
  1048  
  1049  	if(n->type == T) {
  1050  		convlit(&n, types[TBOOL]);
  1051  		if(n->type == T)
  1052  			goto ret;
  1053  	}
  1054  
  1055  	et = n->type->etype;
  1056  	if(et != TBOOL) {
  1057  		yyerror("cgen: bad type %T for %O", n->type, n->op);
  1058  		patch(gins(AEND, N, N), to);
  1059  		goto ret;
  1060  	}
  1061  	nr = N;
  1062  
  1063  	switch(n->op) {
  1064  	default:
  1065  	def:
  1066  		regalloc(&n1, n->type, N);
  1067  		cgen(n, &n1);
  1068  		nodconst(&n2, n->type, 0);
  1069  		gins(optoas(OCMP, n->type), &n1, &n2);
  1070  		a = AJNE;
  1071  		if(!true)
  1072  			a = AJEQ;
  1073  		patch(gbranch(a, n->type, likely), to);
  1074  		regfree(&n1);
  1075  		goto ret;
  1076  
  1077  	case OLITERAL:
  1078  		// need to ask if it is bool?
  1079  		if(!true == !n->val.u.bval)
  1080  			patch(gbranch(AJMP, T, likely), to);
  1081  		goto ret;
  1082  
  1083  	case ONAME:
  1084  		if(n->addable == 0)
  1085  			goto def;
  1086  		nodconst(&n1, n->type, 0);
  1087  		gins(optoas(OCMP, n->type), n, &n1);
  1088  		a = AJNE;
  1089  		if(!true)
  1090  			a = AJEQ;
  1091  		patch(gbranch(a, n->type, likely), to);
  1092  		goto ret;
  1093  
  1094  	case OANDAND:
  1095  		if(!true)
  1096  			goto caseor;
  1097  
  1098  	caseand:
  1099  		p1 = gbranch(AJMP, T, 0);
  1100  		p2 = gbranch(AJMP, T, 0);
  1101  		patch(p1, pc);
  1102  		bgen(n->left, !true, -likely, p2);
  1103  		bgen(n->right, !true, -likely, p2);
  1104  		p1 = gbranch(AJMP, T, 0);
  1105  		patch(p1, to);
  1106  		patch(p2, pc);
  1107  		goto ret;
  1108  
  1109  	case OOROR:
  1110  		if(!true)
  1111  			goto caseand;
  1112  
  1113  	caseor:
  1114  		bgen(n->left, true, likely, to);
  1115  		bgen(n->right, true, likely, to);
  1116  		goto ret;
  1117  
  1118  	case OEQ:
  1119  	case ONE:
  1120  	case OLT:
  1121  	case OGT:
  1122  	case OLE:
  1123  	case OGE:
  1124  		nr = n->right;
  1125  		if(nr == N || nr->type == T)
  1126  			goto ret;
  1127  
  1128  	case ONOT:	// unary
  1129  		nl = n->left;
  1130  		if(nl == N || nl->type == T)
  1131  			goto ret;
  1132  		break;
  1133  	}
  1134  
  1135  	switch(n->op) {
  1136  
  1137  	case ONOT:
  1138  		bgen(nl, !true, likely, to);
  1139  		goto ret;
  1140  
  1141  	case OEQ:
  1142  	case ONE:
  1143  	case OLT:
  1144  	case OGT:
  1145  	case OLE:
  1146  	case OGE:
  1147  		a = n->op;
  1148  		if(!true) {
  1149  			if(isfloat[nr->type->etype]) {
  1150  				// brcom is not valid on floats when NaN is involved.
  1151  				p1 = gbranch(AJMP, T, 0);
  1152  				p2 = gbranch(AJMP, T, 0);
  1153  				patch(p1, pc);
  1154  				ll = n->ninit;   // avoid re-genning ninit
  1155  				n->ninit = nil;
  1156  				bgen(n, 1, -likely, p2);
  1157  				n->ninit = ll;
  1158  				patch(gbranch(AJMP, T, 0), to);
  1159  				patch(p2, pc);
  1160  				goto ret;
  1161  			}				
  1162  			a = brcom(a);
  1163  			true = !true;
  1164  		}
  1165  
  1166  		// make simplest on right
  1167  		if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) {
  1168  			a = brrev(a);
  1169  			r = nl;
  1170  			nl = nr;
  1171  			nr = r;
  1172  		}
  1173  
  1174  		if(isslice(nl->type)) {
  1175  			// front end should only leave cmp to literal nil
  1176  			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
  1177  				yyerror("illegal slice comparison");
  1178  				break;
  1179  			}
  1180  			a = optoas(a, types[tptr]);
  1181  			igen(nl, &n1, N);
  1182  			n1.xoffset += Array_array;
  1183  			n1.type = types[tptr];
  1184  			nodconst(&tmp, types[tptr], 0);
  1185  			gins(optoas(OCMP, types[tptr]), &n1, &tmp);
  1186  			patch(gbranch(a, types[tptr], likely), to);
  1187  			regfree(&n1);
  1188  			break;
  1189  		}
  1190  
  1191  		if(isinter(nl->type)) {
  1192  			// front end should only leave cmp to literal nil
  1193  			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
  1194  				yyerror("illegal interface comparison");
  1195  				break;
  1196  			}
  1197  			a = optoas(a, types[tptr]);
  1198  			igen(nl, &n1, N);
  1199  			n1.type = types[tptr];
  1200  			nodconst(&tmp, types[tptr], 0);
  1201  			gins(optoas(OCMP, types[tptr]), &n1, &tmp);
  1202  			patch(gbranch(a, types[tptr], likely), to);
  1203  			regfree(&n1);
  1204  			break;
  1205  		}
  1206  		if(iscomplex[nl->type->etype]) {
  1207  			complexbool(a, nl, nr, true, likely, to);
  1208  			break;
  1209  		}
  1210  
  1211  		if(nr->ullman >= UINF) {
  1212  			regalloc(&n1, nl->type, N);
  1213  			cgen(nl, &n1);
  1214  
  1215  			tempname(&tmp, nl->type);
  1216  			gmove(&n1, &tmp);
  1217  			regfree(&n1);
  1218  
  1219  			regalloc(&n2, nr->type, N);
  1220  			cgen(nr, &n2);
  1221  
  1222  			regalloc(&n1, nl->type, N);
  1223  			cgen(&tmp, &n1);
  1224  
  1225  			goto cmp;
  1226  		}
  1227  
  1228  		regalloc(&n1, nl->type, N);
  1229  		cgen(nl, &n1);
  1230  
  1231  		if(smallintconst(nr)) {
  1232  			gins(optoas(OCMP, nr->type), &n1, nr);
  1233  			patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
  1234  			regfree(&n1);
  1235  			break;
  1236  		}
  1237  
  1238  		regalloc(&n2, nr->type, N);
  1239  		cgen(nr, &n2);
  1240  	cmp:
  1241  		// only < and <= work right with NaN; reverse if needed
  1242  		l = &n1;
  1243  		r = &n2;
  1244  		if(isfloat[nl->type->etype] && (a == OGT || a == OGE)) {
  1245  			l = &n2;
  1246  			r = &n1;
  1247  			a = brrev(a);
  1248  		}
  1249  
  1250  		gins(optoas(OCMP, nr->type), l, r);
  1251  
  1252  		if(isfloat[nr->type->etype] && (n->op == OEQ || n->op == ONE)) {
  1253  			if(n->op == OEQ) {
  1254  				// neither NE nor P
  1255  				p1 = gbranch(AJNE, T, -likely);
  1256  				p2 = gbranch(AJPS, T, -likely);
  1257  				patch(gbranch(AJMP, T, 0), to);
  1258  				patch(p1, pc);
  1259  				patch(p2, pc);
  1260  			} else {
  1261  				// either NE or P
  1262  				patch(gbranch(AJNE, T, likely), to);
  1263  				patch(gbranch(AJPS, T, likely), to);
  1264  			}
  1265  		} else
  1266  			patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
  1267  		regfree(&n1);
  1268  		regfree(&n2);
  1269  		break;
  1270  	}
  1271  	goto ret;
  1272  
  1273  ret:
  1274  	;
  1275  }
  1276  
  1277  /*
  1278   * n is on stack, either local variable
  1279   * or return value from function call.
  1280   * return n's offset from SP.
  1281   */
  1282  int64
  1283  stkof(Node *n)
  1284  {
  1285  	Type *t;
  1286  	Iter flist;
  1287  	int64 off;
  1288  
  1289  	switch(n->op) {
  1290  	case OINDREG:
  1291  		return n->xoffset;
  1292  
  1293  	case ODOT:
  1294  		t = n->left->type;
  1295  		if(isptr[t->etype])
  1296  			break;
  1297  		off = stkof(n->left);
  1298  		if(off == -1000 || off == 1000)
  1299  			return off;
  1300  		return off + n->xoffset;
  1301  
  1302  	case OINDEX:
  1303  		t = n->left->type;
  1304  		if(!isfixedarray(t))
  1305  			break;
  1306  		off = stkof(n->left);
  1307  		if(off == -1000 || off == 1000)
  1308  			return off;
  1309  		if(isconst(n->right, CTINT))
  1310  			return off + t->type->width * mpgetfix(n->right->val.u.xval);
  1311  		return 1000;
  1312  		
  1313  	case OCALLMETH:
  1314  	case OCALLINTER:
  1315  	case OCALLFUNC:
  1316  		t = n->left->type;
  1317  		if(isptr[t->etype])
  1318  			t = t->type;
  1319  
  1320  		t = structfirst(&flist, getoutarg(t));
  1321  		if(t != T)
  1322  			return t->width;
  1323  		break;
  1324  	}
  1325  
  1326  	// botch - probably failing to recognize address
  1327  	// arithmetic on the above. eg INDEX and DOT
  1328  	return -1000;
  1329  }
  1330  
  1331  /*
  1332   * block copy:
  1333   *	memmove(&ns, &n, w);
  1334   */
  1335  void
  1336  sgen(Node *n, Node *ns, int64 w)
  1337  {
  1338  	Node nodl, nodr, nodsi, noddi, cx, oldcx, tmp;
  1339  	vlong c, q, odst, osrc;
  1340  
  1341  	if(debug['g']) {
  1342  		print("\nsgen w=%lld\n", w);
  1343  		dump("r", n);
  1344  		dump("res", ns);
  1345  	}
  1346  
  1347  	if(n->ullman >= UINF && ns->ullman >= UINF)
  1348  		fatal("sgen UINF");
  1349  
  1350  	if(w < 0)
  1351  		fatal("sgen copy %lld", w);
  1352  
  1353  	// Avoid taking the address for simple enough types.
  1354  	if(componentgen(n, ns))
  1355  		return;
  1356  	
  1357  	if(w == 0) {
  1358  		// evaluate side effects only
  1359  		regalloc(&nodr, types[tptr], N);
  1360  		agen(ns, &nodr);
  1361  		agen(n, &nodr);
  1362  		regfree(&nodr);
  1363  		return;
  1364  	}
  1365  
  1366  	// offset on the stack
  1367  	osrc = stkof(n);
  1368  	odst = stkof(ns);
  1369  
  1370  	if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
  1371  		// osrc and odst both on stack, and at least one is in
  1372  		// an unknown position.  Could generate code to test
  1373  		// for forward/backward copy, but instead just copy
  1374  		// to a temporary location first.
  1375  		tempname(&tmp, n->type);
  1376  		sgen(n, &tmp, w);
  1377  		sgen(&tmp, ns, w);
  1378  		return;
  1379  	}
  1380  
  1381  	if(n->ullman >= ns->ullman) {
  1382  		agenr(n, &nodr, N);
  1383  		agenr(ns, &nodl, N);
  1384  	} else {
  1385  		agenr(ns, &nodl, N);
  1386  		agenr(n, &nodr, N);
  1387  	}
  1388  	nodreg(&noddi, types[tptr], D_DI);
  1389  	nodreg(&nodsi, types[tptr], D_SI);
  1390  	gmove(&nodl, &noddi);
  1391  	gmove(&nodr, &nodsi);
  1392  	regfree(&nodl);
  1393  	regfree(&nodr);
  1394  
  1395  	c = w % 8;	// bytes
  1396  	q = w / 8;	// quads
  1397  
  1398  	savex(D_CX, &cx, &oldcx, N, types[TINT64]);
  1399  
  1400  	// if we are copying forward on the stack and
  1401  	// the src and dst overlap, then reverse direction
  1402  	if(osrc < odst && odst < osrc+w) {
  1403  		// reverse direction
  1404  		gins(ASTD, N, N);		// set direction flag
  1405  		if(c > 0) {
  1406  			gconreg(AADDQ, w-1, D_SI);
  1407  			gconreg(AADDQ, w-1, D_DI);
  1408  
  1409  			gconreg(AMOVQ, c, D_CX);
  1410  			gins(AREP, N, N);	// repeat
  1411  			gins(AMOVSB, N, N);	// MOVB *(SI)-,*(DI)-
  1412  		}
  1413  
  1414  		if(q > 0) {
  1415  			if(c > 0) {
  1416  				gconreg(AADDQ, -7, D_SI);
  1417  				gconreg(AADDQ, -7, D_DI);
  1418  			} else {
  1419  				gconreg(AADDQ, w-8, D_SI);
  1420  				gconreg(AADDQ, w-8, D_DI);
  1421  			}
  1422  			gconreg(AMOVQ, q, D_CX);
  1423  			gins(AREP, N, N);	// repeat
  1424  			gins(AMOVSQ, N, N);	// MOVQ *(SI)-,*(DI)-
  1425  		}
  1426  		// we leave with the flag clear
  1427  		gins(ACLD, N, N);
  1428  	} else {
  1429  		// normal direction
  1430  		if(q >= 4) {
  1431  			gconreg(AMOVQ, q, D_CX);
  1432  			gins(AREP, N, N);	// repeat
  1433  			gins(AMOVSQ, N, N);	// MOVQ *(SI)+,*(DI)+
  1434  		} else
  1435  		while(q > 0) {
  1436  			gins(AMOVSQ, N, N);	// MOVQ *(SI)+,*(DI)+
  1437  			q--;
  1438  		}
  1439  
  1440  		if(c >= 4) {
  1441  			gins(AMOVSL, N, N);	// MOVL *(SI)+,*(DI)+
  1442  			c -= 4;
  1443  		}
  1444  		while(c > 0) {
  1445  			gins(AMOVSB, N, N);	// MOVB *(SI)+,*(DI)+
  1446  			c--;
  1447  		}
  1448  	}
  1449  
  1450  	restx(&cx, &oldcx);
  1451  }
  1452  
  1453  static int
  1454  cadable(Node *n)
  1455  {
  1456  	if(!n->addable) {
  1457  		// dont know how it happens,
  1458  		// but it does
  1459  		return 0;
  1460  	}
  1461  
  1462  	switch(n->op) {
  1463  	case ONAME:
  1464  		return 1;
  1465  	}
  1466  	return 0;
  1467  }
  1468  
  1469  /*
  1470   * copy a composite value by moving its individual components.
  1471   * Slices, strings and interfaces are supported.
  1472   * Small structs or arrays with elements of basic type are
  1473   * also supported.
  1474   * nr is N when assigning a zero value.
  1475   * return 1 if can do, 0 if can't.
  1476   */
  1477  int
  1478  componentgen(Node *nr, Node *nl)
  1479  {
  1480  	Node nodl, nodr;
  1481  	Type *t;
  1482  	int freel, freer;
  1483  	vlong fldcount;
  1484  	vlong loffset, roffset;
  1485  
  1486  	freel = 0;
  1487  	freer = 0;
  1488  
  1489  	switch(nl->type->etype) {
  1490  	default:
  1491  		goto no;
  1492  
  1493  	case TARRAY:
  1494  		t = nl->type;
  1495  
  1496  		// Slices are ok.
  1497  		if(isslice(t))
  1498  			break;
  1499  		// Small arrays are ok.
  1500  		if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
  1501  			break;
  1502  
  1503  		goto no;
  1504  
  1505  	case TSTRUCT:
  1506  		// Small structs with non-fat types are ok.
  1507  		// Zero-sized structs are treated separately elsewhere.
  1508  		fldcount = 0;
  1509  		for(t=nl->type->type; t; t=t->down) {
  1510  			if(isfat(t->type))
  1511  				goto no;
  1512  			if(t->etype != TFIELD)
  1513  				fatal("componentgen: not a TFIELD: %lT", t);
  1514  			fldcount++;
  1515  		}
  1516  		if(fldcount == 0 || fldcount > 3)
  1517  			goto no;
  1518  
  1519  		break;
  1520  
  1521  	case TSTRING:
  1522  	case TINTER:
  1523  		break;
  1524  	}
  1525  
  1526  	nodl = *nl;
  1527  	if(!cadable(nl)) {
  1528  		if(nr == N || !cadable(nr))
  1529  			goto no;
  1530  		igen(nl, &nodl, N);
  1531  		freel = 1;
  1532  	}
  1533  
  1534  	if(nr != N) {
  1535  		nodr = *nr;
  1536  		if(!cadable(nr)) {
  1537  			igen(nr, &nodr, N);
  1538  			freer = 1;
  1539  		}
  1540  	}
  1541  
  1542  	switch(nl->type->etype) {
  1543  	case TARRAY:
  1544  		// componentgen for arrays.
  1545  		t = nl->type;
  1546  		if(!isslice(t)) {
  1547  			nodl.type = t->type;
  1548  			nodr.type = nodl.type;
  1549  			for(fldcount=0; fldcount < t->bound; fldcount++) {
  1550  				if(nr == N)
  1551  					clearslim(&nodl);
  1552  				else
  1553  					gmove(&nodr, &nodl);
  1554  				nodl.xoffset += t->type->width;
  1555  				nodr.xoffset += t->type->width;
  1556  			}
  1557  			goto yes;
  1558  		}
  1559  
  1560  		// componentgen for slices.
  1561  		nodl.xoffset += Array_array;
  1562  		nodl.type = ptrto(nl->type->type);
  1563  
  1564  		if(nr != N) {
  1565  			nodr.xoffset += Array_array;
  1566  			nodr.type = nodl.type;
  1567  		} else
  1568  			nodconst(&nodr, nodl.type, 0);
  1569  		gmove(&nodr, &nodl);
  1570  
  1571  		nodl.xoffset += Array_nel-Array_array;
  1572  		nodl.type = types[simtype[TUINT]];
  1573  
  1574  		if(nr != N) {
  1575  			nodr.xoffset += Array_nel-Array_array;
  1576  			nodr.type = nodl.type;
  1577  		} else
  1578  			nodconst(&nodr, nodl.type, 0);
  1579  		gmove(&nodr, &nodl);
  1580  
  1581  		nodl.xoffset += Array_cap-Array_nel;
  1582  		nodl.type = types[simtype[TUINT]];
  1583  
  1584  		if(nr != N) {
  1585  			nodr.xoffset += Array_cap-Array_nel;
  1586  			nodr.type = nodl.type;
  1587  		} else
  1588  			nodconst(&nodr, nodl.type, 0);
  1589  		gmove(&nodr, &nodl);
  1590  
  1591  		goto yes;
  1592  
  1593  	case TSTRING:
  1594  		nodl.xoffset += Array_array;
  1595  		nodl.type = ptrto(types[TUINT8]);
  1596  
  1597  		if(nr != N) {
  1598  			nodr.xoffset += Array_array;
  1599  			nodr.type = nodl.type;
  1600  		} else
  1601  			nodconst(&nodr, nodl.type, 0);
  1602  		gmove(&nodr, &nodl);
  1603  
  1604  		nodl.xoffset += Array_nel-Array_array;
  1605  		nodl.type = types[simtype[TUINT]];
  1606  
  1607  		if(nr != N) {
  1608  			nodr.xoffset += Array_nel-Array_array;
  1609  			nodr.type = nodl.type;
  1610  		} else
  1611  			nodconst(&nodr, nodl.type, 0);
  1612  		gmove(&nodr, &nodl);
  1613  
  1614  		goto yes;
  1615  
  1616  	case TINTER:
  1617  		nodl.xoffset += Array_array;
  1618  		nodl.type = ptrto(types[TUINT8]);
  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 = ptrto(types[TUINT8]);
  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  		goto yes;
  1638  
  1639  	case TSTRUCT:
  1640  		loffset = nodl.xoffset;
  1641  		roffset = nodr.xoffset;
  1642  		// funarg structs may not begin at offset zero.
  1643  		if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
  1644  			loffset -= nl->type->type->width;
  1645  		if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
  1646  			roffset -= nr->type->type->width;
  1647  
  1648  		for(t=nl->type->type; t; t=t->down) {
  1649  			nodl.xoffset = loffset + t->width;
  1650  			nodl.type = t->type;
  1651  
  1652  			if(nr == N)
  1653  				clearslim(&nodl);
  1654  			else {
  1655  				nodr.xoffset = roffset + t->width;
  1656  				nodr.type = nodl.type;
  1657  				gmove(&nodr, &nodl);
  1658  			}
  1659  		}
  1660  		goto yes;
  1661  	}
  1662  
  1663  no:
  1664  	if(freer)
  1665  		regfree(&nodr);
  1666  	if(freel)
  1667  		regfree(&nodl);
  1668  	return 0;
  1669  
  1670  yes:
  1671  	if(freer)
  1672  		regfree(&nodr);
  1673  	if(freel)
  1674  		regfree(&nodl);
  1675  	return 1;
  1676  }