mirror of
https://github.com/golang/go.git
synced 2025-10-20 03:23:18 +00:00

This removes almost all direct access to Type’s heavily overloaded Type field. Mostly generated by eg, manually checked. Significant manual changes: * reflect.go's typPkg used Type indiscriminately. Use it only for specific etypes. * gen.go's visitComponents contained a usage of Type with structs. Using Type for structs no longer occurs, and the Fatal contained therein has not triggered, so it has been axed. * Scary code in cgen.go's cgen_slice is now explicitly scary. Passes toolstash -cmp. Change-Id: I2dbfb3c959da7ae239f964d83898c204affcabc6 Reviewed-on: https://go-review.googlesource.com/21331 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
1771 lines
32 KiB
Go
1771 lines
32 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/big"
|
|
"cmd/internal/obj"
|
|
"strings"
|
|
)
|
|
|
|
// IntLiteral returns the Node's literal value as an interger.
|
|
func (n *Node) IntLiteral() (x int64, ok bool) {
|
|
switch {
|
|
case n == nil:
|
|
return
|
|
case Isconst(n, CTINT):
|
|
return n.Int(), true
|
|
case Isconst(n, CTBOOL):
|
|
return int64(obj.Bool2int(n.Bool())), true
|
|
}
|
|
return
|
|
}
|
|
|
|
// Int returns n as an int.
|
|
// n must be an integer constant.
|
|
func (n *Node) Int() int64 {
|
|
if !Isconst(n, CTINT) {
|
|
Fatalf("Int(%v)", n)
|
|
}
|
|
return n.Val().U.(*Mpint).Int64()
|
|
}
|
|
|
|
// SetInt sets n's value to i.
|
|
// n must be an integer constant.
|
|
func (n *Node) SetInt(i int64) {
|
|
if !Isconst(n, CTINT) {
|
|
Fatalf("SetInt(%v)", n)
|
|
}
|
|
n.Val().U.(*Mpint).SetInt64(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) {
|
|
Fatalf("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) {
|
|
Fatalf("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()
|
|
fv.Set(oldv)
|
|
|
|
// convert large precision literal floating
|
|
// into limited precision (float64 or float32)
|
|
switch t.Etype {
|
|
case TFLOAT64:
|
|
d := fv.Float64()
|
|
fv.SetFloat64(d)
|
|
|
|
case TFLOAT32:
|
|
d := fv.Float32()
|
|
fv.SetFloat64(d)
|
|
}
|
|
|
|
return fv
|
|
}
|
|
|
|
// NegOne returns a Node of type t with value -1.
|
|
func NegOne(t *Type) *Node {
|
|
n := Nodintconst(-1)
|
|
n = convlit(n, t)
|
|
return n
|
|
}
|
|
|
|
// 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 *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 *Type, explicit bool, reuse canReuseNode) *Node {
|
|
if n == nil || t == nil || n.Type == nil || isideal(t) || n.Type == t {
|
|
return n
|
|
}
|
|
if !explicit && !isideal(n.Type) {
|
|
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 == idealbool {
|
|
if t.Etype == TBOOL {
|
|
n.Type = t
|
|
} else {
|
|
n.Type = 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 && isideal(n.Left.Type), noReuse)
|
|
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 n
|
|
|
|
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
|
|
|
|
n.Left = convlit(n.Left, Types[TFLOAT64])
|
|
n.Right = convlit(n.Right, Types[TFLOAT64])
|
|
|
|
case TCOMPLEX64:
|
|
n.Type = t
|
|
n.Left = convlit(n.Left, Types[TFLOAT32])
|
|
n.Right = convlit(n.Right, Types[TFLOAT32])
|
|
}
|
|
}
|
|
|
|
return n
|
|
}
|
|
|
|
// avoided repeated calculations, errors
|
|
if Eqtype(n.Type, t) {
|
|
return n
|
|
}
|
|
|
|
ct := consttype(n)
|
|
var et EType
|
|
if ct < 0 {
|
|
goto bad
|
|
}
|
|
|
|
et = t.Etype
|
|
if et == TINTER {
|
|
if ct == CTNIL && n.Type == 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:
|
|
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)})
|
|
n.Val().U.(*Mpint).SetInt64(0)
|
|
} 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:
|
|
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 n
|
|
|
|
bad:
|
|
if n.Diag == 0 {
|
|
if !t.Broke {
|
|
Yyerror("cannot convert %v to type %v", n, t)
|
|
}
|
|
n.Diag = 1
|
|
}
|
|
|
|
if isideal(n.Type) {
|
|
n = defaultlitreuse(n, nil, reuse)
|
|
}
|
|
return n
|
|
}
|
|
|
|
func copyval(v Val) Val {
|
|
switch v.Ctype() {
|
|
case CTINT, CTRUNE:
|
|
i := new(Mpint)
|
|
i.Set(v.U.(*Mpint))
|
|
i.Rune = v.U.(*Mpint).Rune
|
|
v.U = i
|
|
|
|
case CTFLT:
|
|
f := newMpflt()
|
|
f.Set(v.U.(*Mpflt))
|
|
v.U = f
|
|
|
|
case CTCPLX:
|
|
c := new(Mpcplx)
|
|
c.Real.Set(&v.U.(*Mpcplx).Real)
|
|
c.Imag.Set(&v.U.(*Mpcplx).Imag)
|
|
v.U = c
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func tocplx(v Val) Val {
|
|
switch v.Ctype() {
|
|
case CTINT, CTRUNE:
|
|
c := new(Mpcplx)
|
|
c.Real.SetInt(v.U.(*Mpint))
|
|
c.Imag.SetFloat64(0.0)
|
|
v.U = c
|
|
|
|
case CTFLT:
|
|
c := new(Mpcplx)
|
|
c.Real.Set(v.U.(*Mpflt))
|
|
c.Imag.SetFloat64(0.0)
|
|
v.U = c
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func toflt(v Val) Val {
|
|
switch v.Ctype() {
|
|
case CTINT, CTRUNE:
|
|
f := newMpflt()
|
|
f.SetInt(v.U.(*Mpint))
|
|
v.U = f
|
|
|
|
case CTCPLX:
|
|
f := newMpflt()
|
|
f.Set(&v.U.(*Mpcplx).Real)
|
|
if v.U.(*Mpcplx).Imag.CmpFloat64(0) != 0 {
|
|
Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, FmtSharp|FmtSign))
|
|
}
|
|
v.U = f
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func toint(v Val) Val {
|
|
switch v.Ctype() {
|
|
case CTRUNE:
|
|
i := new(Mpint)
|
|
i.Set(v.U.(*Mpint))
|
|
v.U = i
|
|
|
|
case CTFLT:
|
|
i := new(Mpint)
|
|
if f := v.U.(*Mpflt); i.SetFloat(f) < 0 {
|
|
msg := "constant %v truncated to integer"
|
|
// provide better error message if SetFloat failed because f was too large
|
|
if f.Val.IsInt() {
|
|
msg = "constant %v overflows integer"
|
|
}
|
|
Yyerror(msg, Fconv(f, FmtSharp))
|
|
}
|
|
v.U = i
|
|
|
|
case CTCPLX:
|
|
i := new(Mpint)
|
|
if i.SetFloat(&v.U.(*Mpcplx).Real) < 0 {
|
|
Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.(*Mpcplx).Real, FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, FmtSharp|FmtSign))
|
|
}
|
|
if v.U.(*Mpcplx).Imag.CmpFloat64(0) != 0 {
|
|
Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, FmtSharp|FmtSign))
|
|
}
|
|
v.U = i
|
|
}
|
|
|
|
return v
|
|
}
|
|
|
|
func doesoverflow(v Val, t *Type) bool {
|
|
switch v.Ctype() {
|
|
case CTINT, CTRUNE:
|
|
if !Isint[t.Etype] {
|
|
Fatalf("overflow: %v integer constant", t)
|
|
}
|
|
if v.U.(*Mpint).Cmp(Minintval[t.Etype]) < 0 || v.U.(*Mpint).Cmp(Maxintval[t.Etype]) > 0 {
|
|
return true
|
|
}
|
|
|
|
case CTFLT:
|
|
if !Isfloat[t.Etype] {
|
|
Fatalf("overflow: %v floating-point constant", t)
|
|
}
|
|
if v.U.(*Mpflt).Cmp(minfltval[t.Etype]) <= 0 || v.U.(*Mpflt).Cmp(maxfltval[t.Etype]) >= 0 {
|
|
return true
|
|
}
|
|
|
|
case CTCPLX:
|
|
if !Iscomplex[t.Etype] {
|
|
Fatalf("overflow: %v complex constant", t)
|
|
}
|
|
if v.U.(*Mpcplx).Real.Cmp(minfltval[t.Etype]) <= 0 || v.U.(*Mpcplx).Real.Cmp(maxfltval[t.Etype]) >= 0 || v.U.(*Mpcplx).Imag.Cmp(minfltval[t.Etype]) <= 0 || v.U.(*Mpcplx).Imag.Cmp(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) {
|
|
Yyerror("constant %s overflows %v", Vconv(v, 0), t)
|
|
}
|
|
}
|
|
|
|
func tostr(v Val) Val {
|
|
switch v.Ctype() {
|
|
case CTINT, CTRUNE:
|
|
if v.U.(*Mpint).Cmp(Minintval[TINT]) < 0 || v.U.(*Mpint).Cmp(Maxintval[TINT]) > 0 {
|
|
Yyerror("overflow in int -> string")
|
|
}
|
|
r := uint(v.U.(*Mpint).Int64())
|
|
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) Ctype {
|
|
if n == nil || n.Op != OLITERAL {
|
|
return -1
|
|
}
|
|
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 int32
|
|
var wr EType
|
|
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)
|
|
}
|
|
|
|
switch uint32(n.Op)<<16 | uint32(v.Ctype()) {
|
|
default:
|
|
if n.Diag == 0 {
|
|
Yyerror("illegal constant expression %v %v", Oconv(n.Op, 0), nl.Type)
|
|
n.Diag = 1
|
|
}
|
|
return
|
|
|
|
case OCONV_ | CTNIL_,
|
|
OARRAYBYTESTR_ | CTNIL_:
|
|
if n.Type.Etype == TSTRING {
|
|
v = tostr(v)
|
|
nl.Type = n.Type
|
|
break
|
|
}
|
|
fallthrough
|
|
|
|
// fall through
|
|
case OCONV_ | CTINT_,
|
|
OCONV_ | CTRUNE_,
|
|
OCONV_ | CTFLT_,
|
|
OCONV_ | CTSTR_,
|
|
OCONV_ | CTBOOL_:
|
|
nl = convlit1(nl, n.Type, true, false)
|
|
v = nl.Val()
|
|
|
|
case OPLUS_ | CTINT_,
|
|
OPLUS_ | CTRUNE_:
|
|
break
|
|
|
|
case OMINUS_ | CTINT_,
|
|
OMINUS_ | CTRUNE_:
|
|
v.U.(*Mpint).Neg()
|
|
|
|
case OCOM_ | CTINT_,
|
|
OCOM_ | CTRUNE_:
|
|
var et 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 {
|
|
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[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)
|
|
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())
|
|
}
|
|
|
|
// run op
|
|
switch uint32(n.Op)<<16 | uint32(v.Ctype()) {
|
|
default:
|
|
goto illegal
|
|
|
|
case OADD_ | CTINT_,
|
|
OADD_ | CTRUNE_:
|
|
v.U.(*Mpint).Add(rv.U.(*Mpint))
|
|
|
|
case OSUB_ | CTINT_,
|
|
OSUB_ | CTRUNE_:
|
|
v.U.(*Mpint).Sub(rv.U.(*Mpint))
|
|
|
|
case OMUL_ | CTINT_,
|
|
OMUL_ | CTRUNE_:
|
|
v.U.(*Mpint).Mul(rv.U.(*Mpint))
|
|
|
|
case ODIV_ | CTINT_,
|
|
ODIV_ | CTRUNE_:
|
|
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_,
|
|
OMOD_ | CTRUNE_:
|
|
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_,
|
|
OLSH_ | CTRUNE_:
|
|
v.U.(*Mpint).Lsh(rv.U.(*Mpint))
|
|
|
|
case ORSH_ | CTINT_,
|
|
ORSH_ | CTRUNE_:
|
|
v.U.(*Mpint).Rsh(rv.U.(*Mpint))
|
|
|
|
case OOR_ | CTINT_,
|
|
OOR_ | CTRUNE_:
|
|
v.U.(*Mpint).Or(rv.U.(*Mpint))
|
|
|
|
case OAND_ | CTINT_,
|
|
OAND_ | CTRUNE_:
|
|
v.U.(*Mpint).And(rv.U.(*Mpint))
|
|
|
|
case OANDNOT_ | CTINT_,
|
|
OANDNOT_ | CTRUNE_:
|
|
v.U.(*Mpint).AndNot(rv.U.(*Mpint))
|
|
|
|
case OXOR_ | CTINT_,
|
|
OXOR_ | CTRUNE_:
|
|
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 == 0 {
|
|
Yyerror("illegal constant expression: floating-point %% operation")
|
|
n.Diag = 1
|
|
}
|
|
|
|
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 rv.U.(*Mpcplx).Real.CmpFloat64(0) == 0 && rv.U.(*Mpcplx).Imag.CmpFloat64(0) == 0 {
|
|
Yyerror("complex division by zero")
|
|
rv.U.(*Mpcplx).Real.SetFloat64(1.0)
|
|
rv.U.(*Mpcplx).Imag.SetFloat64(0.0)
|
|
break
|
|
}
|
|
|
|
cmplxdiv(v.U.(*Mpcplx), rv.U.(*Mpcplx))
|
|
|
|
case OEQ_ | CTNIL_:
|
|
goto settrue
|
|
|
|
case ONE_ | CTNIL_:
|
|
goto setfalse
|
|
|
|
case OEQ_ | CTINT_,
|
|
OEQ_ | CTRUNE_:
|
|
if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) == 0 {
|
|
goto settrue
|
|
}
|
|
goto setfalse
|
|
|
|
case ONE_ | CTINT_,
|
|
ONE_ | CTRUNE_:
|
|
if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) != 0 {
|
|
goto settrue
|
|
}
|
|
goto setfalse
|
|
|
|
case OLT_ | CTINT_,
|
|
OLT_ | CTRUNE_:
|
|
if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) < 0 {
|
|
goto settrue
|
|
}
|
|
goto setfalse
|
|
|
|
case OLE_ | CTINT_,
|
|
OLE_ | CTRUNE_:
|
|
if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) <= 0 {
|
|
goto settrue
|
|
}
|
|
goto setfalse
|
|
|
|
case OGE_ | CTINT_,
|
|
OGE_ | CTRUNE_:
|
|
if v.U.(*Mpint).Cmp(rv.U.(*Mpint)) >= 0 {
|
|
goto settrue
|
|
}
|
|
goto setfalse
|
|
|
|
case OGT_ | CTINT_,
|
|
OGT_ | CTRUNE_:
|
|
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
|
|
}
|
|
|
|
goto ret
|
|
|
|
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 == 0 {
|
|
Yyerror("illegal constant expression: %v %v %v", nl.Type, Oconv(n.Op, 0), nr.Type)
|
|
n.Diag = 1
|
|
}
|
|
}
|
|
|
|
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 = 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 {
|
|
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 || !isideal(n.Type) {
|
|
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 *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 *Type, reuse canReuseNode) *Node {
|
|
if n == nil || !isideal(n.Type) {
|
|
return n
|
|
}
|
|
|
|
if n.Op == OLITERAL && !reuse {
|
|
nn := *n
|
|
n = &nn
|
|
reuse = true
|
|
}
|
|
|
|
lno := setlineno(n)
|
|
ctype := idealkind(n)
|
|
var t1 *Type
|
|
switch ctype {
|
|
default:
|
|
if t != nil {
|
|
return convlit(n, t)
|
|
}
|
|
|
|
if n.Val().Ctype() == CTNIL {
|
|
lineno = 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]
|
|
n = convlit1(n, t1, false, reuse)
|
|
break
|
|
}
|
|
|
|
Yyerror("defaultlit: unknown literal: %v", n)
|
|
|
|
case CTxxx:
|
|
Fatalf("defaultlit: idealkind is CTxxx: %v", Nconv(n, FmtSign))
|
|
|
|
case CTBOOL:
|
|
t1 := Types[TBOOL]
|
|
if t != nil && t.Etype == TBOOL {
|
|
t1 = t
|
|
}
|
|
n = convlit1(n, t1, false, reuse)
|
|
|
|
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 = 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 Isint[t.Etype] {
|
|
t1 = t
|
|
v1 = toint(n.Val())
|
|
} else if Isfloat[t.Etype] {
|
|
t1 = t
|
|
v1 = toflt(n.Val())
|
|
} else if Iscomplex[t.Etype] {
|
|
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 !isideal(l.Type) {
|
|
r = convlit(r, l.Type)
|
|
return l, r
|
|
}
|
|
|
|
if !isideal(r.Type) {
|
|
l = convlit(l, r.Type)
|
|
return l, r
|
|
}
|
|
|
|
if !force {
|
|
return l, r
|
|
}
|
|
|
|
if l.Type.Etype == TBOOL {
|
|
l = convlit(l, Types[TBOOL])
|
|
r = convlit(r, Types[TBOOL])
|
|
}
|
|
|
|
lkind := idealkind(l)
|
|
rkind := idealkind(r)
|
|
if lkind == CTCPLX || rkind == CTCPLX {
|
|
l = convlit(l, Types[TCOMPLEX128])
|
|
r = convlit(r, Types[TCOMPLEX128])
|
|
return l, r
|
|
}
|
|
|
|
if lkind == CTFLT || rkind == CTFLT {
|
|
l = convlit(l, Types[TFLOAT64])
|
|
r = convlit(r, Types[TFLOAT64])
|
|
return l, r
|
|
}
|
|
|
|
if lkind == CTRUNE || rkind == CTRUNE {
|
|
l = convlit(l, runetype)
|
|
r = convlit(r, runetype)
|
|
return l, r
|
|
}
|
|
|
|
l = convlit(l, Types[TINT])
|
|
r = convlit(r, 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:
|
|
if n.Val().U.(*Mpint).Cmp(Minintval[TINT32]) < 0 || n.Val().U.(*Mpint).Cmp(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 n.Val().U.(*Mpint).Cmp(Minintval[TUINT32]) < 0 || n.Val().U.(*Mpint).Cmp(Maxintval[TINT32]) > 0 {
|
|
break
|
|
}
|
|
return int(n.Val().U.(*Mpint).Int64())
|
|
}
|
|
}
|
|
|
|
return -1
|
|
}
|
|
|
|
// convert x to type et and back to int64
|
|
// for sign extension and truncation.
|
|
func iconv(x int64, et EType) 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:
|
|
Fatalf("convconst ctype=%d %v", n.Val().Ctype(), Tconv(t, FmtLong))
|
|
|
|
case CTINT, CTRUNE:
|
|
i = n.Val().U.(*Mpint).Int64()
|
|
|
|
case CTBOOL:
|
|
i = int64(obj.Bool2int(n.Val().U.(bool)))
|
|
|
|
case CTNIL:
|
|
i = 0
|
|
}
|
|
|
|
i = iconv(i, tt)
|
|
con.Val().U.(*Mpint).SetInt64(i)
|
|
return
|
|
}
|
|
|
|
if Isfloat[tt] {
|
|
con.SetVal(toflt(con.Val()))
|
|
if con.Val().Ctype() != CTFLT {
|
|
Fatalf("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
|
|
}
|
|
|
|
Fatalf("convconst %v constant", Tconv(t, 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
|
|
|
|
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) {
|
|
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
|
|
|
|
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)
|
|
}
|
|
|
|
// 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.Elem()
|
|
}
|
|
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 _, n1 := range n.List.Slice() {
|
|
if hascallchan(n1) {
|
|
return true
|
|
}
|
|
}
|
|
for _, n2 := range n.Rlist.Slice() {
|
|
if hascallchan(n2) {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|