// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package gc import "cmd/internal/obj" func overlap_cplx(f *Node, t *Node) bool { // check whether f and t could be overlapping stack references. // not exact, because it's hard to check for the stack register // in portable code. close enough: worst case we will allocate // an extra temporary and the registerizer will clean it up. return f.Op == OINDREG && t.Op == OINDREG && f.Xoffset+f.Type.Width >= t.Xoffset && t.Xoffset+t.Type.Width >= f.Xoffset } func complexbool(op int, nl, nr, res *Node, wantTrue bool, likely int, to *obj.Prog) { // make both sides addable in ullman order if nr != nil { if nl.Ullman > nr.Ullman && !nl.Addable { nl = CgenTemp(nl) } if !nr.Addable { nr = CgenTemp(nr) } } if !nl.Addable { nl = CgenTemp(nl) } // Break nl and nr into real and imaginary components. var lreal, limag, rreal, rimag Node subnode(&lreal, &limag, nl) subnode(&rreal, &rimag, nr) // build tree // if branching: // real(l) == real(r) && imag(l) == imag(r) // if generating a value, use a branch-free version: // real(l) == real(r) & imag(l) == imag(r) realeq := Node{ Op: OEQ, Left: &lreal, Right: &rreal, Type: Types[TBOOL], } imageq := Node{ Op: OEQ, Left: &limag, Right: &rimag, Type: Types[TBOOL], } and := Node{ Op: OANDAND, Left: &realeq, Right: &imageq, Type: Types[TBOOL], } if res != nil { // generating a value and.Op = OAND if op == ONE { and.Op = OOR realeq.Op = ONE imageq.Op = ONE } Bvgen(&and, res, true) return } // generating a branch if op == ONE { wantTrue = !wantTrue } Bgen(&and, wantTrue, likely, to) } // break addable nc-complex into nr-real and ni-imaginary func subnode(nr *Node, ni *Node, nc *Node) { if !nc.Addable { Fatal("subnode not addable") } tc := Simsimtype(nc.Type) tc = cplxsubtype(tc) t := Types[tc] if nc.Op == OLITERAL { nodfconst(nr, t, &nc.Val().U.(*Mpcplx).Real) nodfconst(ni, t, &nc.Val().U.(*Mpcplx).Imag) return } *nr = *nc nr.Type = t *ni = *nc ni.Type = t ni.Xoffset += t.Width } // generate code res = -nl func minus(nl *Node, res *Node) { var ra Node ra.Op = OMINUS ra.Left = nl ra.Type = nl.Type Cgen(&ra, res) } // build and execute tree // real(res) = -real(nl) // imag(res) = -imag(nl) func complexminus(nl *Node, res *Node) { var n1 Node var n2 Node var n5 Node var n6 Node subnode(&n1, &n2, nl) subnode(&n5, &n6, res) minus(&n1, &n5) minus(&n2, &n6) } // build and execute tree // real(res) = real(nl) op real(nr) // imag(res) = imag(nl) op imag(nr) func complexadd(op int, nl *Node, nr *Node, res *Node) { var n1 Node var n2 Node var n3 Node var n4 Node var n5 Node var n6 Node subnode(&n1, &n2, nl) subnode(&n3, &n4, nr) subnode(&n5, &n6, res) var ra Node ra.Op = uint8(op) ra.Left = &n1 ra.Right = &n3 ra.Type = n1.Type Cgen(&ra, &n5) ra = Node{} ra.Op = uint8(op) ra.Left = &n2 ra.Right = &n4 ra.Type = n2.Type Cgen(&ra, &n6) } // build and execute tree // tmp = real(nl)*real(nr) - imag(nl)*imag(nr) // imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr) // real(res) = tmp func complexmul(nl *Node, nr *Node, res *Node) { var n1 Node var n2 Node var n3 Node var n4 Node var n5 Node var n6 Node var tmp Node subnode(&n1, &n2, nl) subnode(&n3, &n4, nr) subnode(&n5, &n6, res) Tempname(&tmp, n5.Type) // real part -> tmp var rm1 Node rm1.Op = OMUL rm1.Left = &n1 rm1.Right = &n3 rm1.Type = n1.Type var rm2 Node rm2.Op = OMUL rm2.Left = &n2 rm2.Right = &n4 rm2.Type = n2.Type var ra Node ra.Op = OSUB ra.Left = &rm1 ra.Right = &rm2 ra.Type = rm1.Type Cgen(&ra, &tmp) // imag part rm1 = Node{} rm1.Op = OMUL rm1.Left = &n1 rm1.Right = &n4 rm1.Type = n1.Type rm2 = Node{} rm2.Op = OMUL rm2.Left = &n2 rm2.Right = &n3 rm2.Type = n2.Type ra = Node{} ra.Op = OADD ra.Left = &rm1 ra.Right = &rm2 ra.Type = rm1.Type Cgen(&ra, &n6) // tmp ->real part Cgen(&tmp, &n5) } func nodfconst(n *Node, t *Type, fval *Mpflt) { *n = Node{} n.Op = OLITERAL n.Addable = true ullmancalc(n) n.SetVal(Val{fval}) n.Type = t if !Isfloat[t.Etype] { Fatal("nodfconst: bad type %v", t) } } func Complexop(n *Node, res *Node) bool { if n != nil && n.Type != nil { if Iscomplex[n.Type.Etype] { goto maybe } } if res != nil && res.Type != nil { if Iscomplex[res.Type.Etype] { goto maybe } } if n.Op == OREAL || n.Op == OIMAG { //dump("\ncomplex-yes", n); return true } //dump("\ncomplex-no", n); return false maybe: switch n.Op { case OCONV, // implemented ops OADD, OSUB, OMUL, OMINUS, OCOMPLEX, OREAL, OIMAG: //dump("\ncomplex-yes", n); return true case ODOT, ODOTPTR, OINDEX, OIND, ONAME: //dump("\ncomplex-yes", n); return true } //dump("\ncomplex-no", n); return false } func Complexmove(f *Node, t *Node) { if Debug['g'] != 0 { Dump("\ncomplexmove-f", f) Dump("complexmove-t", t) } if !t.Addable { Fatal("complexmove: to not addable") } ft := Simsimtype(f.Type) tt := Simsimtype(t.Type) switch uint32(ft)<<16 | uint32(tt) { default: Fatal("complexmove: unknown conversion: %v -> %v\n", f.Type, t.Type) // complex to complex move/convert. // make f addable. // also use temporary if possible stack overlap. case TCOMPLEX64<<16 | TCOMPLEX64, TCOMPLEX64<<16 | TCOMPLEX128, TCOMPLEX128<<16 | TCOMPLEX64, TCOMPLEX128<<16 | TCOMPLEX128: if !f.Addable || overlap_cplx(f, t) { var tmp Node Tempname(&tmp, f.Type) Complexmove(f, &tmp) f = &tmp } var n1 Node var n2 Node subnode(&n1, &n2, f) var n4 Node var n3 Node subnode(&n3, &n4, t) Cgen(&n1, &n3) Cgen(&n2, &n4) } } func Complexgen(n *Node, res *Node) { if Debug['g'] != 0 { Dump("\ncomplexgen-n", n) Dump("complexgen-res", res) } for n.Op == OCONVNOP { n = n.Left } // pick off float/complex opcodes switch n.Op { case OCOMPLEX: if res.Addable { var n1 Node var n2 Node subnode(&n1, &n2, res) var tmp Node Tempname(&tmp, n1.Type) Cgen(n.Left, &tmp) Cgen(n.Right, &n2) Cgen(&tmp, &n1) return } case OREAL, OIMAG: nl := n.Left if !nl.Addable { var tmp Node Tempname(&tmp, nl.Type) Complexgen(nl, &tmp) nl = &tmp } var n1 Node var n2 Node subnode(&n1, &n2, nl) if n.Op == OREAL { Cgen(&n1, res) return } Cgen(&n2, res) return } // perform conversion from n to res tl := Simsimtype(res.Type) tl = cplxsubtype(tl) tr := Simsimtype(n.Type) tr = cplxsubtype(tr) if tl != tr { if !n.Addable { var n1 Node Tempname(&n1, n.Type) Complexmove(n, &n1) n = &n1 } Complexmove(n, res) return } if !res.Addable { var n1 Node Igen(res, &n1, nil) Cgen(n, &n1) Regfree(&n1) return } if n.Addable { Complexmove(n, res) return } switch n.Op { default: Dump("complexgen: unknown op", n) Fatal("complexgen: unknown op %v", Oconv(int(n.Op), 0)) case ODOT, ODOTPTR, OINDEX, OIND, ONAME, // PHEAP or PPARAMREF var OCALLFUNC, OCALLMETH, OCALLINTER: var n1 Node Igen(n, &n1, res) Complexmove(&n1, res) Regfree(&n1) return case OCONV, OADD, OSUB, OMUL, OMINUS, OCOMPLEX, OREAL, OIMAG: break } nl := n.Left if nl == nil { return } nr := n.Right // make both sides addable in ullman order var tnl Node if nr != nil { if nl.Ullman > nr.Ullman && !nl.Addable { Tempname(&tnl, nl.Type) Cgen(nl, &tnl) nl = &tnl } if !nr.Addable { var tnr Node Tempname(&tnr, nr.Type) Cgen(nr, &tnr) nr = &tnr } } if !nl.Addable { Tempname(&tnl, nl.Type) Cgen(nl, &tnl) nl = &tnl } switch n.Op { default: Fatal("complexgen: unknown op %v", Oconv(int(n.Op), 0)) case OCONV: Complexmove(nl, res) case OMINUS: complexminus(nl, res) case OADD, OSUB: complexadd(int(n.Op), nl, nr, res) case OMUL: complexmul(nl, nr, res) } }