github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/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  		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 Op, 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 = 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 = 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  	// complex to complex move/convert.
   297  	// make f addable.
   298  	// also use temporary if possible stack overlap.
   299  	if (ft == TCOMPLEX64 || ft == TCOMPLEX128) && (tt == TCOMPLEX64 || tt == TCOMPLEX128) {
   300  		if !f.Addable || overlap_cplx(f, t) {
   301  			var tmp Node
   302  			Tempname(&tmp, f.Type)
   303  			Complexmove(f, &tmp)
   304  			f = &tmp
   305  		}
   306  
   307  		var n1 Node
   308  		var n2 Node
   309  		subnode(&n1, &n2, f)
   310  		var n4 Node
   311  		var n3 Node
   312  		subnode(&n3, &n4, t)
   313  
   314  		Cgen(&n1, &n3)
   315  		Cgen(&n2, &n4)
   316  	} else {
   317  		Fatalf("complexmove: unknown conversion: %v -> %v\n", f.Type, t.Type)
   318  	}
   319  }
   320  
   321  func Complexgen(n *Node, res *Node) {
   322  	if Debug['g'] != 0 {
   323  		Dump("\ncomplexgen-n", n)
   324  		Dump("complexgen-res", res)
   325  	}
   326  
   327  	for n.Op == OCONVNOP {
   328  		n = n.Left
   329  	}
   330  
   331  	// pick off float/complex opcodes
   332  	switch n.Op {
   333  	case OCOMPLEX:
   334  		if res.Addable {
   335  			var n1 Node
   336  			var n2 Node
   337  			subnode(&n1, &n2, res)
   338  			var tmp Node
   339  			Tempname(&tmp, n1.Type)
   340  			Cgen(n.Left, &tmp)
   341  			Cgen(n.Right, &n2)
   342  			Cgen(&tmp, &n1)
   343  			return
   344  		}
   345  
   346  	case OREAL, OIMAG:
   347  		nl := n.Left
   348  		if !nl.Addable {
   349  			var tmp Node
   350  			Tempname(&tmp, nl.Type)
   351  			Complexgen(nl, &tmp)
   352  			nl = &tmp
   353  		}
   354  
   355  		var n1 Node
   356  		var n2 Node
   357  		subnode(&n1, &n2, nl)
   358  		if n.Op == OREAL {
   359  			Cgen(&n1, res)
   360  			return
   361  		}
   362  
   363  		Cgen(&n2, res)
   364  		return
   365  	}
   366  
   367  	// perform conversion from n to res
   368  	tl := Simsimtype(res.Type)
   369  
   370  	tl = cplxsubtype(tl)
   371  	tr := Simsimtype(n.Type)
   372  	tr = cplxsubtype(tr)
   373  	if tl != tr {
   374  		if !n.Addable {
   375  			var n1 Node
   376  			Tempname(&n1, n.Type)
   377  			Complexmove(n, &n1)
   378  			n = &n1
   379  		}
   380  
   381  		Complexmove(n, res)
   382  		return
   383  	}
   384  
   385  	if !res.Addable {
   386  		var n1 Node
   387  		Igen(res, &n1, nil)
   388  		Cgen(n, &n1)
   389  		Regfree(&n1)
   390  		return
   391  	}
   392  
   393  	if n.Addable {
   394  		Complexmove(n, res)
   395  		return
   396  	}
   397  
   398  	switch n.Op {
   399  	default:
   400  		Dump("complexgen: unknown op", n)
   401  		Fatalf("complexgen: unknown op %v", Oconv(int(n.Op), 0))
   402  
   403  	case ODOT,
   404  		ODOTPTR,
   405  		OINDEX,
   406  		OIND,
   407  		ONAME, // PHEAP or PPARAMREF var
   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", Oconv(int(n.Op), 0))
   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  }