| // 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 { |
| Fatalf("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] { |
| Fatalf("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 { |
| Fatalf("complexmove: to not addable") |
| } |
| |
| ft := Simsimtype(f.Type) |
| tt := Simsimtype(t.Type) |
| switch uint32(ft)<<16 | uint32(tt) { |
| default: |
| Fatalf("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) |
| Fatalf("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: |
| Fatalf("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) |
| } |
| } |