mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Type Op is enfored now. Type EType will need further CLs. Added TODOs where Node.EType is used as a union type. The TODOs have the format `TODO(marvin): Fix Node.EType union type.`. Furthermore: -The flag of Econv function in fmt.go is removed, since unused. -Some cleaning along the way, e.g. declare vars first when getting initialized. Passes go build -toolexec 'toolstash -cmp' -a std. Fixes #11846 Change-Id: I908b955d5a78a195604970983fb9194bd9e9260b Reviewed-on: https://go-review.googlesource.com/14956 Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Marvin Stenger <marvin.stenger94@gmail.com>
474 lines
7.8 KiB
Go
474 lines
7.8 KiB
Go
// 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 Op, 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 Op, 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 = op
|
|
ra.Left = &n1
|
|
ra.Right = &n3
|
|
ra.Type = n1.Type
|
|
Cgen(&ra, &n5)
|
|
|
|
ra = Node{}
|
|
ra.Op = 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)
|
|
// complex to complex move/convert.
|
|
// make f addable.
|
|
// also use temporary if possible stack overlap.
|
|
if (ft == TCOMPLEX64 || ft == TCOMPLEX128) && (tt == TCOMPLEX64 || tt == 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)
|
|
} else {
|
|
Fatalf("complexmove: unknown conversion: %v -> %v\n", f.Type, t.Type)
|
|
}
|
|
}
|
|
|
|
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(n.Op, nl, nr, res)
|
|
|
|
case OMUL:
|
|
complexmul(nl, nr, res)
|
|
}
|
|
}
|