import (
"cmd/compile/internal/types"
- "cmd/internal/src"
"math/big"
"strings"
)
return false
}
- // Only uintptrs may be converted to unsafe.Pointer, which cannot overflow.
- if t.Etype == TUNSAFEPTR {
+ // Only uintptrs may be converted to pointers, which cannot overflow.
+ if t.IsPtr() || t.IsUnsafePtr() {
return false
}
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
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)
- }
+ v = copyval(nl.Val())
// rune values are int values for the purpose of constant folding.
ctype = uint32(v.Ctype())
// 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)
- }
-
+ v = copyval(nl.Val())
rv = nr.Val()
// convert to common ideal
}
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)})
- }
+ setconst(n, v)
return
settrue:
- nn = nodbool(true)
- nn.Orig = saveorig(n)
- if !iscmp[n.Op] {
- nn.Type = nl.Type
- }
- *n = *nn
+ setconst(n, Val{true})
return
setfalse:
- nn = nodbool(false)
- nn.Orig = saveorig(n)
- if !iscmp[n.Op] {
- nn.Type = nl.Type
- }
- *n = *nn
+ setconst(n, Val{false})
return
illegal:
}
}
+// setconst rewrites n as an OLITERAL with value v.
+func setconst(n *Node, v Val) {
+ // Ensure n.Orig still points to a semantically-equivalent
+ // expression after we rewrite n into a constant.
+ if n.Orig == n {
+ var ncopy Node
+ n.Orig = &ncopy
+ ncopy = *n
+ }
+
+ *n = Node{
+ Op: OLITERAL,
+ Pos: n.Pos,
+ Orig: n.Orig,
+ Type: n.Type,
+ Xoffset: BADWIDTH,
+ }
+ 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)})
+ }
+}
+
+func setintconst(n *Node, v int64) {
+ u := new(Mpint)
+ u.SetInt64(v)
+ setconst(n, Val{u})
+}
+
// nodlit returns a new untyped constant with value v.
func nodlit(v Val) *Node {
n := nod(OLITERAL, nil, nil)
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 {
}
var v Node
- nodconst(&v, types.Types[TINT], t.NumElem())
+ v.Type = types.Types[TINT]
+ setintconst(&v, t.NumElem())
nam.Xoffset += int64(array_array)
gdata(&nam, nod(OADDR, vstat, nil), Widthptr)
return n
}
-func saveorignode(n *Node) {
- if n.Orig != nil {
- return
- }
- norig := nod(n.Op, nil, nil)
- *norig = *n
- n.Orig = norig
-}
-
// methcmp sorts methods by name with exported methods first,
// and then non-exported methods by their package path.
type methcmp []*types.Field
return nodlit(Val{u})
}
-func nodconst(n *Node, t *types.Type, v int64) {
- *n = Node{}
- n.Op = OLITERAL
- n.SetAddable(true)
- n.SetVal(Val{new(Mpint)})
- n.Val().U.(*Mpint).SetInt64(v)
- n.Type = t
-
- if t.IsFloat() {
- Fatalf("nodconst: bad type %v", t)
- }
-}
-
func nodnil() *Node {
return nodlit(Val{new(NilVal)})
}
n.Type = nil
return n
}
+ n.Type = types.Types[TUINTPTR]
// any side effects disappear; ignore init
- var r Node
- nodconst(&r, types.Types[TUINTPTR], evalunsafe(n))
- r.Orig = n
- n = &r
+ setintconst(n, evalunsafe(n))
case OCAP, OLEN:
ok |= Erv
return n
}
- // result might be constant
+ n.Type = types.Types[TINT]
+
+ // Result might be constant.
var res int64 = -1 // valid if >= 0
switch t.Etype {
case TSTRING:
}
}
if res >= 0 {
- var r Node
- nodconst(&r, types.Types[TINT], res)
- r.Orig = n
- n = &r
+ setintconst(n, res)
}
- n.Type = types.Types[TINT]
-
case OREAL, OIMAG:
ok |= Erv
if !onearg(n, "%v", n.Op) {
return n
}
- if t.Etype != TIDEAL && !t.IsComplex() {
+ // Determine result type.
+ et := t.Etype
+ switch et {
+ case TIDEAL:
+ // result is ideal
+ case TCOMPLEX64:
+ et = TFLOAT32
+ case TCOMPLEX128:
+ et = TFLOAT64
+ default:
yyerror("invalid argument %L for %v", l, n.Op)
n.Type = nil
return n
}
+ n.Type = types.Types[et]
// if the argument is a constant, the result is a constant
// (any untyped numeric constant can be represented as a
}
re = im
}
- orig := n
- n = nodfltconst(re)
- n.Orig = orig
- }
-
- // determine result type
- et := t.Etype
- switch et {
- case TIDEAL:
- // result is ideal
- case TCOMPLEX64:
- et = TFLOAT32
- case TCOMPLEX128:
- et = TFLOAT64
- default:
- Fatalf("unexpected Etype: %v\n", et)
+ setconst(n, Val{re})
}
- n.Type = types.Types[et]
case OCOMPLEX:
ok |= Erv
case TFLOAT64:
t = types.Types[TCOMPLEX128]
}
+ n.Type = t
if l.Op == OLITERAL && r.Op == OLITERAL {
// make it a complex literal
- r = nodcplxlit(l.Val(), r.Val())
-
- r.Orig = n
- n = r
+ c := new(Mpcplx)
+ c.Real.Set(toflt(l.Val()).U.(*Mpflt))
+ c.Imag.Set(toflt(r.Val()).U.(*Mpflt))
+ setconst(n, Val{c})
}
- n.Type = t
-
case OCLOSE:
if !onearg(n, "%v", n.Op) {
n.Type = nil
case OCONV:
ok |= Erv
- saveorignode(n)
checkwidth(n.Type) // ensure width is calculated for backend
n.Left = typecheck(n.Left, Erv)
n.Left = convlit1(n.Left, n.Type, true, noReuse)
yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why)
n.SetDiag(true)
}
-
n.Op = OCONV
+ n.Type = nil
+ return n
}
switch n.Op {
case OCONVNOP:
if n.Left.Op == OLITERAL {
- r := nod(OXXX, nil, nil)
n.Op = OCONV
- n.Orig = r
- *r = *n
- n.Op = OLITERAL
- n.SetVal(n.Left.Val())
+ setconst(n, n.Left.Val())
} else if t.Etype == n.Type.Etype {
switch t.Etype {
case TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128:
}
if t.IsArray() {
safeexpr(n.Left, init)
- nodconst(n, n.Type, t.NumElem())
+ setintconst(n, t.NumElem())
n.SetTypecheck(1)
}