mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal/gc: major evconst cleanup
Major cleanup to structure the code more similarly to go/constant. Passes "toolstash -cmp" on std cmd. Change-Id: I3ec7a7a24e313f119b0da4095001aad02e317894 Reviewed-on: https://go-review.googlesource.com/c/139901 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
d30d5a6b1e
commit
48dc42b6af
1 changed files with 310 additions and 557 deletions
|
|
@ -40,7 +40,7 @@ func (v Val) Ctype() Ctype {
|
||||||
switch x := v.U.(type) {
|
switch x := v.U.(type) {
|
||||||
default:
|
default:
|
||||||
Fatalf("unexpected Ctype for %T", v.U)
|
Fatalf("unexpected Ctype for %T", v.U)
|
||||||
panic("not reached")
|
panic("unreachable")
|
||||||
case nil:
|
case nil:
|
||||||
return 0
|
return 0
|
||||||
case *NilVal:
|
case *NilVal:
|
||||||
|
|
@ -68,7 +68,7 @@ func eqval(a, b Val) bool {
|
||||||
switch x := a.U.(type) {
|
switch x := a.U.(type) {
|
||||||
default:
|
default:
|
||||||
Fatalf("unexpected Ctype for %T", a.U)
|
Fatalf("unexpected Ctype for %T", a.U)
|
||||||
panic("not reached")
|
panic("unreachable")
|
||||||
case *NilVal:
|
case *NilVal:
|
||||||
return true
|
return true
|
||||||
case bool:
|
case bool:
|
||||||
|
|
@ -96,7 +96,7 @@ func (v Val) Interface() interface{} {
|
||||||
switch x := v.U.(type) {
|
switch x := v.U.(type) {
|
||||||
default:
|
default:
|
||||||
Fatalf("unexpected Interface for %T", v.U)
|
Fatalf("unexpected Interface for %T", v.U)
|
||||||
panic("not reached")
|
panic("unreachable")
|
||||||
case *NilVal:
|
case *NilVal:
|
||||||
return nil
|
return nil
|
||||||
case bool, string:
|
case bool, string:
|
||||||
|
|
@ -424,29 +424,6 @@ bad:
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyval(v Val) Val {
|
|
||||||
switch u := v.U.(type) {
|
|
||||||
case *Mpint:
|
|
||||||
i := new(Mpint)
|
|
||||||
i.Set(u)
|
|
||||||
i.Rune = u.Rune
|
|
||||||
v.U = i
|
|
||||||
|
|
||||||
case *Mpflt:
|
|
||||||
f := newMpflt()
|
|
||||||
f.Set(u)
|
|
||||||
v.U = f
|
|
||||||
|
|
||||||
case *Mpcplx:
|
|
||||||
c := new(Mpcplx)
|
|
||||||
c.Real.Set(&u.Real)
|
|
||||||
c.Imag.Set(&u.Imag)
|
|
||||||
v.U = c
|
|
||||||
}
|
|
||||||
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func tocplx(v Val) Val {
|
func tocplx(v Val) Val {
|
||||||
switch u := v.U.(type) {
|
switch u := v.U.(type) {
|
||||||
case *Mpint:
|
case *Mpint:
|
||||||
|
|
@ -585,10 +562,6 @@ func tostr(v Val) Val {
|
||||||
i = u.Int64()
|
i = u.Int64()
|
||||||
}
|
}
|
||||||
v.U = string(i)
|
v.U = string(i)
|
||||||
|
|
||||||
case *NilVal:
|
|
||||||
// Can happen because of string([]byte(nil)).
|
|
||||||
v.U = ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return v
|
return v
|
||||||
|
|
@ -609,50 +582,55 @@ func Isconst(n *Node, ct Ctype) bool {
|
||||||
return t == ct || (ct == CTINT && t == CTRUNE)
|
return t == ct || (ct == CTINT && t == CTRUNE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if n is constant, rewrite as OLITERAL node.
|
// evconst rewrites constant expressions into OLITERAL nodes.
|
||||||
func evconst(n *Node) {
|
func evconst(n *Node) {
|
||||||
// pick off just the opcodes that can be
|
nl, nr := n.Left, n.Right
|
||||||
// constant evaluated.
|
|
||||||
switch n.Op {
|
|
||||||
default:
|
|
||||||
return
|
|
||||||
|
|
||||||
case OADD,
|
// Pick off just the opcodes that can be constant evaluated.
|
||||||
OAND,
|
switch op := n.Op; op {
|
||||||
OANDAND,
|
case OPLUS, OMINUS, OCOM, ONOT:
|
||||||
OANDNOT,
|
if nl.Op == OLITERAL {
|
||||||
OARRAYBYTESTR,
|
setconst(n, unaryOp(op, nl.Val(), n.Type))
|
||||||
OCOM,
|
}
|
||||||
ODIV,
|
|
||||||
OEQ,
|
case OADD, OSUB, OMUL, ODIV, OMOD, OOR, OXOR, OAND, OANDNOT, OOROR, OANDAND:
|
||||||
OGE,
|
if nl.Op == OLITERAL && nr.Op == OLITERAL {
|
||||||
OGT,
|
setconst(n, binaryOp(nl.Val(), op, nr.Val()))
|
||||||
OLE,
|
}
|
||||||
OLSH,
|
|
||||||
OLT,
|
case OEQ, ONE, OLT, OLE, OGT, OGE:
|
||||||
OMINUS,
|
if nl.Op == OLITERAL && nr.Op == OLITERAL {
|
||||||
OMOD,
|
if nl.Type.IsInterface() != nr.Type.IsInterface() {
|
||||||
OMUL,
|
// Mixed interface/non-interface
|
||||||
ONE,
|
// constant comparison means comparing
|
||||||
ONOT,
|
// nil interface with some typed
|
||||||
OOR,
|
// constant, which is always unequal.
|
||||||
OOROR,
|
// E.g., interface{}(nil) == (*int)(nil).
|
||||||
OPLUS,
|
setboolconst(n, op == ONE)
|
||||||
ORSH,
|
} else {
|
||||||
OSUB,
|
setboolconst(n, compareOp(nl.Val(), op, nr.Val()))
|
||||||
OXOR:
|
}
|
||||||
break
|
}
|
||||||
|
|
||||||
|
case OLSH, ORSH:
|
||||||
|
if nl.Op == OLITERAL && nr.Op == OLITERAL {
|
||||||
|
setconst(n, shiftOp(nl.Val(), op, nr.Val()))
|
||||||
|
}
|
||||||
|
|
||||||
case OCONV:
|
case OCONV:
|
||||||
if n.Type == nil {
|
if n.Type != nil && okforconst[n.Type.Etype] && nl.Op == OLITERAL {
|
||||||
return
|
// TODO(mdempsky): There should be a convval function.
|
||||||
}
|
setconst(n, convlit1(nl, n.Type, true, false).Val())
|
||||||
if !okforconst[n.Type.Etype] && n.Type.Etype != TNIL {
|
}
|
||||||
return
|
|
||||||
|
case OARRAYBYTESTR:
|
||||||
|
// string([]byte(nil)) or string([]rune(nil))
|
||||||
|
if nl.Op == OLITERAL && nl.Val().Ctype() == CTNIL {
|
||||||
|
setconst(n, Val{U: ""})
|
||||||
}
|
}
|
||||||
|
|
||||||
// merge adjacent constants in the argument list.
|
|
||||||
case OADDSTR:
|
case OADDSTR:
|
||||||
|
// Merge adjacent constants in the argument list.
|
||||||
s := n.List.Slice()
|
s := n.List.Slice()
|
||||||
for i1 := 0; i1 < len(s); i1++ {
|
for i1 := 0; i1 < len(s); i1++ {
|
||||||
if Isconst(s[i1], CTSTR) && i1+1 < len(s) && Isconst(s[i1+1], CTSTR) {
|
if Isconst(s[i1], CTSTR) && i1+1 < len(s) && Isconst(s[i1+1], CTSTR) {
|
||||||
|
|
@ -678,521 +656,292 @@ func evconst(n *Node) {
|
||||||
} else {
|
} else {
|
||||||
n.List.Set(s)
|
n.List.Set(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
nl := n.Left
|
|
||||||
if nl == nil || nl.Type == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if consttype(nl) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
wl := nl.Type.Etype
|
|
||||||
if isInt[wl] || isFloat[wl] || isComplex[wl] {
|
|
||||||
wl = TIDEAL
|
|
||||||
}
|
|
||||||
|
|
||||||
// avoid constant conversions in switches below
|
|
||||||
const (
|
|
||||||
CTINT_ = uint32(CTINT)
|
|
||||||
CTRUNE_ = uint32(CTRUNE)
|
|
||||||
CTFLT_ = uint32(CTFLT)
|
|
||||||
CTCPLX_ = uint32(CTCPLX)
|
|
||||||
CTSTR_ = uint32(CTSTR)
|
|
||||||
CTBOOL_ = uint32(CTBOOL)
|
|
||||||
CTNIL_ = uint32(CTNIL)
|
|
||||||
OCONV_ = uint32(OCONV) << 16
|
|
||||||
OARRAYBYTESTR_ = uint32(OARRAYBYTESTR) << 16
|
|
||||||
OPLUS_ = uint32(OPLUS) << 16
|
|
||||||
OMINUS_ = uint32(OMINUS) << 16
|
|
||||||
OCOM_ = uint32(OCOM) << 16
|
|
||||||
ONOT_ = uint32(ONOT) << 16
|
|
||||||
OLSH_ = uint32(OLSH) << 16
|
|
||||||
ORSH_ = uint32(ORSH) << 16
|
|
||||||
OADD_ = uint32(OADD) << 16
|
|
||||||
OSUB_ = uint32(OSUB) << 16
|
|
||||||
OMUL_ = uint32(OMUL) << 16
|
|
||||||
ODIV_ = uint32(ODIV) << 16
|
|
||||||
OMOD_ = uint32(OMOD) << 16
|
|
||||||
OOR_ = uint32(OOR) << 16
|
|
||||||
OAND_ = uint32(OAND) << 16
|
|
||||||
OANDNOT_ = uint32(OANDNOT) << 16
|
|
||||||
OXOR_ = uint32(OXOR) << 16
|
|
||||||
OEQ_ = uint32(OEQ) << 16
|
|
||||||
ONE_ = uint32(ONE) << 16
|
|
||||||
OLT_ = uint32(OLT) << 16
|
|
||||||
OLE_ = uint32(OLE) << 16
|
|
||||||
OGE_ = uint32(OGE) << 16
|
|
||||||
OGT_ = uint32(OGT) << 16
|
|
||||||
OOROR_ = uint32(OOROR) << 16
|
|
||||||
OANDAND_ = uint32(OANDAND) << 16
|
|
||||||
)
|
|
||||||
|
|
||||||
nr := n.Right
|
|
||||||
var rv Val
|
|
||||||
var wr types.EType
|
|
||||||
var ctype uint32
|
|
||||||
var v Val
|
|
||||||
if nr == nil {
|
|
||||||
// copy numeric value to avoid modifying
|
|
||||||
// nl, in case someone still refers to it (e.g. iota).
|
|
||||||
v = copyval(nl.Val())
|
|
||||||
|
|
||||||
// rune values are int values for the purpose of constant folding.
|
|
||||||
ctype = uint32(v.Ctype())
|
|
||||||
if ctype == CTRUNE_ {
|
|
||||||
ctype = CTINT_
|
|
||||||
}
|
|
||||||
|
|
||||||
switch uint32(n.Op)<<16 | ctype {
|
|
||||||
default:
|
|
||||||
if !n.Diag() {
|
|
||||||
yyerror("illegal constant expression %v %v", n.Op, nl.Type)
|
|
||||||
n.SetDiag(true)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
|
|
||||||
case OCONV_ | CTNIL_,
|
|
||||||
OARRAYBYTESTR_ | CTNIL_:
|
|
||||||
if n.Type.IsString() {
|
|
||||||
v = tostr(v)
|
|
||||||
nl.Type = n.Type
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case OCONV_ | CTINT_,
|
|
||||||
OCONV_ | CTFLT_,
|
|
||||||
OCONV_ | CTCPLX_,
|
|
||||||
OCONV_ | CTSTR_,
|
|
||||||
OCONV_ | CTBOOL_:
|
|
||||||
nl = convlit1(nl, n.Type, true, false)
|
|
||||||
v = nl.Val()
|
|
||||||
|
|
||||||
case OPLUS_ | CTINT_:
|
|
||||||
break
|
|
||||||
|
|
||||||
case OMINUS_ | CTINT_:
|
|
||||||
v.U.(*Mpint).Neg()
|
|
||||||
|
|
||||||
case OCOM_ | CTINT_:
|
|
||||||
et := Txxx
|
|
||||||
if nl.Type != nil {
|
|
||||||
et = nl.Type.Etype
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate the mask in b
|
|
||||||
// result will be (a ^ mask)
|
|
||||||
var b Mpint
|
|
||||||
switch et {
|
|
||||||
// signed guys change sign
|
|
||||||
default:
|
|
||||||
b.SetInt64(-1)
|
|
||||||
|
|
||||||
// unsigned guys invert their bits
|
|
||||||
case TUINT8,
|
|
||||||
TUINT16,
|
|
||||||
TUINT32,
|
|
||||||
TUINT64,
|
|
||||||
TUINT,
|
|
||||||
TUINTPTR:
|
|
||||||
b.Set(maxintval[et])
|
|
||||||
}
|
|
||||||
|
|
||||||
v.U.(*Mpint).Xor(&b)
|
|
||||||
|
|
||||||
case OPLUS_ | CTFLT_:
|
|
||||||
break
|
|
||||||
|
|
||||||
case OMINUS_ | CTFLT_:
|
|
||||||
v.U.(*Mpflt).Neg()
|
|
||||||
|
|
||||||
case OPLUS_ | CTCPLX_:
|
|
||||||
break
|
|
||||||
|
|
||||||
case OMINUS_ | CTCPLX_:
|
|
||||||
v.U.(*Mpcplx).Real.Neg()
|
|
||||||
v.U.(*Mpcplx).Imag.Neg()
|
|
||||||
|
|
||||||
case ONOT_ | CTBOOL_:
|
|
||||||
if !v.U.(bool) {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
}
|
|
||||||
goto ret
|
|
||||||
}
|
|
||||||
if nr.Type == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if consttype(nr) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
wr = nr.Type.Etype
|
|
||||||
if isInt[wr] || isFloat[wr] || isComplex[wr] {
|
|
||||||
wr = TIDEAL
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for compatible general types (numeric, string, etc)
|
|
||||||
if wl != wr {
|
|
||||||
if wl == TINTER || wr == TINTER {
|
|
||||||
if n.Op == ONE {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
}
|
|
||||||
goto illegal
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for compatible types.
|
|
||||||
switch n.Op {
|
|
||||||
// ideal const mixes with anything but otherwise must match.
|
|
||||||
default:
|
|
||||||
if nl.Type.Etype != TIDEAL {
|
|
||||||
nr = defaultlit(nr, nl.Type)
|
|
||||||
n.Right = nr
|
|
||||||
}
|
|
||||||
|
|
||||||
if nr.Type.Etype != TIDEAL {
|
|
||||||
nl = defaultlit(nl, nr.Type)
|
|
||||||
n.Left = nl
|
|
||||||
}
|
|
||||||
|
|
||||||
if nl.Type.Etype != nr.Type.Etype {
|
|
||||||
goto illegal
|
|
||||||
}
|
|
||||||
|
|
||||||
// right must be unsigned.
|
|
||||||
// left can be ideal.
|
|
||||||
case OLSH, ORSH:
|
|
||||||
nr = defaultlit(nr, types.Types[TUINT])
|
|
||||||
|
|
||||||
n.Right = nr
|
|
||||||
if nr.Type != nil && (nr.Type.IsSigned() || !nr.Type.IsInteger()) {
|
|
||||||
goto illegal
|
|
||||||
}
|
|
||||||
if nl.Val().Ctype() != CTRUNE {
|
|
||||||
nl.SetVal(toint(nl.Val()))
|
|
||||||
}
|
|
||||||
nr.SetVal(toint(nr.Val()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy numeric value to avoid modifying
|
|
||||||
// n->left, in case someone still refers to it (e.g. iota).
|
|
||||||
v = copyval(nl.Val())
|
|
||||||
rv = nr.Val()
|
|
||||||
|
|
||||||
// convert to common ideal
|
|
||||||
if v.Ctype() == CTCPLX || rv.Ctype() == CTCPLX {
|
|
||||||
v = tocplx(v)
|
|
||||||
rv = tocplx(rv)
|
|
||||||
}
|
|
||||||
|
|
||||||
if v.Ctype() == CTFLT || rv.Ctype() == CTFLT {
|
|
||||||
v = toflt(v)
|
|
||||||
rv = toflt(rv)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rune and int turns into rune.
|
|
||||||
if v.Ctype() == CTRUNE && rv.Ctype() == CTINT {
|
|
||||||
i := new(Mpint)
|
|
||||||
i.Set(rv.U.(*Mpint))
|
|
||||||
i.Rune = true
|
|
||||||
rv.U = i
|
|
||||||
}
|
|
||||||
if v.Ctype() == CTINT && rv.Ctype() == CTRUNE {
|
|
||||||
if n.Op == OLSH || n.Op == ORSH {
|
|
||||||
i := new(Mpint)
|
|
||||||
i.Set(rv.U.(*Mpint))
|
|
||||||
rv.U = i
|
|
||||||
} else {
|
|
||||||
i := new(Mpint)
|
|
||||||
i.Set(v.U.(*Mpint))
|
|
||||||
i.Rune = true
|
|
||||||
v.U = i
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Ctype() != rv.Ctype() {
|
func match(x, y Val) (Val, Val) {
|
||||||
// Use of undefined name as constant?
|
switch {
|
||||||
if (v.Ctype() == 0 || rv.Ctype() == 0) && nerrors > 0 {
|
case x.Ctype() == CTCPLX || y.Ctype() == CTCPLX:
|
||||||
return
|
return tocplx(x), tocplx(y)
|
||||||
}
|
case x.Ctype() == CTFLT || y.Ctype() == CTFLT:
|
||||||
Fatalf("constant type mismatch %v(%d) %v(%d)", nl.Type, v.Ctype(), nr.Type, rv.Ctype())
|
return toflt(x), toflt(y)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rune values are int values for the purpose of constant folding.
|
// Mixed int/rune are fine.
|
||||||
ctype = uint32(v.Ctype())
|
return x, y
|
||||||
if ctype == CTRUNE_ {
|
|
||||||
ctype = CTINT_
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// run op
|
func compareOp(x Val, op Op, y Val) bool {
|
||||||
switch uint32(n.Op)<<16 | ctype {
|
x, y = match(x, y)
|
||||||
default:
|
|
||||||
goto illegal
|
|
||||||
|
|
||||||
case OADD_ | CTINT_:
|
switch x.Ctype() {
|
||||||
v.U.(*Mpint).Add(rv.U.(*Mpint))
|
case CTNIL:
|
||||||
|
_, _ = x.U.(*NilVal), y.U.(*NilVal) // assert dynamic types match
|
||||||
|
switch op {
|
||||||
|
case OEQ:
|
||||||
|
return true
|
||||||
|
case ONE:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
case OSUB_ | CTINT_:
|
case CTBOOL:
|
||||||
v.U.(*Mpint).Sub(rv.U.(*Mpint))
|
x, y := x.U.(bool), y.U.(bool)
|
||||||
|
switch op {
|
||||||
|
case OEQ:
|
||||||
|
return x == y
|
||||||
|
case ONE:
|
||||||
|
return x != y
|
||||||
|
}
|
||||||
|
|
||||||
case OMUL_ | CTINT_:
|
case CTINT, CTRUNE:
|
||||||
v.U.(*Mpint).Mul(rv.U.(*Mpint))
|
x, y := x.U.(*Mpint), y.U.(*Mpint)
|
||||||
|
return cmpZero(x.Cmp(y), op)
|
||||||
|
|
||||||
case ODIV_ | CTINT_:
|
case CTFLT:
|
||||||
if rv.U.(*Mpint).CmpInt64(0) == 0 {
|
x, y := x.U.(*Mpflt), y.U.(*Mpflt)
|
||||||
|
return cmpZero(x.Cmp(y), op)
|
||||||
|
|
||||||
|
case CTCPLX:
|
||||||
|
x, y := x.U.(*Mpcplx), y.U.(*Mpcplx)
|
||||||
|
eq := x.Real.Cmp(&y.Real) == 0 && x.Imag.Cmp(&y.Imag) == 0
|
||||||
|
switch op {
|
||||||
|
case OEQ:
|
||||||
|
return eq
|
||||||
|
case ONE:
|
||||||
|
return !eq
|
||||||
|
}
|
||||||
|
|
||||||
|
case CTSTR:
|
||||||
|
x, y := x.U.(string), y.U.(string)
|
||||||
|
switch op {
|
||||||
|
case OEQ:
|
||||||
|
return x == y
|
||||||
|
case ONE:
|
||||||
|
return x != y
|
||||||
|
case OLT:
|
||||||
|
return x < y
|
||||||
|
case OLE:
|
||||||
|
return x <= y
|
||||||
|
case OGT:
|
||||||
|
return x > y
|
||||||
|
case OGE:
|
||||||
|
return x >= y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Fatalf("compareOp: bad comparison: %v %v %v", x, op, y)
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmpZero(x int, op Op) bool {
|
||||||
|
switch op {
|
||||||
|
case OEQ:
|
||||||
|
return x == 0
|
||||||
|
case ONE:
|
||||||
|
return x != 0
|
||||||
|
case OLT:
|
||||||
|
return x < 0
|
||||||
|
case OLE:
|
||||||
|
return x <= 0
|
||||||
|
case OGT:
|
||||||
|
return x > 0
|
||||||
|
case OGE:
|
||||||
|
return x >= 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Fatalf("cmpZero: want comparison operator, got %v", op)
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func binaryOp(x Val, op Op, y Val) Val {
|
||||||
|
x, y = match(x, y)
|
||||||
|
|
||||||
|
Outer:
|
||||||
|
switch x.Ctype() {
|
||||||
|
case CTBOOL:
|
||||||
|
x, y := x.U.(bool), y.U.(bool)
|
||||||
|
switch op {
|
||||||
|
case OANDAND:
|
||||||
|
return Val{U: x && y}
|
||||||
|
case OOROR:
|
||||||
|
return Val{U: x || y}
|
||||||
|
}
|
||||||
|
|
||||||
|
case CTINT, CTRUNE:
|
||||||
|
x, y := x.U.(*Mpint), y.U.(*Mpint)
|
||||||
|
|
||||||
|
u := new(Mpint)
|
||||||
|
u.Rune = x.Rune || y.Rune
|
||||||
|
u.Set(x)
|
||||||
|
switch op {
|
||||||
|
case OADD:
|
||||||
|
u.Add(y)
|
||||||
|
case OSUB:
|
||||||
|
u.Sub(y)
|
||||||
|
case OMUL:
|
||||||
|
u.Mul(y)
|
||||||
|
case ODIV:
|
||||||
|
if y.CmpInt64(0) == 0 {
|
||||||
yyerror("division by zero")
|
yyerror("division by zero")
|
||||||
v.U.(*Mpint).SetOverflow()
|
u.SetOverflow()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
u.Quo(y)
|
||||||
v.U.(*Mpint).Quo(rv.U.(*Mpint))
|
case OMOD:
|
||||||
|
if y.CmpInt64(0) == 0 {
|
||||||
case OMOD_ | CTINT_:
|
|
||||||
if rv.U.(*Mpint).CmpInt64(0) == 0 {
|
|
||||||
yyerror("division by zero")
|
yyerror("division by zero")
|
||||||
v.U.(*Mpint).SetOverflow()
|
u.SetOverflow()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
u.Rem(y)
|
||||||
|
case OOR:
|
||||||
|
u.Or(y)
|
||||||
|
case OAND:
|
||||||
|
u.And(y)
|
||||||
|
case OANDNOT:
|
||||||
|
u.AndNot(y)
|
||||||
|
case OXOR:
|
||||||
|
u.Xor(y)
|
||||||
|
default:
|
||||||
|
break Outer
|
||||||
|
}
|
||||||
|
return Val{U: u}
|
||||||
|
|
||||||
v.U.(*Mpint).Rem(rv.U.(*Mpint))
|
case CTFLT:
|
||||||
|
x, y := x.U.(*Mpflt), y.U.(*Mpflt)
|
||||||
|
|
||||||
case OLSH_ | CTINT_:
|
u := newMpflt()
|
||||||
v.U.(*Mpint).Lsh(rv.U.(*Mpint))
|
u.Set(x)
|
||||||
|
switch op {
|
||||||
case ORSH_ | CTINT_:
|
case OADD:
|
||||||
v.U.(*Mpint).Rsh(rv.U.(*Mpint))
|
u.Add(y)
|
||||||
|
case OSUB:
|
||||||
case OOR_ | CTINT_:
|
u.Sub(y)
|
||||||
v.U.(*Mpint).Or(rv.U.(*Mpint))
|
case OMUL:
|
||||||
|
u.Mul(y)
|
||||||
case OAND_ | CTINT_:
|
case ODIV:
|
||||||
v.U.(*Mpint).And(rv.U.(*Mpint))
|
if y.CmpFloat64(0) == 0 {
|
||||||
|
|
||||||
case OANDNOT_ | CTINT_:
|
|
||||||
v.U.(*Mpint).AndNot(rv.U.(*Mpint))
|
|
||||||
|
|
||||||
case OXOR_ | CTINT_:
|
|
||||||
v.U.(*Mpint).Xor(rv.U.(*Mpint))
|
|
||||||
|
|
||||||
case OADD_ | CTFLT_:
|
|
||||||
v.U.(*Mpflt).Add(rv.U.(*Mpflt))
|
|
||||||
|
|
||||||
case OSUB_ | CTFLT_:
|
|
||||||
v.U.(*Mpflt).Sub(rv.U.(*Mpflt))
|
|
||||||
|
|
||||||
case OMUL_ | CTFLT_:
|
|
||||||
v.U.(*Mpflt).Mul(rv.U.(*Mpflt))
|
|
||||||
|
|
||||||
case ODIV_ | CTFLT_:
|
|
||||||
if rv.U.(*Mpflt).CmpFloat64(0) == 0 {
|
|
||||||
yyerror("division by zero")
|
yyerror("division by zero")
|
||||||
v.U.(*Mpflt).SetFloat64(1.0)
|
u.SetFloat64(1)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
u.Quo(y)
|
||||||
v.U.(*Mpflt).Quo(rv.U.(*Mpflt))
|
case OMOD:
|
||||||
|
// TODO(mdempsky): Move to typecheck.
|
||||||
// The default case above would print 'ideal % ideal',
|
|
||||||
// which is not quite an ideal error.
|
|
||||||
case OMOD_ | CTFLT_:
|
|
||||||
if !n.Diag() {
|
|
||||||
yyerror("illegal constant expression: floating-point %% operation")
|
yyerror("illegal constant expression: floating-point %% operation")
|
||||||
n.SetDiag(true)
|
default:
|
||||||
|
break Outer
|
||||||
}
|
}
|
||||||
|
return Val{U: u}
|
||||||
|
|
||||||
return
|
case CTCPLX:
|
||||||
|
x, y := x.U.(*Mpcplx), y.U.(*Mpcplx)
|
||||||
|
|
||||||
case OADD_ | CTCPLX_:
|
u := new(Mpcplx)
|
||||||
v.U.(*Mpcplx).Real.Add(&rv.U.(*Mpcplx).Real)
|
u.Real.Set(&x.Real)
|
||||||
v.U.(*Mpcplx).Imag.Add(&rv.U.(*Mpcplx).Imag)
|
u.Imag.Set(&x.Imag)
|
||||||
|
switch op {
|
||||||
case OSUB_ | CTCPLX_:
|
case OADD:
|
||||||
v.U.(*Mpcplx).Real.Sub(&rv.U.(*Mpcplx).Real)
|
u.Real.Add(&y.Real)
|
||||||
v.U.(*Mpcplx).Imag.Sub(&rv.U.(*Mpcplx).Imag)
|
u.Imag.Add(&y.Imag)
|
||||||
|
case OSUB:
|
||||||
case OMUL_ | CTCPLX_:
|
u.Real.Sub(&y.Real)
|
||||||
v.U.(*Mpcplx).Mul(rv.U.(*Mpcplx))
|
u.Imag.Sub(&y.Imag)
|
||||||
|
case OMUL:
|
||||||
case ODIV_ | CTCPLX_:
|
u.Mul(y)
|
||||||
if !v.U.(*Mpcplx).Div(rv.U.(*Mpcplx)) {
|
case ODIV:
|
||||||
|
if !u.Div(y) {
|
||||||
yyerror("complex division by zero")
|
yyerror("complex division by zero")
|
||||||
rv.U.(*Mpcplx).Real.SetFloat64(1.0)
|
u.Real.SetFloat64(1)
|
||||||
rv.U.(*Mpcplx).Imag.SetFloat64(0.0)
|
u.Imag.SetFloat64(0)
|
||||||
break
|
}
|
||||||
|
default:
|
||||||
|
break Outer
|
||||||
|
}
|
||||||
|
return Val{U: u}
|
||||||
}
|
}
|
||||||
|
|
||||||
case OEQ_ | CTNIL_:
|
Fatalf("binaryOp: bad operation: %v %v %v", x, op, y)
|
||||||
goto settrue
|
panic("unreachable")
|
||||||
|
|
||||||
case ONE_ | CTNIL_:
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OEQ_ | CTINT_:
|
|
||||||
if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) == 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case ONE_ | CTINT_:
|
|
||||||
if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) != 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OLT_ | CTINT_:
|
|
||||||
if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) < 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OLE_ | CTINT_:
|
|
||||||
if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) <= 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OGE_ | CTINT_:
|
|
||||||
if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) >= 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OGT_ | CTINT_:
|
|
||||||
if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) > 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OEQ_ | CTFLT_:
|
|
||||||
if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) == 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case ONE_ | CTFLT_:
|
|
||||||
if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) != 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OLT_ | CTFLT_:
|
|
||||||
if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) < 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OLE_ | CTFLT_:
|
|
||||||
if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) <= 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OGE_ | CTFLT_:
|
|
||||||
if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) >= 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OGT_ | CTFLT_:
|
|
||||||
if v.U.(*Mpflt).Cmp(rv.U.(*Mpflt)) > 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OEQ_ | CTCPLX_:
|
|
||||||
if v.U.(*Mpcplx).Real.Cmp(&rv.U.(*Mpcplx).Real) == 0 && v.U.(*Mpcplx).Imag.Cmp(&rv.U.(*Mpcplx).Imag) == 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case ONE_ | CTCPLX_:
|
|
||||||
if v.U.(*Mpcplx).Real.Cmp(&rv.U.(*Mpcplx).Real) != 0 || v.U.(*Mpcplx).Imag.Cmp(&rv.U.(*Mpcplx).Imag) != 0 {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OEQ_ | CTSTR_:
|
|
||||||
if strlit(nl) == strlit(nr) {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case ONE_ | CTSTR_:
|
|
||||||
if strlit(nl) != strlit(nr) {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OLT_ | CTSTR_:
|
|
||||||
if strlit(nl) < strlit(nr) {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OLE_ | CTSTR_:
|
|
||||||
if strlit(nl) <= strlit(nr) {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OGE_ | CTSTR_:
|
|
||||||
if strlit(nl) >= strlit(nr) {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OGT_ | CTSTR_:
|
|
||||||
if strlit(nl) > strlit(nr) {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OOROR_ | CTBOOL_:
|
|
||||||
if v.U.(bool) || rv.U.(bool) {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OANDAND_ | CTBOOL_:
|
|
||||||
if v.U.(bool) && rv.U.(bool) {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case OEQ_ | CTBOOL_:
|
|
||||||
if v.U.(bool) == rv.U.(bool) {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
|
|
||||||
case ONE_ | CTBOOL_:
|
|
||||||
if v.U.(bool) != rv.U.(bool) {
|
|
||||||
goto settrue
|
|
||||||
}
|
|
||||||
goto setfalse
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret:
|
func unaryOp(op Op, x Val, t *types.Type) Val {
|
||||||
setconst(n, v)
|
switch op {
|
||||||
return
|
case OPLUS:
|
||||||
|
switch x.Ctype() {
|
||||||
settrue:
|
case CTINT, CTRUNE, CTFLT, CTCPLX:
|
||||||
setconst(n, Val{true})
|
return x
|
||||||
return
|
|
||||||
|
|
||||||
setfalse:
|
|
||||||
setconst(n, Val{false})
|
|
||||||
return
|
|
||||||
|
|
||||||
illegal:
|
|
||||||
if !n.Diag() {
|
|
||||||
yyerror("illegal constant expression: %v %v %v", nl.Type, n.Op, nr.Type)
|
|
||||||
n.SetDiag(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case OMINUS:
|
||||||
|
switch x.Ctype() {
|
||||||
|
case CTINT, CTRUNE:
|
||||||
|
x := x.U.(*Mpint)
|
||||||
|
u := new(Mpint)
|
||||||
|
u.Rune = x.Rune
|
||||||
|
u.Set(x)
|
||||||
|
u.Neg()
|
||||||
|
return Val{U: u}
|
||||||
|
|
||||||
|
case CTFLT:
|
||||||
|
x := x.U.(*Mpflt)
|
||||||
|
u := newMpflt()
|
||||||
|
u.Set(x)
|
||||||
|
u.Neg()
|
||||||
|
return Val{U: u}
|
||||||
|
|
||||||
|
case CTCPLX:
|
||||||
|
x := x.U.(*Mpcplx)
|
||||||
|
u := new(Mpcplx)
|
||||||
|
u.Real.Set(&x.Real)
|
||||||
|
u.Imag.Set(&x.Imag)
|
||||||
|
u.Real.Neg()
|
||||||
|
u.Imag.Neg()
|
||||||
|
return Val{U: u}
|
||||||
|
}
|
||||||
|
|
||||||
|
case OCOM:
|
||||||
|
x := x.U.(*Mpint)
|
||||||
|
|
||||||
|
u := new(Mpint)
|
||||||
|
u.Rune = x.Rune
|
||||||
|
if t.IsSigned() || t.IsUntyped() {
|
||||||
|
// Signed values change sign.
|
||||||
|
u.SetInt64(-1)
|
||||||
|
} else {
|
||||||
|
// Unsigned values invert their bits.
|
||||||
|
u.Set(maxintval[t.Etype])
|
||||||
|
}
|
||||||
|
u.Xor(x)
|
||||||
|
return Val{U: u}
|
||||||
|
|
||||||
|
case ONOT:
|
||||||
|
return Val{U: !x.U.(bool)}
|
||||||
|
}
|
||||||
|
|
||||||
|
Fatalf("unaryOp: bad operation: %v %v", op, x)
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
|
||||||
|
func shiftOp(x Val, op Op, y Val) Val {
|
||||||
|
if x.Ctype() != CTRUNE {
|
||||||
|
x = toint(x)
|
||||||
|
}
|
||||||
|
y = toint(y)
|
||||||
|
|
||||||
|
u := new(Mpint)
|
||||||
|
u.Set(x.U.(*Mpint))
|
||||||
|
u.Rune = x.U.(*Mpint).Rune
|
||||||
|
switch op {
|
||||||
|
case OLSH:
|
||||||
|
u.Lsh(y.U.(*Mpint))
|
||||||
|
case ORSH:
|
||||||
|
u.Rsh(y.U.(*Mpint))
|
||||||
|
default:
|
||||||
|
Fatalf("shiftOp: bad operator: %v", op)
|
||||||
|
panic("unreachable")
|
||||||
|
}
|
||||||
|
return Val{U: u}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setconst rewrites n as an OLITERAL with value v.
|
// setconst rewrites n as an OLITERAL with value v.
|
||||||
|
|
@ -1223,6 +972,10 @@ func setconst(n *Node, v Val) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setboolconst(n *Node, v bool) {
|
||||||
|
setconst(n, Val{U: v})
|
||||||
|
}
|
||||||
|
|
||||||
func setintconst(n *Node, v int64) {
|
func setintconst(n *Node, v int64) {
|
||||||
u := new(Mpint)
|
u := new(Mpint)
|
||||||
u.SetInt64(v)
|
u.SetInt64(v)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue