blob: 34decd1421392e064190b4331550ea0615f640e0 [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
var tnr Node
var n1 Node
var n2 Node
var n3 Node
var n4 Node
var na Node
var nb Node
var nc Node
// make both sides addable in ullman order
if nr != nil {
if nl.Ullman > nr.Ullman && nl.Addable == 0 {
Tempname(&tnl, nl.Type)
Thearch.Cgen(nl, &tnl)
nl = &tnl
}
if nr.Addable == 0 {
Tempname(&tnr, nr.Type)
Thearch.Cgen(nr, &tnr)
nr = &tnr
}
}
if nl.Addable == 0 {
Tempname(&tnl, nl.Type)
Thearch.Cgen(nl, &tnl)
nl = &tnl
}
// build tree
// real(l) == real(r) && imag(l) == imag(r)
subnode(&n1, &n2, nl)
subnode(&n3, &n4, nr)
na = Node{}
na.Op = OANDAND
na.Left = &nb
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_
}
Thearch.Bgen(&na, true_, likely, to)
}
// break addable nc-complex into nr-real and ni-imaginary
func subnode(nr *Node, ni *Node, nc *Node) {
var tc int
var t *Type
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 = Node{}
ra.Op = OMINUS
ra.Left = nl
ra.Type = nl.Type
Thearch.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
var ra Node
subnode(&n1, &n2, nl)
subnode(&n3, &n4, nr)
subnode(&n5, &n6, res)
ra = Node{}
ra.Op = uint8(op)
ra.Left = &n1
ra.Right = &n3
ra.Type = n1.Type
Thearch.Cgen(&ra, &n5)
ra = Node{}
ra.Op = uint8(op)
ra.Left = &n2
ra.Right = &n4
ra.Type = n2.Type
Thearch.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 rm1 Node
var rm2 Node
var ra Node
var tmp Node
subnode(&n1, &n2, nl)
subnode(&n3, &n4, nr)
subnode(&n5, &n6, res)
Tempname(&tmp, n5.Type)
// real part -> tmp
rm1 = Node{}
rm1.Op = OMUL
rm1.Left = &n1
rm1.Right = &n3
rm1.Type = n1.Type
rm2 = Node{}
rm2.Op = OMUL
rm2.Left = &n2
rm2.Right = &n4
rm2.Type = n2.Type
ra = Node{}
ra.Op = OSUB
ra.Left = &rm1
ra.Right = &rm2
ra.Type = rm1.Type
Thearch.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
Thearch.Cgen(&ra, &n6)
// tmp ->real part
Thearch.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] == 0 {
Fatal("nodfconst: bad type %v", Tconv(t, 0))
}
}
/*
* cplx.c
*/
func Complexop(n *Node, res *Node) bool {
if n != nil && n.Type != nil {
if Iscomplex[n.Type.Etype] != 0 {
goto maybe
}
}
if res != nil && res.Type != nil {
if Iscomplex[res.Type.Etype] != 0 {
goto maybe
}
}
if n.Op == OREAL || n.Op == OIMAG {
goto yes
}
goto no
maybe:
switch n.Op {
case OCONV, // implemented ops
OADD,
OSUB,
OMUL,
OMINUS,
OCOMPLEX,
OREAL,
OIMAG:
goto yes
case ODOT,
ODOTPTR,
OINDEX,
OIND,
ONAME:
goto yes
}
//dump("\ncomplex-no", n);
no:
return false
//dump("\ncomplex-yes", n);
yes:
return true
}
func Complexmove(f *Node, t *Node) {
var ft int
var tt int
var n1 Node
var n2 Node
var n3 Node
var n4 Node
var tmp 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) {
Tempname(&tmp, f.Type)
Complexmove(f, &tmp)
f = &tmp
}
subnode(&n1, &n2, f)
subnode(&n3, &n4, t)
Thearch.Cgen(&n1, &n3)
Thearch.Cgen(&n2, &n4)
}
}
func Complexgen(n *Node, res *Node) {
var nl *Node
var nr *Node
var tnl Node
var tnr Node
var n1 Node
var n2 Node
var tmp Node
var tl int
var tr int
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 {
subnode(&n1, &n2, res)
Tempname(&tmp, n1.Type)
Thearch.Cgen(n.Left, &tmp)
Thearch.Cgen(n.Right, &n2)
Thearch.Cgen(&tmp, &n1)
return
}
case OREAL,
OIMAG:
nl = n.Left
if nl.Addable == 0 {
Tempname(&tmp, nl.Type)
Complexgen(nl, &tmp)
nl = &tmp
}
subnode(&n1, &n2, nl)
if n.Op == OREAL {
Thearch.Cgen(&n1, res)
return
}
Thearch.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 {
Tempname(&n1, n.Type)
Complexmove(n, &n1)
n = &n1
}
Complexmove(n, res)
return
}
if res.Addable == 0 {
Thearch.Igen(res, &n1, nil)
Thearch.Cgen(n, &n1)
Thearch.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:
Thearch.Igen(n, &n1, res)
Complexmove(&n1, res)
Thearch.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
if nr != nil {
if nl.Ullman > nr.Ullman && nl.Addable == 0 {
Tempname(&tnl, nl.Type)
Thearch.Cgen(nl, &tnl)
nl = &tnl
}
if nr.Addable == 0 {
Tempname(&tnr, nr.Type)
Thearch.Cgen(nr, &tnr)
nr = &tnr
}
}
if nl.Addable == 0 {
Tempname(&tnl, nl.Type)
Thearch.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)
}
}