The Go Programming Language

Text file src/cmd/8g/cgen.c

     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 "gg.h"
     9	
    10	void
    11	mgen(Node *n, Node *n1, Node *rg)
    12	{
    13		Node n2;
    14	
    15		n1->op = OEMPTY;
    16	
    17		if(n->addable) {
    18			*n1 = *n;
    19			if(n1->op == OREGISTER || n1->op == OINDREG)
    20				reg[n->val.u.reg]++;
    21			return;
    22		}
    23		tempname(n1, n->type);
    24		cgen(n, n1);
    25		if(n->type->width <= widthptr || isfloat[n->type->etype]) {
    26			n2 = *n1;
    27			regalloc(n1, n->type, rg);
    28			gmove(&n2, n1);
    29		}
    30	}
    31	
    32	void
    33	mfree(Node *n)
    34	{
    35		if(n->op == OREGISTER)
    36			regfree(n);
    37	}
    38	
    39	/*
    40	 * generate:
    41	 *	res = n;
    42	 * simplifies and calls gmove.
    43	 *
    44	 * TODO:
    45	 *	sudoaddable
    46	 */
    47	void
    48	cgen(Node *n, Node *res)
    49	{
    50		Node *nl, *nr, *r, n1, n2, nt, f0, f1;
    51		Prog *p1, *p2, *p3;
    52		int a;
    53	
    54		if(debug['g']) {
    55			dump("\ncgen-n", n);
    56			dump("cgen-res", res);
    57		}
    58	
    59		if(n == N || n->type == T)
    60			fatal("cgen: n nil");
    61		if(res == N || res->type == T)
    62			fatal("cgen: res nil");
    63	
    64		// inline slices
    65		if(cgen_inline(n, res))
    66			return;
    67	
    68		while(n->op == OCONVNOP)
    69			n = n->left;
    70	
    71		// function calls on both sides?  introduce temporary
    72		if(n->ullman >= UINF && res->ullman >= UINF) {
    73			tempname(&n1, n->type);
    74			cgen(n, &n1);
    75			cgen(&n1, res);
    76			return;
    77		}
    78	
    79		// structs etc get handled specially
    80		if(isfat(n->type)) {
    81			if(n->type->width < 0)
    82				fatal("forgot to compute width for %T", n->type);
    83			sgen(n, res, n->type->width);
    84			return;
    85		}
    86	
    87		// update addressability for string, slice
    88		// can't do in walk because n->left->addable
    89		// changes if n->left is an escaping local variable.
    90		switch(n->op) {
    91		case OLEN:
    92			if(isslice(n->left->type) || istype(n->left->type, TSTRING))
    93				n->addable = n->left->addable;
    94			break;
    95		case OCAP:
    96			if(isslice(n->left->type))
    97				n->addable = n->left->addable;
    98			break;
    99		}
   100	
   101		// if both are addressable, move
   102		if(n->addable && res->addable) {
   103			gmove(n, res);
   104			return;
   105		}
   106	
   107		// if both are not addressable, use a temporary.
   108		if(!n->addable && !res->addable) {
   109			// could use regalloc here sometimes,
   110			// but have to check for ullman >= UINF.
   111			tempname(&n1, n->type);
   112			cgen(n, &n1);
   113			cgen(&n1, res);
   114			return;
   115		}
   116	
   117		// if result is not addressable directly but n is,
   118		// compute its address and then store via the address.
   119		if(!res->addable) {
   120			igen(res, &n1, N);
   121			cgen(n, &n1);
   122			regfree(&n1);
   123			return;
   124		}
   125	
   126		// complex types
   127		if(complexop(n, res)) {
   128			complexgen(n, res);
   129			return;
   130		}
   131	
   132		// otherwise, the result is addressable but n is not.
   133		// let's do some computation.
   134	
   135		// use ullman to pick operand to eval first.
   136		nl = n->left;
   137		nr = n->right;
   138		if(nl != N && nl->ullman >= UINF)
   139		if(nr != N && nr->ullman >= UINF) {
   140			// both are hard
   141			tempname(&n1, nl->type);
   142			cgen(nl, &n1);
   143			n2 = *n;
   144			n2.left = &n1;
   145			cgen(&n2, res);
   146			return;
   147		}
   148	
   149		// 64-bit ops are hard on 32-bit machine.
   150		if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
   151			switch(n->op) {
   152			// math goes to cgen64.
   153			case OMINUS:
   154			case OCOM:
   155			case OADD:
   156			case OSUB:
   157			case OMUL:
   158			case OLSH:
   159			case ORSH:
   160			case OAND:
   161			case OOR:
   162			case OXOR:
   163				cgen64(n, res);
   164				return;
   165			}
   166		}
   167	
   168		if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype])
   169			goto flt;
   170	
   171		switch(n->op) {
   172		default:
   173			dump("cgen", n);
   174			fatal("cgen %O", n->op);
   175			break;
   176	
   177		case OREAL:
   178		case OIMAG:
   179		case OCOMPLEX:
   180			fatal("unexpected complex");
   181			return;
   182	
   183		// these call bgen to get a bool value
   184		case OOROR:
   185		case OANDAND:
   186		case OEQ:
   187		case ONE:
   188		case OLT:
   189		case OLE:
   190		case OGE:
   191		case OGT:
   192		case ONOT:
   193			p1 = gbranch(AJMP, T);
   194			p2 = pc;
   195			gmove(nodbool(1), res);
   196			p3 = gbranch(AJMP, T);
   197			patch(p1, pc);
   198			bgen(n, 1, p2);
   199			gmove(nodbool(0), res);
   200			patch(p3, pc);
   201			return;
   202	
   203		case OPLUS:
   204			cgen(nl, res);
   205			return;
   206	
   207		case OMINUS:
   208		case OCOM:
   209			a = optoas(n->op, nl->type);
   210			goto uop;
   211	
   212		// symmetric binary
   213		case OAND:
   214		case OOR:
   215		case OXOR:
   216		case OADD:
   217		case OMUL:
   218			a = optoas(n->op, nl->type);
   219			if(a == AIMULB) {
   220				cgen_bmul(n->op, nl, nr, res);
   221				break;
   222			}
   223			goto sbop;
   224	
   225		// asymmetric binary
   226		case OSUB:
   227			a = optoas(n->op, nl->type);
   228			goto abop;
   229	
   230		case OCONV:
   231			if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
   232				cgen(nl, res);
   233				break;
   234			}
   235	
   236			tempname(&n2, n->type);
   237			mgen(nl, &n1, res);
   238			gmove(&n1, &n2);
   239			gmove(&n2, res);
   240			mfree(&n1);
   241			break;
   242	
   243		case ODOT:
   244		case ODOTPTR:
   245		case OINDEX:
   246		case OIND:
   247		case ONAME:	// PHEAP or PPARAMREF var
   248			igen(n, &n1, res);
   249			gmove(&n1, res);
   250			regfree(&n1);
   251			break;
   252	
   253		case OLEN:
   254			if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
   255				// map has len in the first 32-bit word.
   256				// a zero pointer means zero length
   257				tempname(&n1, types[tptr]);
   258				cgen(nl, &n1);
   259				regalloc(&n2, types[tptr], N);
   260				gmove(&n1, &n2);
   261				n1 = n2;
   262	
   263				nodconst(&n2, types[tptr], 0);
   264				gins(optoas(OCMP, types[tptr]), &n1, &n2);
   265				p1 = gbranch(optoas(OEQ, types[tptr]), T);
   266	
   267				n2 = n1;
   268				n2.op = OINDREG;
   269				n2.type = types[TINT32];
   270				gmove(&n2, &n1);
   271	
   272				patch(p1, pc);
   273	
   274				gmove(&n1, res);
   275				regfree(&n1);
   276				break;
   277			}
   278			if(istype(nl->type, TSTRING) || isslice(nl->type)) {
   279				// both slice and string have len one pointer into the struct.
   280				igen(nl, &n1, res);
   281				n1.type = types[TUINT32];
   282				n1.xoffset += Array_nel;
   283				gmove(&n1, res);
   284				regfree(&n1);
   285				break;
   286			}
   287			fatal("cgen: OLEN: unknown type %lT", nl->type);
   288			break;
   289	
   290		case OCAP:
   291			if(istype(nl->type, TCHAN)) {
   292				// chan has cap in the second 32-bit word.
   293				// a zero pointer means zero length
   294				regalloc(&n1, types[tptr], res);
   295				cgen(nl, &n1);
   296	
   297				nodconst(&n2, types[tptr], 0);
   298				gins(optoas(OCMP, types[tptr]), &n1, &n2);
   299				p1 = gbranch(optoas(OEQ, types[tptr]), T);
   300	
   301				n2 = n1;
   302				n2.op = OINDREG;
   303				n2.xoffset = 4;
   304				n2.type = types[TINT32];
   305				gmove(&n2, &n1);
   306	
   307				patch(p1, pc);
   308	
   309				gmove(&n1, res);
   310				regfree(&n1);
   311				break;
   312			}
   313			if(isslice(nl->type)) {
   314				igen(nl, &n1, res);
   315				n1.op = OINDREG;
   316				n1.type = types[TUINT32];
   317				n1.xoffset = Array_cap;
   318				gmove(&n1, res);
   319				regfree(&n1);
   320				break;
   321			}
   322			fatal("cgen: OCAP: unknown type %lT", nl->type);
   323			break;
   324	
   325		case OADDR:
   326			agen(nl, res);
   327			break;
   328	
   329		case OCALLMETH:
   330			cgen_callmeth(n, 0);
   331			cgen_callret(n, res);
   332			break;
   333	
   334		case OCALLINTER:
   335			cgen_callinter(n, res, 0);
   336			cgen_callret(n, res);
   337			break;
   338	
   339		case OCALLFUNC:
   340			cgen_call(n, 0);
   341			cgen_callret(n, res);
   342			break;
   343	
   344		case OMOD:
   345		case ODIV:
   346			cgen_div(n->op, nl, nr, res);
   347			break;
   348	
   349		case OLSH:
   350		case ORSH:
   351			cgen_shift(n->op, nl, nr, res);
   352			break;
   353		}
   354		return;
   355	
   356	sbop:	// symmetric binary
   357		if(nl->ullman < nr->ullman) {
   358			r = nl;
   359			nl = nr;
   360			nr = r;
   361		}
   362	
   363	abop:	// asymmetric binary
   364		if(nl->ullman >= nr->ullman) {
   365			tempname(&nt, nl->type);
   366			cgen(nl, &nt);
   367			mgen(nr, &n2, N);
   368			regalloc(&n1, nl->type, res);
   369			gmove(&nt, &n1);
   370			gins(a, &n2, &n1);
   371			gmove(&n1, res);
   372			regfree(&n1);
   373			mfree(&n2);
   374		} else {
   375			regalloc(&n2, nr->type, res);
   376			cgen(nr, &n2);
   377			regalloc(&n1, nl->type, N);
   378			cgen(nl, &n1);
   379			gins(a, &n2, &n1);
   380			regfree(&n2);
   381			gmove(&n1, res);
   382			regfree(&n1);
   383		}
   384		return;
   385	
   386	uop:	// unary
   387		tempname(&n1, nl->type);
   388		cgen(nl, &n1);
   389		gins(a, N, &n1);
   390		gmove(&n1, res);
   391		return;
   392	
   393	flt:	// floating-point.  387 (not SSE2) to interoperate with 8c
   394		nodreg(&f0, nl->type, D_F0);
   395		nodreg(&f1, n->type, D_F0+1);
   396		if(nr != N)
   397			goto flt2;
   398	
   399		// unary
   400		cgen(nl, &f0);
   401		if(n->op != OCONV && n->op != OPLUS)
   402			gins(foptoas(n->op, n->type, 0), N, N);
   403		gmove(&f0, res);
   404		return;
   405	
   406	flt2:	// binary
   407		if(nl->ullman >= nr->ullman) {
   408			cgen(nl, &f0);
   409			if(nr->addable)
   410				gins(foptoas(n->op, n->type, 0), nr, &f0);
   411			else {
   412				cgen(nr, &f0);
   413				gins(foptoas(n->op, n->type, Fpop), &f0, &f1);
   414			}
   415		} else {
   416			cgen(nr, &f0);
   417			if(nl->addable)
   418				gins(foptoas(n->op, n->type, Frev), nl, &f0);
   419			else {
   420				cgen(nl, &f0);
   421				gins(foptoas(n->op, n->type, Frev|Fpop), &f0, &f1);
   422			}
   423		}
   424		gmove(&f0, res);
   425		return;
   426	}
   427	
   428	/*
   429	 * generate array index into res.
   430	 * n might be any size; res is 32-bit.
   431	 * returns Prog* to patch to panic call.
   432	 */
   433	Prog*
   434	cgenindex(Node *n, Node *res)
   435	{
   436		Node tmp, lo, hi, zero;
   437	
   438		if(!is64(n->type)) {
   439			cgen(n, res);
   440			return nil;
   441		}
   442	
   443		tempname(&tmp, types[TINT64]);
   444		cgen(n, &tmp);
   445		split64(&tmp, &lo, &hi);
   446		gmove(&lo, res);
   447		if(debug['B']) {
   448			splitclean();
   449			return nil;
   450		}
   451		nodconst(&zero, types[TINT32], 0);
   452		gins(ACMPL, &hi, &zero);
   453		splitclean();
   454		return gbranch(AJNE, T);
   455	}
   456			
   457	/*
   458	 * address gen
   459	 *	res = &n;
   460	 */
   461	void
   462	agen(Node *n, Node *res)
   463	{
   464		Node *nl, *nr;
   465		Node n1, n2, n3, n4, tmp;
   466		Type *t;
   467		uint32 w;
   468		uint64 v;
   469		Prog *p1, *p2;
   470	
   471		if(debug['g']) {
   472			dump("\nagen-res", res);
   473			dump("agen-r", n);
   474		}
   475		if(n == N || n->type == T || res == N || res->type == T)
   476			fatal("agen");
   477	
   478		while(n->op == OCONVNOP)
   479			n = n->left;
   480	
   481		// addressable var is easy
   482		if(n->addable) {
   483			if(n->op == OREGISTER)
   484				fatal("agen OREGISTER");
   485			regalloc(&n1, types[tptr], res);
   486			gins(ALEAL, n, &n1);
   487			gmove(&n1, res);
   488			regfree(&n1);
   489			return;
   490		}
   491	
   492		// let's compute
   493		nl = n->left;
   494		nr = n->right;
   495	
   496		switch(n->op) {
   497		default:
   498			fatal("agen %O", n->op);
   499	
   500		case OCALLMETH:
   501			cgen_callmeth(n, 0);
   502			cgen_aret(n, res);
   503			break;
   504	
   505		case OCALLINTER:
   506			cgen_callinter(n, res, 0);
   507			cgen_aret(n, res);
   508			break;
   509	
   510		case OCALLFUNC:
   511			cgen_call(n, 0);
   512			cgen_aret(n, res);
   513			break;
   514	
   515		case OINDEX:
   516			p2 = nil;  // to be patched to panicindex.
   517			w = n->type->width;
   518			if(nr->addable) {
   519				if(!isconst(nr, CTINT))
   520					tempname(&tmp, types[TINT32]);
   521				if(!isconst(nl, CTSTR))
   522					agenr(nl, &n3, res);
   523				if(!isconst(nr, CTINT)) {
   524					p2 = cgenindex(nr, &tmp);
   525					regalloc(&n1, tmp.type, N);
   526					gmove(&tmp, &n1);
   527				}
   528			} else if(nl->addable) {
   529				if(!isconst(nr, CTINT)) {
   530					tempname(&tmp, types[TINT32]);
   531					p2 = cgenindex(nr, &tmp);
   532					regalloc(&n1, tmp.type, N);
   533					gmove(&tmp, &n1);
   534				}
   535				if(!isconst(nl, CTSTR)) {
   536					regalloc(&n3, types[tptr], res);
   537					agen(nl, &n3);
   538				}
   539			} else {
   540				tempname(&tmp, types[TINT32]);
   541				p2 = cgenindex(nr, &tmp);
   542				nr = &tmp;
   543				if(!isconst(nl, CTSTR))
   544					agenr(nl, &n3, res);
   545				regalloc(&n1, tmp.type, N);
   546				gins(optoas(OAS, tmp.type), &tmp, &n1);
   547			}
   548	
   549			// &a is in &n3 (allocated in res)
   550			// i is in &n1 (if not constant)
   551			// w is width
   552	
   553			// explicit check for nil if array is large enough
   554			// that we might derive too big a pointer.
   555			if(isfixedarray(nl->type) && nl->type->width >= unmappedzero) {
   556				regalloc(&n4, types[tptr], &n3);
   557				gmove(&n3, &n4);
   558				n4.op = OINDREG;
   559				n4.type = types[TUINT8];
   560				n4.xoffset = 0;
   561				gins(ATESTB, nodintconst(0), &n4);
   562				regfree(&n4);
   563			}
   564	
   565			// constant index
   566			if(isconst(nr, CTINT)) {
   567				if(isconst(nl, CTSTR))
   568					fatal("constant string constant index");
   569				v = mpgetfix(nr->val.u.xval);
   570				if(isslice(nl->type) || nl->type->etype == TSTRING) {
   571					if(!debug['B'] && !n->etype) {
   572						n1 = n3;
   573						n1.op = OINDREG;
   574						n1.type = types[tptr];
   575						n1.xoffset = Array_nel;
   576						nodconst(&n2, types[TUINT32], v);
   577						gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
   578						p1 = gbranch(optoas(OGT, types[TUINT32]), T);
   579						ginscall(panicindex, 0);
   580						patch(p1, pc);
   581					}
   582	
   583					n1 = n3;
   584					n1.op = OINDREG;
   585					n1.type = types[tptr];
   586					n1.xoffset = Array_array;
   587					gmove(&n1, &n3);
   588				}
   589	
   590				if (v*w != 0) {
   591					nodconst(&n2, types[tptr], v*w);
   592					gins(optoas(OADD, types[tptr]), &n2, &n3);
   593				}
   594				gmove(&n3, res);
   595				regfree(&n3);
   596				break;
   597			}
   598	
   599			regalloc(&n2, types[TINT32], &n1);			// i
   600			gmove(&n1, &n2);
   601			regfree(&n1);
   602	
   603			if(!debug['B'] && !n->etype) {
   604				// check bounds
   605				if(isconst(nl, CTSTR))
   606					nodconst(&n1, types[TUINT32], nl->val.u.sval->len);
   607				else if(isslice(nl->type) || nl->type->etype == TSTRING) {
   608					n1 = n3;
   609					n1.op = OINDREG;
   610					n1.type = types[tptr];
   611					n1.xoffset = Array_nel;
   612				} else
   613					nodconst(&n1, types[TUINT32], nl->type->bound);
   614				gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
   615				p1 = gbranch(optoas(OLT, types[TUINT32]), T);
   616				if(p2)
   617					patch(p2, pc);
   618				ginscall(panicindex, 0);
   619				patch(p1, pc);
   620			}
   621			
   622			if(isconst(nl, CTSTR)) {
   623				regalloc(&n3, types[tptr], res);
   624				p1 = gins(ALEAL, N, &n3);
   625				datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
   626				p1->from.scale = 1;
   627				p1->from.index = n2.val.u.reg;
   628				goto indexdone;
   629			}
   630	
   631			if(isslice(nl->type) || nl->type->etype == TSTRING) {
   632				n1 = n3;
   633				n1.op = OINDREG;
   634				n1.type = types[tptr];
   635				n1.xoffset = Array_array;
   636				gmove(&n1, &n3);
   637			}
   638	
   639			if(w == 0) {
   640				// nothing to do
   641			} else if(w == 1 || w == 2 || w == 4 || w == 8) {
   642				p1 = gins(ALEAL, &n2, &n3);
   643				p1->from.scale = w;
   644				p1->from.index = p1->from.type;
   645				p1->from.type = p1->to.type + D_INDIR;
   646			} else {
   647				nodconst(&n1, types[TUINT32], w);
   648				gins(optoas(OMUL, types[TUINT32]), &n1, &n2);
   649				gins(optoas(OADD, types[tptr]), &n2, &n3);
   650			}
   651	
   652		indexdone:
   653			gmove(&n3, res);
   654			regfree(&n2);
   655			regfree(&n3);
   656			break;
   657	
   658		case ONAME:
   659			// should only get here with names in this func.
   660			if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
   661				dump("bad agen", n);
   662				fatal("agen: bad ONAME funcdepth %d != %d",
   663					n->funcdepth, funcdepth);
   664			}
   665	
   666			// should only get here for heap vars or paramref
   667			if(!(n->class & PHEAP) && n->class != PPARAMREF) {
   668				dump("bad agen", n);
   669				fatal("agen: bad ONAME class %#x", n->class);
   670			}
   671			cgen(n->heapaddr, res);
   672			if(n->xoffset != 0) {
   673				nodconst(&n1, types[tptr], n->xoffset);
   674				gins(optoas(OADD, types[tptr]), &n1, res);
   675			}
   676			break;
   677	
   678		case OIND:
   679			cgen(nl, res);
   680			break;
   681	
   682		case ODOT:
   683			t = nl->type;
   684			agen(nl, res);
   685			if(n->xoffset != 0) {
   686				nodconst(&n1, types[tptr], n->xoffset);
   687				gins(optoas(OADD, types[tptr]), &n1, res);
   688			}
   689			break;
   690	
   691		case ODOTPTR:
   692			t = nl->type;
   693			if(!isptr[t->etype])
   694				fatal("agen: not ptr %N", n);
   695			cgen(nl, res);
   696			if(n->xoffset != 0) {
   697				// explicit check for nil if struct is large enough
   698				// that we might derive too big a pointer.
   699				if(nl->type->type->width >= unmappedzero) {
   700					regalloc(&n1, types[tptr], res);
   701					gmove(res, &n1);
   702					n1.op = OINDREG;
   703					n1.type = types[TUINT8];
   704					n1.xoffset = 0;
   705					gins(ATESTB, nodintconst(0), &n1);
   706					regfree(&n1);
   707				}
   708				nodconst(&n1, types[tptr], n->xoffset);
   709				gins(optoas(OADD, types[tptr]), &n1, res);
   710			}
   711			break;
   712		}
   713	}
   714	
   715	/*
   716	 * generate:
   717	 *	newreg = &n;
   718	 *	res = newreg
   719	 *
   720	 * on exit, a has been changed to be *newreg.
   721	 * caller must regfree(a).
   722	 */
   723	void
   724	igen(Node *n, Node *a, Node *res)
   725	{
   726		Node n1;
   727		Type *fp;
   728		Iter flist;
   729	  
   730		switch(n->op) {
   731		case ONAME:
   732			if((n->class&PHEAP) || n->class == PPARAMREF)
   733				break;
   734			*a = *n;
   735			return;
   736	 
   737		case OCALLFUNC:
   738			fp = structfirst(&flist, getoutarg(n->left->type));
   739			cgen_call(n, 0);
   740			memset(a, 0, sizeof *a);
   741			a->op = OINDREG;
   742			a->val.u.reg = D_SP;
   743			a->addable = 1;
   744			a->xoffset = fp->width;
   745			a->type = n->type;
   746			return;
   747		}
   748		// release register for now, to avoid
   749		// confusing tempname.
   750		if(res != N && res->op == OREGISTER)
   751			reg[res->val.u.reg]--;
   752		tempname(&n1, types[tptr]);
   753		agen(n, &n1);
   754		if(res != N && res->op == OREGISTER)
   755			reg[res->val.u.reg]++;
   756		regalloc(a, types[tptr], res);
   757		gmove(&n1, a);
   758		a->op = OINDREG;
   759		a->type = n->type;
   760	}
   761	
   762	/*
   763	 * generate:
   764	 *	newreg = &n;
   765	 *
   766	 * caller must regfree(a).
   767	 */
   768	void
   769	agenr(Node *n, Node *a, Node *res)
   770	{
   771		Node n1;
   772	
   773		tempname(&n1, types[tptr]);
   774		agen(n, &n1);
   775		regalloc(a, types[tptr], res);
   776		gmove(&n1, a);
   777	}
   778	
   779	/*
   780	 * branch gen
   781	 *	if(n == true) goto to;
   782	 */
   783	void
   784	bgen(Node *n, int true, Prog *to)
   785	{
   786		int et, a;
   787		Node *nl, *nr, *r;
   788		Node n1, n2, tmp, t1, t2, ax;
   789		Prog *p1, *p2;
   790	
   791		if(debug['g']) {
   792			dump("\nbgen", n);
   793		}
   794	
   795		if(n == N)
   796			n = nodbool(1);
   797	
   798		if(n->ninit != nil)
   799			genlist(n->ninit);
   800	
   801		nl = n->left;
   802		nr = n->right;
   803	
   804		if(n->type == T) {
   805			convlit(&n, types[TBOOL]);
   806			if(n->type == T)
   807				return;
   808		}
   809	
   810		et = n->type->etype;
   811		if(et != TBOOL) {
   812			yyerror("cgen: bad type %T for %O", n->type, n->op);
   813			patch(gins(AEND, N, N), to);
   814			return;
   815		}
   816		nl = N;
   817		nr = N;
   818	
   819		switch(n->op) {
   820		default:
   821		def:
   822			regalloc(&n1, n->type, N);
   823			cgen(n, &n1);
   824			nodconst(&n2, n->type, 0);
   825			gins(optoas(OCMP, n->type), &n1, &n2);
   826			a = AJNE;
   827			if(!true)
   828				a = AJEQ;
   829			patch(gbranch(a, n->type), to);
   830			regfree(&n1);
   831			return;
   832	
   833		case OLITERAL:
   834			// need to ask if it is bool?
   835			if(!true == !n->val.u.bval)
   836				patch(gbranch(AJMP, T), to);
   837			return;
   838	
   839		case ONAME:
   840			if(!n->addable)
   841				goto def;
   842			nodconst(&n1, n->type, 0);
   843			gins(optoas(OCMP, n->type), n, &n1);
   844			a = AJNE;
   845			if(!true)
   846				a = AJEQ;
   847			patch(gbranch(a, n->type), to);
   848			return;
   849	
   850		case OANDAND:
   851			if(!true)
   852				goto caseor;
   853	
   854		caseand:
   855			p1 = gbranch(AJMP, T);
   856			p2 = gbranch(AJMP, T);
   857			patch(p1, pc);
   858			bgen(n->left, !true, p2);
   859			bgen(n->right, !true, p2);
   860			p1 = gbranch(AJMP, T);
   861			patch(p1, to);
   862			patch(p2, pc);
   863			return;
   864	
   865		case OOROR:
   866			if(!true)
   867				goto caseand;
   868	
   869		caseor:
   870			bgen(n->left, true, to);
   871			bgen(n->right, true, to);
   872			return;
   873	
   874		case OEQ:
   875		case ONE:
   876		case OLT:
   877		case OGT:
   878		case OLE:
   879		case OGE:
   880			nr = n->right;
   881			if(nr == N || nr->type == T)
   882				return;
   883	
   884		case ONOT:	// unary
   885			nl = n->left;
   886			if(nl == N || nl->type == T)
   887				return;
   888		}
   889	
   890		switch(n->op) {
   891		case ONOT:
   892			bgen(nl, !true, to);
   893			break;
   894	
   895		case OEQ:
   896		case ONE:
   897		case OLT:
   898		case OGT:
   899		case OLE:
   900		case OGE:
   901			a = n->op;
   902			if(!true) {
   903				if(isfloat[nl->type->etype]) {
   904					// brcom is not valid on floats when NaN is involved.
   905					p1 = gbranch(AJMP, T);
   906					p2 = gbranch(AJMP, T);
   907					patch(p1, pc);
   908					bgen(n, 1, p2);
   909					patch(gbranch(AJMP, T), to);
   910					patch(p2, pc);
   911					break;
   912				}				
   913				a = brcom(a);
   914				true = !true;
   915			}
   916	
   917			// make simplest on right
   918			if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) {
   919				a = brrev(a);
   920				r = nl;
   921				nl = nr;
   922				nr = r;
   923			}
   924	
   925			if(isslice(nl->type)) {
   926				// front end should only leave cmp to literal nil
   927				if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
   928					yyerror("illegal array comparison");
   929					break;
   930				}
   931				a = optoas(a, types[tptr]);
   932				regalloc(&n1, types[tptr], N);
   933				agen(nl, &n1);
   934				n2 = n1;
   935				n2.op = OINDREG;
   936				n2.xoffset = Array_array;
   937				n2.type = types[tptr];
   938				nodconst(&tmp, types[tptr], 0);
   939				gins(optoas(OCMP, types[tptr]), &n2, &tmp);
   940				patch(gbranch(a, types[tptr]), to);
   941				regfree(&n1);
   942				break;
   943			}
   944	
   945			if(isinter(nl->type)) {
   946				// front end should only leave cmp to literal nil
   947				if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
   948					yyerror("illegal interface comparison");
   949					break;
   950				}
   951				a = optoas(a, types[tptr]);
   952				regalloc(&n1, types[tptr], N);
   953				agen(nl, &n1);
   954				n2 = n1;
   955				n2.op = OINDREG;
   956				n2.xoffset = 0;
   957				nodconst(&tmp, types[tptr], 0);
   958				gins(optoas(OCMP, types[tptr]), &n2, &tmp);
   959				patch(gbranch(a, types[tptr]), to);
   960				regfree(&n1);
   961				break;
   962			}
   963	
   964			if(isfloat[nr->type->etype]) {
   965				a = brrev(a);	// because the args are stacked
   966				if(a == OGE || a == OGT) {
   967					// only < and <= work right with NaN; reverse if needed
   968					r = nr;
   969					nr = nl;
   970					nl = r;
   971					a = brrev(a);
   972				}
   973				nodreg(&tmp, nr->type, D_F0);
   974				nodreg(&n2, nr->type, D_F0 + 1);
   975				nodreg(&ax, types[TUINT16], D_AX);
   976				et = simsimtype(nr->type);
   977				if(et == TFLOAT64) {
   978					if(nl->ullman > nr->ullman) {
   979						cgen(nl, &tmp);
   980						cgen(nr, &tmp);
   981						gins(AFXCHD, &tmp, &n2);
   982					} else {
   983						cgen(nr, &tmp);
   984						cgen(nl, &tmp);
   985					}
   986					gins(AFUCOMIP, &tmp, &n2);
   987					gins(AFMOVDP, &tmp, &tmp);	// annoying pop but still better than STSW+SAHF
   988				} else {
   989					// TODO(rsc): The moves back and forth to memory
   990					// here are for truncating the value to 32 bits.
   991					// This handles 32-bit comparison but presumably
   992					// all the other ops have the same problem.
   993					// We need to figure out what the right general
   994					// solution is, besides telling people to use float64.
   995					tempname(&t1, types[TFLOAT32]);
   996					tempname(&t2, types[TFLOAT32]);
   997					cgen(nr, &t1);
   998					cgen(nl, &t2);
   999					gmove(&t2, &tmp);
  1000					gins(AFCOMFP, &t1, &tmp);
  1001					gins(AFSTSW, N, &ax);
  1002					gins(ASAHF, N, N);
  1003				}
  1004				if(a == OEQ) {
  1005					// neither NE nor P
  1006					p1 = gbranch(AJNE, T);
  1007					p2 = gbranch(AJPS, T);
  1008					patch(gbranch(AJMP, T), to);
  1009					patch(p1, pc);
  1010					patch(p2, pc);
  1011				} else if(a == ONE) {
  1012					// either NE or P
  1013					patch(gbranch(AJNE, T), to);
  1014					patch(gbranch(AJPS, T), to);
  1015				} else
  1016					patch(gbranch(optoas(a, nr->type), T), to);
  1017				break;
  1018			}
  1019			if(iscomplex[nl->type->etype]) {
  1020				complexbool(a, nl, nr, true, to);
  1021				break;
  1022			}
  1023	
  1024			if(is64(nr->type)) {
  1025				if(!nl->addable) {
  1026					tempname(&n1, nl->type);
  1027					cgen(nl, &n1);
  1028					nl = &n1;
  1029				}
  1030				if(!nr->addable) {
  1031					tempname(&n2, nr->type);
  1032					cgen(nr, &n2);
  1033					nr = &n2;
  1034				}
  1035				cmp64(nl, nr, a, to);
  1036				break;
  1037			}
  1038	
  1039			a = optoas(a, nr->type);
  1040	
  1041			if(nr->ullman >= UINF) {
  1042				tempname(&n1, nl->type);
  1043				tempname(&tmp, nr->type);
  1044				cgen(nl, &n1);
  1045				cgen(nr, &tmp);
  1046				regalloc(&n2, nr->type, N);
  1047				cgen(&tmp, &n2);
  1048				goto cmp;
  1049			}
  1050	
  1051			tempname(&n1, nl->type);
  1052			cgen(nl, &n1);
  1053	
  1054			if(smallintconst(nr)) {
  1055				gins(optoas(OCMP, nr->type), &n1, nr);
  1056				patch(gbranch(a, nr->type), to);
  1057				break;
  1058			}
  1059	
  1060			tempname(&tmp, nr->type);
  1061			cgen(nr, &tmp);
  1062			regalloc(&n2, nr->type, N);
  1063			gmove(&tmp, &n2);
  1064	
  1065	cmp:
  1066			gins(optoas(OCMP, nr->type), &n1, &n2);
  1067			patch(gbranch(a, nr->type), to);
  1068			regfree(&n2);
  1069			break;
  1070		}
  1071	}
  1072	
  1073	/*
  1074	 * n is on stack, either local variable
  1075	 * or return value from function call.
  1076	 * return n's offset from SP.
  1077	 */
  1078	int32
  1079	stkof(Node *n)
  1080	{
  1081		Type *t;
  1082		Iter flist;
  1083		int32 off;
  1084	
  1085		switch(n->op) {
  1086		case OINDREG:
  1087			return n->xoffset;
  1088	
  1089		case ODOT:
  1090			t = n->left->type;
  1091			if(isptr[t->etype])
  1092				break;
  1093			off = stkof(n->left);
  1094			if(off == -1000 || off == 1000)
  1095				return off;
  1096			return off + n->xoffset;
  1097	
  1098		case OINDEX:
  1099			t = n->left->type;
  1100			if(!isfixedarray(t))
  1101				break;
  1102			off = stkof(n->left);
  1103			if(off == -1000 || off == 1000)
  1104				return off;
  1105			if(isconst(n->right, CTINT))
  1106				return off + t->type->width * mpgetfix(n->right->val.u.xval);
  1107			return 1000;
  1108			
  1109		case OCALLMETH:
  1110		case OCALLINTER:
  1111		case OCALLFUNC:
  1112			t = n->left->type;
  1113			if(isptr[t->etype])
  1114				t = t->type;
  1115	
  1116			t = structfirst(&flist, getoutarg(t));
  1117			if(t != T)
  1118				return t->width;
  1119			break;
  1120		}
  1121	
  1122		// botch - probably failing to recognize address
  1123		// arithmetic on the above. eg INDEX and DOT
  1124		return -1000;
  1125	}
  1126	
  1127	/*
  1128	 * struct gen
  1129	 *	memmove(&res, &n, w);
  1130	 */
  1131	void
  1132	sgen(Node *n, Node *res, int32 w)
  1133	{
  1134		Node dst, src, tdst, tsrc;
  1135		int32 c, q, odst, osrc;
  1136	
  1137		if(debug['g']) {
  1138			print("\nsgen w=%d\n", w);
  1139			dump("r", n);
  1140			dump("res", res);
  1141		}
  1142		if(w == 0)
  1143			return;
  1144		if(n->ullman >= UINF && res->ullman >= UINF) {
  1145			fatal("sgen UINF");
  1146		}
  1147	
  1148		if(w < 0)
  1149			fatal("sgen copy %d", w);
  1150	
  1151		// offset on the stack
  1152		osrc = stkof(n);
  1153		odst = stkof(res);
  1154		
  1155		if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
  1156			// osrc and odst both on stack, and at least one is in
  1157			// an unknown position.  Could generate code to test
  1158			// for forward/backward copy, but instead just copy
  1159			// to a temporary location first.
  1160			tempname(&tsrc, n->type);
  1161			sgen(n, &tsrc, w);
  1162			sgen(&tsrc, res, w);
  1163			return;
  1164		}
  1165	
  1166		nodreg(&dst, types[tptr], D_DI);
  1167		nodreg(&src, types[tptr], D_SI);
  1168	
  1169		tempname(&tsrc, types[tptr]);
  1170		tempname(&tdst, types[tptr]);
  1171		if(!n->addable)
  1172			agen(n, &tsrc);
  1173		if(!res->addable)
  1174			agen(res, &tdst);
  1175		if(n->addable)
  1176			agen(n, &src);
  1177		else
  1178			gmove(&tsrc, &src);
  1179		if(res->addable)
  1180			agen(res, &dst);
  1181		else
  1182			gmove(&tdst, &dst);
  1183	
  1184		c = w % 4;	// bytes
  1185		q = w / 4;	// doublewords
  1186	
  1187		// if we are copying forward on the stack and
  1188		// the src and dst overlap, then reverse direction
  1189		if(osrc < odst && odst < osrc+w) {
  1190			// reverse direction
  1191			gins(ASTD, N, N);		// set direction flag
  1192			if(c > 0) {
  1193				gconreg(AADDL, w-1, D_SI);
  1194				gconreg(AADDL, w-1, D_DI);
  1195	
  1196				gconreg(AMOVL, c, D_CX);
  1197				gins(AREP, N, N);	// repeat
  1198				gins(AMOVSB, N, N);	// MOVB *(SI)-,*(DI)-
  1199			}
  1200	
  1201			if(q > 0) {
  1202				if(c > 0) {
  1203					gconreg(AADDL, -3, D_SI);
  1204					gconreg(AADDL, -3, D_DI);
  1205				} else {
  1206					gconreg(AADDL, w-4, D_SI);
  1207					gconreg(AADDL, w-4, D_DI);
  1208				}
  1209				gconreg(AMOVL, q, D_CX);
  1210				gins(AREP, N, N);	// repeat
  1211				gins(AMOVSL, N, N);	// MOVL *(SI)-,*(DI)-
  1212			}
  1213			// we leave with the flag clear
  1214			gins(ACLD, N, N);
  1215		} else {
  1216			gins(ACLD, N, N);	// paranoia.  TODO(rsc): remove?
  1217			// normal direction
  1218			if(q >= 4) {
  1219				gconreg(AMOVL, q, D_CX);
  1220				gins(AREP, N, N);	// repeat
  1221				gins(AMOVSL, N, N);	// MOVL *(SI)+,*(DI)+
  1222			} else
  1223			while(q > 0) {
  1224				gins(AMOVSL, N, N);	// MOVL *(SI)+,*(DI)+
  1225				q--;
  1226			}
  1227			while(c > 0) {
  1228				gins(AMOVSB, N, N);	// MOVB *(SI)+,*(DI)+
  1229				c--;
  1230			}
  1231		}
  1232	}
  1233	

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.