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