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