// 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
}