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