2015-02-13 14:40:36 -05:00
|
|
|
// 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/internal/obj"
|
|
|
|
|
|
|
|
/*
|
|
|
|
* truncate float literal fv to 32-bit or 64-bit precision
|
|
|
|
* according to type; return truncated value.
|
|
|
|
*/
|
|
|
|
func truncfltlit(oldv *Mpflt, t *Type) *Mpflt {
|
|
|
|
var d float64
|
|
|
|
var fv *Mpflt
|
|
|
|
var v Val
|
|
|
|
|
|
|
|
if t == nil {
|
|
|
|
return oldv
|
|
|
|
}
|
|
|
|
|
|
|
|
v = Val{}
|
|
|
|
v.Ctype = CTFLT
|
|
|
|
v.U.Fval = oldv
|
|
|
|
overflow(v, t)
|
|
|
|
|
|
|
|
fv = new(Mpflt)
|
|
|
|
*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) {
|
2015-02-17 22:13:49 -05:00
|
|
|
convlit1(np, t, false)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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).
|
|
|
|
*/
|
2015-02-17 22:13:49 -05:00
|
|
|
func convlit1(np **Node, t *Type, explicit bool) {
|
2015-02-13 14:40:36 -05:00
|
|
|
var ct int
|
|
|
|
var et int
|
|
|
|
var n *Node
|
|
|
|
var nn *Node
|
|
|
|
|
|
|
|
n = *np
|
2015-02-17 22:13:49 -05:00
|
|
|
if n == nil || t == nil || n.Type == nil || isideal(t) || n.Type == t {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if !explicit && !isideal(n.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
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:
|
2015-02-17 22:13:49 -05:00
|
|
|
if okforconst[t.Etype] == 0 && n.Type.Etype != TNIL {
|
2015-02-13 14:40:36 -05:00
|
|
|
defaultlit(&n, nil)
|
|
|
|
*np = n
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
case OLSH,
|
|
|
|
ORSH:
|
2015-02-17 22:13:49 -05:00
|
|
|
convlit1(&n.Left, t, explicit && isideal(n.Left.Type))
|
2015-02-13 14:40:36 -05:00
|
|
|
t = n.Left.Type
|
|
|
|
if t != nil && t.Etype == TIDEAL && n.Val.Ctype != CTINT {
|
|
|
|
n.Val = toint(n.Val)
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if t != nil && Isint[t.Etype] == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("invalid operation: %v (shift of type %v)", Nconv(n, 0), Tconv(t, 0))
|
|
|
|
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)
|
|
|
|
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:
|
2015-02-17 22:13:49 -05:00
|
|
|
if !Isslice(t) {
|
2015-02-13 14:40:36 -05:00
|
|
|
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.Val.U.Xval = new(Mpint)
|
|
|
|
Mpmovecfix(n.Val.U.Xval, 0)
|
|
|
|
n.Val.Ctype = CTINT
|
|
|
|
} else {
|
|
|
|
goto bad
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
case CTSTR,
|
|
|
|
CTBOOL:
|
|
|
|
if et != int(n.Type.Etype) {
|
|
|
|
goto bad
|
|
|
|
}
|
|
|
|
|
|
|
|
case CTINT,
|
|
|
|
CTRUNE,
|
|
|
|
CTFLT,
|
|
|
|
CTCPLX:
|
|
|
|
ct = int(n.Val.Ctype)
|
|
|
|
if Isint[et] != 0 {
|
|
|
|
switch ct {
|
|
|
|
default:
|
|
|
|
goto bad
|
|
|
|
|
|
|
|
case CTCPLX,
|
|
|
|
CTFLT,
|
|
|
|
CTRUNE:
|
|
|
|
n.Val = toint(n.Val)
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
// flowthrough
|
|
|
|
case CTINT:
|
|
|
|
overflow(n.Val, t)
|
|
|
|
}
|
|
|
|
} else if Isfloat[et] != 0 {
|
|
|
|
switch ct {
|
|
|
|
default:
|
|
|
|
goto bad
|
|
|
|
|
|
|
|
case CTCPLX,
|
|
|
|
CTINT,
|
|
|
|
CTRUNE:
|
|
|
|
n.Val = toflt(n.Val)
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
// flowthrough
|
|
|
|
case CTFLT:
|
|
|
|
n.Val.U.Fval = truncfltlit(n.Val.U.Fval, t)
|
|
|
|
}
|
|
|
|
} else if Iscomplex[et] != 0 {
|
|
|
|
switch ct {
|
|
|
|
default:
|
|
|
|
goto bad
|
|
|
|
|
|
|
|
case CTFLT,
|
|
|
|
CTINT,
|
|
|
|
CTRUNE:
|
|
|
|
n.Val = tocplx(n.Val)
|
|
|
|
|
|
|
|
case CTCPLX:
|
|
|
|
overflow(n.Val, t)
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
} else if et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit {
|
2015-02-13 14:40:36 -05:00
|
|
|
n.Val = tostr(n.Val)
|
|
|
|
} else {
|
|
|
|
goto bad
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n.Type = t
|
|
|
|
return
|
|
|
|
|
|
|
|
bad:
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Diag == 0 {
|
|
|
|
if t.Broke == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("cannot convert %v to type %v", Nconv(n, 0), Tconv(t, 0))
|
|
|
|
}
|
|
|
|
n.Diag = 1
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if isideal(n.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
defaultlit(&n, nil)
|
|
|
|
*np = n
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func copyval(v Val) Val {
|
|
|
|
var i *Mpint
|
|
|
|
var f *Mpflt
|
|
|
|
var c *Mpcplx
|
|
|
|
|
|
|
|
switch v.Ctype {
|
|
|
|
case CTINT,
|
|
|
|
CTRUNE:
|
|
|
|
i = new(Mpint)
|
|
|
|
mpmovefixfix(i, v.U.Xval)
|
|
|
|
v.U.Xval = i
|
|
|
|
|
|
|
|
case CTFLT:
|
|
|
|
f = new(Mpflt)
|
|
|
|
mpmovefltflt(f, v.U.Fval)
|
|
|
|
v.U.Fval = f
|
|
|
|
|
|
|
|
case CTCPLX:
|
|
|
|
c = new(Mpcplx)
|
|
|
|
mpmovefltflt(&c.Real, &v.U.Cval.Real)
|
|
|
|
mpmovefltflt(&c.Imag, &v.U.Cval.Imag)
|
|
|
|
v.U.Cval = c
|
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func tocplx(v Val) Val {
|
|
|
|
var c *Mpcplx
|
|
|
|
|
|
|
|
switch v.Ctype {
|
|
|
|
case CTINT,
|
|
|
|
CTRUNE:
|
|
|
|
c = new(Mpcplx)
|
|
|
|
Mpmovefixflt(&c.Real, v.U.Xval)
|
|
|
|
Mpmovecflt(&c.Imag, 0.0)
|
|
|
|
v.Ctype = CTCPLX
|
|
|
|
v.U.Cval = c
|
|
|
|
|
|
|
|
case CTFLT:
|
|
|
|
c = new(Mpcplx)
|
|
|
|
mpmovefltflt(&c.Real, v.U.Fval)
|
|
|
|
Mpmovecflt(&c.Imag, 0.0)
|
|
|
|
v.Ctype = CTCPLX
|
|
|
|
v.U.Cval = c
|
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func toflt(v Val) Val {
|
|
|
|
var f *Mpflt
|
|
|
|
|
|
|
|
switch v.Ctype {
|
|
|
|
case CTINT,
|
|
|
|
CTRUNE:
|
|
|
|
f = new(Mpflt)
|
|
|
|
Mpmovefixflt(f, v.U.Xval)
|
|
|
|
v.Ctype = CTFLT
|
|
|
|
v.U.Fval = f
|
|
|
|
|
|
|
|
case CTCPLX:
|
|
|
|
f = new(Mpflt)
|
|
|
|
mpmovefltflt(f, &v.U.Cval.Real)
|
|
|
|
if mpcmpfltc(&v.U.Cval.Imag, 0) != 0 {
|
|
|
|
Yyerror("constant %v%vi truncated to real", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign))
|
|
|
|
}
|
|
|
|
v.Ctype = CTFLT
|
|
|
|
v.U.Fval = f
|
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func toint(v Val) Val {
|
|
|
|
var i *Mpint
|
|
|
|
|
|
|
|
switch v.Ctype {
|
|
|
|
case CTRUNE:
|
|
|
|
v.Ctype = CTINT
|
|
|
|
|
|
|
|
case CTFLT:
|
|
|
|
i = new(Mpint)
|
|
|
|
if mpmovefltfix(i, v.U.Fval) < 0 {
|
|
|
|
Yyerror("constant %v truncated to integer", Fconv(v.U.Fval, obj.FmtSharp))
|
|
|
|
}
|
|
|
|
v.Ctype = CTINT
|
|
|
|
v.U.Xval = i
|
|
|
|
|
|
|
|
case CTCPLX:
|
|
|
|
i = new(Mpint)
|
|
|
|
if mpmovefltfix(i, &v.U.Cval.Real) < 0 {
|
|
|
|
Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign))
|
|
|
|
}
|
|
|
|
if mpcmpfltc(&v.U.Cval.Imag, 0) != 0 {
|
|
|
|
Yyerror("constant %v%vi truncated to real", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign))
|
|
|
|
}
|
|
|
|
v.Ctype = CTINT
|
|
|
|
v.U.Xval = i
|
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func doesoverflow(v Val, t *Type) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
switch v.Ctype {
|
|
|
|
case CTINT,
|
|
|
|
CTRUNE:
|
2015-02-17 22:13:49 -05:00
|
|
|
if Isint[t.Etype] == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Fatal("overflow: %v integer constant", Tconv(t, 0))
|
|
|
|
}
|
|
|
|
if Mpcmpfixfix(v.U.Xval, Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[t.Etype]) > 0 {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case CTFLT:
|
2015-02-17 22:13:49 -05:00
|
|
|
if Isfloat[t.Etype] == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Fatal("overflow: %v floating-point constant", Tconv(t, 0))
|
|
|
|
}
|
|
|
|
if mpcmpfltflt(v.U.Fval, minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.Fval, maxfltval[t.Etype]) >= 0 {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case CTCPLX:
|
2015-02-17 22:13:49 -05:00
|
|
|
if Iscomplex[t.Etype] == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Fatal("overflow: %v complex constant", Tconv(t, 0))
|
|
|
|
}
|
|
|
|
if mpcmpfltflt(&v.U.Cval.Real, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.Cval.Real, maxfltval[t.Etype]) >= 0 || mpcmpfltflt(&v.U.Cval.Imag, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.Cval.Imag, maxfltval[t.Etype]) >= 0 {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func overflow(v Val, t *Type) {
|
|
|
|
// v has already been converted
|
|
|
|
// to appropriate form for t.
|
|
|
|
if t == nil || t.Etype == TIDEAL {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if !doesoverflow(v, t) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch v.Ctype {
|
|
|
|
case CTINT,
|
|
|
|
CTRUNE:
|
|
|
|
Yyerror("constant %v overflows %v", Bconv(v.U.Xval, 0), Tconv(t, 0))
|
|
|
|
|
|
|
|
case CTFLT:
|
|
|
|
Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), Tconv(t, 0))
|
|
|
|
|
|
|
|
case CTCPLX:
|
|
|
|
Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), Tconv(t, 0))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func tostr(v Val) Val {
|
|
|
|
var rune_ uint
|
|
|
|
var s *Strlit
|
|
|
|
|
|
|
|
switch v.Ctype {
|
|
|
|
case CTINT,
|
|
|
|
CTRUNE:
|
|
|
|
if Mpcmpfixfix(v.U.Xval, Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[TINT]) > 0 {
|
|
|
|
Yyerror("overflow in int -> string")
|
|
|
|
}
|
|
|
|
rune_ = uint(Mpgetfix(v.U.Xval))
|
|
|
|
s = &Strlit{S: string(rune_)}
|
|
|
|
v = Val{}
|
|
|
|
v.Ctype = CTSTR
|
|
|
|
v.U.Sval = s
|
|
|
|
|
|
|
|
case CTFLT:
|
|
|
|
Yyerror("no float -> string")
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
case CTNIL:
|
|
|
|
v = Val{}
|
|
|
|
v.Ctype = CTSTR
|
|
|
|
v.U.Sval = new(Strlit)
|
|
|
|
}
|
|
|
|
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func consttype(n *Node) int {
|
|
|
|
if n == nil || n.Op != OLITERAL {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
return int(n.Val.Ctype)
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func Isconst(n *Node, ct int) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
var t int
|
|
|
|
|
|
|
|
t = consttype(n)
|
|
|
|
|
|
|
|
// If the caller is asking for CTINT, allow CTRUNE too.
|
|
|
|
// Makes life easier for back ends.
|
2015-02-17 22:13:49 -05:00
|
|
|
return t == ct || (ct == CTINT && t == CTRUNE)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
func saveorig(n *Node) *Node {
|
|
|
|
var n1 *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) {
|
|
|
|
var nl *Node
|
|
|
|
var nr *Node
|
|
|
|
var norig *Node
|
|
|
|
var str *Strlit
|
|
|
|
var wl int
|
|
|
|
var wr int
|
|
|
|
var lno int
|
|
|
|
var et int
|
|
|
|
var v Val
|
|
|
|
var rv Val
|
|
|
|
var b Mpint
|
|
|
|
var l1 *NodeList
|
|
|
|
var l2 *NodeList
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if okforconst[n.Type.Etype] == 0 && n.Type.Etype != TNIL {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// merge adjacent constants in the argument list.
|
|
|
|
case OADDSTR:
|
|
|
|
for l1 = n.List; l1 != nil; l1 = l1.Next {
|
2015-02-17 22:13:49 -05:00
|
|
|
if Isconst(l1.N, CTSTR) && l1.Next != nil && Isconst(l1.Next.N, CTSTR) {
|
2015-02-13 14:40:36 -05:00
|
|
|
// merge from l1 up to but not including l2
|
|
|
|
str = new(Strlit)
|
|
|
|
l2 = l1
|
2015-02-17 22:13:49 -05:00
|
|
|
for l2 != nil && Isconst(l2.N, CTSTR) {
|
2015-02-13 14:40:36 -05:00
|
|
|
nr = l2.N
|
|
|
|
str.S += nr.Val.U.Sval.S
|
|
|
|
l2 = l2.Next
|
|
|
|
}
|
|
|
|
|
|
|
|
nl = Nod(OXXX, nil, nil)
|
|
|
|
*nl = *l1.N
|
|
|
|
nl.Orig = nl
|
|
|
|
nl.Val.Ctype = CTSTR
|
|
|
|
nl.Val.U.Sval = str
|
|
|
|
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.
|
2015-02-17 22:13:49 -05:00
|
|
|
if count(n.List) == 1 && Isconst(n.List.N, CTSTR) {
|
2015-02-13 14:40:36 -05:00
|
|
|
n.Op = OLITERAL
|
|
|
|
n.Val = 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] != 0 || Isfloat[wl] != 0 || Iscomplex[wl] != 0 {
|
|
|
|
wl = TIDEAL
|
|
|
|
}
|
|
|
|
|
|
|
|
nr = n.Right
|
|
|
|
if nr == nil {
|
|
|
|
goto unary
|
|
|
|
}
|
|
|
|
if nr.Type == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if consttype(nr) < 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
wr = int(nr.Type.Etype)
|
|
|
|
if Isint[wr] != 0 || Isfloat[wr] != 0 || Iscomplex[wr] != 0 {
|
|
|
|
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
|
2015-02-17 22:13:49 -05:00
|
|
|
if nr.Type != nil && (Issigned[nr.Type.Etype] != 0 || Isint[nr.Type.Etype] == 0) {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto illegal
|
|
|
|
}
|
|
|
|
if nl.Val.Ctype != CTRUNE {
|
|
|
|
nl.Val = toint(nl.Val)
|
|
|
|
}
|
|
|
|
nr.Val = 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 {
|
|
|
|
rv.Ctype = CTRUNE
|
|
|
|
}
|
|
|
|
if v.Ctype == CTINT && rv.Ctype == CTRUNE {
|
|
|
|
if n.Op == OLSH || n.Op == ORSH {
|
|
|
|
rv.Ctype = CTINT
|
|
|
|
} else {
|
|
|
|
v.Ctype = CTRUNE
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)", Tconv(nl.Type, 0), v.Ctype, Tconv(nr.Type, 0), 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.Xval, rv.U.Xval, 0)
|
|
|
|
|
|
|
|
case OSUB<<16 | CTINT,
|
|
|
|
OSUB<<16 | CTRUNE:
|
|
|
|
mpsubfixfix(v.U.Xval, rv.U.Xval)
|
|
|
|
|
|
|
|
case OMUL<<16 | CTINT,
|
|
|
|
OMUL<<16 | CTRUNE:
|
|
|
|
mpmulfixfix(v.U.Xval, rv.U.Xval)
|
|
|
|
|
|
|
|
case ODIV<<16 | CTINT,
|
|
|
|
ODIV<<16 | CTRUNE:
|
|
|
|
if mpcmpfixc(rv.U.Xval, 0) == 0 {
|
|
|
|
Yyerror("division by zero")
|
|
|
|
Mpmovecfix(v.U.Xval, 1)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
mpdivfixfix(v.U.Xval, rv.U.Xval)
|
|
|
|
|
|
|
|
case OMOD<<16 | CTINT,
|
|
|
|
OMOD<<16 | CTRUNE:
|
|
|
|
if mpcmpfixc(rv.U.Xval, 0) == 0 {
|
|
|
|
Yyerror("division by zero")
|
|
|
|
Mpmovecfix(v.U.Xval, 1)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
mpmodfixfix(v.U.Xval, rv.U.Xval)
|
|
|
|
|
|
|
|
case OLSH<<16 | CTINT,
|
|
|
|
OLSH<<16 | CTRUNE:
|
|
|
|
mplshfixfix(v.U.Xval, rv.U.Xval)
|
|
|
|
|
|
|
|
case ORSH<<16 | CTINT,
|
|
|
|
ORSH<<16 | CTRUNE:
|
|
|
|
mprshfixfix(v.U.Xval, rv.U.Xval)
|
|
|
|
|
|
|
|
case OOR<<16 | CTINT,
|
|
|
|
OOR<<16 | CTRUNE:
|
|
|
|
mporfixfix(v.U.Xval, rv.U.Xval)
|
|
|
|
|
|
|
|
case OAND<<16 | CTINT,
|
|
|
|
OAND<<16 | CTRUNE:
|
|
|
|
mpandfixfix(v.U.Xval, rv.U.Xval)
|
|
|
|
|
|
|
|
case OANDNOT<<16 | CTINT,
|
|
|
|
OANDNOT<<16 | CTRUNE:
|
|
|
|
mpandnotfixfix(v.U.Xval, rv.U.Xval)
|
|
|
|
|
|
|
|
case OXOR<<16 | CTINT,
|
|
|
|
OXOR<<16 | CTRUNE:
|
|
|
|
mpxorfixfix(v.U.Xval, rv.U.Xval)
|
|
|
|
|
|
|
|
case OADD<<16 | CTFLT:
|
|
|
|
mpaddfltflt(v.U.Fval, rv.U.Fval)
|
|
|
|
|
|
|
|
case OSUB<<16 | CTFLT:
|
|
|
|
mpsubfltflt(v.U.Fval, rv.U.Fval)
|
|
|
|
|
|
|
|
case OMUL<<16 | CTFLT:
|
|
|
|
mpmulfltflt(v.U.Fval, rv.U.Fval)
|
|
|
|
|
|
|
|
case ODIV<<16 | CTFLT:
|
|
|
|
if mpcmpfltc(rv.U.Fval, 0) == 0 {
|
|
|
|
Yyerror("division by zero")
|
|
|
|
Mpmovecflt(v.U.Fval, 1.0)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
mpdivfltflt(v.U.Fval, rv.U.Fval)
|
|
|
|
|
|
|
|
// The default case above would print 'ideal % ideal',
|
|
|
|
// which is not quite an ideal error.
|
|
|
|
case OMOD<<16 | CTFLT:
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Diag == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("illegal constant expression: floating-point % operation")
|
|
|
|
n.Diag = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
case OADD<<16 | CTCPLX:
|
|
|
|
mpaddfltflt(&v.U.Cval.Real, &rv.U.Cval.Real)
|
|
|
|
mpaddfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag)
|
|
|
|
|
|
|
|
case OSUB<<16 | CTCPLX:
|
|
|
|
mpsubfltflt(&v.U.Cval.Real, &rv.U.Cval.Real)
|
|
|
|
mpsubfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag)
|
|
|
|
|
|
|
|
case OMUL<<16 | CTCPLX:
|
|
|
|
cmplxmpy(v.U.Cval, rv.U.Cval)
|
|
|
|
|
|
|
|
case ODIV<<16 | CTCPLX:
|
|
|
|
if mpcmpfltc(&rv.U.Cval.Real, 0) == 0 && mpcmpfltc(&rv.U.Cval.Imag, 0) == 0 {
|
|
|
|
Yyerror("complex division by zero")
|
|
|
|
Mpmovecflt(&rv.U.Cval.Real, 1.0)
|
|
|
|
Mpmovecflt(&rv.U.Cval.Imag, 0.0)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
cmplxdiv(v.U.Cval, rv.U.Cval)
|
|
|
|
|
|
|
|
case OEQ<<16 | CTNIL:
|
|
|
|
goto settrue
|
|
|
|
|
|
|
|
case ONE<<16 | CTNIL:
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OEQ<<16 | CTINT,
|
|
|
|
OEQ<<16 | CTRUNE:
|
|
|
|
if Mpcmpfixfix(v.U.Xval, rv.U.Xval) == 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case ONE<<16 | CTINT,
|
|
|
|
ONE<<16 | CTRUNE:
|
|
|
|
if Mpcmpfixfix(v.U.Xval, rv.U.Xval) != 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OLT<<16 | CTINT,
|
|
|
|
OLT<<16 | CTRUNE:
|
|
|
|
if Mpcmpfixfix(v.U.Xval, rv.U.Xval) < 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OLE<<16 | CTINT,
|
|
|
|
OLE<<16 | CTRUNE:
|
|
|
|
if Mpcmpfixfix(v.U.Xval, rv.U.Xval) <= 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OGE<<16 | CTINT,
|
|
|
|
OGE<<16 | CTRUNE:
|
|
|
|
if Mpcmpfixfix(v.U.Xval, rv.U.Xval) >= 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OGT<<16 | CTINT,
|
|
|
|
OGT<<16 | CTRUNE:
|
|
|
|
if Mpcmpfixfix(v.U.Xval, rv.U.Xval) > 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OEQ<<16 | CTFLT:
|
|
|
|
if mpcmpfltflt(v.U.Fval, rv.U.Fval) == 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case ONE<<16 | CTFLT:
|
|
|
|
if mpcmpfltflt(v.U.Fval, rv.U.Fval) != 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OLT<<16 | CTFLT:
|
|
|
|
if mpcmpfltflt(v.U.Fval, rv.U.Fval) < 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OLE<<16 | CTFLT:
|
|
|
|
if mpcmpfltflt(v.U.Fval, rv.U.Fval) <= 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OGE<<16 | CTFLT:
|
|
|
|
if mpcmpfltflt(v.U.Fval, rv.U.Fval) >= 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OGT<<16 | CTFLT:
|
|
|
|
if mpcmpfltflt(v.U.Fval, rv.U.Fval) > 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OEQ<<16 | CTCPLX:
|
|
|
|
if mpcmpfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) == 0 && mpcmpfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) == 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case ONE<<16 | CTCPLX:
|
|
|
|
if mpcmpfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) != 0 || mpcmpfltflt(&v.U.Cval.Imag, &rv.U.Cval.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.Bval != 0 || rv.U.Bval != 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OANDAND<<16 | CTBOOL:
|
|
|
|
if v.U.Bval != 0 && rv.U.Bval != 0 {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case OEQ<<16 | CTBOOL:
|
|
|
|
if v.U.Bval == rv.U.Bval {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
|
|
|
|
case ONE<<16 | CTBOOL:
|
|
|
|
if v.U.Bval != rv.U.Bval {
|
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
}
|
|
|
|
|
|
|
|
goto ret
|
|
|
|
|
|
|
|
// copy numeric value to avoid modifying
|
|
|
|
// nl, in case someone still refers to it (e.g. iota).
|
|
|
|
unary:
|
|
|
|
v = nl.Val
|
|
|
|
|
|
|
|
if wl == TIDEAL {
|
|
|
|
v = copyval(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
switch uint32(n.Op)<<16 | uint32(v.Ctype) {
|
|
|
|
default:
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Diag == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("illegal constant expression %v %v", Oconv(int(n.Op), 0), Tconv(nl.Type, 0))
|
|
|
|
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:
|
2015-02-17 22:13:49 -05:00
|
|
|
convlit1(&nl, n.Type, true)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
v = nl.Val
|
|
|
|
|
|
|
|
case OPLUS<<16 | CTINT,
|
|
|
|
OPLUS<<16 | CTRUNE:
|
|
|
|
break
|
|
|
|
|
|
|
|
case OMINUS<<16 | CTINT,
|
|
|
|
OMINUS<<16 | CTRUNE:
|
|
|
|
mpnegfix(v.U.Xval)
|
|
|
|
|
|
|
|
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)
|
|
|
|
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.Xval, &b)
|
|
|
|
|
|
|
|
case OPLUS<<16 | CTFLT:
|
|
|
|
break
|
|
|
|
|
|
|
|
case OMINUS<<16 | CTFLT:
|
|
|
|
mpnegflt(v.U.Fval)
|
|
|
|
|
|
|
|
case OPLUS<<16 | CTCPLX:
|
|
|
|
break
|
|
|
|
|
|
|
|
case OMINUS<<16 | CTCPLX:
|
|
|
|
mpnegflt(&v.U.Cval.Real)
|
|
|
|
mpnegflt(&v.U.Cval.Imag)
|
|
|
|
|
|
|
|
case ONOT<<16 | CTBOOL:
|
2015-02-17 22:13:49 -05:00
|
|
|
if v.U.Bval == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
goto settrue
|
|
|
|
}
|
|
|
|
goto setfalse
|
|
|
|
}
|
|
|
|
|
|
|
|
ret:
|
|
|
|
norig = saveorig(n)
|
|
|
|
*n = *nl
|
|
|
|
|
|
|
|
// restore value of n->orig.
|
|
|
|
n.Orig = norig
|
|
|
|
|
|
|
|
n.Val = 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.Val.U.Fval = truncfltlit(v.U.Fval, n.Type)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
|
|
|
|
settrue:
|
|
|
|
norig = saveorig(n)
|
2015-02-17 22:13:49 -05:00
|
|
|
*n = *Nodbool(true)
|
2015-02-13 14:40:36 -05:00
|
|
|
n.Orig = norig
|
|
|
|
return
|
|
|
|
|
|
|
|
setfalse:
|
|
|
|
norig = saveorig(n)
|
2015-02-17 22:13:49 -05:00
|
|
|
*n = *Nodbool(false)
|
2015-02-13 14:40:36 -05:00
|
|
|
n.Orig = norig
|
|
|
|
return
|
|
|
|
|
|
|
|
illegal:
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Diag == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("illegal constant expression: %v %v %v", Tconv(nl.Type, 0), Oconv(int(n.Op), 0), Tconv(nr.Type, 0))
|
|
|
|
n.Diag = 1
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func nodlit(v Val) *Node {
|
|
|
|
var n *Node
|
|
|
|
|
|
|
|
n = Nod(OLITERAL, nil, nil)
|
|
|
|
n.Val = 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 {
|
|
|
|
var n *Node
|
|
|
|
var c *Mpcplx
|
|
|
|
|
|
|
|
r = toflt(r)
|
|
|
|
i = toflt(i)
|
|
|
|
|
|
|
|
c = new(Mpcplx)
|
|
|
|
n = Nod(OLITERAL, nil, nil)
|
|
|
|
n.Type = Types[TIDEAL]
|
|
|
|
n.Val.U.Cval = c
|
|
|
|
n.Val.Ctype = CTCPLX
|
|
|
|
|
|
|
|
if r.Ctype != CTFLT || i.Ctype != CTFLT {
|
|
|
|
Fatal("nodcplxlit ctype %d/%d", r.Ctype, i.Ctype)
|
|
|
|
}
|
|
|
|
|
|
|
|
mpmovefltflt(&c.Real, r.U.Fval)
|
|
|
|
mpmovefltflt(&c.Imag, i.U.Fval)
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
|
|
|
// idealkind returns a constant kind like consttype
|
|
|
|
// but for an arbitrary "ideal" (untyped constant) expression.
|
|
|
|
func idealkind(n *Node) int {
|
|
|
|
var k1 int
|
|
|
|
var k2 int
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if n == nil || !isideal(n.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
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
|
|
|
|
}
|
|
|
|
fallthrough
|
|
|
|
|
|
|
|
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) {
|
|
|
|
var lno int
|
|
|
|
var ctype int
|
|
|
|
var n *Node
|
|
|
|
var nn *Node
|
|
|
|
var t1 *Type
|
|
|
|
|
|
|
|
n = *np
|
2015-02-17 22:13:49 -05:00
|
|
|
if n == nil || !isideal(n.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if n.Op == OLITERAL {
|
|
|
|
nn = Nod(OXXX, nil, nil)
|
|
|
|
*nn = *n
|
|
|
|
n = nn
|
|
|
|
*np = n
|
|
|
|
}
|
|
|
|
|
|
|
|
lno = int(setlineno(n))
|
|
|
|
ctype = idealkind(n)
|
|
|
|
switch ctype {
|
|
|
|
default:
|
|
|
|
if t != nil {
|
|
|
|
Convlit(np, t)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if n.Val.Ctype == CTNIL {
|
|
|
|
lineno = int32(lno)
|
2015-02-17 22:13:49 -05:00
|
|
|
if n.Diag == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
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", Nconv(n, 0))
|
|
|
|
|
|
|
|
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] != 0 {
|
|
|
|
t1 = t
|
|
|
|
n.Val = toint(n.Val)
|
|
|
|
} else if Isfloat[t.Etype] != 0 {
|
|
|
|
t1 = t
|
|
|
|
n.Val = toflt(n.Val)
|
|
|
|
} else if Iscomplex[t.Etype] != 0 {
|
|
|
|
t1 = t
|
|
|
|
n.Val = 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) {
|
|
|
|
var l *Node
|
|
|
|
var r *Node
|
|
|
|
var lkind int
|
|
|
|
var rkind int
|
|
|
|
|
|
|
|
l = *lp
|
|
|
|
r = *rp
|
|
|
|
if l.Type == nil || r.Type == nil {
|
|
|
|
return
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if !isideal(l.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
Convlit(rp, l.Type)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if !isideal(r.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
Convlit(lp, r.Type)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if force == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
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.Sval.S, r.Val.U.Sval.S)
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func Smallintconst(n *Node) bool {
|
|
|
|
if n.Op == OLITERAL && Isconst(n, CTINT) && n.Type != nil {
|
2015-02-13 14:40:36 -05:00
|
|
|
switch Simtype[n.Type.Etype] {
|
|
|
|
case TINT8,
|
|
|
|
TUINT8,
|
|
|
|
TINT16,
|
|
|
|
TUINT16,
|
|
|
|
TINT32,
|
|
|
|
TUINT32,
|
|
|
|
TBOOL,
|
|
|
|
TPTR32:
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
case TIDEAL,
|
|
|
|
TINT64,
|
|
|
|
TUINT64,
|
|
|
|
TPTR64:
|
|
|
|
if Mpcmpfixfix(n.Val.U.Xval, Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT32]) > 0 {
|
|
|
|
break
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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.Xval, Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT32]) > 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
return int(Mpgetfix(n.Val.U.Xval))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* convert constant val to type t; leave in con.
|
|
|
|
* for back end.
|
|
|
|
*/
|
|
|
|
func Convconst(con *Node, t *Type, val *Val) {
|
|
|
|
var i int64
|
|
|
|
var tt int
|
|
|
|
|
|
|
|
tt = Simsimtype(t)
|
|
|
|
|
|
|
|
// copy the constant for conversion
|
|
|
|
Nodconst(con, Types[TINT8], 0)
|
|
|
|
|
|
|
|
con.Type = t
|
|
|
|
con.Val = *val
|
|
|
|
|
|
|
|
if Isint[tt] != 0 {
|
|
|
|
con.Val.Ctype = CTINT
|
|
|
|
con.Val.U.Xval = new(Mpint)
|
|
|
|
switch val.Ctype {
|
|
|
|
default:
|
|
|
|
Fatal("convconst ctype=%d %v", val.Ctype, Tconv(t, obj.FmtLong))
|
|
|
|
|
|
|
|
case CTINT,
|
|
|
|
CTRUNE:
|
|
|
|
i = Mpgetfix(val.U.Xval)
|
|
|
|
|
|
|
|
case CTBOOL:
|
|
|
|
i = int64(val.U.Bval)
|
|
|
|
|
|
|
|
case CTNIL:
|
|
|
|
i = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
i = iconv(i, tt)
|
|
|
|
Mpmovecfix(con.Val.U.Xval, i)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if Isfloat[tt] != 0 {
|
|
|
|
con.Val = toflt(con.Val)
|
|
|
|
if con.Val.Ctype != CTFLT {
|
|
|
|
Fatal("convconst ctype=%d %v", con.Val.Ctype, Tconv(t, 0))
|
|
|
|
}
|
|
|
|
if tt == TFLOAT32 {
|
|
|
|
con.Val.U.Fval = truncfltlit(con.Val.U.Fval, t)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if Iscomplex[tt] != 0 {
|
|
|
|
con.Val = tocplx(con.Val)
|
|
|
|
if tt == TCOMPLEX64 {
|
|
|
|
con.Val.U.Cval.Real = *truncfltlit(&con.Val.U.Cval.Real, Types[TFLOAT32])
|
|
|
|
con.Val.U.Cval.Imag = *truncfltlit(&con.Val.U.Cval.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.
|
2015-02-17 22:13:49 -05:00
|
|
|
func isgoconst(n *Node) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
var l *Node
|
|
|
|
var t *Type
|
|
|
|
|
|
|
|
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:
|
2015-02-17 22:13:49 -05:00
|
|
|
if isgoconst(n.Left) && (n.Right == nil || isgoconst(n.Right)) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case OCONV:
|
2015-02-17 22:13:49 -05:00
|
|
|
if okforconst[n.Type.Etype] != 0 && isgoconst(n.Left) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case OLEN,
|
|
|
|
OCAP:
|
|
|
|
l = n.Left
|
2015-02-17 22:13:49 -05:00
|
|
|
if isgoconst(l) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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] != 0 {
|
|
|
|
t = t.Type
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
if Isfixedarray(t) && !hascallchan(l) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case OLITERAL:
|
|
|
|
if n.Val.Ctype != CTNIL {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case ONAME:
|
|
|
|
l = n.Sym.Def
|
|
|
|
if l != nil && l.Op == OLITERAL && n.Val.Ctype != CTNIL {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
case ONONAME:
|
|
|
|
if n.Sym.Def != nil && n.Sym.Def.Op == OIOTA {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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" {
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//dump("nonconst", n);
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
func hascallchan(n *Node) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
var l *NodeList
|
|
|
|
|
|
|
|
if n == nil {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
switch n.Op {
|
|
|
|
case OAPPEND,
|
|
|
|
OCALL,
|
|
|
|
OCALLFUNC,
|
|
|
|
OCALLINTER,
|
|
|
|
OCALLMETH,
|
|
|
|
OCAP,
|
|
|
|
OCLOSE,
|
|
|
|
OCOMPLEX,
|
|
|
|
OCOPY,
|
|
|
|
ODELETE,
|
|
|
|
OIMAG,
|
|
|
|
OLEN,
|
|
|
|
OMAKE,
|
|
|
|
ONEW,
|
|
|
|
OPANIC,
|
|
|
|
OPRINT,
|
|
|
|
OPRINTN,
|
|
|
|
OREAL,
|
|
|
|
ORECOVER,
|
|
|
|
ORECV:
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if hascallchan(n.Left) || hascallchan(n.Right) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
for l = n.List; l != nil; l = l.Next {
|
2015-02-17 22:13:49 -05:00
|
|
|
if hascallchan(l.N) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for l = n.Rlist; l != nil; l = l.Next {
|
2015-02-17 22:13:49 -05:00
|
|
|
if hascallchan(l.N) {
|
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|