blob: fe4c38c285dcb21124645416cab16e5c591100ac [file] [log] [blame]
// 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 CASE(a int, b int) int {
return a<<16 | b
}
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 *Node, nr *Node, true_ bool, likely int, to *obj.Prog) {
var tnl Node
// make both sides addable in ullman order
if nr != nil {
if nl.Ullman > nr.Ullman && nl.Addable == 0 {
Tempname(&tnl, nl.Type)
Cgen(nl, &tnl)
nl = &tnl
}
if nr.Addable == 0 {
var tnr Node
Tempname(&tnr, nr.Type)
Cgen(nr, &tnr)
nr = &tnr
}
}
if nl.Addable == 0 {
Tempname(&tnl, nl.Type)
Cgen(nl, &tnl)
nl = &tnl
}
// build tree
// real(l) == real(r) && imag(l) == imag(r)
var n2 Node
var n1 Node
subnode(&n1, &n2, nl)
var n3 Node
var n4 Node
subnode(&n3, &n4, nr)
var na Node
na.Op = OANDAND
var nb Node
na.Left = &nb
var nc Node
na.Right = &nc
na.Type = Types[TBOOL]
nb = Node{}
nb.Op = OEQ
nb.Left = &n1
nb.Right = &n3
nb.Type = Types[TBOOL]
nc = Node{}
nc.Op = OEQ
nc.Left = &n2
nc.Right = &n4
nc.Type = Types[TBOOL]
if op == ONE {
true_ = !true_
}
Bgen(&na, true_, likely, to)
}
// break addable nc-complex into nr-real and ni-imaginary
func subnode(nr *Node, ni *Node, nc *Node) {
if nc.Addable == 0 {
Fatal("subnode not addable")
}
tc := Simsimtype(nc.Type)
tc = cplxsubtype(tc)
t := Types[tc]
if nc.Op == OLITERAL {
nodfconst(nr, t, &nc.Val.U.Cval.Real)
nodfconst(ni, t, &nc.Val.U.Cval.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 = 1
ullmancalc(n)
n.Val.U.Fval = fval
n.Val.Ctype = CTFLT
n.Type = t
if !Isfloat[t.Etype] {
Fatal("nodfconst: bad type %v", Tconv(t, 0))
}
}
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 == 0 {
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", Tconv(f.Type, 0), Tconv(t.Type, 0))
// 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 == 0 || 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 != 0 {
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 == 0 {
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 == 0 {
var n1 Node
Tempname(&n1, n.Type)
Complexmove(n, &n1)
n = &n1
}
Complexmove(n, res)
return
}
if res.Addable == 0 {
var n1 Node
Igen(res, &n1, nil)
Cgen(n, &n1)
Regfree(&n1)
return
}
if n.Addable != 0 {
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 == 0 {
Tempname(&tnl, nl.Type)
Cgen(nl, &tnl)
nl = &tnl
}
if nr.Addable == 0 {
var tnr Node
Tempname(&tnr, nr.Type)
Cgen(nr, &tnr)
nr = &tnr
}
}
if nl.Addable == 0 {
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)
}
}