From: Matthew Dempsky Date: Thu, 4 Oct 2018 23:49:53 +0000 (-0700) Subject: cmd/compile/internal/gc: major evconst cleanup X-Git-Tag: go1.12beta1~840 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=48dc42b6afe7ad13102c55b8200c9f4577a88c84;p=gostls13.git 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 TryBot-Result: Gobot Gobot Reviewed-by: Robert Griesemer --- diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go index effed1f4ac..e60e05df04 100644 --- a/src/cmd/compile/internal/gc/const.go +++ b/src/cmd/compile/internal/gc/const.go @@ -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 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()) } - 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: + // 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 - } - - 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())) +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) } - // 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) - } + // Mixed int/rune are fine. + return x, y +} - if v.Ctype() == CTFLT || rv.Ctype() == CTFLT { - v = toflt(v) - rv = toflt(rv) - } +func compareOp(x Val, op Op, y Val) bool { + x, y = match(x, y) - // 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 + 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 } - } - if v.Ctype() != rv.Ctype() { - // Use of undefined name as constant? - if (v.Ctype() == 0 || rv.Ctype() == 0) && nerrors > 0 { - return + case CTBOOL: + x, y := x.U.(bool), y.U.(bool) + switch op { + 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_: - v.U.(*Mpint).Mul(rv.U.(*Mpint)) + case CTINT, CTRUNE: + x, y := x.U.(*Mpint), y.U.(*Mpint) + return cmpZero(x.Cmp(y), op) - case ODIV_ | CTINT_: - if rv.U.(*Mpint).CmpInt64(0) == 0 { - yyerror("division by zero") - v.U.(*Mpint).SetOverflow() - break - } - - v.U.(*Mpint).Quo(rv.U.(*Mpint)) + case CTFLT: + x, y := x.U.(*Mpflt), y.U.(*Mpflt) + return cmpZero(x.Cmp(y), op) - case OMOD_ | CTINT_: - if rv.U.(*Mpint).CmpInt64(0) == 0 { - yyerror("division by zero") - v.U.(*Mpint).SetOverflow() - break + 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 } - v.U.(*Mpint).Rem(rv.U.(*Mpint)) - - 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 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") +} - case OSUB_ | CTFLT_: - v.U.(*Mpflt).Sub(rv.U.(*Mpflt)) +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") +} - case OMUL_ | CTFLT_: - v.U.(*Mpflt).Mul(rv.U.(*Mpflt)) +func binaryOp(x Val, op Op, y Val) Val { + x, y = match(x, y) - case ODIV_ | CTFLT_: - if rv.U.(*Mpflt).CmpFloat64(0) == 0 { - yyerror("division by zero") - v.U.(*Mpflt).SetFloat64(1.0) - break +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") + 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)) - - // The default case above would print 'ideal % ideal', - // which is not quite an ideal error. - case OMOD_ | CTFLT_: - if !n.Diag() { + case CTFLT: + x, y := x.U.(*Mpflt), y.U.(*Mpflt) + + 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") + u.SetFloat64(1) + break + } + u.Quo(y) + case OMOD: + // TODO(mdempsky): Move to typecheck. yyerror("illegal constant expression: floating-point %% operation") - n.SetDiag(true) - } - - 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 + default: + break Outer } - goto setfalse + return Val{U: u} - case OOROR_ | CTBOOL_: - if v.U.(bool) || rv.U.(bool) { - goto settrue + case CTCPLX: + x, y := x.U.(*Mpcplx), y.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") + u.Real.SetFloat64(1) + u.Imag.SetFloat64(0) + } + default: + break Outer } - goto setfalse + return Val{U: u} + } - case OANDAND_ | CTBOOL_: - if v.U.(bool) && rv.U.(bool) { - goto settrue - } - goto setfalse + Fatalf("binaryOp: bad operation: %v %v %v", x, op, y) + panic("unreachable") +} - case OEQ_ | CTBOOL_: - if v.U.(bool) == rv.U.(bool) { - goto settrue +func unaryOp(op Op, x Val, t *types.Type) Val { + switch op { + 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_: - if v.U.(bool) != rv.U.(bool) { - goto settrue - } - goto setfalse + case ONOT: + return Val{U: !x.U.(bool)} } -ret: - setconst(n, v) - return - -settrue: - setconst(n, Val{true}) - return + Fatalf("unaryOp: bad operation: %v %v", op, x) + panic("unreachable") +} -setfalse: - setconst(n, Val{false}) - return +func shiftOp(x Val, op Op, y Val) Val { + if x.Ctype() != CTRUNE { + x = toint(x) + } + y = toint(y) -illegal: - if !n.Diag() { - yyerror("illegal constant expression: %v %v %v", nl.Type, n.Op, nr.Type) - n.SetDiag(true) + 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)