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