Commit 48dc42b6 authored by Matthew Dempsky's avatar Matthew Dempsky

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: 's avatarRobert Griesemer <gri@golang.org>
parent d30d5a6b
...@@ -40,7 +40,7 @@ func (v Val) Ctype() Ctype { ...@@ -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 { ...@@ -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{} { ...@@ -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: ...@@ -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 { ...@@ -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 { ...@@ -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) { ...@@ -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 func match(x, y Val) (Val, Val) {
if nr.Type != nil && (nr.Type.IsSigned() || !nr.Type.IsInteger()) { switch {
goto illegal case x.Ctype() == CTCPLX || y.Ctype() == CTCPLX:
} return tocplx(x), tocplx(y)
if nl.Val().Ctype() != CTRUNE { case x.Ctype() == CTFLT || y.Ctype() == CTFLT:
nl.SetVal(toint(nl.Val())) return toflt(x), toflt(y)
}
nr.SetVal(toint(nr.Val()))
} }
// copy numeric value to avoid modifying // Mixed int/rune are fine.
// n->left, in case someone still refers to it (e.g. iota). return x, y
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 { func compareOp(x Val, op Op, y Val) bool {
v = toflt(v) x, y = match(x, y)
rv = toflt(rv)
}
// Rune and int turns into rune. switch x.Ctype() {
if v.Ctype() == CTRUNE && rv.Ctype() == CTINT { case CTNIL:
i := new(Mpint) _, _ = x.U.(*NilVal), y.U.(*NilVal) // assert dynamic types match
i.Set(rv.U.(*Mpint)) switch op {
i.Rune = true case OEQ:
rv.U = i return true
} case ONE:
if v.Ctype() == CTINT && rv.Ctype() == CTRUNE { return false
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() { case CTBOOL:
// Use of undefined name as constant? x, y := x.U.(bool), y.U.(bool)
if (v.Ctype() == 0 || rv.Ctype() == 0) && nerrors > 0 { switch op {
return case OEQ:
return x == y
case ONE:
return x != y
} }
Fatalf("constant type mismatch %v(%d) %v(%d)", nl.Type, v.Ctype(), nr.Type, rv.Ctype())
}
// rune values are int values for the purpose of constant folding.
ctype = uint32(v.Ctype())
if ctype == CTRUNE_ {
ctype = CTINT_
}
// run op
switch uint32(n.Op)<<16 | ctype {
default:
goto illegal
case OADD_ | CTINT_:
v.U.(*Mpint).Add(rv.U.(*Mpint))
case OSUB_ | CTINT_:
v.U.(*Mpint).Sub(rv.U.(*Mpint))
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)
yyerror("division by zero") return cmpZero(x.Cmp(y), op)
v.U.(*Mpint).SetOverflow()
break
}
v.U.(*Mpint).Quo(rv.U.(*Mpint))
case OMOD_ | CTINT_: case CTCPLX:
if rv.U.(*Mpint).CmpInt64(0) == 0 { x, y := x.U.(*Mpcplx), y.U.(*Mpcplx)
yyerror("division by zero") eq := x.Real.Cmp(&y.Real) == 0 && x.Imag.Cmp(&y.Imag) == 0
v.U.(*Mpint).SetOverflow() switch op {
break case OEQ:
return eq
case ONE:
return !eq
} }
v.U.(*Mpint).Rem(rv.U.(*Mpint)) case CTSTR:
x, y := x.U.(string), y.U.(string)
case OLSH_ | CTINT_: switch op {
v.U.(*Mpint).Lsh(rv.U.(*Mpint)) case OEQ:
return x == y
case ORSH_ | CTINT_: case ONE:
v.U.(*Mpint).Rsh(rv.U.(*Mpint)) return x != y
case OLT:
case OOR_ | CTINT_: return x < y
v.U.(*Mpint).Or(rv.U.(*Mpint)) case OLE:
return x <= y
case OAND_ | CTINT_: case OGT:
v.U.(*Mpint).And(rv.U.(*Mpint)) return x > y
case OGE:
case OANDNOT_ | CTINT_: return x >= y
v.U.(*Mpint).AndNot(rv.U.(*Mpint)) }
}
case OXOR_ | CTINT_:
v.U.(*Mpint).Xor(rv.U.(*Mpint)) Fatalf("compareOp: bad comparison: %v %v %v", x, op, y)
panic("unreachable")
case OADD_ | CTFLT_: }
v.U.(*Mpflt).Add(rv.U.(*Mpflt))
case OSUB_ | CTFLT_: func cmpZero(x int, op Op) bool {
v.U.(*Mpflt).Sub(rv.U.(*Mpflt)) 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")
}
case OMUL_ | CTFLT_: func binaryOp(x Val, op Op, y Val) Val {
v.U.(*Mpflt).Mul(rv.U.(*Mpflt)) x, y = match(x, y)
case ODIV_ | CTFLT_: Outer:
if rv.U.(*Mpflt).CmpFloat64(0) == 0 { switch x.Ctype() {
yyerror("division by zero") case CTBOOL:
v.U.(*Mpflt).SetFloat64(1.0) x, y := x.U.(bool), y.U.(bool)
break 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")
u.SetOverflow()
break
}
u.Quo(y)
case OMOD:
if y.CmpInt64(0) == 0 {
yyerror("division by zero")
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.(*Mpflt).Quo(rv.U.(*Mpflt)) case CTFLT:
x, y := x.U.(*Mpflt), y.U.(*Mpflt)
// The default case above would print 'ideal % ideal',
// which is not quite an ideal error. u := newMpflt()
case OMOD_ | CTFLT_: u.Set(x)
if !n.Diag() { 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")
u.SetFloat64(1)
break
}
u.Quo(y)
case OMOD:
// TODO(mdempsky): Move to typecheck.
yyerror("illegal constant expression: floating-point %% operation") yyerror("illegal constant expression: floating-point %% operation")
n.SetDiag(true) default:
} break Outer
return
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)) {
yyerror("complex division by zero")
rv.U.(*Mpcplx).Real.SetFloat64(1.0)
rv.U.(*Mpcplx).Imag.SetFloat64(0.0)
break
}
case OEQ_ | CTNIL_:
goto settrue
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 return Val{U: u}
case OOROR_ | CTBOOL_: case CTCPLX:
if v.U.(bool) || rv.U.(bool) { x, y := x.U.(*Mpcplx), y.U.(*Mpcplx)
goto settrue
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")
u.Real.SetFloat64(1)
u.Imag.SetFloat64(0)
}
default:
break Outer
} }
goto setfalse return Val{U: u}
}
case OANDAND_ | CTBOOL_: Fatalf("binaryOp: bad operation: %v %v %v", x, op, y)
if v.U.(bool) && rv.U.(bool) { panic("unreachable")
goto settrue }
}
goto setfalse
case OEQ_ | CTBOOL_: func unaryOp(op Op, x Val, t *types.Type) Val {
if v.U.(bool) == rv.U.(bool) { switch op {
goto settrue case OPLUS:
switch x.Ctype() {
case CTINT, CTRUNE, CTFLT, CTCPLX:
return x
}
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])
} }
goto setfalse u.Xor(x)
return Val{U: u}
case ONE_ | CTBOOL_: case ONOT:
if v.U.(bool) != rv.U.(bool) { return Val{U: !x.U.(bool)}
goto settrue
}
goto setfalse
} }
ret: Fatalf("unaryOp: bad operation: %v %v", op, x)
setconst(n, v) panic("unreachable")
return }
settrue:
setconst(n, Val{true})
return
setfalse: func shiftOp(x Val, op Op, y Val) Val {
setconst(n, Val{false}) if x.Ctype() != CTRUNE {
return x = toint(x)
}
y = toint(y)
illegal: u := new(Mpint)
if !n.Diag() { u.Set(x.U.(*Mpint))
yyerror("illegal constant expression: %v %v %v", nl.Type, n.Op, nr.Type) u.Rune = x.U.(*Mpint).Rune
n.SetDiag(true) 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) { ...@@ -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)
......
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