// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package gc import ( "cmd/compile/internal/big" "cmd/internal/obj" "strings" ) // Int returns n as an int. // n must be an integer constant. func (n *Node) Int() int64 { if !Isconst(n, CTINT) { Fatal("Int(%v)", n) } return Mpgetfix(n.Val().U.(*Mpint)) } // SetInt sets n's value to i. // n must be an integer constant. func (n *Node) SetInt(i int64) { if !Isconst(n, CTINT) { Fatal("SetInt(%v)", n) } Mpmovecfix(n.Val().U.(*Mpint), i) } // SetBigInt sets n's value to x. // n must be an integer constant. func (n *Node) SetBigInt(x *big.Int) { if !Isconst(n, CTINT) { Fatal("SetBigInt(%v)", n) } n.Val().U.(*Mpint).Val.Set(x) } // Bool returns n as an bool. // n must be an boolean constant. func (n *Node) Bool() bool { if !Isconst(n, CTBOOL) { Fatal("Int(%v)", n) } return n.Val().U.(bool) } /* * truncate float literal fv to 32-bit or 64-bit precision * according to type; return truncated value. */ func truncfltlit(oldv *Mpflt, t *Type) *Mpflt { if t == nil { return oldv } var v Val v.U = oldv overflow(v, t) fv := newMpflt() mpmovefltflt(fv, oldv) // convert large precision literal floating // into limited precision (float64 or float32) switch t.Etype { case TFLOAT64: d := mpgetflt(fv) Mpmovecflt(fv, d) case TFLOAT32: d := mpgetflt32(fv) Mpmovecflt(fv, d) } return fv } /* * convert n, if literal, to type t. * implicit conversion. */ func Convlit(np **Node, t *Type) { convlit1(np, t, false) } /* * convert n, if literal, to type t. * return a new node if necessary * (if n is a named constant, can't edit n->type directly). */ func convlit1(np **Node, t *Type, explicit bool) { n := *np if n == nil || t == nil || n.Type == nil || isideal(t) || n.Type == t { return } if !explicit && !isideal(n.Type) { return } if n.Op == OLITERAL { nn := Nod(OXXX, nil, nil) *nn = *n n = nn *np = n } switch n.Op { default: if n.Type == idealbool { if t.Etype == TBOOL { n.Type = t } else { n.Type = Types[TBOOL] } } if n.Type.Etype == TIDEAL { Convlit(&n.Left, t) Convlit(&n.Right, t) n.Type = t } return // target is invalid type for a constant? leave alone. case OLITERAL: if !okforconst[t.Etype] && n.Type.Etype != TNIL { defaultlit(&n, nil) *np = n return } case OLSH, ORSH: convlit1(&n.Left, t, explicit && isideal(n.Left.Type)) t = n.Left.Type if t != nil && t.Etype == TIDEAL && n.Val().Ctype() != CTINT { n.SetVal(toint(n.Val())) } if t != nil && !Isint[t.Etype] { Yyerror("invalid operation: %v (shift of type %v)", n, t) t = nil } n.Type = t return case OCOMPLEX: if n.Type.Etype == TIDEAL { switch t.Etype { // If trying to convert to non-complex type, // leave as complex128 and let typechecker complain. default: t = Types[TCOMPLEX128] fallthrough //fallthrough case TCOMPLEX128: n.Type = t Convlit(&n.Left, Types[TFLOAT64]) Convlit(&n.Right, Types[TFLOAT64]) case TCOMPLEX64: n.Type = t Convlit(&n.Left, Types[TFLOAT32]) Convlit(&n.Right, Types[TFLOAT32]) } } return } // avoided repeated calculations, errors if Eqtype(n.Type, t) { return } ct := consttype(n) var et int if ct < 0 { goto bad } et = int(t.Etype) if et == TINTER { if ct == CTNIL && n.Type == Types[TNIL] { n.Type = t return } defaultlit(np, nil) return } switch ct { default: goto bad case CTNIL: switch et { default: n.Type = nil goto bad // let normal conversion code handle it case TSTRING: return case TARRAY: if !Isslice(t) { goto bad } case TPTR32, TPTR64, TINTER, TMAP, TCHAN, TFUNC, TUNSAFEPTR: break // A nil literal may be converted to uintptr // if it is an unsafe.Pointer case TUINTPTR: if n.Type.Etype == TUNSAFEPTR { n.SetVal(Val{new(Mpint)}) Mpmovecfix(n.Val().U.(*Mpint), 0) } else { goto bad } } case CTSTR, CTBOOL: if et != int(n.Type.Etype) { goto bad } case CTINT, CTRUNE, CTFLT, CTCPLX: if n.Type.Etype == TUNSAFEPTR && t.Etype != TUINTPTR { goto bad } ct := int(n.Val().Ctype()) if Isint[et] { switch ct { default: goto bad case CTCPLX, CTFLT, CTRUNE: n.SetVal(toint(n.Val())) fallthrough // flowthrough case CTINT: overflow(n.Val(), t) } } else if Isfloat[et] { switch ct { default: goto bad case CTCPLX, CTINT, CTRUNE: n.SetVal(toflt(n.Val())) fallthrough // flowthrough case CTFLT: n.SetVal(Val{truncfltlit(n.Val().U.(*Mpflt), t)}) } } else if Iscomplex[et] { switch ct { default: goto bad case CTFLT, CTINT, CTRUNE: n.SetVal(tocplx(n.Val())) case CTCPLX: overflow(n.Val(), t) } } else if et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit { n.SetVal(tostr(n.Val())) } else { goto bad } } n.Type = t return bad: if n.Diag == 0 { if t.Broke == 0 { Yyerror("cannot convert %v to type %v", n, t) } n.Diag = 1 } if isideal(n.Type) { defaultlit(&n, nil) *np = n } } func copyval(v Val) Val { switch v.Ctype() { case CTINT, CTRUNE: i := new(Mpint) mpmovefixfix(i, v.U.(*Mpint)) i.Rune = v.U.(*Mpint).Rune v.U = i case CTFLT: f := newMpflt() mpmovefltflt(f, v.U.(*Mpflt)) v.U = f case CTCPLX: c := new(Mpcplx) mpmovefltflt(&c.Real, &v.U.(*Mpcplx).Real) mpmovefltflt(&c.Imag, &v.U.(*Mpcplx).Imag) v.U = c } return v } func tocplx(v Val) Val { switch v.Ctype() { case CTINT, CTRUNE: c := new(Mpcplx) Mpmovefixflt(&c.Real, v.U.(*Mpint)) Mpmovecflt(&c.Imag, 0.0) v.U = c case CTFLT: c := new(Mpcplx) mpmovefltflt(&c.Real, v.U.(*Mpflt)) Mpmovecflt(&c.Imag, 0.0) v.U = c } return v } func toflt(v Val) Val { switch v.Ctype() { case CTINT, CTRUNE: f := newMpflt() Mpmovefixflt(f, v.U.(*Mpint)) v.U = f case CTCPLX: f := newMpflt() mpmovefltflt(f, &v.U.(*Mpcplx).Real) if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 { Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign)) } v.U = f } return v } func toint(v Val) Val { switch v.Ctype() { case CTRUNE: i := new(Mpint) mpmovefixfix(i, v.U.(*Mpint)) v.U = i case CTFLT: i := new(Mpint) if mpmovefltfix(i, v.U.(*Mpflt)) < 0 { Yyerror("constant %v truncated to integer", Fconv(v.U.(*Mpflt), obj.FmtSharp)) } v.U = i case CTCPLX: i := new(Mpint) if mpmovefltfix(i, &v.U.(*Mpcplx).Real) < 0 { Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign)) } if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 { Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign)) } v.U = i } return v } func doesoverflow(v Val, t *Type) bool { switch v.Ctype() { case CTINT, CTRUNE: if !Isint[t.Etype] { Fatal("overflow: %v integer constant", t) } if Mpcmpfixfix(v.U.(*Mpint), Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[t.Etype]) > 0 { return true } case CTFLT: if !Isfloat[t.Etype] { Fatal("overflow: %v floating-point constant", t) } if mpcmpfltflt(v.U.(*Mpflt), minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.(*Mpflt), maxfltval[t.Etype]) >= 0 { return true } case CTCPLX: if !Iscomplex[t.Etype] { Fatal("overflow: %v complex constant", t) } if mpcmpfltflt(&v.U.(*Mpcplx).Real, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Real, maxfltval[t.Etype]) >= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, maxfltval[t.Etype]) >= 0 { return true } } return false } func overflow(v Val, t *Type) { // v has already been converted // to appropriate form for t. if t == nil || t.Etype == TIDEAL { return } // Only uintptrs may be converted to unsafe.Pointer, which cannot overflow. if t.Etype == TUNSAFEPTR { return } if !doesoverflow(v, t) { return } switch v.Ctype() { case CTINT, CTRUNE: Yyerror("constant %v overflows %v", v.U.(*Mpint), t) case CTFLT: Yyerror("constant %v overflows %v", Fconv(v.U.(*Mpflt), obj.FmtSharp), t) case CTCPLX: Yyerror("constant %v overflows %v", Fconv(v.U.(*Mpflt), obj.FmtSharp), t) } } func tostr(v Val) Val { switch v.Ctype() { case CTINT, CTRUNE: if Mpcmpfixfix(v.U.(*Mpint), Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[TINT]) > 0 { Yyerror("overflow in int -> string") } r := uint(Mpgetfix(v.U.(*Mpint))) v = Val{} v.U = string(r) case CTFLT: Yyerror("no float -> string") fallthrough case CTNIL: v = Val{} v.U = "" } return v } func consttype(n *Node) int { if n == nil || n.Op != OLITERAL { return -1 } return int(n.Val().Ctype()) } func Isconst(n *Node, ct int) bool { t := consttype(n) // If the caller is asking for CTINT, allow CTRUNE too. // Makes life easier for back ends. return t == ct || (ct == CTINT && t == CTRUNE) } func saveorig(n *Node) *Node { if n == n.Orig { // duplicate node for n->orig. n1 := Nod(OLITERAL, nil, nil) n.Orig = n1 *n1 = *n } return n.Orig } /* * if n is constant, rewrite as OLITERAL node. */ func evconst(n *Node) { // pick off just the opcodes that can be // constant evaluated. switch n.Op { default: return 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 case OCONV: if n.Type == nil { return } if !okforconst[n.Type.Etype] && n.Type.Etype != TNIL { return } // merge adjacent constants in the argument list. case OADDSTR: var nr *Node var nl *Node var l2 *NodeList for l1 := n.List; l1 != nil; l1 = l1.Next { if Isconst(l1.N, CTSTR) && l1.Next != nil && Isconst(l1.Next.N, CTSTR) { // merge from l1 up to but not including l2 var strs []string l2 = l1 for l2 != nil && Isconst(l2.N, CTSTR) { nr = l2.N strs = append(strs, nr.Val().U.(string)) l2 = l2.Next } nl = Nod(OXXX, nil, nil) *nl = *l1.N nl.Orig = nl nl.SetVal(Val{strings.Join(strs, "")}) l1.N = nl l1.Next = l2 } } // fix list end pointer. for l2 := n.List; l2 != nil; l2 = l2.Next { n.List.End = l2 } // collapse single-constant list to single constant. if count(n.List) == 1 && Isconst(n.List.N, CTSTR) { n.Op = OLITERAL n.SetVal(n.List.N.Val()) } return } nl := n.Left if nl == nil || nl.Type == nil { return } if consttype(nl) < 0 { return } wl := int(nl.Type.Etype) if Isint[wl] || Isfloat[wl] || Iscomplex[wl] { wl = TIDEAL } nr := n.Right var rv Val var lno int var wr int var v Val var norig *Node if nr == nil { // copy numeric value to avoid modifying // nl, in case someone still refers to it (e.g. iota). v = nl.Val() if wl == TIDEAL { v = copyval(v) } switch uint32(n.Op)<<16 | uint32(v.Ctype()) { default: if n.Diag == 0 { Yyerror("illegal constant expression %v %v", Oconv(int(n.Op), 0), nl.Type) n.Diag = 1 } return case OCONV<<16 | CTNIL, OARRAYBYTESTR<<16 | CTNIL: if n.Type.Etype == TSTRING { v = tostr(v) nl.Type = n.Type break } fallthrough // fall through case OCONV<<16 | CTINT, OCONV<<16 | CTRUNE, OCONV<<16 | CTFLT, OCONV<<16 | CTSTR: convlit1(&nl, n.Type, true) v = nl.Val() case OPLUS<<16 | CTINT, OPLUS<<16 | CTRUNE: break case OMINUS<<16 | CTINT, OMINUS<<16 | CTRUNE: mpnegfix(v.U.(*Mpint)) case OCOM<<16 | CTINT, OCOM<<16 | CTRUNE: et := Txxx if nl.Type != nil { et = int(nl.Type.Etype) } // calculate the mask in b // result will be (a ^ mask) var b Mpint switch et { // signed guys change sign default: Mpmovecfix(&b, -1) // unsigned guys invert their bits case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR: mpmovefixfix(&b, Maxintval[et]) } mpxorfixfix(v.U.(*Mpint), &b) case OPLUS<<16 | CTFLT: break case OMINUS<<16 | CTFLT: mpnegflt(v.U.(*Mpflt)) case OPLUS<<16 | CTCPLX: break case OMINUS<<16 | CTCPLX: mpnegflt(&v.U.(*Mpcplx).Real) mpnegflt(&v.U.(*Mpcplx).Imag) case ONOT<<16 | CTBOOL: if !v.U.(bool) { goto settrue } goto setfalse } goto ret } if nr.Type == nil { return } if consttype(nr) < 0 { return } wr = int(nr.Type.Etype) if Isint[wr] || Isfloat[wr] || Iscomplex[wr] { wr = TIDEAL } // check for compatible general types (numeric, string, etc) if wl != wr { goto illegal } // check for compatible types. switch n.Op { // ideal const mixes with anything but otherwise must match. default: if nl.Type.Etype != TIDEAL { defaultlit(&nr, nl.Type) n.Right = nr } if nr.Type.Etype != TIDEAL { 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: defaultlit(&nr, Types[TUINT]) n.Right = nr if nr.Type != nil && (Issigned[nr.Type.Etype] || !Isint[nr.Type.Etype]) { 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 = nl.Val() if wl == TIDEAL { v = copyval(v) } 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) mpmovefixfix(i, 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) mpmovefixfix(i, rv.U.(*Mpint)) rv.U = i } else { i := new(Mpint) mpmovefixfix(i, v.U.(*Mpint)) i.Rune = true v.U = i } } if v.Ctype() != rv.Ctype() { // Use of undefined name as constant? if (v.Ctype() == 0 || rv.Ctype() == 0) && nerrors > 0 { return } Fatal("constant type mismatch %v(%d) %v(%d)", nl.Type, v.Ctype(), nr.Type, rv.Ctype()) } // run op switch uint32(n.Op)<<16 | uint32(v.Ctype()) { default: goto illegal case OADD<<16 | CTINT, OADD<<16 | CTRUNE: mpaddfixfix(v.U.(*Mpint), rv.U.(*Mpint), 0) case OSUB<<16 | CTINT, OSUB<<16 | CTRUNE: mpsubfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OMUL<<16 | CTINT, OMUL<<16 | CTRUNE: mpmulfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case ODIV<<16 | CTINT, ODIV<<16 | CTRUNE: if mpcmpfixc(rv.U.(*Mpint), 0) == 0 { Yyerror("division by zero") mpsetovf(v.U.(*Mpint)) break } mpdivfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OMOD<<16 | CTINT, OMOD<<16 | CTRUNE: if mpcmpfixc(rv.U.(*Mpint), 0) == 0 { Yyerror("division by zero") mpsetovf(v.U.(*Mpint)) break } mpmodfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OLSH<<16 | CTINT, OLSH<<16 | CTRUNE: mplshfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case ORSH<<16 | CTINT, ORSH<<16 | CTRUNE: mprshfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OOR<<16 | CTINT, OOR<<16 | CTRUNE: mporfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OAND<<16 | CTINT, OAND<<16 | CTRUNE: mpandfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OANDNOT<<16 | CTINT, OANDNOT<<16 | CTRUNE: mpandnotfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OXOR<<16 | CTINT, OXOR<<16 | CTRUNE: mpxorfixfix(v.U.(*Mpint), rv.U.(*Mpint)) case OADD<<16 | CTFLT: mpaddfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) case OSUB<<16 | CTFLT: mpsubfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) case OMUL<<16 | CTFLT: mpmulfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) case ODIV<<16 | CTFLT: if mpcmpfltc(rv.U.(*Mpflt), 0) == 0 { Yyerror("division by zero") Mpmovecflt(v.U.(*Mpflt), 1.0) break } mpdivfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) // The default case above would print 'ideal % ideal', // which is not quite an ideal error. case OMOD<<16 | CTFLT: if n.Diag == 0 { Yyerror("illegal constant expression: floating-point %% operation") n.Diag = 1 } return case OADD<<16 | CTCPLX: mpaddfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) mpaddfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) case OSUB<<16 | CTCPLX: mpsubfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) mpsubfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) case OMUL<<16 | CTCPLX: cmplxmpy(v.U.(*Mpcplx), rv.U.(*Mpcplx)) case ODIV<<16 | CTCPLX: if mpcmpfltc(&rv.U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&rv.U.(*Mpcplx).Imag, 0) == 0 { Yyerror("complex division by zero") Mpmovecflt(&rv.U.(*Mpcplx).Real, 1.0) Mpmovecflt(&rv.U.(*Mpcplx).Imag, 0.0) break } cmplxdiv(v.U.(*Mpcplx), rv.U.(*Mpcplx)) case OEQ<<16 | CTNIL: goto settrue case ONE<<16 | CTNIL: goto setfalse case OEQ<<16 | CTINT, OEQ<<16 | CTRUNE: if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) == 0 { goto settrue } goto setfalse case ONE<<16 | CTINT, ONE<<16 | CTRUNE: if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) != 0 { goto settrue } goto setfalse case OLT<<16 | CTINT, OLT<<16 | CTRUNE: if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) < 0 { goto settrue } goto setfalse case OLE<<16 | CTINT, OLE<<16 | CTRUNE: if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) <= 0 { goto settrue } goto setfalse case OGE<<16 | CTINT, OGE<<16 | CTRUNE: if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) >= 0 { goto settrue } goto setfalse case OGT<<16 | CTINT, OGT<<16 | CTRUNE: if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) > 0 { goto settrue } goto setfalse case OEQ<<16 | CTFLT: if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) == 0 { goto settrue } goto setfalse case ONE<<16 | CTFLT: if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) != 0 { goto settrue } goto setfalse case OLT<<16 | CTFLT: if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) < 0 { goto settrue } goto setfalse case OLE<<16 | CTFLT: if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) <= 0 { goto settrue } goto setfalse case OGE<<16 | CTFLT: if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) >= 0 { goto settrue } goto setfalse case OGT<<16 | CTFLT: if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) > 0 { goto settrue } goto setfalse case OEQ<<16 | CTCPLX: if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) == 0 && mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) == 0 { goto settrue } goto setfalse case ONE<<16 | CTCPLX: if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) != 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) != 0 { goto settrue } goto setfalse case OEQ<<16 | CTSTR: if cmpslit(nl, nr) == 0 { goto settrue } goto setfalse case ONE<<16 | CTSTR: if cmpslit(nl, nr) != 0 { goto settrue } goto setfalse case OLT<<16 | CTSTR: if cmpslit(nl, nr) < 0 { goto settrue } goto setfalse case OLE<<16 | CTSTR: if cmpslit(nl, nr) <= 0 { goto settrue } goto setfalse case OGE<<16 | CTSTR: if cmpslit(nl, nr) >= 0 { goto settrue } goto setfalse case OGT<<16 | CTSTR: if cmpslit(nl, nr) > 0 { goto settrue } goto setfalse case OOROR<<16 | CTBOOL: if v.U.(bool) || rv.U.(bool) { goto settrue } goto setfalse case OANDAND<<16 | CTBOOL: if v.U.(bool) && rv.U.(bool) { goto settrue } goto setfalse case OEQ<<16 | CTBOOL: if v.U.(bool) == rv.U.(bool) { goto settrue } goto setfalse case ONE<<16 | CTBOOL: if v.U.(bool) != rv.U.(bool) { goto settrue } goto setfalse } goto ret ret: norig = saveorig(n) *n = *nl // restore value of n->orig. n.Orig = norig n.SetVal(v) // check range. lno = int(setlineno(n)) overflow(v, n.Type) lineno = int32(lno) // truncate precision for non-ideal float. if v.Ctype() == CTFLT && n.Type.Etype != TIDEAL { n.SetVal(Val{truncfltlit(v.U.(*Mpflt), n.Type)}) } return settrue: norig = saveorig(n) *n = *Nodbool(true) n.Orig = norig return setfalse: norig = saveorig(n) *n = *Nodbool(false) n.Orig = norig return illegal: if n.Diag == 0 { Yyerror("illegal constant expression: %v %v %v", nl.Type, Oconv(int(n.Op), 0), nr.Type) n.Diag = 1 } return } func nodlit(v Val) *Node { n := Nod(OLITERAL, nil, nil) n.SetVal(v) switch v.Ctype() { default: Fatal("nodlit ctype %d", v.Ctype()) case CTSTR: n.Type = idealstring case CTBOOL: n.Type = idealbool case CTINT, CTRUNE, CTFLT, CTCPLX: n.Type = Types[TIDEAL] case CTNIL: n.Type = Types[TNIL] } return n } func nodcplxlit(r Val, i Val) *Node { r = toflt(r) i = toflt(i) c := new(Mpcplx) n := Nod(OLITERAL, nil, nil) n.Type = Types[TIDEAL] n.SetVal(Val{c}) if r.Ctype() != CTFLT || i.Ctype() != CTFLT { Fatal("nodcplxlit ctype %d/%d", r.Ctype(), i.Ctype()) } mpmovefltflt(&c.Real, r.U.(*Mpflt)) mpmovefltflt(&c.Imag, i.U.(*Mpflt)) return n } // idealkind returns a constant kind like consttype // but for an arbitrary "ideal" (untyped constant) expression. func idealkind(n *Node) int { if n == nil || !isideal(n.Type) { return CTxxx } switch n.Op { default: return CTxxx case OLITERAL: return int(n.Val().Ctype()) // numeric kinds. case OADD, OAND, OANDNOT, OCOM, ODIV, OMINUS, OMOD, OMUL, OSUB, OXOR, OOR, OPLUS: k1 := idealkind(n.Left) k2 := idealkind(n.Right) if k1 > k2 { return k1 } else { return k2 } case OREAL, OIMAG: return CTFLT case OCOMPLEX: return CTCPLX case OADDSTR: return CTSTR case OANDAND, OEQ, OGE, OGT, OLE, OLT, ONE, ONOT, OOROR, OCMPSTR, OCMPIFACE: return CTBOOL // shifts (beware!). case OLSH, ORSH: return idealkind(n.Left) } } func defaultlit(np **Node, t *Type) { n := *np if n == nil || !isideal(n.Type) { return } if n.Op == OLITERAL { nn := Nod(OXXX, nil, nil) *nn = *n n = nn *np = n } lno := int(setlineno(n)) ctype := idealkind(n) var t1 *Type switch ctype { default: if t != nil { Convlit(np, t) return } if n.Val().Ctype() == CTNIL { lineno = int32(lno) if n.Diag == 0 { Yyerror("use of untyped nil") n.Diag = 1 } n.Type = nil break } if n.Val().Ctype() == CTSTR { t1 := Types[TSTRING] Convlit(np, t1) break } Yyerror("defaultlit: unknown literal: %v", n) case CTxxx: Fatal("defaultlit: idealkind is CTxxx: %v", Nconv(n, obj.FmtSign)) case CTBOOL: t1 := Types[TBOOL] if t != nil && t.Etype == TBOOL { t1 = t } Convlit(np, t1) case CTINT: t1 = Types[TINT] goto num case CTRUNE: t1 = runetype goto num case CTFLT: t1 = Types[TFLOAT64] goto num case CTCPLX: t1 = Types[TCOMPLEX128] goto num } lineno = int32(lno) return num: if t != nil { if Isint[t.Etype] { t1 = t n.SetVal(toint(n.Val())) } else if Isfloat[t.Etype] { t1 = t n.SetVal(toflt(n.Val())) } else if Iscomplex[t.Etype] { t1 = t n.SetVal(tocplx(n.Val())) } } overflow(n.Val(), t1) Convlit(np, t1) lineno = int32(lno) return } /* * defaultlit on both nodes simultaneously; * if they're both ideal going in they better * get the same type going out. * force means must assign concrete (non-ideal) type. */ func defaultlit2(lp **Node, rp **Node, force int) { l := *lp r := *rp if l.Type == nil || r.Type == nil { return } if !isideal(l.Type) { Convlit(rp, l.Type) return } if !isideal(r.Type) { Convlit(lp, r.Type) return } if force == 0 { return } if l.Type.Etype == TBOOL { Convlit(lp, Types[TBOOL]) Convlit(rp, Types[TBOOL]) } lkind := idealkind(l) rkind := idealkind(r) if lkind == CTCPLX || rkind == CTCPLX { Convlit(lp, Types[TCOMPLEX128]) Convlit(rp, Types[TCOMPLEX128]) return } if lkind == CTFLT || rkind == CTFLT { Convlit(lp, Types[TFLOAT64]) Convlit(rp, Types[TFLOAT64]) return } if lkind == CTRUNE || rkind == CTRUNE { Convlit(lp, runetype) Convlit(rp, runetype) return } Convlit(lp, Types[TINT]) Convlit(rp, Types[TINT]) } func cmpslit(l, r *Node) int { return stringsCompare(l.Val().U.(string), r.Val().U.(string)) } func Smallintconst(n *Node) bool { if n.Op == OLITERAL && Isconst(n, CTINT) && n.Type != nil { switch Simtype[n.Type.Etype] { case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TBOOL, TPTR32: return true case TIDEAL, TINT64, TUINT64, TPTR64: if Mpcmpfixfix(n.Val().U.(*Mpint), Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val().U.(*Mpint), Maxintval[TINT32]) > 0 { break } return true } } return false } func nonnegconst(n *Node) int { if n.Op == OLITERAL && n.Type != nil { switch Simtype[n.Type.Etype] { // check negative and 2^31 case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TIDEAL: if Mpcmpfixfix(n.Val().U.(*Mpint), Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val().U.(*Mpint), Maxintval[TINT32]) > 0 { break } return int(Mpgetfix(n.Val().U.(*Mpint))) } } return -1 } /* * convert x to type et and back to int64 * for sign extension and truncation. */ func iconv(x int64, et int) int64 { switch et { case TINT8: x = int64(int8(x)) case TUINT8: x = int64(uint8(x)) case TINT16: x = int64(int16(x)) case TUINT16: x = int64(uint64(x)) case TINT32: x = int64(int32(x)) case TUINT32: x = int64(uint32(x)) case TINT64, TUINT64: break } return x } // Convconst converts constant node n to type t and // places the result in con. func (n *Node) Convconst(con *Node, t *Type) { tt := Simsimtype(t) // copy the constant for conversion Nodconst(con, Types[TINT8], 0) con.Type = t con.SetVal(n.Val()) if Isint[tt] { con.SetVal(Val{new(Mpint)}) var i int64 switch n.Val().Ctype() { default: Fatal("convconst ctype=%d %v", n.Val().Ctype(), Tconv(t, obj.FmtLong)) case CTINT, CTRUNE: i = Mpgetfix(n.Val().U.(*Mpint)) case CTBOOL: i = int64(obj.Bool2int(n.Val().U.(bool))) case CTNIL: i = 0 } i = iconv(i, tt) Mpmovecfix(con.Val().U.(*Mpint), i) return } if Isfloat[tt] { con.SetVal(toflt(con.Val())) if con.Val().Ctype() != CTFLT { Fatal("convconst ctype=%d %v", con.Val().Ctype(), t) } if tt == TFLOAT32 { con.SetVal(Val{truncfltlit(con.Val().U.(*Mpflt), t)}) } return } if Iscomplex[tt] { con.SetVal(tocplx(con.Val())) if tt == TCOMPLEX64 { con.Val().U.(*Mpcplx).Real = *truncfltlit(&con.Val().U.(*Mpcplx).Real, Types[TFLOAT32]) con.Val().U.(*Mpcplx).Imag = *truncfltlit(&con.Val().U.(*Mpcplx).Imag, Types[TFLOAT32]) } return } Fatal("convconst %v constant", Tconv(t, obj.FmtLong)) } // complex multiply v *= rv // (a, b) * (c, d) = (a*c - b*d, b*c + a*d) func cmplxmpy(v *Mpcplx, rv *Mpcplx) { var ac Mpflt var bd Mpflt var bc Mpflt var ad Mpflt mpmovefltflt(&ac, &v.Real) mpmulfltflt(&ac, &rv.Real) // ac mpmovefltflt(&bd, &v.Imag) mpmulfltflt(&bd, &rv.Imag) // bd mpmovefltflt(&bc, &v.Imag) mpmulfltflt(&bc, &rv.Real) // bc mpmovefltflt(&ad, &v.Real) mpmulfltflt(&ad, &rv.Imag) // ad mpmovefltflt(&v.Real, &ac) mpsubfltflt(&v.Real, &bd) // ac-bd mpmovefltflt(&v.Imag, &bc) mpaddfltflt(&v.Imag, &ad) // bc+ad } // complex divide v /= rv // (a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d) func cmplxdiv(v *Mpcplx, rv *Mpcplx) { var ac Mpflt var bd Mpflt var bc Mpflt var ad Mpflt var cc_plus_dd Mpflt mpmovefltflt(&cc_plus_dd, &rv.Real) mpmulfltflt(&cc_plus_dd, &rv.Real) // cc mpmovefltflt(&ac, &rv.Imag) mpmulfltflt(&ac, &rv.Imag) // dd mpaddfltflt(&cc_plus_dd, &ac) // cc+dd mpmovefltflt(&ac, &v.Real) mpmulfltflt(&ac, &rv.Real) // ac mpmovefltflt(&bd, &v.Imag) mpmulfltflt(&bd, &rv.Imag) // bd mpmovefltflt(&bc, &v.Imag) mpmulfltflt(&bc, &rv.Real) // bc mpmovefltflt(&ad, &v.Real) mpmulfltflt(&ad, &rv.Imag) // ad mpmovefltflt(&v.Real, &ac) mpaddfltflt(&v.Real, &bd) // ac+bd mpdivfltflt(&v.Real, &cc_plus_dd) // (ac+bd)/(cc+dd) mpmovefltflt(&v.Imag, &bc) mpsubfltflt(&v.Imag, &ad) // bc-ad mpdivfltflt(&v.Imag, &cc_plus_dd) // (bc+ad)/(cc+dd) } // Is n a Go language constant (as opposed to a compile-time constant)? // Expressions derived from nil, like string([]byte(nil)), while they // may be known at compile time, are not Go language constants. // Only called for expressions known to evaluated to compile-time // constants. func isgoconst(n *Node) bool { if n.Orig != nil { n = n.Orig } switch n.Op { case OADD, OADDSTR, OAND, OANDAND, OANDNOT, OCOM, ODIV, OEQ, OGE, OGT, OLE, OLSH, OLT, OMINUS, OMOD, OMUL, ONE, ONOT, OOR, OOROR, OPLUS, ORSH, OSUB, OXOR, OIOTA, OCOMPLEX, OREAL, OIMAG: if isgoconst(n.Left) && (n.Right == nil || isgoconst(n.Right)) { return true } case OCONV: if okforconst[n.Type.Etype] && isgoconst(n.Left) { return true } case OLEN, OCAP: l := n.Left if isgoconst(l) { return true } // Special case: len/cap is constant when applied to array or // pointer to array when the expression does not contain // function calls or channel receive operations. t := l.Type if t != nil && Isptr[t.Etype] { t = t.Type } if Isfixedarray(t) && !hascallchan(l) { return true } case OLITERAL: if n.Val().Ctype() != CTNIL { return true } case ONAME: l := n.Sym.Def if l != nil && l.Op == OLITERAL && n.Val().Ctype() != CTNIL { return true } case ONONAME: if n.Sym.Def != nil && n.Sym.Def.Op == OIOTA { return true } // Only constant calls are unsafe.Alignof, Offsetof, and Sizeof. case OCALL: l := n.Left for l.Op == OPAREN { l = l.Left } if l.Op != ONAME || l.Sym.Pkg != unsafepkg { break } if l.Sym.Name == "Alignof" || l.Sym.Name == "Offsetof" || l.Sym.Name == "Sizeof" { return true } } //dump("nonconst", n); return false } func hascallchan(n *Node) bool { if n == nil { return false } switch n.Op { case OAPPEND, OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OCAP, OCLOSE, OCOMPLEX, OCOPY, ODELETE, OIMAG, OLEN, OMAKE, ONEW, OPANIC, OPRINT, OPRINTN, OREAL, ORECOVER, ORECV: return true } if hascallchan(n.Left) || hascallchan(n.Right) { return true } for l := n.List; l != nil; l = l.Next { if hascallchan(l.N) { return true } } for l := n.Rlist; l != nil; l = l.Next { if hascallchan(l.N) { return true } } return false }