mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Before, -1 meant a node being nil or not an OLITERAL, and 0 meant an OLITERAL missing a Val. However, the use of this value was confusing and led to some issues, such as swt.go checking for < 0 instead of <= 0, causing panics. We never need to differentiate these two cases, so collapse both into 0. To make it clear that negative values can no longer happen, make Ctype an uint8. With this change, we can now get rid of the two n.Type == nil checks in swt.go added to fix a couple of these panics. Thanks to Matthew Dempsky for spotting this inconsistency. Fixes #22001. Change-Id: I51c65a76f38a3e16788b6a3b57932dad3436dc7e Reviewed-on: https://go-review.googlesource.com/69510 Run-TryBot: Daniel Martí <mvdan@mvdan.cc> Reviewed-by: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
1781 lines
33 KiB
Go
1781 lines
33 KiB
Go
// 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/types"
|
|
"cmd/internal/src"
|
|
"math/big"
|
|
"strings"
|
|
)
|
|
|
|
// Ctype describes the constant kind of an "ideal" (untyped) constant.
|
|
type Ctype uint8
|
|
|
|
const (
|
|
CTxxx Ctype = iota
|
|
|
|
CTINT
|
|
CTRUNE
|
|
CTFLT
|
|
CTCPLX
|
|
CTSTR
|
|
CTBOOL
|
|
CTNIL
|
|
)
|
|
|
|
type Val struct {
|
|
// U contains one of:
|
|
// bool bool when n.ValCtype() == CTBOOL
|
|
// *Mpint int when n.ValCtype() == CTINT, rune when n.ValCtype() == CTRUNE
|
|
// *Mpflt float when n.ValCtype() == CTFLT
|
|
// *Mpcplx pair of floats when n.ValCtype() == CTCPLX
|
|
// string string when n.ValCtype() == CTSTR
|
|
// *Nilval when n.ValCtype() == CTNIL
|
|
U interface{}
|
|
}
|
|
|
|
func (v Val) Ctype() Ctype {
|
|
switch x := v.U.(type) {
|
|
default:
|
|
Fatalf("unexpected Ctype for %T", v.U)
|
|
panic("not reached")
|
|
case nil:
|
|
return 0
|
|
case *NilVal:
|
|
return CTNIL
|
|
case bool:
|
|
return CTBOOL
|
|
case *Mpint:
|
|
if x.Rune {
|
|
return CTRUNE
|
|
}
|
|
return CTINT
|
|
case *Mpflt:
|
|
return CTFLT
|
|
case *Mpcplx:
|
|
return CTCPLX
|
|
case string:
|
|
return CTSTR
|
|
}
|
|
}
|
|
|
|
func eqval(a, b Val) bool {
|
|
if a.Ctype() != b.Ctype() {
|
|
return false
|
|
}
|
|
switch x := a.U.(type) {
|
|
default:
|
|
Fatalf("unexpected Ctype for %T", a.U)
|
|
panic("not reached")
|
|
case *NilVal:
|
|
return true
|
|
case bool:
|
|
y := b.U.(bool)
|
|
return x == y
|
|
case *Mpint:
|
|
y := b.U.(*Mpint)
|
|
return x.Cmp(y) == 0
|
|
case *Mpflt:
|
|
y := b.U.(*Mpflt)
|
|
return x.Cmp(y) == 0
|
|
case *Mpcplx:
|
|
y := b.U.(*Mpcplx)
|
|
return x.Real.Cmp(&y.Real) == 0 && x.Imag.Cmp(&y.Imag) == 0
|
|
case string:
|
|
y := b.U.(string)
|
|
return x == y
|
|
}
|
|
}
|
|
|
|
// Interface returns the constant value stored in v as an interface{}.
|
|
// It returns int64s for ints and runes, float64s for floats,
|
|
// complex128s for complex values, and nil for constant nils.
|
|
func (v Val) Interface() interface{} {
|
|
switch x := v.U.(type) {
|
|
default:
|
|
Fatalf("unexpected Interface for %T", v.U)
|
|
panic("not reached")
|
|
case *NilVal:
|
|
return nil
|
|
case bool, string:
|
|
return x
|
|
case *Mpint:
|
|
return x.Int64()
|
|
case *Mpflt:
|
|
return x.Float64()
|
|
case *Mpcplx:
|
|
return complex(x.Real.Float64(), x.Imag.Float64())
|
|
}
|
|
}
|
|
|
|
type NilVal struct{}
|
|
|
|
// Int64 returns n as an int64.
|
|
// n must be an integer or rune constant.
|
|
func (n *Node) Int64() int64 {
|
|
if !Isconst(n, CTINT) {
|
|
Fatalf("Int64(%v)", n)
|
|
}
|
|
return n.Val().U.(*Mpint).Int64()
|
|
}
|
|
|
|
// Bool returns n as a bool.
|
|
// n must be a boolean constant.
|
|
func (n *Node) Bool() bool {
|
|
if !Isconst(n, CTBOOL) {
|
|
Fatalf("Bool(%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 *types.Type) *Mpflt {
|
|
if t == nil {
|
|
return oldv
|
|
}
|
|
|
|
if overflow(Val{oldv}, t) {
|
|
// If there was overflow, simply continuing would set the
|
|
// value to Inf which in turn would lead to spurious follow-on
|
|
// errors. Avoid this by returning the existing value.
|
|
return oldv
|
|
}
|
|
|
|
fv := newMpflt()
|
|
|
|
// convert large precision literal floating
|
|
// into limited precision (float64 or float32)
|
|
switch t.Etype {
|
|
case types.TFLOAT32:
|
|
fv.SetFloat64(oldv.Float32())
|
|
case types.TFLOAT64:
|
|
fv.SetFloat64(oldv.Float64())
|
|
default:
|
|
Fatalf("truncfltlit: unexpected Etype %v", t.Etype)
|
|
}
|
|
|
|
return fv
|
|
}
|
|
|
|
// truncate Real and Imag parts of Mpcplx to 32-bit or 64-bit
|
|
// precision, according to type; return truncated value. In case of
|
|
// overflow, calls yyerror but does not truncate the input value.
|
|
func trunccmplxlit(oldv *Mpcplx, t *types.Type) *Mpcplx {
|
|
if t == nil {
|
|
return oldv
|
|
}
|
|
|
|
if overflow(Val{oldv}, t) {
|
|
// If there was overflow, simply continuing would set the
|
|
// value to Inf which in turn would lead to spurious follow-on
|
|
// errors. Avoid this by returning the existing value.
|
|
return oldv
|
|
}
|
|
|
|
cv := newMpcmplx()
|
|
|
|
switch t.Etype {
|
|
case types.TCOMPLEX64:
|
|
cv.Real.SetFloat64(oldv.Real.Float32())
|
|
cv.Imag.SetFloat64(oldv.Imag.Float32())
|
|
case types.TCOMPLEX128:
|
|
cv.Real.SetFloat64(oldv.Real.Float64())
|
|
cv.Imag.SetFloat64(oldv.Imag.Float64())
|
|
default:
|
|
Fatalf("trunccplxlit: unexpected Etype %v", t.Etype)
|
|
}
|
|
|
|
return cv
|
|
}
|
|
|
|
// canReuseNode indicates whether it is known to be safe
|
|
// to reuse a Node.
|
|
type canReuseNode bool
|
|
|
|
const (
|
|
noReuse canReuseNode = false // not necessarily safe to reuse
|
|
reuseOK canReuseNode = true // safe to reuse
|
|
)
|
|
|
|
// convert n, if literal, to type t.
|
|
// implicit conversion.
|
|
// The result of convlit MUST be assigned back to n, e.g.
|
|
// n.Left = convlit(n.Left, t)
|
|
func convlit(n *Node, t *types.Type) *Node {
|
|
return convlit1(n, t, false, noReuse)
|
|
}
|
|
|
|
// convlit1 converts n, if literal, to type t.
|
|
// It returns a new node if necessary.
|
|
// The result of convlit1 MUST be assigned back to n, e.g.
|
|
// n.Left = convlit1(n.Left, t, explicit, reuse)
|
|
func convlit1(n *Node, t *types.Type, explicit bool, reuse canReuseNode) *Node {
|
|
if n == nil || t == nil || n.Type == nil || t.IsUntyped() || n.Type == t {
|
|
return n
|
|
}
|
|
if !explicit && !n.Type.IsUntyped() {
|
|
return n
|
|
}
|
|
|
|
if n.Op == OLITERAL && !reuse {
|
|
// Can't always set n.Type directly on OLITERAL nodes.
|
|
// See discussion on CL 20813.
|
|
nn := *n
|
|
n = &nn
|
|
reuse = true
|
|
}
|
|
|
|
switch n.Op {
|
|
default:
|
|
if n.Type == types.Idealbool {
|
|
if t.IsBoolean() {
|
|
n.Type = t
|
|
} else {
|
|
n.Type = types.Types[TBOOL]
|
|
}
|
|
}
|
|
|
|
if n.Type.Etype == TIDEAL {
|
|
n.Left = convlit(n.Left, t)
|
|
n.Right = convlit(n.Right, t)
|
|
n.Type = t
|
|
}
|
|
|
|
return n
|
|
|
|
// target is invalid type for a constant? leave alone.
|
|
case OLITERAL:
|
|
if !okforconst[t.Etype] && n.Type.Etype != TNIL {
|
|
return defaultlitreuse(n, nil, reuse)
|
|
}
|
|
|
|
case OLSH, ORSH:
|
|
n.Left = convlit1(n.Left, t, explicit && n.Left.Type.IsUntyped(), noReuse)
|
|
t = n.Left.Type
|
|
if t != nil && t.Etype == TIDEAL && n.Val().Ctype() != CTINT {
|
|
n.SetVal(toint(n.Val()))
|
|
}
|
|
if t != nil && !t.IsInteger() {
|
|
yyerror("invalid operation: %v (shift of type %v)", n, t)
|
|
t = nil
|
|
}
|
|
|
|
n.Type = t
|
|
return n
|
|
|
|
case OCOMPLEX:
|
|
if n.Type.Etype == TIDEAL {
|
|
switch t.Etype {
|
|
default:
|
|
// If trying to convert to non-complex type,
|
|
// leave as complex128 and let typechecker complain.
|
|
t = types.Types[TCOMPLEX128]
|
|
fallthrough
|
|
case types.TCOMPLEX128:
|
|
n.Type = t
|
|
n.Left = convlit(n.Left, types.Types[TFLOAT64])
|
|
n.Right = convlit(n.Right, types.Types[TFLOAT64])
|
|
|
|
case TCOMPLEX64:
|
|
n.Type = t
|
|
n.Left = convlit(n.Left, types.Types[TFLOAT32])
|
|
n.Right = convlit(n.Right, types.Types[TFLOAT32])
|
|
}
|
|
}
|
|
|
|
return n
|
|
}
|
|
|
|
// avoided repeated calculations, errors
|
|
if eqtype(n.Type, t) {
|
|
return n
|
|
}
|
|
|
|
ct := consttype(n)
|
|
var et types.EType
|
|
if ct == 0 {
|
|
goto bad
|
|
}
|
|
|
|
et = t.Etype
|
|
if et == TINTER {
|
|
if ct == CTNIL && n.Type == types.Types[TNIL] {
|
|
n.Type = t
|
|
return n
|
|
}
|
|
return defaultlitreuse(n, nil, reuse)
|
|
}
|
|
|
|
switch ct {
|
|
default:
|
|
goto bad
|
|
|
|
case CTNIL:
|
|
switch et {
|
|
default:
|
|
n.Type = nil
|
|
goto bad
|
|
|
|
// let normal conversion code handle it
|
|
case TSTRING:
|
|
return n
|
|
|
|
case TARRAY:
|
|
goto bad
|
|
|
|
case TPTR32,
|
|
TPTR64,
|
|
TINTER,
|
|
TMAP,
|
|
TCHAN,
|
|
TFUNC,
|
|
TSLICE,
|
|
TUNSAFEPTR:
|
|
break
|
|
|
|
// A nil literal may be converted to uintptr
|
|
// if it is an unsafe.Pointer
|
|
case TUINTPTR:
|
|
if n.Type.Etype == TUNSAFEPTR {
|
|
i := new(Mpint)
|
|
i.SetInt64(0)
|
|
n.SetVal(Val{i})
|
|
} else {
|
|
goto bad
|
|
}
|
|
}
|
|
|
|
case CTSTR, CTBOOL:
|
|
if et != n.Type.Etype {
|
|
goto bad
|
|
}
|
|
|
|
case CTINT, CTRUNE, CTFLT, CTCPLX:
|
|
if n.Type.Etype == TUNSAFEPTR && t.Etype != TUINTPTR {
|
|
goto bad
|
|
}
|
|
ct := n.Val().Ctype()
|
|
if isInt[et] {
|
|
switch ct {
|
|
default:
|
|
goto bad
|
|
|
|
case CTCPLX, CTFLT, CTRUNE:
|
|
n.SetVal(toint(n.Val()))
|
|
fallthrough
|
|
|
|
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
|
|
|
|
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()))
|
|
fallthrough
|
|
|
|
case CTCPLX:
|
|
n.SetVal(Val{trunccmplxlit(n.Val().U.(*Mpcplx), t)})
|
|
}
|
|
} else if et == types.TSTRING && (ct == CTINT || ct == CTRUNE) && explicit {
|
|
n.SetVal(tostr(n.Val()))
|
|
} else {
|
|
goto bad
|
|
}
|
|
}
|
|
|
|
n.Type = t
|
|
return n
|
|
|
|
bad:
|
|
if !n.Diag() {
|
|
if !t.Broke() {
|
|
yyerror("cannot convert %L to type %v", n, t)
|
|
}
|
|
n.SetDiag(true)
|
|
}
|
|
|
|
if n.Type.IsUntyped() {
|
|
n = defaultlitreuse(n, nil, reuse)
|
|
}
|
|
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:
|
|
c := new(Mpcplx)
|
|
c.Real.SetInt(u)
|
|
c.Imag.SetFloat64(0.0)
|
|
v.U = c
|
|
|
|
case *Mpflt:
|
|
c := new(Mpcplx)
|
|
c.Real.Set(u)
|
|
c.Imag.SetFloat64(0.0)
|
|
v.U = c
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func toflt(v Val) Val {
|
|
switch u := v.U.(type) {
|
|
case *Mpint:
|
|
f := newMpflt()
|
|
f.SetInt(u)
|
|
v.U = f
|
|
|
|
case *Mpcplx:
|
|
f := newMpflt()
|
|
f.Set(&u.Real)
|
|
if u.Imag.CmpFloat64(0) != 0 {
|
|
yyerror("constant %v%vi truncated to real", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp|FmtSign))
|
|
}
|
|
v.U = f
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func toint(v Val) Val {
|
|
switch u := v.U.(type) {
|
|
case *Mpint:
|
|
if u.Rune {
|
|
i := new(Mpint)
|
|
i.Set(u)
|
|
v.U = i
|
|
}
|
|
|
|
case *Mpflt:
|
|
i := new(Mpint)
|
|
if !i.SetFloat(u) {
|
|
if i.checkOverflow(0) {
|
|
yyerror("integer too large")
|
|
} else {
|
|
// The value of u cannot be represented as an integer;
|
|
// so we need to print an error message.
|
|
// Unfortunately some float values cannot be
|
|
// reasonably formatted for inclusion in an error
|
|
// message (example: 1 + 1e-100), so first we try to
|
|
// format the float; if the truncation resulted in
|
|
// something that looks like an integer we omit the
|
|
// value from the error message.
|
|
// (See issue #11371).
|
|
var t big.Float
|
|
t.Parse(fconv(u, FmtSharp), 10)
|
|
if t.IsInt() {
|
|
yyerror("constant truncated to integer")
|
|
} else {
|
|
yyerror("constant %v truncated to integer", fconv(u, FmtSharp))
|
|
}
|
|
}
|
|
}
|
|
v.U = i
|
|
|
|
case *Mpcplx:
|
|
i := new(Mpint)
|
|
if !i.SetFloat(&u.Real) || u.Imag.CmpFloat64(0) != 0 {
|
|
yyerror("constant %v%vi truncated to integer", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp|FmtSign))
|
|
}
|
|
|
|
v.U = i
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func doesoverflow(v Val, t *types.Type) bool {
|
|
switch u := v.U.(type) {
|
|
case *Mpint:
|
|
if !t.IsInteger() {
|
|
Fatalf("overflow: %v integer constant", t)
|
|
}
|
|
return u.Cmp(minintval[t.Etype]) < 0 || u.Cmp(maxintval[t.Etype]) > 0
|
|
|
|
case *Mpflt:
|
|
if !t.IsFloat() {
|
|
Fatalf("overflow: %v floating-point constant", t)
|
|
}
|
|
return u.Cmp(minfltval[t.Etype]) <= 0 || u.Cmp(maxfltval[t.Etype]) >= 0
|
|
|
|
case *Mpcplx:
|
|
if !t.IsComplex() {
|
|
Fatalf("overflow: %v complex constant", t)
|
|
}
|
|
return u.Real.Cmp(minfltval[t.Etype]) <= 0 || u.Real.Cmp(maxfltval[t.Etype]) >= 0 ||
|
|
u.Imag.Cmp(minfltval[t.Etype]) <= 0 || u.Imag.Cmp(maxfltval[t.Etype]) >= 0
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func overflow(v Val, t *types.Type) bool {
|
|
// v has already been converted
|
|
// to appropriate form for t.
|
|
if t == nil || t.Etype == TIDEAL {
|
|
return false
|
|
}
|
|
|
|
// Only uintptrs may be converted to unsafe.Pointer, which cannot overflow.
|
|
if t.Etype == TUNSAFEPTR {
|
|
return false
|
|
}
|
|
|
|
if doesoverflow(v, t) {
|
|
yyerror("constant %v overflows %v", v, t)
|
|
return true
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
func tostr(v Val) Val {
|
|
switch u := v.U.(type) {
|
|
case *Mpint:
|
|
var i int64 = 0xFFFD
|
|
if u.Cmp(minintval[TUINT32]) >= 0 && u.Cmp(maxintval[TUINT32]) <= 0 {
|
|
i = u.Int64()
|
|
}
|
|
v.U = string(i)
|
|
|
|
case *NilVal:
|
|
// Can happen because of string([]byte(nil)).
|
|
v.U = ""
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func consttype(n *Node) Ctype {
|
|
if n == nil || n.Op != OLITERAL {
|
|
return 0
|
|
}
|
|
return n.Val().Ctype()
|
|
}
|
|
|
|
func Isconst(n *Node, ct Ctype) 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:
|
|
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) {
|
|
// merge from i1 up to but not including i2
|
|
var strs []string
|
|
i2 := i1
|
|
for i2 < len(s) && Isconst(s[i2], CTSTR) {
|
|
strs = append(strs, s[i2].Val().U.(string))
|
|
i2++
|
|
}
|
|
|
|
nl := *s[i1]
|
|
nl.Orig = &nl
|
|
nl.SetVal(Val{strings.Join(strs, "")})
|
|
s[i1] = &nl
|
|
s = append(s[:i1+1], s[i2:]...)
|
|
}
|
|
}
|
|
|
|
if len(s) == 1 && Isconst(s[0], CTSTR) {
|
|
n.Op = OLITERAL
|
|
n.SetVal(s[0].Val())
|
|
} 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 lno src.XPos
|
|
var wr types.EType
|
|
var ctype uint32
|
|
var v Val
|
|
var norig *Node
|
|
var nn *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)
|
|
}
|
|
|
|
// 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_:
|
|
var et types.EType = 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()))
|
|
}
|
|
|
|
// 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)
|
|
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
|
|
}
|
|
}
|
|
|
|
if v.Ctype() != rv.Ctype() {
|
|
// Use of undefined name as constant?
|
|
if (v.Ctype() == 0 || rv.Ctype() == 0) && nerrors > 0 {
|
|
return
|
|
}
|
|
Fatalf("constant type mismatch %v(%d) %v(%d)", nl.Type, v.Ctype(), nr.Type, rv.Ctype())
|
|
}
|
|
|
|
// 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 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 OMOD_ | CTINT_:
|
|
if rv.U.(*Mpint).CmpInt64(0) == 0 {
|
|
yyerror("division by zero")
|
|
v.U.(*Mpint).SetOverflow()
|
|
break
|
|
}
|
|
|
|
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 OSUB_ | CTFLT_:
|
|
v.U.(*Mpflt).Sub(rv.U.(*Mpflt))
|
|
|
|
case OMUL_ | CTFLT_:
|
|
v.U.(*Mpflt).Mul(rv.U.(*Mpflt))
|
|
|
|
case ODIV_ | CTFLT_:
|
|
if rv.U.(*Mpflt).CmpFloat64(0) == 0 {
|
|
yyerror("division by zero")
|
|
v.U.(*Mpflt).SetFloat64(1.0)
|
|
break
|
|
}
|
|
|
|
v.U.(*Mpflt).Quo(rv.U.(*Mpflt))
|
|
|
|
// The default case above would print 'ideal % ideal',
|
|
// which is not quite an ideal error.
|
|
case OMOD_ | CTFLT_:
|
|
if !n.Diag() {
|
|
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_:
|
|
cmplxmpy(v.U.(*Mpcplx), rv.U.(*Mpcplx))
|
|
|
|
case ODIV_ | CTCPLX_:
|
|
if !cmplxdiv(v.U.(*Mpcplx), 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
|
|
|
|
case OOROR_ | CTBOOL_:
|
|
if v.U.(bool) || rv.U.(bool) {
|
|
goto settrue
|
|
}
|
|
goto setfalse
|
|
|
|
case OANDAND_ | CTBOOL_:
|
|
if v.U.(bool) && rv.U.(bool) {
|
|
goto settrue
|
|
}
|
|
goto setfalse
|
|
|
|
case OEQ_ | CTBOOL_:
|
|
if v.U.(bool) == rv.U.(bool) {
|
|
goto settrue
|
|
}
|
|
goto setfalse
|
|
|
|
case ONE_ | CTBOOL_:
|
|
if v.U.(bool) != rv.U.(bool) {
|
|
goto settrue
|
|
}
|
|
goto setfalse
|
|
}
|
|
|
|
ret:
|
|
norig = saveorig(n)
|
|
*n = *nl
|
|
|
|
// restore value of n->orig.
|
|
n.Orig = norig
|
|
|
|
n.SetVal(v)
|
|
|
|
// check range.
|
|
lno = setlineno(n)
|
|
overflow(v, n.Type)
|
|
lineno = 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:
|
|
nn = nodbool(true)
|
|
nn.Orig = saveorig(n)
|
|
if !iscmp[n.Op] {
|
|
nn.Type = nl.Type
|
|
}
|
|
*n = *nn
|
|
return
|
|
|
|
setfalse:
|
|
nn = nodbool(false)
|
|
nn.Orig = saveorig(n)
|
|
if !iscmp[n.Op] {
|
|
nn.Type = nl.Type
|
|
}
|
|
*n = *nn
|
|
return
|
|
|
|
illegal:
|
|
if !n.Diag() {
|
|
yyerror("illegal constant expression: %v %v %v", nl.Type, n.Op, nr.Type)
|
|
n.SetDiag(true)
|
|
}
|
|
}
|
|
|
|
func nodlit(v Val) *Node {
|
|
n := nod(OLITERAL, nil, nil)
|
|
n.SetVal(v)
|
|
switch v.Ctype() {
|
|
default:
|
|
Fatalf("nodlit ctype %d", v.Ctype())
|
|
|
|
case CTSTR:
|
|
n.Type = types.Idealstring
|
|
|
|
case CTBOOL:
|
|
n.Type = types.Idealbool
|
|
|
|
case CTINT, CTRUNE, CTFLT, CTCPLX:
|
|
n.Type = types.Types[TIDEAL]
|
|
|
|
case CTNIL:
|
|
n.Type = types.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.Types[TIDEAL]
|
|
n.SetVal(Val{c})
|
|
|
|
if r.Ctype() != CTFLT || i.Ctype() != CTFLT {
|
|
Fatalf("nodcplxlit ctype %d/%d", r.Ctype(), i.Ctype())
|
|
}
|
|
|
|
c.Real.Set(r.U.(*Mpflt))
|
|
c.Imag.Set(i.U.(*Mpflt))
|
|
return n
|
|
}
|
|
|
|
// idealkind returns a constant kind like consttype
|
|
// but for an arbitrary "ideal" (untyped constant) expression.
|
|
func idealkind(n *Node) Ctype {
|
|
if n == nil || !n.Type.IsUntyped() {
|
|
return CTxxx
|
|
}
|
|
|
|
switch n.Op {
|
|
default:
|
|
return CTxxx
|
|
|
|
case OLITERAL:
|
|
return 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)
|
|
}
|
|
}
|
|
|
|
// The result of defaultlit MUST be assigned back to n, e.g.
|
|
// n.Left = defaultlit(n.Left, t)
|
|
func defaultlit(n *Node, t *types.Type) *Node {
|
|
return defaultlitreuse(n, t, noReuse)
|
|
}
|
|
|
|
// The result of defaultlitreuse MUST be assigned back to n, e.g.
|
|
// n.Left = defaultlitreuse(n.Left, t, reuse)
|
|
func defaultlitreuse(n *Node, t *types.Type, reuse canReuseNode) *Node {
|
|
if n == nil || !n.Type.IsUntyped() {
|
|
return n
|
|
}
|
|
|
|
if n.Op == OLITERAL && !reuse {
|
|
nn := *n
|
|
n = &nn
|
|
reuse = true
|
|
}
|
|
|
|
lno := setlineno(n)
|
|
ctype := idealkind(n)
|
|
var t1 *types.Type
|
|
switch ctype {
|
|
default:
|
|
if t != nil {
|
|
return convlit(n, t)
|
|
}
|
|
|
|
if n.Val().Ctype() == CTNIL {
|
|
lineno = lno
|
|
if !n.Diag() {
|
|
yyerror("use of untyped nil")
|
|
n.SetDiag(true)
|
|
}
|
|
|
|
n.Type = nil
|
|
break
|
|
}
|
|
|
|
if n.Val().Ctype() == CTSTR {
|
|
t1 := types.Types[TSTRING]
|
|
n = convlit1(n, t1, false, reuse)
|
|
break
|
|
}
|
|
|
|
yyerror("defaultlit: unknown literal: %v", n)
|
|
|
|
case CTxxx:
|
|
Fatalf("defaultlit: idealkind is CTxxx: %+v", n)
|
|
|
|
case CTBOOL:
|
|
t1 := types.Types[TBOOL]
|
|
if t != nil && t.IsBoolean() {
|
|
t1 = t
|
|
}
|
|
n = convlit1(n, t1, false, reuse)
|
|
|
|
case CTINT:
|
|
t1 = types.Types[TINT]
|
|
goto num
|
|
|
|
case CTRUNE:
|
|
t1 = types.Runetype
|
|
goto num
|
|
|
|
case CTFLT:
|
|
t1 = types.Types[TFLOAT64]
|
|
goto num
|
|
|
|
case CTCPLX:
|
|
t1 = types.Types[TCOMPLEX128]
|
|
goto num
|
|
}
|
|
|
|
lineno = lno
|
|
return n
|
|
|
|
num:
|
|
// Note: n.Val().Ctype() can be CTxxx (not a constant) here
|
|
// in the case of an untyped non-constant value, like 1<<i.
|
|
v1 := n.Val()
|
|
if t != nil {
|
|
if t.IsInteger() {
|
|
t1 = t
|
|
v1 = toint(n.Val())
|
|
} else if t.IsFloat() {
|
|
t1 = t
|
|
v1 = toflt(n.Val())
|
|
} else if t.IsComplex() {
|
|
t1 = t
|
|
v1 = tocplx(n.Val())
|
|
}
|
|
if n.Val().Ctype() != CTxxx {
|
|
n.SetVal(v1)
|
|
}
|
|
}
|
|
|
|
if n.Val().Ctype() != CTxxx {
|
|
overflow(n.Val(), t1)
|
|
}
|
|
n = convlit1(n, t1, false, reuse)
|
|
lineno = lno
|
|
return n
|
|
}
|
|
|
|
// 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.
|
|
// The results of defaultlit2 MUST be assigned back to l and r, e.g.
|
|
// n.Left, n.Right = defaultlit2(n.Left, n.Right, force)
|
|
func defaultlit2(l *Node, r *Node, force bool) (*Node, *Node) {
|
|
if l.Type == nil || r.Type == nil {
|
|
return l, r
|
|
}
|
|
if !l.Type.IsUntyped() {
|
|
r = convlit(r, l.Type)
|
|
return l, r
|
|
}
|
|
|
|
if !r.Type.IsUntyped() {
|
|
l = convlit(l, r.Type)
|
|
return l, r
|
|
}
|
|
|
|
if !force {
|
|
return l, r
|
|
}
|
|
|
|
if l.Type.IsBoolean() {
|
|
l = convlit(l, types.Types[TBOOL])
|
|
r = convlit(r, types.Types[TBOOL])
|
|
}
|
|
|
|
lkind := idealkind(l)
|
|
rkind := idealkind(r)
|
|
if lkind == CTCPLX || rkind == CTCPLX {
|
|
l = convlit(l, types.Types[TCOMPLEX128])
|
|
r = convlit(r, types.Types[TCOMPLEX128])
|
|
return l, r
|
|
}
|
|
|
|
if lkind == CTFLT || rkind == CTFLT {
|
|
l = convlit(l, types.Types[TFLOAT64])
|
|
r = convlit(r, types.Types[TFLOAT64])
|
|
return l, r
|
|
}
|
|
|
|
if lkind == CTRUNE || rkind == CTRUNE {
|
|
l = convlit(l, types.Runetype)
|
|
r = convlit(r, types.Runetype)
|
|
return l, r
|
|
}
|
|
|
|
l = convlit(l, types.Types[TINT])
|
|
r = convlit(r, types.Types[TINT])
|
|
|
|
return l, r
|
|
}
|
|
|
|
// strlit returns the value of a literal string Node as a string.
|
|
func strlit(n *Node) string {
|
|
return n.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:
|
|
v, ok := n.Val().U.(*Mpint)
|
|
if ok && v.Cmp(minintval[TINT32]) > 0 && v.Cmp(maxintval[TINT32]) < 0 {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// nonnegintconst checks if Node n contains a constant expression
|
|
// representable as a non-negative small integer, and returns its
|
|
// (integer) value if that's the case. Otherwise, it returns -1.
|
|
func nonnegintconst(n *Node) int64 {
|
|
if n.Op != OLITERAL {
|
|
return -1
|
|
}
|
|
|
|
// toint will leave n.Val unchanged if it's not castable to an
|
|
// Mpint, so we still have to guard the conversion.
|
|
v := toint(n.Val())
|
|
vi, ok := v.U.(*Mpint)
|
|
if !ok || vi.CmpInt64(0) < 0 || vi.Cmp(maxintval[TINT32]) > 0 {
|
|
return -1
|
|
}
|
|
|
|
return vi.Int64()
|
|
}
|
|
|
|
// 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
|
|
|
|
ac.Set(&v.Real)
|
|
ac.Mul(&rv.Real) // ac
|
|
|
|
bd.Set(&v.Imag)
|
|
|
|
bd.Mul(&rv.Imag) // bd
|
|
|
|
bc.Set(&v.Imag)
|
|
|
|
bc.Mul(&rv.Real) // bc
|
|
|
|
ad.Set(&v.Real)
|
|
|
|
ad.Mul(&rv.Imag) // ad
|
|
|
|
v.Real.Set(&ac)
|
|
|
|
v.Real.Sub(&bd) // ac-bd
|
|
|
|
v.Imag.Set(&bc)
|
|
|
|
v.Imag.Add(&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) bool {
|
|
if rv.Real.CmpFloat64(0) == 0 && rv.Imag.CmpFloat64(0) == 0 {
|
|
return false
|
|
}
|
|
|
|
var ac Mpflt
|
|
var bd Mpflt
|
|
var bc Mpflt
|
|
var ad Mpflt
|
|
var cc_plus_dd Mpflt
|
|
|
|
cc_plus_dd.Set(&rv.Real)
|
|
|
|
cc_plus_dd.Mul(&rv.Real) // cc
|
|
|
|
ac.Set(&rv.Imag)
|
|
|
|
ac.Mul(&rv.Imag) // dd
|
|
|
|
cc_plus_dd.Add(&ac) // cc+dd
|
|
|
|
// We already checked that c and d are not both zero, but we can't
|
|
// assume that c²+d² != 0 follows, because for tiny values of c
|
|
// and/or d c²+d² can underflow to zero. Check that c²+d² is
|
|
// nonzero,return if it's not.
|
|
if cc_plus_dd.CmpFloat64(0) == 0 {
|
|
return false
|
|
}
|
|
|
|
ac.Set(&v.Real)
|
|
|
|
ac.Mul(&rv.Real) // ac
|
|
|
|
bd.Set(&v.Imag)
|
|
|
|
bd.Mul(&rv.Imag) // bd
|
|
|
|
bc.Set(&v.Imag)
|
|
|
|
bc.Mul(&rv.Real) // bc
|
|
|
|
ad.Set(&v.Real)
|
|
|
|
ad.Mul(&rv.Imag) // ad
|
|
|
|
v.Real.Set(&ac)
|
|
|
|
v.Real.Add(&bd) // ac+bd
|
|
v.Real.Quo(&cc_plus_dd) // (ac+bd)/(cc+dd)
|
|
|
|
v.Imag.Set(&bc)
|
|
|
|
v.Imag.Sub(&ad) // bc-ad
|
|
v.Imag.Quo(&cc_plus_dd) // (bc+ad)/(cc+dd)
|
|
|
|
return true
|
|
}
|
|
|
|
// 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 && t.IsPtr() {
|
|
t = t.Elem()
|
|
}
|
|
if t != nil && t.IsArray() && !hascallchan(l) {
|
|
return true
|
|
}
|
|
|
|
case OLITERAL:
|
|
if n.Val().Ctype() != CTNIL {
|
|
return true
|
|
}
|
|
|
|
case ONAME:
|
|
l := asNode(n.Sym.Def)
|
|
if l != nil && l.Op == OLITERAL && n.Val().Ctype() != CTNIL {
|
|
return true
|
|
}
|
|
|
|
case ONONAME:
|
|
if asNode(n.Sym.Def) != nil && asNode(n.Sym.Def).Op == OIOTA {
|
|
return true
|
|
}
|
|
|
|
case OALIGNOF, OOFFSETOF, OSIZEOF:
|
|
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 _, n1 := range n.List.Slice() {
|
|
if hascallchan(n1) {
|
|
return true
|
|
}
|
|
}
|
|
for _, n2 := range n.Rlist.Slice() {
|
|
if hascallchan(n2) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|