github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/cplx.go (about)

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