github.com/euank/go@v0.0.0-20160829210321-495514729181/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 Op, 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  		u := nc.Val().U.(*Mpcplx)
    93  		nodfconst(nr, t, &u.Real)
    94  		nodfconst(ni, t, &u.Imag)
    95  		return
    96  	}
    97  
    98  	*nr = *nc
    99  	nr.Type = t
   100  
   101  	*ni = *nc
   102  	ni.Type = t
   103  	ni.Xoffset += t.Width
   104  }
   105  
   106  // generate code res = -nl
   107  func minus(nl *Node, res *Node) {
   108  	var ra Node
   109  	ra.Op = OMINUS
   110  	ra.Left = nl
   111  	ra.Type = nl.Type
   112  	Cgen(&ra, res)
   113  }
   114  
   115  // build and execute tree
   116  //	real(res) = -real(nl)
   117  //	imag(res) = -imag(nl)
   118  func complexminus(nl *Node, res *Node) {
   119  	var n1 Node
   120  	var n2 Node
   121  	var n5 Node
   122  	var n6 Node
   123  
   124  	subnode(&n1, &n2, nl)
   125  	subnode(&n5, &n6, res)
   126  
   127  	minus(&n1, &n5)
   128  	minus(&n2, &n6)
   129  }
   130  
   131  // build and execute tree
   132  //	real(res) = real(nl) op real(nr)
   133  //	imag(res) = imag(nl) op imag(nr)
   134  func complexadd(op Op, nl *Node, nr *Node, res *Node) {
   135  	var n1 Node
   136  	var n2 Node
   137  	var n3 Node
   138  	var n4 Node
   139  	var n5 Node
   140  	var n6 Node
   141  
   142  	subnode(&n1, &n2, nl)
   143  	subnode(&n3, &n4, nr)
   144  	subnode(&n5, &n6, res)
   145  
   146  	var ra Node
   147  	ra.Op = op
   148  	ra.Left = &n1
   149  	ra.Right = &n3
   150  	ra.Type = n1.Type
   151  	Cgen(&ra, &n5)
   152  
   153  	ra = Node{}
   154  	ra.Op = op
   155  	ra.Left = &n2
   156  	ra.Right = &n4
   157  	ra.Type = n2.Type
   158  	Cgen(&ra, &n6)
   159  }
   160  
   161  // build and execute tree
   162  //	tmp       = real(nl)*real(nr) - imag(nl)*imag(nr)
   163  //	imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
   164  //	real(res) = tmp
   165  func complexmul(nl *Node, nr *Node, res *Node) {
   166  	var n1 Node
   167  	var n2 Node
   168  	var n3 Node
   169  	var n4 Node
   170  	var n5 Node
   171  	var n6 Node
   172  	var tmp Node
   173  
   174  	subnode(&n1, &n2, nl)
   175  	subnode(&n3, &n4, nr)
   176  	subnode(&n5, &n6, res)
   177  	Tempname(&tmp, n5.Type)
   178  
   179  	// real part -> tmp
   180  	var rm1 Node
   181  
   182  	rm1.Op = OMUL
   183  	rm1.Left = &n1
   184  	rm1.Right = &n3
   185  	rm1.Type = n1.Type
   186  
   187  	var rm2 Node
   188  	rm2.Op = OMUL
   189  	rm2.Left = &n2
   190  	rm2.Right = &n4
   191  	rm2.Type = n2.Type
   192  
   193  	var ra Node
   194  	ra.Op = OSUB
   195  	ra.Left = &rm1
   196  	ra.Right = &rm2
   197  	ra.Type = rm1.Type
   198  	Cgen(&ra, &tmp)
   199  
   200  	// imag part
   201  	rm1 = Node{}
   202  
   203  	rm1.Op = OMUL
   204  	rm1.Left = &n1
   205  	rm1.Right = &n4
   206  	rm1.Type = n1.Type
   207  
   208  	rm2 = Node{}
   209  	rm2.Op = OMUL
   210  	rm2.Left = &n2
   211  	rm2.Right = &n3
   212  	rm2.Type = n2.Type
   213  
   214  	ra = Node{}
   215  	ra.Op = OADD
   216  	ra.Left = &rm1
   217  	ra.Right = &rm2
   218  	ra.Type = rm1.Type
   219  	Cgen(&ra, &n6)
   220  
   221  	// tmp ->real part
   222  	Cgen(&tmp, &n5)
   223  }
   224  
   225  func nodfconst(n *Node, t *Type, fval *Mpflt) {
   226  	*n = Node{}
   227  	n.Op = OLITERAL
   228  	n.Addable = true
   229  	ullmancalc(n)
   230  	n.SetVal(Val{fval})
   231  	n.Type = t
   232  
   233  	if !t.IsFloat() {
   234  		Fatalf("nodfconst: bad type %v", t)
   235  	}
   236  }
   237  
   238  func Complexop(n *Node, res *Node) bool {
   239  	if n != nil && n.Type != nil {
   240  		if n.Type.IsComplex() {
   241  			goto maybe
   242  		}
   243  	}
   244  
   245  	if res != nil && res.Type != nil {
   246  		if res.Type.IsComplex() {
   247  			goto maybe
   248  		}
   249  	}
   250  
   251  	if n.Op == OREAL || n.Op == OIMAG {
   252  		//dump("\ncomplex-yes", n);
   253  		return true
   254  	}
   255  
   256  	//dump("\ncomplex-no", n);
   257  	return false
   258  
   259  maybe:
   260  	switch n.Op {
   261  	case OCONV, // implemented ops
   262  		OADD,
   263  		OSUB,
   264  		OMUL,
   265  		OMINUS,
   266  		OCOMPLEX,
   267  		OREAL,
   268  		OIMAG:
   269  		//dump("\ncomplex-yes", n);
   270  		return true
   271  
   272  	case ODOT,
   273  		ODOTPTR,
   274  		OINDEX,
   275  		OIND,
   276  		ONAME:
   277  		//dump("\ncomplex-yes", n);
   278  		return true
   279  	}
   280  
   281  	//dump("\ncomplex-no", n);
   282  	return false
   283  }
   284  
   285  func Complexmove(f *Node, t *Node) {
   286  	if Debug['g'] != 0 {
   287  		Dump("\ncomplexmove-f", f)
   288  		Dump("complexmove-t", t)
   289  	}
   290  
   291  	if !t.Addable {
   292  		Fatalf("complexmove: to not addable")
   293  	}
   294  
   295  	ft := Simsimtype(f.Type)
   296  	tt := Simsimtype(t.Type)
   297  	// complex to complex move/convert.
   298  	// make f addable.
   299  	// also use temporary if possible stack overlap.
   300  	if (ft == TCOMPLEX64 || ft == TCOMPLEX128) && (tt == TCOMPLEX64 || tt == TCOMPLEX128) {
   301  		if !f.Addable || overlap_cplx(f, t) {
   302  			var tmp Node
   303  			Tempname(&tmp, f.Type)
   304  			Complexmove(f, &tmp)
   305  			f = &tmp
   306  		}
   307  
   308  		var n1 Node
   309  		var n2 Node
   310  		subnode(&n1, &n2, f)
   311  		var n4 Node
   312  		var n3 Node
   313  		subnode(&n3, &n4, t)
   314  
   315  		Cgen(&n1, &n3)
   316  		Cgen(&n2, &n4)
   317  	} else {
   318  		Fatalf("complexmove: unknown conversion: %v -> %v\n", f.Type, t.Type)
   319  	}
   320  }
   321  
   322  func Complexgen(n *Node, res *Node) {
   323  	if Debug['g'] != 0 {
   324  		Dump("\ncomplexgen-n", n)
   325  		Dump("complexgen-res", res)
   326  	}
   327  
   328  	for n.Op == OCONVNOP {
   329  		n = n.Left
   330  	}
   331  
   332  	// pick off float/complex opcodes
   333  	switch n.Op {
   334  	case OCOMPLEX:
   335  		if res.Addable {
   336  			var n1 Node
   337  			var n2 Node
   338  			subnode(&n1, &n2, res)
   339  			var tmp Node
   340  			Tempname(&tmp, n1.Type)
   341  			Cgen(n.Left, &tmp)
   342  			Cgen(n.Right, &n2)
   343  			Cgen(&tmp, &n1)
   344  			return
   345  		}
   346  
   347  	case OREAL, OIMAG:
   348  		nl := n.Left
   349  		if !nl.Addable {
   350  			var tmp Node
   351  			Tempname(&tmp, nl.Type)
   352  			Complexgen(nl, &tmp)
   353  			nl = &tmp
   354  		}
   355  
   356  		var n1 Node
   357  		var n2 Node
   358  		subnode(&n1, &n2, nl)
   359  		if n.Op == OREAL {
   360  			Cgen(&n1, res)
   361  			return
   362  		}
   363  
   364  		Cgen(&n2, res)
   365  		return
   366  	}
   367  
   368  	// perform conversion from n to res
   369  	tl := Simsimtype(res.Type)
   370  
   371  	tl = cplxsubtype(tl)
   372  	tr := Simsimtype(n.Type)
   373  	tr = cplxsubtype(tr)
   374  	if tl != tr {
   375  		if !n.Addable {
   376  			var n1 Node
   377  			Tempname(&n1, n.Type)
   378  			Complexmove(n, &n1)
   379  			n = &n1
   380  		}
   381  
   382  		Complexmove(n, res)
   383  		return
   384  	}
   385  
   386  	if !res.Addable {
   387  		var n1 Node
   388  		Igen(res, &n1, nil)
   389  		Cgen(n, &n1)
   390  		Regfree(&n1)
   391  		return
   392  	}
   393  
   394  	if n.Addable {
   395  		Complexmove(n, res)
   396  		return
   397  	}
   398  
   399  	switch n.Op {
   400  	default:
   401  		Dump("complexgen: unknown op", n)
   402  		Fatalf("complexgen: unknown op %v", n.Op)
   403  
   404  	case ODOT,
   405  		ODOTPTR,
   406  		OINDEX,
   407  		OIND,
   408  		OCALLFUNC,
   409  		OCALLMETH,
   410  		OCALLINTER:
   411  		var n1 Node
   412  		Igen(n, &n1, res)
   413  
   414  		Complexmove(&n1, res)
   415  		Regfree(&n1)
   416  		return
   417  
   418  	case OCONV,
   419  		OADD,
   420  		OSUB,
   421  		OMUL,
   422  		OMINUS,
   423  		OCOMPLEX,
   424  		OREAL,
   425  		OIMAG:
   426  		break
   427  	}
   428  
   429  	nl := n.Left
   430  	if nl == nil {
   431  		return
   432  	}
   433  	nr := n.Right
   434  
   435  	// make both sides addable in ullman order
   436  	var tnl Node
   437  	if nr != nil {
   438  		if nl.Ullman > nr.Ullman && !nl.Addable {
   439  			Tempname(&tnl, nl.Type)
   440  			Cgen(nl, &tnl)
   441  			nl = &tnl
   442  		}
   443  
   444  		if !nr.Addable {
   445  			var tnr Node
   446  			Tempname(&tnr, nr.Type)
   447  			Cgen(nr, &tnr)
   448  			nr = &tnr
   449  		}
   450  	}
   451  
   452  	if !nl.Addable {
   453  		Tempname(&tnl, nl.Type)
   454  		Cgen(nl, &tnl)
   455  		nl = &tnl
   456  	}
   457  
   458  	switch n.Op {
   459  	default:
   460  		Fatalf("complexgen: unknown op %v", n.Op)
   461  
   462  	case OCONV:
   463  		Complexmove(nl, res)
   464  
   465  	case OMINUS:
   466  		complexminus(nl, res)
   467  
   468  	case OADD, OSUB:
   469  		complexadd(n.Op, nl, nr, res)
   470  
   471  	case OMUL:
   472  		complexmul(nl, nr, res)
   473  	}
   474  }