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) {
|
||||
default:
|
||||
Fatalf("unexpected Ctype for %T", v.U)
|
||||
panic("not reached")
|
||||
panic("unreachable")
|
||||
case nil:
|
||||
return 0
|
||||
case *NilVal:
|
||||
|
|
@ -68,7 +68,7 @@ func eqval(a, b Val) bool {
|
|||
switch x := a.U.(type) {
|
||||
default:
|
||||
Fatalf("unexpected Ctype for %T", a.U)
|
||||
panic("not reached")
|
||||
panic("unreachable")
|
||||
case *NilVal:
|
||||
return true
|
||||
case bool:
|
||||
|
|
@ -96,7 +96,7 @@ func (v Val) Interface() interface{} {
|
|||
switch x := v.U.(type) {
|
||||
default:
|
||||
Fatalf("unexpected Interface for %T", v.U)
|
||||
panic("not reached")
|
||||
panic("unreachable")
|
||||
case *NilVal:
|
||||
return nil
|
||||
case bool, string:
|
||||
|
|
@ -424,29 +424,6 @@ bad:
|
|||
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 {
|
||||
switch u := v.U.(type) {
|
||||
case *Mpint:
|
||||
|
|
@ -585,10 +562,6 @@ func tostr(v Val) Val {
|
|||
i = u.Int64()
|
||||
}
|
||||
v.U = string(i)
|
||||
|
||||
case *NilVal:
|
||||
// Can happen because of string([]byte(nil)).
|
||||
v.U = ""
|
||||
}
|
||||
|
||||
return v
|
||||
|
|
@ -609,50 +582,55 @@ func Isconst(n *Node, ct Ctype) bool {
|
|||
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) {
|
||||
// pick off just the opcodes that can be
|
||||
// constant evaluated.
|
||||
switch n.Op {
|
||||
default:
|
||||
return
|
||||
nl, nr := n.Left, n.Right
|
||||
|
||||
case OADD,
|
||||
OAND,
|
||||
OANDAND,
|
||||
OANDNOT,
|
||||
OARRAYBYTESTR,
|
||||
OCOM,
|
||||
ODIV,
|
||||
OEQ,
|
||||
OGE,
|
||||
OGT,
|
||||
OLE,
|
||||
OLSH,
|
||||
OLT,
|
||||
OMINUS,
|
||||
OMOD,
|
||||
OMUL,
|
||||
ONE,
|
||||
ONOT,
|
||||
OOR,
|
||||
OOROR,
|
||||
OPLUS,
|
||||
ORSH,
|
||||
OSUB,
|
||||
OXOR:
|
||||
break
|
||||
// Pick off just the opcodes that can be constant evaluated.
|
||||
switch op := n.Op; op {
|
||||
case OPLUS, OMINUS, OCOM, ONOT:
|
||||
if nl.Op == OLITERAL {
|
||||
setconst(n, unaryOp(op, nl.Val(), n.Type))
|
||||
}
|
||||
|
||||
case OADD, OSUB, OMUL, ODIV, OMOD, OOR, OXOR, OAND, OANDNOT, OOROR, OANDAND:
|
||||
if nl.Op == OLITERAL && nr.Op == OLITERAL {
|
||||
setconst(n, binaryOp(nl.Val(), op, nr.Val()))
|
||||
}
|
||||
|
||||
case OEQ, ONE, OLT, OLE, OGT, OGE:
|
||||
if nl.Op == OLITERAL && nr.Op == OLITERAL {
|
||||
if nl.Type.IsInterface() != nr.Type.IsInterface() {
|
||||
// Mixed interface/non-interface
|
||||
// constant comparison means comparing
|
||||
// nil interface with some typed
|
||||
// constant, which is always unequal.
|
||||
// E.g., interface{}(nil) == (*int)(nil).
|
||||
setboolconst(n, op == ONE)
|
||||
} else {
|
||||
setboolconst(n, compareOp(nl.Val(), op, nr.Val()))
|
||||
}
|
||||
}
|
||||
|
||||
case OLSH, ORSH:
|
||||
if nl.Op == OLITERAL && nr.Op == OLITERAL {
|
||||
setconst(n, shiftOp(nl.Val(), op, nr.Val()))
|
||||
}
|
||||
|
||||
case OCONV:
|
||||
if n.Type == nil {
|
||||
return
|
||||
}
|
||||
if !okforconst[n.Type.Etype] && n.Type.Etype != TNIL {
|
||||
return
|
||||
if n.Type != nil && okforconst[n.Type.Etype] && nl.Op == OLITERAL {
|
||||
// TODO(mdempsky): There should be a convval function.
|
||||
setconst(n, convlit1(nl, n.Type, true, false).Val())
|
||||
}
|
||||
|
||||
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:
|
||||
// Merge adjacent constants in the argument list.
|
||||
s := n.List.Slice()
|
||||
for i1 := 0; i1 < len(s); i1++ {
|
||||
if Isconst(s[i1], CTSTR) && i1+1 < len(s) && Isconst(s[i1+1], CTSTR) {
|
||||
|
|
@ -678,521 +656,292 @@ func evconst(n *Node) {
|
|||
} else {
|
||||
n.List.Set(s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
func match(x, y Val) (Val, Val) {
|
||||
switch {
|
||||
case x.Ctype() == CTCPLX || y.Ctype() == CTCPLX:
|
||||
return tocplx(x), tocplx(y)
|
||||
case x.Ctype() == CTFLT || y.Ctype() == CTFLT:
|
||||
return toflt(x), toflt(y)
|
||||
}
|
||||
|
||||
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
|
||||
// Mixed int/rune are fine.
|
||||
return x, y
|
||||
}
|
||||
|
||||
func compareOp(x Val, op Op, y Val) bool {
|
||||
x, y = match(x, y)
|
||||
|
||||
switch x.Ctype() {
|
||||
case CTNIL:
|
||||
_, _ = x.U.(*NilVal), y.U.(*NilVal) // assert dynamic types match
|
||||
switch op {
|
||||
case OEQ:
|
||||
return true
|
||||
case ONE:
|
||||
return false
|
||||
}
|
||||
|
||||
// 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_
|
||||
case CTBOOL:
|
||||
x, y := x.U.(bool), y.U.(bool)
|
||||
switch op {
|
||||
case OEQ:
|
||||
return x == y
|
||||
case ONE:
|
||||
return x != y
|
||||
}
|
||||
|
||||
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 CTINT, CTRUNE:
|
||||
x, y := x.U.(*Mpint), y.U.(*Mpint)
|
||||
return cmpZero(x.Cmp(y), op)
|
||||
|
||||
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 CTFLT:
|
||||
x, y := x.U.(*Mpflt), y.U.(*Mpflt)
|
||||
return cmpZero(x.Cmp(y), op)
|
||||
|
||||
case OPLUS_ | CTINT_:
|
||||
break
|
||||
|
||||
case OMINUS_ | CTINT_:
|
||||
v.U.(*Mpint).Neg()
|
||||
|
||||
case OCOM_ | CTINT_:
|
||||
et := Txxx
|
||||
if nl.Type != nil {
|
||||
et = nl.Type.Etype
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
if v.Ctype() != rv.Ctype() {
|
||||
// Use of undefined name as constant?
|
||||
if (v.Ctype() == 0 || rv.Ctype() == 0) && nerrors > 0 {
|
||||
return
|
||||
}
|
||||
Fatalf("constant type mismatch %v(%d) %v(%d)", nl.Type, v.Ctype(), nr.Type, rv.Ctype())
|
||||
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
|
||||
}
|
||||
|
||||
// rune values are int values for the purpose of constant folding.
|
||||
ctype = uint32(v.Ctype())
|
||||
if ctype == CTRUNE_ {
|
||||
ctype = CTINT_
|
||||
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}
|
||||
}
|
||||
|
||||
// run op
|
||||
switch uint32(n.Op)<<16 | ctype {
|
||||
default:
|
||||
goto illegal
|
||||
case CTINT, CTRUNE:
|
||||
x, y := x.U.(*Mpint), y.U.(*Mpint)
|
||||
|
||||
case OADD_ | CTINT_:
|
||||
v.U.(*Mpint).Add(rv.U.(*Mpint))
|
||||
|
||||
case OSUB_ | CTINT_:
|
||||
v.U.(*Mpint).Sub(rv.U.(*Mpint))
|
||||
|
||||
case OMUL_ | CTINT_:
|
||||
v.U.(*Mpint).Mul(rv.U.(*Mpint))
|
||||
|
||||
case ODIV_ | CTINT_:
|
||||
if rv.U.(*Mpint).CmpInt64(0) == 0 {
|
||||
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")
|
||||
v.U.(*Mpint).SetOverflow()
|
||||
u.SetOverflow()
|
||||
break
|
||||
}
|
||||
|
||||
v.U.(*Mpint).Quo(rv.U.(*Mpint))
|
||||
|
||||
case OMOD_ | CTINT_:
|
||||
if rv.U.(*Mpint).CmpInt64(0) == 0 {
|
||||
u.Quo(y)
|
||||
case OMOD:
|
||||
if y.CmpInt64(0) == 0 {
|
||||
yyerror("division by zero")
|
||||
v.U.(*Mpint).SetOverflow()
|
||||
u.SetOverflow()
|
||||
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_:
|
||||
v.U.(*Mpint).Lsh(rv.U.(*Mpint))
|
||||
|
||||
case ORSH_ | CTINT_:
|
||||
v.U.(*Mpint).Rsh(rv.U.(*Mpint))
|
||||
|
||||
case OOR_ | CTINT_:
|
||||
v.U.(*Mpint).Or(rv.U.(*Mpint))
|
||||
|
||||
case OAND_ | CTINT_:
|
||||
v.U.(*Mpint).And(rv.U.(*Mpint))
|
||||
|
||||
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 {
|
||||
u := newMpflt()
|
||||
u.Set(x)
|
||||
switch op {
|
||||
case OADD:
|
||||
u.Add(y)
|
||||
case OSUB:
|
||||
u.Sub(y)
|
||||
case OMUL:
|
||||
u.Mul(y)
|
||||
case ODIV:
|
||||
if y.CmpFloat64(0) == 0 {
|
||||
yyerror("division by zero")
|
||||
v.U.(*Mpflt).SetFloat64(1.0)
|
||||
u.SetFloat64(1)
|
||||
break
|
||||
}
|
||||
|
||||
v.U.(*Mpflt).Quo(rv.U.(*Mpflt))
|
||||
|
||||
// The default case above would print 'ideal % ideal',
|
||||
// which is not quite an ideal error.
|
||||
case OMOD_ | CTFLT_:
|
||||
if !n.Diag() {
|
||||
u.Quo(y)
|
||||
case OMOD:
|
||||
// TODO(mdempsky): Move to typecheck.
|
||||
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_:
|
||||
v.U.(*Mpcplx).Real.Add(&rv.U.(*Mpcplx).Real)
|
||||
v.U.(*Mpcplx).Imag.Add(&rv.U.(*Mpcplx).Imag)
|
||||
|
||||
case OSUB_ | CTCPLX_:
|
||||
v.U.(*Mpcplx).Real.Sub(&rv.U.(*Mpcplx).Real)
|
||||
v.U.(*Mpcplx).Imag.Sub(&rv.U.(*Mpcplx).Imag)
|
||||
|
||||
case OMUL_ | CTCPLX_:
|
||||
v.U.(*Mpcplx).Mul(rv.U.(*Mpcplx))
|
||||
|
||||
case ODIV_ | CTCPLX_:
|
||||
if !v.U.(*Mpcplx).Div(rv.U.(*Mpcplx)) {
|
||||
u := new(Mpcplx)
|
||||
u.Real.Set(&x.Real)
|
||||
u.Imag.Set(&x.Imag)
|
||||
switch op {
|
||||
case OADD:
|
||||
u.Real.Add(&y.Real)
|
||||
u.Imag.Add(&y.Imag)
|
||||
case OSUB:
|
||||
u.Real.Sub(&y.Real)
|
||||
u.Imag.Sub(&y.Imag)
|
||||
case OMUL:
|
||||
u.Mul(y)
|
||||
case ODIV:
|
||||
if !u.Div(y) {
|
||||
yyerror("complex division by zero")
|
||||
rv.U.(*Mpcplx).Real.SetFloat64(1.0)
|
||||
rv.U.(*Mpcplx).Imag.SetFloat64(0.0)
|
||||
break
|
||||
u.Real.SetFloat64(1)
|
||||
u.Imag.SetFloat64(0)
|
||||
}
|
||||
default:
|
||||
break Outer
|
||||
}
|
||||
return Val{U: u}
|
||||
}
|
||||
|
||||
case OEQ_ | CTNIL_:
|
||||
goto settrue
|
||||
Fatalf("binaryOp: bad operation: %v %v %v", x, op, y)
|
||||
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
|
||||
func unaryOp(op Op, x Val, t *types.Type) Val {
|
||||
switch op {
|
||||
case OPLUS:
|
||||
switch x.Ctype() {
|
||||
case CTINT, CTRUNE, CTFLT, CTCPLX:
|
||||
return x
|
||||
}
|
||||
|
||||
ret:
|
||||
setconst(n, v)
|
||||
return
|
||||
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}
|
||||
|
||||
settrue:
|
||||
setconst(n, Val{true})
|
||||
return
|
||||
case CTFLT:
|
||||
x := x.U.(*Mpflt)
|
||||
u := newMpflt()
|
||||
u.Set(x)
|
||||
u.Neg()
|
||||
return Val{U: u}
|
||||
|
||||
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 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.
|
||||
|
|
@ -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) {
|
||||
u := new(Mpint)
|
||||
u.SetInt64(v)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue