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