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)
} }
} }
......
...@@ -345,18 +345,13 @@ func Cgen(n *Node, res *Node) { ...@@ -345,18 +345,13 @@ func Cgen(n *Node, res *Node) {
Dump("cgen-res", res) Dump("cgen-res", res)
Fatal("cgen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign)) Fatal("cgen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
// these call bgen to get a bool value // these call bgen to get a bool value
case OOROR, case OOROR, OANDAND,
OANDAND, OEQ, ONE,
OEQ, OLT, OLE,
ONE, OGE, OGT,
OLT,
OLE,
OGE,
OGT,
ONOT: ONOT:
p1 := Gbranch(obj.AJMP, nil, 0) p1 := Gbranch(obj.AJMP, nil, 0)
p2 := Pc p2 := Pc
Thearch.Gmove(Nodbool(true), res) Thearch.Gmove(Nodbool(true), res)
p3 := Gbranch(obj.AJMP, nil, 0) p3 := Gbranch(obj.AJMP, nil, 0)
...@@ -1639,22 +1634,22 @@ func Igen(n *Node, a *Node, res *Node) { ...@@ -1639,22 +1634,22 @@ func Igen(n *Node, a *Node, res *Node) {
a.Type = n.Type a.Type = n.Type
} }
/* // Bgen generates code for branches:
* generate: //
* if(n == true) goto to; // if n == wantTrue {
*/ // goto to
func Bgen(n *Node, true_ bool, likely int, to *obj.Prog) { // }
func Bgen(n *Node, wantTrue bool, likely int, to *obj.Prog) {
if Debug['g'] != 0 { if Debug['g'] != 0 {
Dump("\nbgen", n) fmt.Printf("\nbgen wantTrue=%t likely=%d to=%v\n", wantTrue, likely, to)
Dump("bgen", n)
} }
if n == nil { if n == nil {
n = Nodbool(true) n = Nodbool(true)
} }
if n.Ninit != nil { Genlist(n.Ninit)
Genlist(n.Ninit)
}
if n.Type == nil { if n.Type == nil {
Convlit(&n, Types[TBOOL]) Convlit(&n, Types[TBOOL])
...@@ -1663,8 +1658,7 @@ func Bgen(n *Node, true_ bool, likely int, to *obj.Prog) { ...@@ -1663,8 +1658,7 @@ func Bgen(n *Node, true_ bool, likely int, to *obj.Prog) {
} }
} }
et := int(n.Type.Etype) if n.Type.Etype != TBOOL {
if et != TBOOL {
Yyerror("cgen: bad type %v for %v", Tconv(n.Type, 0), Oconv(int(n.Op), 0)) Yyerror("cgen: bad type %v for %v", Tconv(n.Type, 0), Oconv(int(n.Op), 0))
Patch(Thearch.Gins(obj.AEND, nil, nil), to) Patch(Thearch.Gins(obj.AEND, nil, nil), to)
return return
...@@ -1672,204 +1666,172 @@ func Bgen(n *Node, true_ bool, likely int, to *obj.Prog) { ...@@ -1672,204 +1666,172 @@ func Bgen(n *Node, true_ bool, likely int, to *obj.Prog) {
for n.Op == OCONVNOP { for n.Op == OCONVNOP {
n = n.Left n = n.Left
if n.Ninit != nil { Genlist(n.Ninit)
Genlist(n.Ninit)
}
} }
if Thearch.Bgen_float != nil && n.Left != nil && Isfloat[n.Left.Type.Etype] { if Thearch.Bgen_float != nil && n.Left != nil && Isfloat[n.Left.Type.Etype] {
Thearch.Bgen_float(n, bool2int(true_), likely, to) Thearch.Bgen_float(n, wantTrue, likely, to)
return return
} }
var nl *Node
var nr *Node
switch n.Op { switch n.Op {
default: default:
goto def var tmp Node
Regalloc(&tmp, n.Type, nil)
Cgen(n, &tmp)
bgenNonZero(&tmp, wantTrue, likely, to)
Regfree(&tmp)
return
// need to ask if it is bool? case ONAME:
case OLITERAL: if n.Addable && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' {
if true_ == n.Val.U.Bval { // no need for a temporary
Patch(Gbranch(obj.AJMP, nil, likely), to) bgenNonZero(n, wantTrue, likely, to)
return
} }
var tmp Node
Regalloc(&tmp, n.Type, nil)
Cgen(n, &tmp)
bgenNonZero(&tmp, wantTrue, likely, to)
Regfree(&tmp)
return return
case ONAME: case OLITERAL:
if !n.Addable || Ctxt.Arch.Thechar == '5' || Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' { // n is a constant. If n == wantTrue, jump; otherwise do nothing.
goto def if !Isconst(n, CTBOOL) {
Fatal("bgen: non-bool const %v\n", Nconv(n, obj.FmtLong))
} }
var n1 Node if wantTrue == n.Val.U.Bval {
Nodconst(&n1, n.Type, 0) Patch(Gbranch(obj.AJMP, nil, likely), to)
Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &n1)
a := Thearch.Optoas(ONE, n.Type)
if !true_ {
a = Thearch.Optoas(OEQ, n.Type)
} }
Patch(Gbranch(a, n.Type, likely), to)
return return
case OANDAND, OOROR: case OANDAND, OOROR:
if (n.Op == OANDAND) == true_ { if (n.Op == OANDAND) == wantTrue {
p1 := Gbranch(obj.AJMP, nil, 0) p1 := Gbranch(obj.AJMP, nil, 0)
p2 := Gbranch(obj.AJMP, nil, 0) p2 := Gbranch(obj.AJMP, nil, 0)
Patch(p1, Pc) Patch(p1, Pc)
Bgen(n.Left, !true_, -likely, p2) Bgen(n.Left, !wantTrue, -likely, p2)
Bgen(n.Right, !true_, -likely, p2) Bgen(n.Right, !wantTrue, -likely, p2)
p1 = Gbranch(obj.AJMP, nil, 0) p1 = Gbranch(obj.AJMP, nil, 0)
Patch(p1, to) Patch(p1, to)
Patch(p2, Pc) Patch(p2, Pc)
} else { } else {
Bgen(n.Left, true_, likely, to) Bgen(n.Left, wantTrue, likely, to)
Bgen(n.Right, true_, likely, to) Bgen(n.Right, wantTrue, likely, to)
} }
return return
case OEQ, ONE, OLT, OGT, OLE, OGE:
nr = n.Right
if nr == nil || nr.Type == nil {
return
}
fallthrough
case ONOT: // unary case ONOT: // unary
nl = n.Left if n.Left == nil || n.Left.Type == nil {
if nl == nil || nl.Type == nil {
return return
} }
} Bgen(n.Left, !wantTrue, likely, to)
switch n.Op {
case ONOT:
Bgen(nl, !true_, likely, to)
return return
case OEQ, ONE, OLT, OGT, OLE, OGE: case OEQ, ONE, OLT, OGT, OLE, OGE:
a := int(n.Op) if n.Left == nil || n.Left.Type == nil || n.Right == nil || n.Right.Type == nil {
if !true_ { return
if Isfloat[nr.Type.Etype] {
// brcom is not valid on floats when NaN is involved.
p1 := Gbranch(obj.AJMP, nil, 0)
p2 := Gbranch(obj.AJMP, nil, 0)
Patch(p1, Pc)
ll := n.Ninit // avoid re-genning ninit
n.Ninit = nil
Bgen(n, true, -likely, p2)
n.Ninit = ll
Patch(Gbranch(obj.AJMP, nil, 0), to)
Patch(p2, Pc)
return
}
a = Brcom(a)
true_ = !true_
} }
}
// make simplest on right // n.Op is one of OEQ, ONE, OLT, OGT, OLE, OGE
if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) { nl := n.Left
a = Brrev(a) nr := n.Right
r := nl a := int(n.Op)
nl = nr
nr = r if !wantTrue {
if Isfloat[nr.Type.Etype] {
// Brcom is not valid on floats when NaN is involved.
p1 := Gbranch(obj.AJMP, nil, 0)
p2 := Gbranch(obj.AJMP, nil, 0)
Patch(p1, Pc)
ll := n.Ninit // avoid re-genning Ninit
n.Ninit = nil
Bgen(n, true, -likely, p2)
n.Ninit = ll
Patch(Gbranch(obj.AJMP, nil, 0), to)
Patch(p2, Pc)
return
} }
if Isslice(nl.Type) { a = Brcom(a)
// front end should only leave cmp to literal nil }
if (a != OEQ && a != ONE) || nr.Op != OLITERAL { wantTrue = true
Yyerror("illegal slice comparison")
break
}
a = Thearch.Optoas(a, Types[Tptr]) // make simplest on right
var n1 Node if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) {
Igen(nl, &n1, nil) a = Brrev(a)
n1.Xoffset += int64(Array_array) nl, nr = nr, nl
n1.Type = Types[Tptr] }
var n2 Node
Regalloc(&n2, Types[Tptr], &n1)
Cgen(&n1, &n2)
Regfree(&n1)
var tmp Node
Nodconst(&tmp, Types[Tptr], 0)
Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n2, &tmp)
Patch(Gbranch(a, Types[Tptr], likely), to)
Regfree(&n2)
break
}
if Isinter(nl.Type) { if Isslice(nl.Type) || Isinter(nl.Type) {
// front end should only leave cmp to literal nil // front end should only leave cmp to literal nil
if (a != OEQ && a != ONE) || nr.Op != OLITERAL { if (a != OEQ && a != ONE) || nr.Op != OLITERAL {
if Isslice(nl.Type) {
Yyerror("illegal slice comparison")
} else {
Yyerror("illegal interface comparison") Yyerror("illegal interface comparison")
break
} }
return
a = Thearch.Optoas(a, Types[Tptr])
var n1 Node
Igen(nl, &n1, nil)
n1.Type = Types[Tptr]
var n2 Node
Regalloc(&n2, Types[Tptr], &n1)
Cgen(&n1, &n2)
Regfree(&n1)
var tmp Node
Nodconst(&tmp, Types[Tptr], 0)
Thearch.Gins(Thearch.Optoas(OCMP, Types[Tptr]), &n2, &tmp)
Patch(Gbranch(a, Types[Tptr], likely), to)
Regfree(&n2)
break
} }
if Iscomplex[nl.Type.Etype] { var ptr Node
Complexbool(a, nl, nr, true_, likely, to) Igen(nl, &ptr, nil)
break if Isslice(nl.Type) {
ptr.Xoffset += int64(Array_array)
} }
ptr.Type = Types[Tptr]
var tmp Node
Regalloc(&tmp, ptr.Type, &ptr)
Cgen(&ptr, &tmp)
Regfree(&ptr)
bgenNonZero(&tmp, a == OEQ != wantTrue, likely, to)
Regfree(&tmp)
return
}
if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) { if Iscomplex[nl.Type.Etype] {
if !nl.Addable || Isconst(nl, CTINT) { complexbool(a, nl, nr, wantTrue, likely, to)
var n1 Node return
Tempname(&n1, nl.Type) }
Cgen(nl, &n1)
nl = &n1
}
if !nr.Addable {
var n2 Node
Tempname(&n2, nr.Type)
Cgen(nr, &n2)
nr = &n2
}
Thearch.Cmp64(nl, nr, a, likely, to) if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) {
break if !nl.Addable || Isconst(nl, CTINT) {
nl = CgenTemp(nl)
}
if !nr.Addable {
nr = CgenTemp(nr)
} }
Thearch.Cmp64(nl, nr, a, likely, to)
return
}
if nr.Ullman >= UINF {
var n1 Node var n1 Node
var n2 Node Regalloc(&n1, nl.Type, nil)
if nr.Ullman >= UINF { Cgen(nl, &n1)
Regalloc(&n1, nl.Type, nil)
Cgen(nl, &n1)
var tmp Node
Tempname(&tmp, nl.Type)
Thearch.Gmove(&n1, &tmp)
Regfree(&n1)
Regalloc(&n2, nr.Type, nil)
Cgen(nr, &n2)
Regalloc(&n1, nl.Type, nil) var tmp Node
Cgen(&tmp, &n1) Tempname(&tmp, nl.Type)
Thearch.Gmove(&n1, &tmp)
Regfree(&n1)
goto cmp var n2 Node
} Regalloc(&n2, nr.Type, nil)
Cgen(nr, &n2)
Regfree(&n2)
Regalloc(&n1, nl.Type, nil)
Cgen(&tmp, &n1)
Regfree(&n1)
} else {
var n1 Node
if !nl.Addable && Ctxt.Arch.Thechar == '8' { if !nl.Addable && Ctxt.Arch.Thechar == '8' {
Tempname(&n1, nl.Type) Tempname(&n1, nl.Type)
} else { } else {
Regalloc(&n1, nl.Type, nil) Regalloc(&n1, nl.Type, nil)
defer Regfree(&n1)
} }
Cgen(nl, &n1) Cgen(nl, &n1)
nl = &n1 nl = &n1
...@@ -1877,92 +1839,93 @@ func Bgen(n *Node, true_ bool, likely int, to *obj.Prog) { ...@@ -1877,92 +1839,93 @@ func Bgen(n *Node, true_ bool, likely int, to *obj.Prog) {
if Smallintconst(nr) && Ctxt.Arch.Thechar != '9' { if Smallintconst(nr) && Ctxt.Arch.Thechar != '9' {
Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr) Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr)
Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to) Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
if n1.Op == OREGISTER { return
Regfree(&n1)
}
break
} }
if !nr.Addable && Ctxt.Arch.Thechar == '8' { if !nr.Addable && Ctxt.Arch.Thechar == '8' {
var tmp Node nr = CgenTemp(nr)
Tempname(&tmp, nr.Type)
Cgen(nr, &tmp)
nr = &tmp
} }
var n2 Node
Regalloc(&n2, nr.Type, nil) Regalloc(&n2, nr.Type, nil)
Cgen(nr, &n2) Cgen(nr, &n2)
nr = &n2 nr = &n2
Regfree(&n2)
}
cmp: l, r := nl, nr
l, r := nl, nr
// On x86, only < and <= work right with NaN; reverse if needed
if Ctxt.Arch.Thechar == '6' && Isfloat[nl.Type.Etype] && (a == OGT || a == OGE) {
l, r = r, l
a = Brrev(a)
}
Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r) // On x86, only < and <= work right with NaN; reverse if needed
if Ctxt.Arch.Thechar == '6' && Isfloat[nl.Type.Etype] && (a == OGT || a == OGE) {
l, r = r, l
a = Brrev(a)
}
if Ctxt.Arch.Thechar == '6' && Isfloat[nr.Type.Etype] && (n.Op == OEQ || n.Op == ONE) { // Do the comparison.
if n.Op == OEQ { Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r)
// Handle floating point special cases.
// Note that 8g has Bgen_float and is handled above.
if Isfloat[nl.Type.Etype] {
switch Ctxt.Arch.Thechar {
case '5':
switch n.Op {
case ONE:
Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to)
Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
default:
p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely)
Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
Patch(p, Pc)
}
return
case '6':
switch n.Op {
case OEQ:
// neither NE nor P // neither NE nor P
p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely) p1 := Gbranch(Thearch.Optoas(ONE, nr.Type), nil, -likely)
p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely) p2 := Gbranch(Thearch.Optoas(OPS, nr.Type), nil, -likely)
Patch(Gbranch(obj.AJMP, nil, 0), to) Patch(Gbranch(obj.AJMP, nil, 0), to)
Patch(p1, Pc) Patch(p1, Pc)
Patch(p2, Pc) Patch(p2, Pc)
} else { return
case ONE:
// either NE or P // either NE or P
Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to) Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to)
Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to) Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to)
return
} }
} else if Ctxt.Arch.Thechar == '5' && Isfloat[nl.Type.Etype] { case '7', '9':
if n.Op == ONE { switch n.Op {
Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to)
Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
} else {
p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely)
Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
Patch(p, Pc)
}
} else if (Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9') && Isfloat[nl.Type.Etype] && (a == OLE || a == OGE) {
// On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =. // On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =.
if a == OLE { // TODO(josh): Convert a <= b to b > a instead?
a = OLT case OLE, OGE:
} else { if a == OLE {
a = OGT a = OLT
} else {
a = OGT
}
Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to)
return
} }
Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
Patch(Gbranch(Thearch.Optoas(OEQ, nr.Type), nr.Type, likely), to)
} else {
Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
}
if n1.Op == OREGISTER {
Regfree(&n1)
}
if n2.Op == OREGISTER {
Regfree(&n2)
} }
} }
return // Not a special case. Insert an appropriate conditional jump.
Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
}
def: func bgenNonZero(n *Node, wantTrue bool, likely int, to *obj.Prog) {
// TODO: Optimize on systems that can compare to zero easily. // TODO: Optimize on systems that can compare to zero easily.
var n1 Node a := ONE
Regalloc(&n1, n.Type, nil) if !wantTrue {
Cgen(n, &n1) a = OEQ
var n2 Node }
Nodconst(&n2, n.Type, 0) var zero Node
Thearch.Gins(Thearch.Optoas(OCMP, n.Type), &n1, &n2) Nodconst(&zero, n.Type, 0)
a := Thearch.Optoas(ONE, n.Type) Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &zero)
if !true_ { Patch(Gbranch(Thearch.Optoas(a, n.Type), n.Type, likely), to)
a = Thearch.Optoas(OEQ, n.Type)
}
Patch(Gbranch(a, n.Type, likely), to)
Regfree(&n1)
return
} }
/* /*
......
...@@ -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