Commit 4a7e5bca authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

cmd/internal/gc: clean up bgen

This cleanup is in anticipation of implementing
jump-free booleans (CL 2284) and zero-aware
comparisons (issue 10381).

No functional changes. Passes toolstash -cmp.

Change-Id: I50f394c60fa2927e177d7fc85b75085060a9e912
Reviewed-on: https://go-review.googlesource.com/8738Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent 6a2b0c0b
...@@ -738,42 +738,74 @@ abop: // asymmetric binary ...@@ -738,42 +738,74 @@ abop: // asymmetric binary
return return
} }
func bgen_float(n *gc.Node, true_ int, likely int, to *obj.Prog) { func bgen_float(n *gc.Node, wantTrue bool, likely int, to *obj.Prog) {
nl := n.Left nl := n.Left
nr := n.Right nr := n.Right
a := int(n.Op) a := int(n.Op)
if true_ == 0 { if !wantTrue {
// brcom is not valid on floats when NaN is involved. // brcom is not valid on floats when NaN is involved.
p1 := gc.Gbranch(obj.AJMP, nil, 0) p1 := gc.Gbranch(obj.AJMP, nil, 0)
p2 := gc.Gbranch(obj.AJMP, nil, 0) p2 := gc.Gbranch(obj.AJMP, nil, 0)
gc.Patch(p1, gc.Pc) gc.Patch(p1, gc.Pc)
// No need to avoid re-genning ninit. // No need to avoid re-genning ninit.
bgen_float(n, 1, -likely, p2) bgen_float(n, true, -likely, p2)
gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
gc.Patch(p2, gc.Pc) gc.Patch(p2, gc.Pc)
return return
} }
var tmp gc.Node if gc.Thearch.Use387 {
var et int a = gc.Brrev(a) // because the args are stacked
var n2 gc.Node if a == gc.OGE || a == gc.OGT {
var ax gc.Node // only < and <= work right with NaN; reverse if needed
if !gc.Thearch.Use387 { nl, nr = nr, nl
if !nl.Addable { a = gc.Brrev(a)
var n1 gc.Node
gc.Tempname(&n1, nl.Type)
gc.Cgen(nl, &n1)
nl = &n1
} }
var ax, n2, tmp gc.Node
gc.Nodreg(&tmp, nr.Type, x86.REG_F0)
gc.Nodreg(&n2, nr.Type, x86.REG_F0+1)
gc.Nodreg(&ax, gc.Types[gc.TUINT16], x86.REG_AX)
if gc.Simsimtype(nr.Type) == gc.TFLOAT64 {
if nl.Ullman > nr.Ullman {
gc.Cgen(nl, &tmp)
gc.Cgen(nr, &tmp)
gins(x86.AFXCHD, &tmp, &n2)
} else {
gc.Cgen(nr, &tmp)
gc.Cgen(nl, &tmp)
}
gins(x86.AFUCOMIP, &tmp, &n2)
gins(x86.AFMOVDP, &tmp, &tmp) // annoying pop but still better than STSW+SAHF
} else {
// TODO(rsc): The moves back and forth to memory
// here are for truncating the value to 32 bits.
// This handles 32-bit comparison but presumably
// all the other ops have the same problem.
// We need to figure out what the right general
// solution is, besides telling people to use float64.
var t1 gc.Node
gc.Tempname(&t1, gc.Types[gc.TFLOAT32])
var t2 gc.Node
gc.Tempname(&t2, gc.Types[gc.TFLOAT32])
gc.Cgen(nr, &t1)
gc.Cgen(nl, &t2)
gmove(&t2, &tmp)
gins(x86.AFCOMFP, &t1, &tmp)
gins(x86.AFSTSW, nil, &ax)
gins(x86.ASAHF, nil, nil)
}
} else {
// Not 387
if !nl.Addable {
nl = gc.CgenTemp(nl)
}
if !nr.Addable { if !nr.Addable {
var tmp gc.Node nr = gc.CgenTemp(nr)
gc.Tempname(&tmp, nr.Type)
gc.Cgen(nr, &tmp)
nr = &tmp
} }
var n2 gc.Node var n2 gc.Node
...@@ -790,10 +822,7 @@ func bgen_float(n *gc.Node, true_ int, likely int, to *obj.Prog) { ...@@ -790,10 +822,7 @@ func bgen_float(n *gc.Node, true_ int, likely int, to *obj.Prog) {
if a == gc.OGE || a == gc.OGT { if a == gc.OGE || a == gc.OGT {
// only < and <= work right with NaN; reverse if needed // only < and <= work right with NaN; reverse if needed
r := nr nl, nr = nr, nl
nr = nl
nl = r
a = gc.Brrev(a) a = gc.Brrev(a)
} }
...@@ -802,75 +831,21 @@ func bgen_float(n *gc.Node, true_ int, likely int, to *obj.Prog) { ...@@ -802,75 +831,21 @@ func bgen_float(n *gc.Node, true_ int, likely int, to *obj.Prog) {
gc.Regfree(nl) gc.Regfree(nl)
} }
gc.Regfree(nr) gc.Regfree(nr)
goto ret
} else {
goto x87
} }
x87: switch a {
a = gc.Brrev(a) // because the args are stacked case gc.OEQ:
if a == gc.OGE || a == gc.OGT {
// only < and <= work right with NaN; reverse if needed
r := nr
nr = nl
nl = r
a = gc.Brrev(a)
}
gc.Nodreg(&tmp, nr.Type, x86.REG_F0)
gc.Nodreg(&n2, nr.Type, x86.REG_F0+1)
gc.Nodreg(&ax, gc.Types[gc.TUINT16], x86.REG_AX)
et = gc.Simsimtype(nr.Type)
if et == gc.TFLOAT64 {
if nl.Ullman > nr.Ullman {
gc.Cgen(nl, &tmp)
gc.Cgen(nr, &tmp)
gins(x86.AFXCHD, &tmp, &n2)
} else {
gc.Cgen(nr, &tmp)
gc.Cgen(nl, &tmp)
}
gins(x86.AFUCOMIP, &tmp, &n2)
gins(x86.AFMOVDP, &tmp, &tmp) // annoying pop but still better than STSW+SAHF
} else {
// TODO(rsc): The moves back and forth to memory
// here are for truncating the value to 32 bits.
// This handles 32-bit comparison but presumably
// all the other ops have the same problem.
// We need to figure out what the right general
// solution is, besides telling people to use float64.
var t1 gc.Node
gc.Tempname(&t1, gc.Types[gc.TFLOAT32])
var t2 gc.Node
gc.Tempname(&t2, gc.Types[gc.TFLOAT32])
gc.Cgen(nr, &t1)
gc.Cgen(nl, &t2)
gmove(&t2, &tmp)
gins(x86.AFCOMFP, &t1, &tmp)
gins(x86.AFSTSW, nil, &ax)
gins(x86.ASAHF, nil, nil)
}
goto ret
ret:
if a == gc.OEQ {
// neither NE nor P // neither NE nor P
p1 := gc.Gbranch(x86.AJNE, nil, -likely) p1 := gc.Gbranch(x86.AJNE, nil, -likely)
p2 := gc.Gbranch(x86.AJPS, nil, -likely) p2 := gc.Gbranch(x86.AJPS, nil, -likely)
gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to) gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
gc.Patch(p1, gc.Pc) gc.Patch(p1, gc.Pc)
gc.Patch(p2, gc.Pc) gc.Patch(p2, gc.Pc)
} else if a == gc.ONE { case gc.ONE:
// either NE or P // either NE or P
gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to) gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
gc.Patch(gc.Gbranch(x86.AJPS, nil, likely), to) gc.Patch(gc.Gbranch(x86.AJPS, nil, likely), to)
} else { default:
gc.Patch(gc.Gbranch(optoas(a, nr.Type), nil, likely), to) gc.Patch(gc.Gbranch(optoas(a, nr.Type), nil, likely), to)
} }
} }
......
This diff is collapsed.
...@@ -6,10 +6,6 @@ package gc ...@@ -6,10 +6,6 @@ package gc
import "cmd/internal/obj" import "cmd/internal/obj"
func CASE(a int, b int) int {
return a<<16 | b
}
func overlap_cplx(f *Node, t *Node) bool { func overlap_cplx(f *Node, t *Node) bool {
// check whether f and t could be overlapping stack references. // check whether f and t could be overlapping stack references.
// not exact, because it's hard to check for the stack register // not exact, because it's hard to check for the stack register
...@@ -18,67 +14,52 @@ func overlap_cplx(f *Node, t *Node) bool { ...@@ -18,67 +14,52 @@ func overlap_cplx(f *Node, t *Node) bool {
return f.Op == OINDREG && t.Op == OINDREG && f.Xoffset+f.Type.Width >= t.Xoffset && t.Xoffset+t.Type.Width >= f.Xoffset 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) { func complexbool(op int, nl, nr *Node, wantTrue bool, likely int, to *obj.Prog) {
var tnl Node
// make both sides addable in ullman order // make both sides addable in ullman order
if nr != nil { if nr != nil {
if nl.Ullman > nr.Ullman && !nl.Addable { if nl.Ullman > nr.Ullman && !nl.Addable {
Tempname(&tnl, nl.Type) nl = CgenTemp(nl)
Cgen(nl, &tnl)
nl = &tnl
} }
if !nr.Addable { if !nr.Addable {
var tnr Node nr = CgenTemp(nr)
Tempname(&tnr, nr.Type)
Cgen(nr, &tnr)
nr = &tnr
} }
} }
if !nl.Addable { if !nl.Addable {
Tempname(&tnl, nl.Type) nl = CgenTemp(nl)
Cgen(nl, &tnl)
nl = &tnl
} }
// 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 // build tree
// real(l) == real(r) && imag(l) == imag(r) // real(l) == real(r) && imag(l) == imag(r)
realeq := Node{
var n2 Node Op: OEQ,
var n1 Node Left: &lreal,
subnode(&n1, &n2, nl) Right: &rreal,
Type: Types[TBOOL],
var n3 Node }
var n4 Node imageq := Node{
subnode(&n3, &n4, nr) Op: OEQ,
Left: &limag,
var na Node Right: &rimag,
na.Op = OANDAND Type: Types[TBOOL],
var nb Node }
na.Left = &nb and := Node{
var nc Node Op: OANDAND,
na.Right = &nc Left: &realeq,
na.Type = Types[TBOOL] Right: &imageq,
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 { if op == ONE {
true_ = !true_ wantTrue = !wantTrue
} }
Bgen(&na, true_, likely, to) Bgen(&and, wantTrue, likely, to)
} }
// break addable nc-complex into nr-real and ni-imaginary // break addable nc-complex into nr-real and ni-imaginary
......
...@@ -1091,6 +1091,14 @@ func cgen_callmeth(n *Node, proc int) { ...@@ -1091,6 +1091,14 @@ func cgen_callmeth(n *Node, proc int) {
cgen_call(&n2, proc) cgen_call(&n2, proc)
} }
// CgenTemp creates a temporary node, assigns n to it, and returns it.
func CgenTemp(n *Node) *Node {
var tmp Node
Tempname(&tmp, n.Type)
Cgen(n, &tmp)
return &tmp
}
func checklabels() { func checklabels() {
var l *NodeList var l *NodeList
......
...@@ -776,8 +776,8 @@ type Arch struct { ...@@ -776,8 +776,8 @@ type Arch struct {
AddIndex func(*Node, int64, *Node) bool // optional AddIndex func(*Node, int64, *Node) bool // optional
Betypeinit func() Betypeinit func()
Bgen_float func(*Node, int, int, *obj.Prog) // optional Bgen_float func(*Node, bool, int, *obj.Prog) // optional
Cgen64 func(*Node, *Node) // only on 32-bit systems Cgen64 func(*Node, *Node) // only on 32-bit systems
Cgenindex func(*Node, *Node, bool) *obj.Prog Cgenindex func(*Node, *Node, bool) *obj.Prog
Cgen_bmul func(int, *Node, *Node, *Node) bool Cgen_bmul func(int, *Node, *Node, *Node) bool
Cgen_float func(*Node, *Node) // optional Cgen_float func(*Node, *Node) // optional
......
...@@ -1796,10 +1796,8 @@ func getinargx(t *Type) *Type { ...@@ -1796,10 +1796,8 @@ func getinargx(t *Type) *Type {
return *getinarg(t) return *getinarg(t)
} }
/* // Brcom returns !(op).
* return !(op) // For example, Brcom(==) is !=.
* eg == <=> !=
*/
func Brcom(a int) int { func Brcom(a int) int {
switch a { switch a {
case OEQ: case OEQ:
...@@ -1815,15 +1813,12 @@ func Brcom(a int) int { ...@@ -1815,15 +1813,12 @@ func Brcom(a int) int {
case OGE: case OGE:
return OLT return OLT
} }
Fatal("brcom: no com for %v\n", Oconv(a, 0))
Fatal("brcom: no com for %v\n", Oconv(int(a), 0))
return a return a
} }
/* // Brrev returns reverse(op).
* return reverse(op) // For example, Brrev(<) is >.
* eg a op b <=> b r(op) a
*/
func Brrev(a int) int { func Brrev(a int) int {
switch a { switch a {
case OEQ: case OEQ:
...@@ -1839,8 +1834,7 @@ func Brrev(a int) int { ...@@ -1839,8 +1834,7 @@ func Brrev(a int) int {
case OGE: case OGE:
return OLE return OLE
} }
Fatal("brrev: no rev for %v\n", Oconv(a, 0))
Fatal("brcom: no rev for %v\n", Oconv(int(a), 0))
return a return a
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment