github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/5g/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, f0, f1;
    19  	int a, w, rg;
    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  	switch(n->op) {
    34  	case OSLICE:
    35  	case OSLICEARR:
    36  	case OSLICESTR:
    37  	case OSLICE3:
    38  	case OSLICE3ARR:
    39  		if (res->op != ONAME || !res->addable) {
    40  			tempname(&n1, n->type);
    41  			cgen_slice(n, &n1);
    42  			cgen(&n1, res);
    43  		} else
    44  			cgen_slice(n, res);
    45  		return;
    46  	case OEFACE:
    47  		if (res->op != ONAME || !res->addable) {
    48  			tempname(&n1, n->type);
    49  			cgen_eface(n, &n1);
    50  			cgen(&n1, res);
    51  		} else
    52  			cgen_eface(n, res);
    53  		return;
    54  	}
    55  
    56  	while(n->op == OCONVNOP)
    57  		n = n->left;
    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  
    78  	// update addressability for string, slice
    79  	// can't do in walk because n->left->addable
    80  	// changes if n->left is an escaping local variable.
    81  	switch(n->op) {
    82  	case OSPTR:
    83  	case OLEN:
    84  		if(isslice(n->left->type) || istype(n->left->type, TSTRING))
    85  			n->addable = n->left->addable;
    86  		break;
    87  	case OCAP:
    88  		if(isslice(n->left->type))
    89  			n->addable = n->left->addable;
    90  		break;
    91  	case OITAB:
    92  		n->addable = n->left->addable;
    93  		break;
    94  	}
    95  
    96  	// if both are addressable, move
    97  	if(n->addable && res->addable) {
    98  		if(is64(n->type) || is64(res->type) ||
    99  		   n->op == OREGISTER || res->op == OREGISTER ||
   100  		   iscomplex[n->type->etype] || iscomplex[res->type->etype]) {
   101  			gmove(n, res);
   102  		} else {
   103  			regalloc(&n1, n->type, N);
   104  			gmove(n, &n1);
   105  			cgen(&n1, res);
   106  			regfree(&n1);
   107  		}
   108  		goto ret;
   109  	}
   110  
   111  	// if both are not addressable, use a temporary.
   112  	if(!n->addable && !res->addable) {
   113  		// could use regalloc here sometimes,
   114  		// but have to check for ullman >= UINF.
   115  		tempname(&n1, n->type);
   116  		cgen(n, &n1);
   117  		cgen(&n1, res);
   118  		return;
   119  	}
   120  
   121  	// if result is not addressable directly but n is,
   122  	// compute its address and then store via the address.
   123  	if(!res->addable) {
   124  		igen(res, &n1, N);
   125  		cgen(n, &n1);
   126  		regfree(&n1);
   127  		return;
   128  	}
   129  
   130  	if(complexop(n, res)) {
   131  		complexgen(n, res);
   132  		return;
   133  	}
   134  
   135  	// if n is sudoaddable generate addr and move
   136  	if (!is64(n->type) && !is64(res->type) && !iscomplex[n->type->etype] && !iscomplex[res->type->etype]) {
   137  		a = optoas(OAS, n->type);
   138  		if(sudoaddable(a, n, &addr, &w)) {
   139  			if (res->op != OREGISTER) {
   140  				regalloc(&n2, res->type, N);
   141  				p1 = gins(a, N, &n2);
   142  				p1->from = addr;
   143  				if(debug['g'])
   144  					print("%P [ignore previous line]\n", p1);
   145  				gmove(&n2, res);
   146  				regfree(&n2);
   147  			} else {
   148  				p1 = gins(a, N, res);
   149  				p1->from = addr;
   150  				if(debug['g'])
   151  					print("%P [ignore previous line]\n", p1);
   152  			}
   153  			sudoclean();
   154  			goto ret;
   155  		}
   156  	}
   157  
   158  	// otherwise, the result is addressable but n is not.
   159  	// let's do some computation.
   160  
   161  	nl = n->left;
   162  	nr = n->right;
   163  
   164  	if(nl != N && nl->ullman >= UINF)
   165  	if(nr != N && nr->ullman >= UINF) {
   166  		tempname(&n1, nl->type);
   167  		cgen(nl, &n1);
   168  		n2 = *n;
   169  		n2.left = &n1;
   170  		cgen(&n2, res);
   171  		goto ret;
   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  		goto flt;
   196  	switch(n->op) {
   197  	default:
   198  		dump("cgen", n);
   199  		fatal("cgen: unknown op %+hN", n);
   200  		break;
   201  
   202  	case OREAL:
   203  	case OIMAG:
   204  	case OCOMPLEX:
   205  		fatal("unexpected complex");
   206  		break;
   207  
   208  	// these call bgen to get a bool value
   209  	case OOROR:
   210  	case OANDAND:
   211  	case OEQ:
   212  	case ONE:
   213  	case OLT:
   214  	case OLE:
   215  	case OGE:
   216  	case OGT:
   217  	case ONOT:
   218  		p1 = gbranch(AB, T, 0);
   219  		p2 = pc;
   220  		gmove(nodbool(1), res);
   221  		p3 = gbranch(AB, T, 0);
   222  		patch(p1, pc);
   223  		bgen(n, 1, 0, p2);
   224  		gmove(nodbool(0), res);
   225  		patch(p3, pc);
   226  		goto ret;
   227  
   228  	case OPLUS:
   229  		cgen(nl, res);
   230  		goto ret;
   231  
   232  	// unary
   233  	case OCOM:
   234  		a = optoas(OXOR, nl->type);
   235  		regalloc(&n1, nl->type, N);
   236  		cgen(nl, &n1);
   237  		nodconst(&n2, nl->type, -1);
   238  		gins(a, &n2, &n1);
   239  		gmove(&n1, res);
   240  		regfree(&n1);
   241  		goto ret;
   242  
   243  	case OMINUS:
   244  		regalloc(&n1, nl->type, N);
   245  		cgen(nl, &n1);
   246  		nodconst(&n2, nl->type, 0);
   247  		gins(optoas(OMINUS, nl->type), &n2, &n1);
   248  		gmove(&n1, res);
   249  		regfree(&n1);
   250  		goto ret;
   251  
   252  	// symmetric binary
   253  	case OAND:
   254  	case OOR:
   255  	case OXOR:
   256  	case OADD:
   257  	case OADDPTR:
   258  	case OMUL:
   259  		a = optoas(n->op, nl->type);
   260  		goto sbop;
   261  
   262  	// asymmetric binary
   263  	case OSUB:
   264  		a = optoas(n->op, nl->type);
   265  		goto abop;
   266  
   267  	case OHMUL:
   268  		cgen_hmul(nl, nr, res);
   269  		break;
   270  
   271  	case OLROT:
   272  	case OLSH:
   273  	case ORSH:
   274  		cgen_shift(n->op, n->bounded, nl, nr, res);
   275  		break;
   276  
   277  	case OCONV:
   278  		if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
   279  			cgen(nl, res);
   280  			break;
   281  		}
   282  		if(nl->addable && !is64(nl->type)) {
   283  			regalloc(&n1, nl->type, res);
   284  			gmove(nl, &n1);
   285  		} else {
   286  			if(n->type->width > widthptr || is64(nl->type) || isfloat[nl->type->etype])
   287  				tempname(&n1, nl->type);
   288  			else
   289  				regalloc(&n1, nl->type, res);
   290  			cgen(nl, &n1);
   291  		}
   292  		if(n->type->width > widthptr || is64(n->type) || isfloat[n->type->etype])
   293  			tempname(&n2, n->type);
   294  		else
   295  			regalloc(&n2, n->type, N);
   296  		gmove(&n1, &n2);
   297  		gmove(&n2, res);
   298  		if(n1.op == OREGISTER)
   299  			regfree(&n1);
   300  		if(n2.op == OREGISTER)
   301  			regfree(&n2);
   302  		break;
   303  
   304  	case ODOT:
   305  	case ODOTPTR:
   306  	case OINDEX:
   307  	case OIND:
   308  	case ONAME:	// PHEAP or PPARAMREF var
   309  		igen(n, &n1, res);
   310  		gmove(&n1, res);
   311  		regfree(&n1);
   312  		break;
   313  
   314  	case OITAB:
   315  		// interface table is first word of interface value
   316  		igen(nl, &n1, res);
   317  		n1.type = n->type;
   318  		gmove(&n1, res);
   319  		regfree(&n1);
   320  		break;
   321  
   322  	case OSPTR:
   323  		// pointer is the first word of string or slice.
   324  		if(isconst(nl, CTSTR)) {
   325  			regalloc(&n1, types[tptr], res);
   326  			p1 = gins(AMOVW, N, &n1);
   327  			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
   328  			gmove(&n1, res);
   329  			regfree(&n1);
   330  			break;
   331  		}
   332  		igen(nl, &n1, res);
   333  		n1.type = n->type;
   334  		gmove(&n1, res);
   335  		regfree(&n1);
   336  		break;
   337  
   338  	case OLEN:
   339  		if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
   340  			// map has len in the first 32-bit word.
   341  			// a zero pointer means zero length
   342  			regalloc(&n1, types[tptr], res);
   343  			cgen(nl, &n1);
   344  
   345  			nodconst(&n2, types[tptr], 0);
   346  			gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
   347  			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
   348  
   349  			n2 = n1;
   350  			n2.op = OINDREG;
   351  			n2.type = types[TINT32];
   352  			gmove(&n2, &n1);
   353  
   354  			patch(p1, pc);
   355  
   356  			gmove(&n1, res);
   357  			regfree(&n1);
   358  			break;
   359  		}
   360  		if(istype(nl->type, TSTRING) || isslice(nl->type)) {
   361  			// both slice and string have len one pointer into the struct.
   362  			igen(nl, &n1, res);
   363  			n1.type = types[TUINT32];
   364  			n1.xoffset += Array_nel;
   365  			gmove(&n1, res);
   366  			regfree(&n1);
   367  			break;
   368  		}
   369  		fatal("cgen: OLEN: unknown type %lT", nl->type);
   370  		break;
   371  
   372  	case OCAP:
   373  		if(istype(nl->type, TCHAN)) {
   374  			// chan has cap in the second 32-bit word.
   375  			// a zero pointer means zero length
   376  			regalloc(&n1, types[tptr], res);
   377  			cgen(nl, &n1);
   378  
   379  			nodconst(&n2, types[tptr], 0);
   380  			gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
   381  			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
   382  
   383  			n2 = n1;
   384  			n2.op = OINDREG;
   385  			n2.xoffset = 4;
   386  			n2.type = types[TINT32];
   387  			gmove(&n2, &n1);
   388  
   389  			patch(p1, pc);
   390  
   391  			gmove(&n1, res);
   392  			regfree(&n1);
   393  			break;
   394  		}
   395  		if(isslice(nl->type)) {
   396  			igen(nl, &n1, res);
   397  			n1.type = types[TUINT32];
   398  			n1.xoffset += Array_cap;
   399  			gmove(&n1, res);
   400  			regfree(&n1);
   401  			break;
   402  		}
   403  		fatal("cgen: OCAP: unknown type %lT", nl->type);
   404  		break;
   405  
   406  	case OADDR:
   407  		agen(nl, res);
   408  		break;
   409  
   410  	case OCALLMETH:
   411  	case OCALLFUNC:
   412  		// Release res so that it is available for cgen_call.
   413  		// Pick it up again after the call.
   414  		rg = -1;
   415  		if(n->ullman >= UINF) {
   416  			if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
   417  				rg = res->val.u.reg;
   418  				reg[rg]--;
   419  			}
   420  		}
   421  		if(n->op == OCALLMETH)
   422  			cgen_callmeth(n, 0);
   423  		else
   424  			cgen_call(n, 0);
   425  		if(rg >= 0)
   426  			reg[rg]++;
   427  		cgen_callret(n, res);
   428  		break;
   429  
   430  	case OCALLINTER:
   431  		cgen_callinter(n, res, 0);
   432  		cgen_callret(n, res);
   433  		break;
   434  
   435  	case OMOD:
   436  	case ODIV:
   437  		a = optoas(n->op, nl->type);
   438  		goto abop;
   439  	}
   440  	goto ret;
   441  
   442  sbop:	// symmetric binary
   443  	if(nl->ullman < nr->ullman) {
   444  		r = nl;
   445  		nl = nr;
   446  		nr = r;
   447  	}
   448  
   449  abop:	// asymmetric binary
   450  	// TODO(kaib): use fewer registers here.
   451  	if(nl->ullman >= nr->ullman) {
   452  		regalloc(&n1, nl->type, res);
   453  		cgen(nl, &n1);
   454  		switch(n->op) {
   455  		case OADD:
   456  		case OSUB:
   457  		case OAND:
   458  		case OOR:
   459  		case OXOR:
   460  			if(smallintconst(nr)) {
   461  				n2 = *nr;
   462  				break;
   463  			}
   464  		default:
   465  			regalloc(&n2, nr->type, N);
   466  			cgen(nr, &n2);
   467  		}
   468  	} else {
   469  		switch(n->op) {
   470  		case OADD:
   471  		case OSUB:
   472  		case OAND:
   473  		case OOR:
   474  		case OXOR:
   475  			if(smallintconst(nr)) {
   476  				n2 = *nr;
   477  				break;
   478  			}
   479  		default:
   480  			regalloc(&n2, nr->type, res);
   481  			cgen(nr, &n2);
   482  		}
   483  		regalloc(&n1, nl->type, N);
   484  		cgen(nl, &n1);
   485  	}
   486  	gins(a, &n2, &n1);
   487  	// Normalize result for types smaller than word.
   488  	if(n->type->width < widthptr) {
   489  		switch(n->op) {
   490  		case OADD:
   491  		case OSUB:
   492  		case OMUL:
   493  			gins(optoas(OAS, n->type), &n1, &n1);
   494  			break;
   495  		}
   496  	}
   497  	gmove(&n1, res);
   498  	regfree(&n1);
   499  	if(n2.op != OLITERAL)
   500  		regfree(&n2);
   501  	goto ret;
   502  
   503  flt:	// floating-point.
   504  	regalloc(&f0, nl->type, res);
   505  	if(nr != N)
   506  		goto flt2;
   507  
   508  	if(n->op == OMINUS) {
   509  		nr = nodintconst(-1);
   510  		convlit(&nr, n->type);
   511  		n->op = OMUL;
   512  		goto flt2;
   513  	}
   514  
   515  	// unary
   516  	cgen(nl, &f0);
   517  	if(n->op != OCONV && n->op != OPLUS)
   518  		gins(optoas(n->op, n->type), &f0, &f0);
   519  	gmove(&f0, res);
   520  	regfree(&f0);
   521  	goto ret;
   522  
   523  flt2:	// binary
   524  	if(nl->ullman >= nr->ullman) {
   525  		cgen(nl, &f0);
   526  		regalloc(&f1, n->type, N);
   527  		gmove(&f0, &f1);
   528  		cgen(nr, &f0);
   529  		gins(optoas(n->op, n->type), &f0, &f1);
   530  	} else {
   531  		cgen(nr, &f0);
   532  		regalloc(&f1, n->type, N);
   533  		cgen(nl, &f1);
   534  		gins(optoas(n->op, n->type), &f0, &f1);
   535  	}
   536  	gmove(&f1, res);
   537  	regfree(&f0);
   538  	regfree(&f1);
   539  	goto ret;
   540  
   541  ret:
   542  	;
   543  }
   544  
   545  /*
   546   * generate array index into res.
   547   * n might be any size; res is 32-bit.
   548   * returns Prog* to patch to panic call.
   549   */
   550  Prog*
   551  cgenindex(Node *n, Node *res, int bounded)
   552  {
   553  	Node tmp, lo, hi, zero, n1, n2;
   554  
   555  	if(!is64(n->type)) {
   556  		cgen(n, res);
   557  		return nil;
   558  	}
   559  
   560  	tempname(&tmp, types[TINT64]);
   561  	cgen(n, &tmp);
   562  	split64(&tmp, &lo, &hi);
   563  	gmove(&lo, res);
   564  	if(bounded) {
   565  		splitclean();
   566  		return nil;
   567  	}
   568  	regalloc(&n1, types[TINT32], N);
   569  	regalloc(&n2, types[TINT32], N);
   570  	nodconst(&zero, types[TINT32], 0);
   571  	gmove(&hi, &n1);
   572  	gmove(&zero, &n2);
   573  	gcmp(ACMP, &n1, &n2);
   574  	regfree(&n2);
   575  	regfree(&n1);
   576  	splitclean();
   577  	return gbranch(ABNE, T, -1);
   578  }
   579  
   580  /*
   581   * generate:
   582   *	res = &n;
   583   * The generated code checks that the result is not nil.
   584   */
   585  void
   586  agen(Node *n, Node *res)
   587  {
   588  	Node *nl;
   589  	Node n1, n2, n3;
   590  	int r;
   591  
   592  	if(debug['g']) {
   593  		dump("\nagen-res", res);
   594  		dump("agen-r", n);
   595  	}
   596  	if(n == N || n->type == T || res == N || res->type == T)
   597  		fatal("agen");
   598  
   599  	while(n->op == OCONVNOP)
   600  		n = n->left;
   601  
   602  	if(isconst(n, CTNIL) && n->type->width > widthptr) {
   603  		// Use of a nil interface or nil slice.
   604  		// Create a temporary we can take the address of and read.
   605  		// The generated code is just going to panic, so it need not
   606  		// be terribly efficient. See issue 3670.
   607  		tempname(&n1, n->type);
   608  		gvardef(&n1);
   609  		clearfat(&n1);
   610  		regalloc(&n2, types[tptr], res);
   611  		gins(AMOVW, &n1, &n2);
   612  		gmove(&n2, res);
   613  		regfree(&n2);
   614  		goto ret;
   615  	}
   616  		
   617  
   618  	if(n->addable) {
   619  		memset(&n1, 0, sizeof n1);
   620  		n1.op = OADDR;
   621  		n1.left = n;
   622  		regalloc(&n2, types[tptr], res);
   623  		gins(AMOVW, &n1, &n2);
   624  		gmove(&n2, res);
   625  		regfree(&n2);
   626  		goto ret;
   627  	}
   628  
   629  	nl = n->left;
   630  
   631  	switch(n->op) {
   632  	default:
   633  		fatal("agen: unknown op %+hN", n);
   634  		break;
   635  
   636  	case OCALLMETH:
   637  	case OCALLFUNC:
   638  		// Release res so that it is available for cgen_call.
   639  		// Pick it up again after the call.
   640  		r = -1;
   641  		if(n->ullman >= UINF) {
   642  			if(res->op == OREGISTER || res->op == OINDREG) {
   643  				r = res->val.u.reg;
   644  				reg[r]--;
   645  			}
   646  		}
   647  		if(n->op == OCALLMETH)
   648  			cgen_callmeth(n, 0);
   649  		else
   650  			cgen_call(n, 0);
   651  		if(r >= 0)
   652  			reg[r]++;
   653  		cgen_aret(n, res);
   654  		break;
   655  
   656  	case OCALLINTER:
   657  		cgen_callinter(n, res, 0);
   658  		cgen_aret(n, res);
   659  		break;
   660  
   661  	case OSLICE:
   662  	case OSLICEARR:
   663  	case OSLICESTR:
   664  	case OSLICE3:
   665  	case OSLICE3ARR:
   666  		tempname(&n1, n->type);
   667  		cgen_slice(n, &n1);
   668  		agen(&n1, res);
   669  		break;
   670  
   671  	case OEFACE:
   672  		tempname(&n1, n->type);
   673  		cgen_eface(n, &n1);
   674  		agen(&n1, res);
   675  		break;
   676  
   677  	case OINDEX:
   678  		agenr(n, &n1, res);
   679  		gmove(&n1, res);
   680  		regfree(&n1);
   681  		break;
   682  
   683  	case ONAME:
   684  		// should only get here with names in this func.
   685  		if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
   686  			dump("bad agen", n);
   687  			fatal("agen: bad ONAME funcdepth %d != %d",
   688  				n->funcdepth, funcdepth);
   689  		}
   690  
   691  		// should only get here for heap vars or paramref
   692  		if(!(n->class & PHEAP) && n->class != PPARAMREF) {
   693  			dump("bad agen", n);
   694  			fatal("agen: bad ONAME class %#x", n->class);
   695  		}
   696  		cgen(n->heapaddr, res);
   697  		if(n->xoffset != 0) {
   698  			nodconst(&n1, types[TINT32], n->xoffset);
   699  			regalloc(&n2, n1.type, N);
   700  			regalloc(&n3, types[TINT32], N);
   701  			gmove(&n1, &n2);
   702  			gmove(res, &n3);
   703  			gins(optoas(OADD, types[tptr]), &n2, &n3);
   704  			gmove(&n3, res);
   705  			regfree(&n2);
   706  			regfree(&n3);
   707  		}
   708  		break;
   709  
   710  	case OIND:
   711  		cgen(nl, res);
   712  		cgen_checknil(res);
   713  		break;
   714  
   715  	case ODOT:
   716  		agen(nl, res);
   717  		if(n->xoffset != 0) {
   718  			nodconst(&n1, types[TINT32], n->xoffset);
   719  			regalloc(&n2, n1.type, N);
   720  			regalloc(&n3, types[TINT32], N);
   721  			gmove(&n1, &n2);
   722  			gmove(res, &n3);
   723  			gins(optoas(OADD, types[tptr]), &n2, &n3);
   724  			gmove(&n3, res);
   725  			regfree(&n2);
   726  			regfree(&n3);
   727  		}
   728  		break;
   729  
   730  	case ODOTPTR:
   731  		cgen(nl, res);
   732  		cgen_checknil(res);
   733  		if(n->xoffset != 0) {
   734  			nodconst(&n1, types[TINT32], n->xoffset);
   735  			regalloc(&n2, n1.type, N);
   736  			regalloc(&n3, types[tptr], N);
   737  			gmove(&n1, &n2);
   738  			gmove(res, &n3);
   739  			gins(optoas(OADD, types[tptr]), &n2, &n3);
   740  			gmove(&n3, res);
   741  			regfree(&n2);
   742  			regfree(&n3);
   743  		}
   744  		break;
   745  	}
   746  
   747  ret:
   748  	;
   749  }
   750  
   751  /*
   752   * generate:
   753   *	newreg = &n;
   754   *	res = newreg
   755   *
   756   * on exit, a has been changed to be *newreg.
   757   * caller must regfree(a).
   758   * The generated code checks that the result is not *nil.
   759   */
   760  void
   761  igen(Node *n, Node *a, Node *res)
   762  {
   763  	Node n1;
   764  	int r;
   765  
   766  	if(debug['g']) {
   767  		dump("\nigen-n", n);
   768  	}
   769  	switch(n->op) {
   770  	case ONAME:
   771  		if((n->class&PHEAP) || n->class == PPARAMREF)
   772  			break;
   773  		*a = *n;
   774  		return;
   775  
   776  	case OINDREG:
   777  		// Increase the refcount of the register so that igen's caller
   778  		// has to call regfree.
   779  		if(n->val.u.reg != REGSP)
   780  			reg[n->val.u.reg]++;
   781  		*a = *n;
   782  		return;
   783  
   784  	case ODOT:
   785  		igen(n->left, a, res);
   786  		a->xoffset += n->xoffset;
   787  		a->type = n->type;
   788  		return;
   789  
   790  	case ODOTPTR:
   791  		if(n->left->addable
   792  			|| n->left->op == OCALLFUNC
   793  			|| n->left->op == OCALLMETH
   794  			|| n->left->op == OCALLINTER) {
   795  			// igen-able nodes.
   796  			igen(n->left, &n1, res);
   797  			regalloc(a, types[tptr], &n1);
   798  			gmove(&n1, a);
   799  			regfree(&n1);
   800  		} else {
   801  			regalloc(a, types[tptr], res);
   802  			cgen(n->left, a);
   803  		}
   804  		cgen_checknil(a);
   805  		a->op = OINDREG;
   806  		a->xoffset = n->xoffset;
   807  		a->type = n->type;
   808  		return;
   809  
   810  	case OCALLMETH:
   811  	case OCALLFUNC:
   812  	case OCALLINTER:
   813  		// Release res so that it is available for cgen_call.
   814  		// Pick it up again after the call.
   815  		r = -1;
   816  		if(n->ullman >= UINF) {
   817  			if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
   818  				r = res->val.u.reg;
   819  				reg[r]--;
   820  			}
   821  		}
   822  		switch(n->op) {
   823  		case OCALLMETH:
   824  			cgen_callmeth(n, 0);
   825  			break;
   826  		case OCALLFUNC:
   827  			cgen_call(n, 0);
   828  			break;
   829  		case OCALLINTER:
   830  			cgen_callinter(n, N, 0);
   831  			break;
   832  		}
   833  		if(r >= 0)
   834  			reg[r]++;
   835  		regalloc(a, types[tptr], res);
   836  		cgen_aret(n, a);
   837  		a->op = OINDREG;
   838  		a->type = n->type;
   839  		return;
   840  	}
   841  
   842  	agenr(n, a, res);
   843  	a->op = OINDREG;
   844  	a->type = n->type;
   845  }
   846  
   847  /*
   848   * allocate a register in res and generate
   849   *  newreg = &n
   850   * The caller must call regfree(a).
   851   */
   852  void
   853  cgenr(Node *n, Node *a, Node *res)
   854  {
   855  	Node n1;
   856  
   857  	if(debug['g'])
   858  		dump("cgenr-n", n);
   859  
   860  	if(isfat(n->type))
   861  		fatal("cgenr on fat node");
   862  
   863  	if(n->addable) {
   864  		regalloc(a, types[tptr], res);
   865  		gmove(n, a);
   866  		return;
   867  	}
   868  
   869  	switch(n->op) {
   870  	case ONAME:
   871  	case ODOT:
   872  	case ODOTPTR:
   873  	case OINDEX:
   874  	case OCALLFUNC:
   875  	case OCALLMETH:
   876  	case OCALLINTER:
   877  		igen(n, &n1, res);
   878  		regalloc(a, types[tptr], &n1);
   879  		gmove(&n1, a);
   880  		regfree(&n1);
   881  		break;
   882  	default:
   883  		regalloc(a, n->type, res);
   884  		cgen(n, a);
   885  		break;
   886  	}
   887  }
   888  
   889  /*
   890   * generate:
   891   *	newreg = &n;
   892   *
   893   * caller must regfree(a).
   894   * The generated code checks that the result is not nil.
   895   */
   896  void
   897  agenr(Node *n, Node *a, Node *res)
   898  {
   899  	Node *nl, *nr;
   900  	Node n1, n2, n3, n4, tmp;
   901  	Prog *p1, *p2;
   902  	uint32 w;
   903  	uint64 v;
   904  	int bounded;
   905  
   906  	if(debug['g'])
   907  		dump("agenr-n", n);
   908  
   909  	nl = n->left;
   910  	nr = n->right;
   911  
   912  	switch(n->op) {
   913  	case ODOT:
   914  	case ODOTPTR:
   915  	case OCALLFUNC:
   916  	case OCALLMETH:
   917  	case OCALLINTER:
   918  		igen(n, &n1, res);
   919  		regalloc(a, types[tptr], &n1);
   920  		agen(&n1, a);
   921  		regfree(&n1);
   922  		break;
   923  
   924  	case OIND:
   925  		cgenr(n->left, a, res);
   926  		cgen_checknil(a);
   927  		break;
   928  
   929  	case OINDEX:
   930  		p2 = nil;  // to be patched to panicindex.
   931  		w = n->type->width;
   932  		bounded = debug['B'] || n->bounded;
   933  		if(nr->addable) {
   934  			if(!isconst(nr, CTINT))
   935  				tempname(&tmp, types[TINT32]);
   936  			if(!isconst(nl, CTSTR))
   937  				agenr(nl, &n3, res);
   938  			if(!isconst(nr, CTINT)) {
   939  				p2 = cgenindex(nr, &tmp, bounded);
   940  				regalloc(&n1, tmp.type, N);
   941  				gmove(&tmp, &n1);
   942  			}
   943  		} else
   944  		if(nl->addable) {
   945  			if(!isconst(nr, CTINT)) {
   946  				tempname(&tmp, types[TINT32]);
   947  				p2 = cgenindex(nr, &tmp, bounded);
   948  				regalloc(&n1, tmp.type, N);
   949  				gmove(&tmp, &n1);
   950  			}
   951  			if(!isconst(nl, CTSTR)) {
   952  				agenr(nl, &n3, res);
   953  			}
   954  		} else {
   955  			tempname(&tmp, types[TINT32]);
   956  			p2 = cgenindex(nr, &tmp, bounded);
   957  			nr = &tmp;
   958  			if(!isconst(nl, CTSTR))
   959  				agenr(nl, &n3, res);
   960  			regalloc(&n1, tmp.type, N);
   961  			gins(optoas(OAS, tmp.type), &tmp, &n1);
   962  		}
   963  
   964  		// &a is in &n3 (allocated in res)
   965  		// i is in &n1 (if not constant)
   966  		// w is width
   967  
   968  		// constant index
   969  		if(isconst(nr, CTINT)) {
   970  			if(isconst(nl, CTSTR))
   971  				fatal("constant string constant index");
   972  			v = mpgetfix(nr->val.u.xval);
   973  			if(isslice(nl->type) || nl->type->etype == TSTRING) {
   974  				if(!debug['B'] && !n->bounded) {
   975  					n1 = n3;
   976  					n1.op = OINDREG;
   977  					n1.type = types[tptr];
   978  					n1.xoffset = Array_nel;
   979  					regalloc(&n4, n1.type, N);
   980  					gmove(&n1, &n4);
   981  					nodconst(&n2, types[TUINT32], v);
   982  					gcmp(optoas(OCMP, types[TUINT32]), &n4, &n2);
   983  					regfree(&n4);
   984  					p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
   985  					ginscall(panicindex, 0);
   986  					patch(p1, pc);
   987  				}
   988  
   989  				n1 = n3;
   990  				n1.op = OINDREG;
   991  				n1.type = types[tptr];
   992  				n1.xoffset = Array_array;
   993  				gmove(&n1, &n3);
   994  			}
   995  
   996  			nodconst(&n2, types[tptr], v*w);
   997  			gins(optoas(OADD, types[tptr]), &n2, &n3);
   998  			*a = n3;
   999  			break;
  1000  		}
  1001  
  1002  		regalloc(&n2, types[TINT32], &n1);			// i
  1003  		gmove(&n1, &n2);
  1004  		regfree(&n1);
  1005  
  1006  		if(!debug['B'] && !n->bounded) {
  1007  			// check bounds
  1008  			if(isconst(nl, CTSTR)) {
  1009  				nodconst(&n4, types[TUINT32], nl->val.u.sval->len);
  1010  			} else if(isslice(nl->type) || nl->type->etype == TSTRING) {
  1011  				n1 = n3;
  1012  				n1.op = OINDREG;
  1013  				n1.type = types[tptr];
  1014  				n1.xoffset = Array_nel;
  1015  				regalloc(&n4, types[TUINT32], N);
  1016  				gmove(&n1, &n4);
  1017  			} else {
  1018  				nodconst(&n4, types[TUINT32], nl->type->bound);
  1019  			}
  1020  			gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
  1021  			if(n4.op == OREGISTER)
  1022  				regfree(&n4);
  1023  			p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
  1024  			if(p2)
  1025  				patch(p2, pc);
  1026  			ginscall(panicindex, 0);
  1027  			patch(p1, pc);
  1028  		}
  1029  		
  1030  		if(isconst(nl, CTSTR)) {
  1031  			regalloc(&n3, types[tptr], res);
  1032  			p1 = gins(AMOVW, N, &n3);
  1033  			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
  1034  			p1->from.type = D_CONST;
  1035  		} else
  1036  		if(isslice(nl->type) || nl->type->etype == TSTRING) {
  1037  			n1 = n3;
  1038  			n1.op = OINDREG;
  1039  			n1.type = types[tptr];
  1040  			n1.xoffset = Array_array;
  1041  			gmove(&n1, &n3);
  1042  		}
  1043  
  1044  		if(w == 0) {
  1045  			// nothing to do
  1046  		} else if(w == 1 || w == 2 || w == 4 || w == 8) {
  1047  			memset(&n4, 0, sizeof n4);
  1048  			n4.op = OADDR;
  1049  			n4.left = &n2;
  1050  			cgen(&n4, &n3);
  1051  			if (w == 1)
  1052  				gins(AADD, &n2, &n3);
  1053  			else if(w == 2)
  1054  				gshift(AADD, &n2, SHIFT_LL, 1, &n3);
  1055  			else if(w == 4)
  1056  				gshift(AADD, &n2, SHIFT_LL, 2, &n3);
  1057  			else if(w == 8)
  1058  				gshift(AADD, &n2, SHIFT_LL, 3, &n3);
  1059  		} else {
  1060  			regalloc(&n4, types[TUINT32], N);
  1061  			nodconst(&n1, types[TUINT32], w);
  1062  			gmove(&n1, &n4);
  1063  			gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
  1064  			gins(optoas(OADD, types[tptr]), &n2, &n3);
  1065  			regfree(&n4);
  1066  		}
  1067  
  1068  		*a = n3;
  1069  		regfree(&n2);
  1070  		break;
  1071  
  1072  	default:
  1073  		regalloc(a, types[tptr], res);
  1074  		agen(n, a);
  1075  		break;
  1076  	}
  1077  }
  1078  
  1079  void
  1080  gencmp0(Node *n, Type *t, int o, int likely, Prog *to)
  1081  {
  1082  	Node n1, n2, n3;
  1083  	int a;
  1084  
  1085  	regalloc(&n1, t, N);
  1086  	cgen(n, &n1);
  1087  	a = optoas(OCMP, t);
  1088  	if(a != ACMP) {
  1089  		nodconst(&n2, t, 0);
  1090  		regalloc(&n3, t, N);
  1091  		gmove(&n2, &n3);
  1092  		gcmp(a, &n1, &n3);
  1093  		regfree(&n3);
  1094  	} else
  1095  		gins(ATST, &n1, N);
  1096  	a = optoas(o, t);
  1097  	patch(gbranch(a, t, likely), to);
  1098  	regfree(&n1);
  1099  }
  1100  
  1101  /*
  1102   * generate:
  1103   *	if(n == true) goto to;
  1104   */
  1105  void
  1106  bgen(Node *n, int true, int likely, Prog *to)
  1107  {
  1108  	int et, a;
  1109  	Node *nl, *nr, *r;
  1110  	Node n1, n2, n3, n4, tmp;
  1111  	NodeList *ll;
  1112  	Prog *p1, *p2;
  1113  
  1114  	USED(n4);			// in unreachable code below
  1115  	if(debug['g']) {
  1116  		dump("\nbgen", n);
  1117  	}
  1118  
  1119  	if(n == N)
  1120  		n = nodbool(1);
  1121  
  1122  	if(n->ninit != nil)
  1123  		genlist(n->ninit);
  1124  
  1125  	if(n->type == T) {
  1126  		convlit(&n, types[TBOOL]);
  1127  		if(n->type == T)
  1128  			goto ret;
  1129  	}
  1130  
  1131  	et = n->type->etype;
  1132  	if(et != TBOOL) {
  1133  		yyerror("cgen: bad type %T for %O", n->type, n->op);
  1134  		patch(gins(AEND, N, N), to);
  1135  		goto ret;
  1136  	}
  1137  	nr = N;
  1138  
  1139  	switch(n->op) {
  1140  	default:
  1141  		a = ONE;
  1142  		if(!true)
  1143  			a = OEQ;
  1144  		gencmp0(n, n->type, a, likely, to);
  1145  		goto ret;
  1146  
  1147  	case OLITERAL:
  1148  		// need to ask if it is bool?
  1149  		if(!true == !n->val.u.bval)
  1150  			patch(gbranch(AB, T, 0), to);
  1151  		goto ret;
  1152  
  1153  	case OANDAND:
  1154  		if(!true)
  1155  			goto caseor;
  1156  
  1157  	caseand:
  1158  		p1 = gbranch(AB, T, 0);
  1159  		p2 = gbranch(AB, T, 0);
  1160  		patch(p1, pc);
  1161  		bgen(n->left, !true, -likely, p2);
  1162  		bgen(n->right, !true, -likely, p2);
  1163  		p1 = gbranch(AB, T, 0);
  1164  		patch(p1, to);
  1165  		patch(p2, pc);
  1166  		goto ret;
  1167  
  1168  	case OOROR:
  1169  		if(!true)
  1170  			goto caseand;
  1171  
  1172  	caseor:
  1173  		bgen(n->left, true, likely, to);
  1174  		bgen(n->right, true, likely, to);
  1175  		goto ret;
  1176  
  1177  	case OEQ:
  1178  	case ONE:
  1179  	case OLT:
  1180  	case OGT:
  1181  	case OLE:
  1182  	case OGE:
  1183  		nr = n->right;
  1184  		if(nr == N || nr->type == T)
  1185  			goto ret;
  1186  
  1187  	case ONOT:	// unary
  1188  		nl = n->left;
  1189  		if(nl == N || nl->type == T)
  1190  			goto ret;
  1191  	}
  1192  
  1193  	switch(n->op) {
  1194  
  1195  	case ONOT:
  1196  		bgen(nl, !true, likely, to);
  1197  		goto ret;
  1198  
  1199  	case OEQ:
  1200  	case ONE:
  1201  	case OLT:
  1202  	case OGT:
  1203  	case OLE:
  1204  	case OGE:
  1205  		a = n->op;
  1206  		if(!true) {
  1207  			if(isfloat[nl->type->etype]) {
  1208  				// brcom is not valid on floats when NaN is involved.
  1209  				p1 = gbranch(AB, T, 0);
  1210  				p2 = gbranch(AB, T, 0);
  1211  				patch(p1, pc);
  1212  				ll = n->ninit;
  1213  				n->ninit = nil;
  1214  				bgen(n, 1, -likely, p2);
  1215  				n->ninit = ll;
  1216  				patch(gbranch(AB, T, 0), to);
  1217  				patch(p2, pc);
  1218  				goto ret;
  1219  			}				
  1220  			a = brcom(a);
  1221  			true = !true;
  1222  		}
  1223  
  1224  		// make simplest on right
  1225  		if(nl->op == OLITERAL || (nl->ullman < UINF && nl->ullman < nr->ullman)) {
  1226  			a = brrev(a);
  1227  			r = nl;
  1228  			nl = nr;
  1229  			nr = r;
  1230  		}
  1231  
  1232  		if(isslice(nl->type)) {
  1233  			// only valid to cmp darray to literal nil
  1234  			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
  1235  				yyerror("illegal array comparison");
  1236  				break;
  1237  			}
  1238  
  1239  			igen(nl, &n1, N);
  1240  			n1.xoffset += Array_array;
  1241  			n1.type = types[tptr];
  1242  			gencmp0(&n1, types[tptr], a, likely, to);
  1243  			regfree(&n1);
  1244  			break;
  1245  		}
  1246  
  1247  		if(isinter(nl->type)) {
  1248  			// front end shold only leave cmp to literal nil
  1249  			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
  1250  				yyerror("illegal interface comparison");
  1251  				break;
  1252  			}
  1253  
  1254  			igen(nl, &n1, N);
  1255  			n1.type = types[tptr];
  1256  			n1.xoffset += 0;
  1257  			gencmp0(&n1, types[tptr], a, likely, to);
  1258  			regfree(&n1);
  1259  			break;
  1260  		}
  1261  
  1262  		if(iscomplex[nl->type->etype]) {
  1263  			complexbool(a, nl, nr, true, likely, to);
  1264  			break;
  1265  		}
  1266  
  1267  		if(is64(nr->type)) {
  1268  			if(!nl->addable) {
  1269  				tempname(&n1, nl->type);
  1270  				cgen(nl, &n1);
  1271  				nl = &n1;
  1272  			}
  1273  			if(!nr->addable) {
  1274  				tempname(&n2, nr->type);
  1275  				cgen(nr, &n2);
  1276  				nr = &n2;
  1277  			}
  1278  			cmp64(nl, nr, a, likely, to);
  1279  			break;
  1280  		}
  1281  
  1282  		if(nr->op == OLITERAL) {
  1283  			if(isconst(nr, CTINT) &&  mpgetfix(nr->val.u.xval) == 0) {
  1284  				gencmp0(nl, nl->type, a, likely, to);
  1285  				break;
  1286  			}
  1287  			if(nr->val.ctype == CTNIL) {
  1288  				gencmp0(nl, nl->type, a, likely, to);
  1289  				break;
  1290  			}
  1291  		}
  1292  
  1293  		a = optoas(a, nr->type);
  1294  
  1295  		if(nr->ullman >= UINF) {
  1296  			regalloc(&n1, nl->type, N);
  1297  			cgen(nl, &n1);
  1298  
  1299  			tempname(&tmp, nl->type);
  1300  			gmove(&n1, &tmp);
  1301  			regfree(&n1);
  1302  
  1303  			regalloc(&n2, nr->type, N);
  1304  			cgen(nr, &n2);
  1305  
  1306  			regalloc(&n1, nl->type, N);
  1307  			cgen(&tmp, &n1);
  1308  
  1309  			gcmp(optoas(OCMP, nr->type), &n1, &n2);
  1310  			patch(gbranch(a, nr->type, likely), to);
  1311  
  1312  			regfree(&n1);
  1313  			regfree(&n2);
  1314  			break;
  1315  		}
  1316  
  1317  		tempname(&n3, nl->type);
  1318  		cgen(nl, &n3);
  1319  
  1320  		tempname(&tmp, nr->type);
  1321  		cgen(nr, &tmp);
  1322  
  1323  		regalloc(&n1, nl->type, N);
  1324  		gmove(&n3, &n1);
  1325  
  1326  		regalloc(&n2, nr->type, N);
  1327  		gmove(&tmp, &n2);
  1328  
  1329  		gcmp(optoas(OCMP, nr->type), &n1, &n2);
  1330  		if(isfloat[nl->type->etype]) {
  1331  			if(n->op == ONE) {
  1332  				p1 = gbranch(ABVS, nr->type, likely);
  1333  				patch(gbranch(a, nr->type, likely), to);
  1334  				patch(p1, to);
  1335  			} else {
  1336  				p1 = gbranch(ABVS, nr->type, -likely);
  1337  				patch(gbranch(a, nr->type, likely), to);
  1338  				patch(p1, pc);
  1339  			}
  1340  		} else {
  1341  			patch(gbranch(a, nr->type, likely), to);
  1342  		}
  1343  		regfree(&n1);
  1344  		regfree(&n2);
  1345  		break;
  1346  	}
  1347  	goto ret;
  1348  
  1349  ret:
  1350  	;
  1351  }
  1352  
  1353  /*
  1354   * n is on stack, either local variable
  1355   * or return value from function call.
  1356   * return n's offset from SP.
  1357   */
  1358  int32
  1359  stkof(Node *n)
  1360  {
  1361  	Type *t;
  1362  	Iter flist;
  1363  	int32 off;
  1364  
  1365  	switch(n->op) {
  1366  	case OINDREG:
  1367  		return n->xoffset;
  1368  
  1369  	case ODOT:
  1370  		t = n->left->type;
  1371  		if(isptr[t->etype])
  1372  			break;
  1373  		off = stkof(n->left);
  1374  		if(off == -1000 || off == 1000)
  1375  			return off;
  1376  		return off + n->xoffset;
  1377  
  1378  	case OINDEX:
  1379  		t = n->left->type;
  1380  		if(!isfixedarray(t))
  1381  			break;
  1382  		off = stkof(n->left);
  1383  		if(off == -1000 || off == 1000)
  1384  			return off;
  1385  		if(isconst(n->right, CTINT))
  1386  			return off + t->type->width * mpgetfix(n->right->val.u.xval);
  1387  		return 1000;
  1388  		
  1389  	case OCALLMETH:
  1390  	case OCALLINTER:
  1391  	case OCALLFUNC:
  1392  		t = n->left->type;
  1393  		if(isptr[t->etype])
  1394  			t = t->type;
  1395  
  1396  		t = structfirst(&flist, getoutarg(t));
  1397  		if(t != T)
  1398  			return t->width + 4;	// correct for LR
  1399  		break;
  1400  	}
  1401  
  1402  	// botch - probably failing to recognize address
  1403  	// arithmetic on the above. eg INDEX and DOT
  1404  	return -1000;
  1405  }
  1406  
  1407  /*
  1408   * block copy:
  1409   *	memmove(&res, &n, w);
  1410   * NB: character copy assumed little endian architecture
  1411   */
  1412  void
  1413  sgen(Node *n, Node *res, int64 w)
  1414  {
  1415  	Node dst, src, tmp, nend, r0, r1, r2, *f;
  1416  	int32 c, odst, osrc;
  1417  	int dir, align, op;
  1418  	Prog *p, *ploop;
  1419  	NodeList *l;
  1420  
  1421  	if(debug['g']) {
  1422  		print("\nsgen w=%lld\n", w);
  1423  		dump("r", n);
  1424  		dump("res", res);
  1425  	}
  1426  
  1427  	if(n->ullman >= UINF && res->ullman >= UINF)
  1428  		fatal("sgen UINF");
  1429  
  1430  	if(w < 0 || (int32)w != w)
  1431  		fatal("sgen copy %lld", w);
  1432  
  1433  	if(n->type == T)
  1434  		fatal("sgen: missing type");
  1435  
  1436  	if(w == 0) {
  1437  		// evaluate side effects only.
  1438  		regalloc(&dst, types[tptr], N);
  1439  		agen(res, &dst);
  1440  		agen(n, &dst);
  1441  		regfree(&dst);
  1442  		return;
  1443  	}
  1444  
  1445  	// If copying .args, that's all the results, so record definition sites
  1446  	// for them for the liveness analysis.
  1447  	if(res->op == ONAME && strcmp(res->sym->name, ".args") == 0)
  1448  		for(l = curfn->dcl; l != nil; l = l->next)
  1449  			if(l->n->class == PPARAMOUT)
  1450  				gvardef(l->n);
  1451  
  1452  	// Avoid taking the address for simple enough types.
  1453  	if(componentgen(n, res))
  1454  		return;
  1455  	
  1456  	// determine alignment.
  1457  	// want to avoid unaligned access, so have to use
  1458  	// smaller operations for less aligned types.
  1459  	// for example moving [4]byte must use 4 MOVB not 1 MOVW.
  1460  	align = n->type->align;
  1461  	switch(align) {
  1462  	default:
  1463  		fatal("sgen: invalid alignment %d for %T", align, n->type);
  1464  	case 1:
  1465  		op = AMOVB;
  1466  		break;
  1467  	case 2:
  1468  		op = AMOVH;
  1469  		break;
  1470  	case 4:
  1471  		op = AMOVW;
  1472  		break;
  1473  	}
  1474  	if(w%align)
  1475  		fatal("sgen: unaligned size %lld (align=%d) for %T", w, align, n->type);
  1476  	c = w / align;
  1477  
  1478  	// offset on the stack
  1479  	osrc = stkof(n);
  1480  	odst = stkof(res);
  1481  	if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
  1482  		// osrc and odst both on stack, and at least one is in
  1483  		// an unknown position.  Could generate code to test
  1484  		// for forward/backward copy, but instead just copy
  1485  		// to a temporary location first.
  1486  		tempname(&tmp, n->type);
  1487  		sgen(n, &tmp, w);
  1488  		sgen(&tmp, res, w);
  1489  		return;
  1490  	}
  1491  	if(osrc%align != 0 || odst%align != 0)
  1492  		fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align);
  1493  
  1494  	// if we are copying forward on the stack and
  1495  	// the src and dst overlap, then reverse direction
  1496  	dir = align;
  1497  	if(osrc < odst && odst < osrc+w)
  1498  		dir = -dir;
  1499  
  1500  	if(op == AMOVW && dir > 0 && c >= 4 && c <= 128) {
  1501  		r0.op = OREGISTER;
  1502  		r0.val.u.reg = REGALLOC_R0;
  1503  		r1.op = OREGISTER;
  1504  		r1.val.u.reg = REGALLOC_R0 + 1;
  1505  		r2.op = OREGISTER;
  1506  		r2.val.u.reg = REGALLOC_R0 + 2;
  1507  
  1508  		regalloc(&src, types[tptr], &r1);
  1509  		regalloc(&dst, types[tptr], &r2);
  1510  		if(n->ullman >= res->ullman) {
  1511  			// eval n first
  1512  			agen(n, &src);
  1513  			if(res->op == ONAME)
  1514  				gvardef(res);
  1515  			agen(res, &dst);
  1516  		} else {
  1517  			// eval res first
  1518  			if(res->op == ONAME)
  1519  				gvardef(res);
  1520  			agen(res, &dst);
  1521  			agen(n, &src);
  1522  		}
  1523  		regalloc(&tmp, types[tptr], &r0);
  1524  		f = sysfunc("duffcopy");
  1525  		p = gins(ADUFFCOPY, N, f);
  1526  		afunclit(&p->to, f);
  1527  		// 8 and 128 = magic constants: see ../../pkg/runtime/asm_arm.s
  1528  		p->to.offset = 8*(128-c);
  1529  
  1530  		regfree(&tmp);
  1531  		regfree(&src);
  1532  		regfree(&dst);
  1533  		return;
  1534  	}
  1535  	
  1536  	if(n->ullman >= res->ullman) {
  1537  		agenr(n, &dst, res);	// temporarily use dst
  1538  		regalloc(&src, types[tptr], N);
  1539  		gins(AMOVW, &dst, &src);
  1540  		if(res->op == ONAME)
  1541  			gvardef(res);
  1542  		agen(res, &dst);
  1543  	} else {
  1544  		if(res->op == ONAME)
  1545  			gvardef(res);
  1546  		agenr(res, &dst, res);
  1547  		agenr(n, &src, N);
  1548  	}
  1549  
  1550  	regalloc(&tmp, types[TUINT32], N);
  1551  
  1552  	// set up end marker
  1553  	memset(&nend, 0, sizeof nend);
  1554  	if(c >= 4) {
  1555  		regalloc(&nend, types[TUINT32], N);
  1556  
  1557  		p = gins(AMOVW, &src, &nend);
  1558  		p->from.type = D_CONST;
  1559  		if(dir < 0)
  1560  			p->from.offset = dir;
  1561  		else
  1562  			p->from.offset = w;
  1563  	}
  1564  
  1565  	// move src and dest to the end of block if necessary
  1566  	if(dir < 0) {
  1567  		p = gins(AMOVW, &src, &src);
  1568  		p->from.type = D_CONST;
  1569  		p->from.offset = w + dir;
  1570  
  1571  		p = gins(AMOVW, &dst, &dst);
  1572  		p->from.type = D_CONST;
  1573  		p->from.offset = w + dir;
  1574  	}
  1575  	
  1576  	// move
  1577  	if(c >= 4) {
  1578  		p = gins(op, &src, &tmp);
  1579  		p->from.type = D_OREG;
  1580  		p->from.offset = dir;
  1581  		p->scond |= C_PBIT;
  1582  		ploop = p;
  1583  
  1584  		p = gins(op, &tmp, &dst);
  1585  		p->to.type = D_OREG;
  1586  		p->to.offset = dir;
  1587  		p->scond |= C_PBIT;
  1588  
  1589  		p = gins(ACMP, &src, N);
  1590  		raddr(&nend, p);
  1591  
  1592  		patch(gbranch(ABNE, T, 0), ploop);
  1593   		regfree(&nend);
  1594  	} else {
  1595  		while(c-- > 0) {
  1596  			p = gins(op, &src, &tmp);
  1597  			p->from.type = D_OREG;
  1598  			p->from.offset = dir;
  1599  			p->scond |= C_PBIT;
  1600  	
  1601  			p = gins(op, &tmp, &dst);
  1602  			p->to.type = D_OREG;
  1603  			p->to.offset = dir;
  1604  			p->scond |= C_PBIT;
  1605  		}
  1606  	}
  1607  
  1608  	regfree(&dst);
  1609  	regfree(&src);
  1610  	regfree(&tmp);
  1611  }
  1612  
  1613  static int
  1614  cadable(Node *n)
  1615  {
  1616  	if(!n->addable) {
  1617  		// dont know how it happens,
  1618  		// but it does
  1619  		return 0;
  1620  	}
  1621  
  1622  	switch(n->op) {
  1623  	case ONAME:
  1624  		return 1;
  1625  	}
  1626  	return 0;
  1627  }
  1628  
  1629  /*
  1630   * copy a composite value by moving its individual components.
  1631   * Slices, strings and interfaces are supported.
  1632   * nr is N when assigning a zero value.
  1633   * return 1 if can do, 0 if cant.
  1634   */
  1635  int
  1636  componentgen(Node *nr, Node *nl)
  1637  {
  1638  	Node nodl, nodr, tmp;
  1639  	int freel, freer;
  1640  
  1641  	freel = 0;
  1642  	freer = 0;
  1643  
  1644  	switch(nl->type->etype) {
  1645  	default:
  1646  		goto no;
  1647  
  1648  	case TARRAY:
  1649  		if(!isslice(nl->type))
  1650  			goto no;
  1651  	case TSTRING:
  1652  	case TINTER:
  1653  		break;
  1654  	}
  1655  
  1656  	nodl = *nl;
  1657  	if(!cadable(nl)) {
  1658  		if(nr == N || !cadable(nr))
  1659  			goto no;
  1660  		igen(nl, &nodl, N);
  1661  		freel = 1;
  1662  	}
  1663  
  1664  	if(nr != N) {
  1665  		nodr = *nr;
  1666  		if(!cadable(nr)) {
  1667  			igen(nr, &nodr, N);
  1668  			freer = 1;
  1669  		}
  1670  	} else {
  1671  		// When zeroing, prepare a register containing zero.
  1672  		nodconst(&tmp, nl->type, 0);
  1673  		regalloc(&nodr, types[TUINT], N);
  1674  		gmove(&tmp, &nodr);
  1675  		freer = 1;
  1676  	}
  1677  
  1678  	// nl and nr are 'cadable' which basically means they are names (variables) now.
  1679  	// If they are the same variable, don't generate any code, because the
  1680  	// VARDEF we generate will mark the old value as dead incorrectly.
  1681  	// (And also the assignments are useless.)
  1682  	if(nr != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
  1683  		goto yes;
  1684  
  1685  	switch(nl->type->etype) {
  1686  	case TARRAY:
  1687  		if(nl->op == ONAME)
  1688  			gvardef(nl);
  1689  		nodl.xoffset += Array_array;
  1690  		nodl.type = ptrto(nl->type->type);
  1691  
  1692  		if(nr != N) {
  1693  			nodr.xoffset += Array_array;
  1694  			nodr.type = nodl.type;
  1695  		}
  1696  		gmove(&nodr, &nodl);
  1697  
  1698  		nodl.xoffset += Array_nel-Array_array;
  1699  		nodl.type = types[simtype[TUINT]];
  1700  
  1701  		if(nr != N) {
  1702  			nodr.xoffset += Array_nel-Array_array;
  1703  			nodr.type = nodl.type;
  1704  		}
  1705  		gmove(&nodr, &nodl);
  1706  
  1707  		nodl.xoffset += Array_cap-Array_nel;
  1708  		nodl.type = types[simtype[TUINT]];
  1709  
  1710  		if(nr != N) {
  1711  			nodr.xoffset += Array_cap-Array_nel;
  1712  			nodr.type = nodl.type;
  1713  		}
  1714  		gmove(&nodr, &nodl);
  1715  
  1716  		goto yes;
  1717  
  1718  	case TSTRING:
  1719  		if(nl->op == ONAME)
  1720  			gvardef(nl);
  1721  		nodl.xoffset += Array_array;
  1722  		nodl.type = ptrto(types[TUINT8]);
  1723  
  1724  		if(nr != N) {
  1725  			nodr.xoffset += Array_array;
  1726  			nodr.type = nodl.type;
  1727  		}
  1728  		gmove(&nodr, &nodl);
  1729  
  1730  		nodl.xoffset += Array_nel-Array_array;
  1731  		nodl.type = types[simtype[TUINT]];
  1732  
  1733  		if(nr != N) {
  1734  			nodr.xoffset += Array_nel-Array_array;
  1735  			nodr.type = nodl.type;
  1736  		}
  1737  		gmove(&nodr, &nodl);
  1738  
  1739  		goto yes;
  1740  
  1741  	case TINTER:
  1742  		if(nl->op == ONAME)
  1743  			gvardef(nl);
  1744  		nodl.xoffset += Array_array;
  1745  		nodl.type = ptrto(types[TUINT8]);
  1746  
  1747  		if(nr != N) {
  1748  			nodr.xoffset += Array_array;
  1749  			nodr.type = nodl.type;
  1750  		}
  1751  		gmove(&nodr, &nodl);
  1752  
  1753  		nodl.xoffset += Array_nel-Array_array;
  1754  		nodl.type = ptrto(types[TUINT8]);
  1755  
  1756  		if(nr != N) {
  1757  			nodr.xoffset += Array_nel-Array_array;
  1758  			nodr.type = nodl.type;
  1759  		}
  1760  		gmove(&nodr, &nodl);
  1761  
  1762  		goto yes;
  1763  	}
  1764  
  1765  no:
  1766  	if(freer)
  1767  		regfree(&nodr);
  1768  	if(freel)
  1769  		regfree(&nodl);
  1770  	return 0;
  1771  
  1772  yes:
  1773  	if(freer)
  1774  		regfree(&nodr);
  1775  	if(freel)
  1776  		regfree(&nodl);
  1777  	return 1;
  1778  }