The Go Programming Language

Text file src/cmd/gc/cplx.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	#include "gg.h"
     6	
     7	static	void	subnode(Node *nr, Node *ni, Node *nc);
     8	static	void	minus(Node *nl, Node *res);
     9		void	complexminus(Node*, Node*);
    10		void	complexadd(int op, Node*, Node*, Node*);
    11		void	complexmul(Node*, Node*, Node*);
    12	
    13	#define	CASE(a,b)	(((a)<<16)|((b)<<0))
    14	
    15	static int
    16	overlap(Node *f, Node *t)
    17	{
    18		// check whether f and t could be overlapping stack references.
    19		// not exact, because it's hard to check for the stack register
    20		// in portable code.  close enough: worst case we will allocate
    21		// an extra temporary and the registerizer will clean it up.
    22		return f->op == OINDREG &&
    23			t->op == OINDREG &&
    24			f->xoffset+f->type->width >= t->xoffset &&
    25			t->xoffset+t->type->width >= f->xoffset;
    26	}
    27	
    28	/*
    29	 * generate:
    30	 *	res = n;
    31	 * simplifies and calls gmove.
    32	 */
    33	void
    34	complexmove(Node *f, Node *t)
    35	{
    36		int ft, tt;
    37		Node n1, n2, n3, n4;
    38	
    39		if(debug['g']) {
    40			dump("\ncomplexmove-f", f);
    41			dump("complexmove-t", t);
    42		}
    43	
    44		if(!t->addable)
    45			fatal("complexmove: to not addable");
    46	
    47		ft = simsimtype(f->type);
    48		tt = simsimtype(t->type);
    49		switch(CASE(ft,tt)) {
    50	
    51		default:
    52			fatal("complexmove: unknown conversion: %T -> %T\n",
    53				f->type, t->type);
    54	
    55		case CASE(TCOMPLEX64,TCOMPLEX64):
    56		case CASE(TCOMPLEX64,TCOMPLEX128):
    57		case CASE(TCOMPLEX128,TCOMPLEX64):
    58		case CASE(TCOMPLEX128,TCOMPLEX128):
    59			// complex to complex move/convert.
    60			// make f addable.
    61			// also use temporary if possible stack overlap.
    62			if(!f->addable || overlap(f, t)) {
    63				tempname(&n1, f->type);
    64				complexmove(f, &n1);
    65				f = &n1;
    66			}
    67	
    68			subnode(&n1, &n2, f);
    69			subnode(&n3, &n4, t);
    70	
    71			cgen(&n1, &n3);
    72			cgen(&n2, &n4);
    73			break;
    74		}
    75	}
    76	
    77	int
    78	complexop(Node *n, Node *res)
    79	{
    80		if(n != N && n->type != T)
    81		if(iscomplex[n->type->etype]) {
    82			goto maybe;
    83		}
    84		if(res != N && res->type != T)
    85		if(iscomplex[res->type->etype]) {
    86			goto maybe;
    87		}
    88	
    89		if(n->op == OREAL || n->op == OIMAG)
    90			goto yes;
    91	
    92		goto no;
    93	
    94	maybe:
    95		switch(n->op) {
    96		case OCONV:	// implemented ops
    97		case OADD:
    98		case OSUB:
    99		case OMUL:
   100		case OMINUS:
   101		case OCOMPLEX:
   102		case OREAL:
   103		case OIMAG:
   104			goto yes;
   105	
   106		case ODOT:
   107		case ODOTPTR:
   108		case OINDEX:
   109		case OIND:
   110		case ONAME:
   111			goto yes;
   112		}
   113	
   114	no:
   115	//dump("\ncomplex-no", n);
   116		return 0;
   117	yes:
   118	//dump("\ncomplex-yes", n);
   119		return 1;
   120	}
   121	
   122	void
   123	complexgen(Node *n, Node *res)
   124	{
   125		Node *nl, *nr;
   126		Node tnl, tnr;
   127		Node n1, n2, tmp;
   128		int tl, tr;
   129	
   130		if(debug['g']) {
   131			dump("\ncomplexgen-n", n);
   132			dump("complexgen-res", res);
   133		}
   134	
   135		// pick off float/complex opcodes
   136		switch(n->op) {
   137		case OCOMPLEX:
   138			if(res->addable) {
   139				subnode(&n1, &n2, res);
   140				tempname(&tmp, n1.type);
   141				cgen(n->left, &tmp);
   142				cgen(n->right, &n2);
   143				cgen(&tmp, &n1);
   144				return;
   145			}
   146			break;
   147	
   148		case OREAL:
   149		case OIMAG:
   150			nl = n->left;
   151			if(!nl->addable) {
   152				tempname(&tmp, nl->type);
   153				complexgen(nl, &tmp);
   154				nl = &tmp;
   155			}
   156			subnode(&n1, &n2, nl);
   157			if(n->op == OREAL) {
   158				cgen(&n1, res);
   159				return;
   160			}
   161			cgen(&n2, res);
   162			return;
   163		}
   164	
   165		// perform conversion from n to res
   166		tl = simsimtype(res->type);
   167		tl = cplxsubtype(tl);
   168		tr = simsimtype(n->type);
   169		tr = cplxsubtype(tr);
   170		if(tl != tr) {
   171			if(!n->addable) {
   172				tempname(&n1, n->type);
   173				complexmove(n, &n1);
   174				n = &n1;
   175			}
   176			complexmove(n, res);
   177			return;
   178		}
   179	
   180		if(!res->addable) {
   181			igen(res, &n1, N);
   182			cgen(n, &n1);
   183			regfree(&n1);
   184			return;
   185		}
   186		if(n->addable) {
   187			complexmove(n, res);
   188			return;
   189		}
   190	
   191		switch(n->op) {
   192		default:
   193			dump("complexgen: unknown op", n);
   194			fatal("complexgen: unknown op %O", n->op);
   195	
   196		case ODOT:
   197		case ODOTPTR:
   198		case OINDEX:
   199		case OIND:
   200		case ONAME:	// PHEAP or PPARAMREF var
   201		case OCALLFUNC:
   202			igen(n, &n1, res);
   203			complexmove(&n1, res);
   204			regfree(&n1);
   205			return;
   206	
   207		case OCONV:
   208		case OADD:
   209		case OSUB:
   210		case OMUL:
   211		case OMINUS:
   212		case OCOMPLEX:
   213		case OREAL:
   214		case OIMAG:
   215			break;
   216		}
   217	
   218		nl = n->left;
   219		if(nl == N)
   220			return;
   221		nr = n->right;
   222	
   223		// make both sides addable in ullman order
   224		if(nr != N) {
   225			if(nl->ullman > nr->ullman && !nl->addable) {
   226				tempname(&tnl, nl->type);
   227				cgen(nl, &tnl);
   228				nl = &tnl;
   229			}
   230			if(!nr->addable) {
   231				tempname(&tnr, nr->type);
   232				cgen(nr, &tnr);
   233				nr = &tnr;
   234			}
   235		}
   236		if(!nl->addable) {
   237			tempname(&tnl, nl->type);
   238			cgen(nl, &tnl);
   239			nl = &tnl;
   240		}
   241	
   242		switch(n->op) {
   243		default:
   244			fatal("complexgen: unknown op %O", n->op);
   245			break;
   246	
   247		case OCONV:
   248			complexmove(nl, res);
   249			break;
   250	
   251		case OMINUS:
   252			complexminus(nl, res);
   253			break;
   254	
   255		case OADD:
   256		case OSUB:
   257			complexadd(n->op, nl, nr, res);
   258			break;
   259	
   260		case OMUL:
   261			complexmul(nl, nr, res);
   262			break;
   263		}
   264	}
   265	
   266	void
   267	complexbool(int op, Node *nl, Node *nr, int true, Prog *to)
   268	{
   269		Node tnl, tnr;
   270		Node n1, n2, n3, n4;
   271		Node na, nb, nc;
   272	
   273		// make both sides addable in ullman order
   274		if(nr != N) {
   275			if(nl->ullman > nr->ullman && !nl->addable) {
   276				tempname(&tnl, nl->type);
   277				cgen(nl, &tnl);
   278				nl = &tnl;
   279			}
   280			if(!nr->addable) {
   281				tempname(&tnr, nr->type);
   282				cgen(nr, &tnr);
   283				nr = &tnr;
   284			}
   285		}
   286		if(!nl->addable) {
   287			tempname(&tnl, nl->type);
   288			cgen(nl, &tnl);
   289			nl = &tnl;
   290		}
   291	
   292		// build tree
   293		// real(l) == real(r) && imag(l) == imag(r)
   294	
   295		subnode(&n1, &n2, nl);
   296		subnode(&n3, &n4, nr);
   297	
   298		memset(&na, 0, sizeof(na));
   299		na.op = OANDAND;
   300		na.left = &nb;
   301		na.right = &nc;
   302		na.type = types[TBOOL];
   303	
   304		memset(&nb, 0, sizeof(na));
   305		nb.op = OEQ;
   306		nb.left = &n1;
   307		nb.right = &n3;
   308		nb.type = types[TBOOL];
   309	
   310		memset(&nc, 0, sizeof(na));
   311		nc.op = OEQ;
   312		nc.left = &n2;
   313		nc.right = &n4;
   314		nc.type = types[TBOOL];
   315	
   316		if(op == ONE)
   317			true = !true;
   318	
   319		bgen(&na, true, to);
   320	}
   321	
   322	void
   323	nodfconst(Node *n, Type *t, Mpflt* fval)
   324	{
   325		memset(n, 0, sizeof(*n));
   326		n->op = OLITERAL;
   327		n->addable = 1;
   328		ullmancalc(n);
   329		n->val.u.fval = fval;
   330		n->val.ctype = CTFLT;
   331		n->type = t;
   332	
   333		if(!isfloat[t->etype])
   334			fatal("nodfconst: bad type %T", t);
   335	}
   336	
   337	// break addable nc-complex into nr-real and ni-imaginary
   338	static void
   339	subnode(Node *nr, Node *ni, Node *nc)
   340	{
   341		int tc;
   342		Type *t;
   343	
   344		if(!nc->addable)
   345			fatal("subnode not addable");
   346	
   347		tc = simsimtype(nc->type);
   348		tc = cplxsubtype(tc);
   349		t = types[tc];
   350	
   351		if(nc->op == OLITERAL) {
   352			nodfconst(nr, t, &nc->val.u.cval->real);
   353			nodfconst(ni, t, &nc->val.u.cval->imag);
   354			return;
   355		}
   356	
   357		*nr = *nc;
   358		nr->type = t;
   359	
   360		*ni = *nc;
   361		ni->type = t;
   362		ni->xoffset += t->width;
   363	}
   364	
   365	// generate code res = -nl
   366	static void
   367	minus(Node *nl, Node *res)
   368	{
   369		Node ra;
   370	
   371		memset(&ra, 0, sizeof(ra));
   372		ra.op = OMINUS;
   373		ra.left = nl;
   374		ra.type = nl->type;
   375		cgen(&ra, res);
   376	}
   377	
   378	// build and execute tree
   379	//	real(res) = -real(nl)
   380	//	imag(res) = -imag(nl)
   381	void
   382	complexminus(Node *nl, Node *res)
   383	{
   384		Node n1, n2, n5, n6;
   385	
   386		subnode(&n1, &n2, nl);
   387		subnode(&n5, &n6, res);
   388	
   389		minus(&n1, &n5);
   390		minus(&n2, &n6);
   391	}
   392	
   393	
   394	// build and execute tree
   395	//	real(res) = real(nl) op real(nr)
   396	//	imag(res) = imag(nl) op imag(nr)
   397	void
   398	complexadd(int op, Node *nl, Node *nr, Node *res)
   399	{
   400		Node n1, n2, n3, n4, n5, n6;
   401		Node ra;
   402	
   403		subnode(&n1, &n2, nl);
   404		subnode(&n3, &n4, nr);
   405		subnode(&n5, &n6, res);
   406	
   407		memset(&ra, 0, sizeof(ra));
   408		ra.op = op;
   409		ra.left = &n1;
   410		ra.right = &n3;
   411		ra.type = n1.type;
   412		cgen(&ra, &n5);
   413	
   414		memset(&ra, 0, sizeof(ra));
   415		ra.op = op;
   416		ra.left = &n2;
   417		ra.right = &n4;
   418		ra.type = n2.type;
   419		cgen(&ra, &n6);
   420	}
   421	
   422	// build and execute tree
   423	//	tmp       = real(nl)*real(nr) - imag(nl)*imag(nr)
   424	//	imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
   425	//	real(res) = tmp
   426	void
   427	complexmul(Node *nl, Node *nr, Node *res)
   428	{
   429		Node n1, n2, n3, n4, n5, n6;
   430		Node rm1, rm2, ra, tmp;
   431	
   432		subnode(&n1, &n2, nl);
   433		subnode(&n3, &n4, nr);
   434		subnode(&n5, &n6, res);
   435		tempname(&tmp, n5.type);
   436	
   437		// real part -> tmp
   438		memset(&rm1, 0, sizeof(ra));
   439		rm1.op = OMUL;
   440		rm1.left = &n1;
   441		rm1.right = &n3;
   442		rm1.type = n1.type;
   443	
   444		memset(&rm2, 0, sizeof(ra));
   445		rm2.op = OMUL;
   446		rm2.left = &n2;
   447		rm2.right = &n4;
   448		rm2.type = n2.type;
   449	
   450		memset(&ra, 0, sizeof(ra));
   451		ra.op = OSUB;
   452		ra.left = &rm1;
   453		ra.right = &rm2;
   454		ra.type = rm1.type;
   455		cgen(&ra, &tmp);
   456	
   457		// imag part
   458		memset(&rm1, 0, sizeof(ra));
   459		rm1.op = OMUL;
   460		rm1.left = &n1;
   461		rm1.right = &n4;
   462		rm1.type = n1.type;
   463	
   464		memset(&rm2, 0, sizeof(ra));
   465		rm2.op = OMUL;
   466		rm2.left = &n2;
   467		rm2.right = &n3;
   468		rm2.type = n2.type;
   469	
   470		memset(&ra, 0, sizeof(ra));
   471		ra.op = OADD;
   472		ra.left = &rm1;
   473		ra.right = &rm2;
   474		ra.type = rm1.type;
   475		cgen(&ra, &n6);
   476	
   477		// tmp ->real part
   478		cgen(&tmp, &n5);
   479	}

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