[dev.regabi] cmd/compile: replace Val with go/constant.Value

This replaces the compiler's legacy constant representation with
go/constant, which is used by go/types. This should ease integrating
with the new go/types-based type checker in the future.

Performance difference is mixed, but there's still room for
improvement.

name                      old time/op       new time/op       delta
Template                        280ms ± 6%        281ms ± 6%    ~     (p=0.488 n=592+587)
Unicode                         132ms ±11%        129ms ±11%  -2.61%  (p=0.000 n=592+591)
GoTypes                         865ms ± 3%        866ms ± 3%  +0.16%  (p=0.019 n=572+577)
Compiler                        3.60s ± 3%        3.60s ± 3%    ~     (p=0.083 n=578+582)
SSA                             8.27s ± 2%        8.28s ± 2%  +0.14%  (p=0.002 n=575+580)
Flate                           177ms ± 8%        176ms ± 8%    ~     (p=0.133 n=580+590)
GoParser                        238ms ± 7%        237ms ± 6%    ~     (p=0.569 n=587+591)
Reflect                         542ms ± 4%        543ms ± 4%    ~     (p=0.064 n=581+579)
Tar                             244ms ± 6%        244ms ± 6%    ~     (p=0.880 n=586+584)
XML                             322ms ± 5%        322ms ± 5%    ~     (p=0.449 n=589+590)
LinkCompiler                    454ms ± 6%        453ms ± 6%    ~     (p=0.249 n=585+583)
ExternalLinkCompiler            1.35s ± 4%        1.35s ± 4%    ~     (p=0.968 n=590+588)
LinkWithoutDebugCompiler        279ms ± 7%        280ms ± 7%    ~     (p=0.270 n=589+586)
[Geo mean]                      535ms             534ms       -0.17%

name                      old user-time/op  new user-time/op  delta
Template                        599ms ±22%        602ms ±21%    ~     (p=0.377 n=588+590)
Unicode                         410ms ±43%        376ms ±39%  -8.36%  (p=0.000 n=596+586)
GoTypes                         1.96s ±15%        1.97s ±17%  +0.70%  (p=0.031 n=596+594)
Compiler                        7.47s ± 9%        7.50s ± 8%  +0.38%  (p=0.031 n=591+583)
SSA                             16.2s ± 4%        16.2s ± 5%    ~     (p=0.617 n=531+531)
Flate                           298ms ±25%        292ms ±30%  -2.14%  (p=0.001 n=594+596)
GoParser                        379ms ±20%        381ms ±21%    ~     (p=0.312 n=578+584)
Reflect                         1.24s ±20%        1.25s ±23%  +0.88%  (p=0.031 n=592+596)
Tar                             471ms ±23%        473ms ±21%    ~     (p=0.616 n=593+587)
XML                             674ms ±20%        681ms ±21%  +1.03%  (p=0.050 n=584+587)
LinkCompiler                    842ms ±10%        839ms ±10%    ~     (p=0.074 n=587+590)
ExternalLinkCompiler            1.65s ± 7%        1.65s ± 7%    ~     (p=0.767 n=590+585)
LinkWithoutDebugCompiler        378ms ±11%        379ms ±12%    ~     (p=0.677 n=591+586)
[Geo mean]                      1.02s             1.02s       -0.52%

name                      old alloc/op      new alloc/op      delta
Template                       37.4MB ± 0%       37.4MB ± 0%  +0.06%  (p=0.000 n=589+585)
Unicode                        29.6MB ± 0%       28.6MB ± 0%  -3.11%  (p=0.000 n=574+566)
GoTypes                         120MB ± 0%        120MB ± 0%  -0.01%  (p=0.000 n=594+593)
Compiler                        568MB ± 0%        568MB ± 0%  -0.02%  (p=0.000 n=588+591)
SSA                            1.45GB ± 0%       1.45GB ± 0%  -0.16%  (p=0.000 n=596+592)
Flate                          22.6MB ± 0%       22.5MB ± 0%  -0.36%  (p=0.000 n=593+595)
GoParser                       30.1MB ± 0%       30.1MB ± 0%  -0.01%  (p=0.000 n=590+594)
Reflect                        77.8MB ± 0%       77.8MB ± 0%    ~     (p=0.631 n=584+591)
Tar                            34.1MB ± 0%       34.1MB ± 0%  -0.04%  (p=0.000 n=584+588)
XML                            43.6MB ± 0%       43.6MB ± 0%  +0.07%  (p=0.000 n=593+591)
LinkCompiler                   98.6MB ± 0%       98.6MB ± 0%    ~     (p=0.096 n=590+589)
ExternalLinkCompiler           89.6MB ± 0%       89.6MB ± 0%    ~     (p=0.695 n=590+587)
LinkWithoutDebugCompiler       57.2MB ± 0%       57.2MB ± 0%    ~     (p=0.674 n=590+589)
[Geo mean]                     78.5MB            78.3MB       -0.28%

name                      old allocs/op     new allocs/op     delta
Template                         379k ± 0%         380k ± 0%  +0.33%  (p=0.000 n=593+590)
Unicode                          344k ± 0%         338k ± 0%  -1.67%  (p=0.000 n=594+589)
GoTypes                         1.30M ± 0%        1.31M ± 0%  +0.19%  (p=0.000 n=592+591)
Compiler                        5.40M ± 0%        5.41M ± 0%  +0.23%  (p=0.000 n=587+585)
SSA                             14.2M ± 0%        14.2M ± 0%  +0.08%  (p=0.000 n=594+591)
Flate                            231k ± 0%         230k ± 0%  -0.42%  (p=0.000 n=588+589)
GoParser                         314k ± 0%         315k ± 0%  +0.16%  (p=0.000 n=587+594)
Reflect                          975k ± 0%         976k ± 0%  +0.10%  (p=0.000 n=590+594)
Tar                              344k ± 0%         345k ± 0%  +0.24%  (p=0.000 n=595+590)
XML                              422k ± 0%         424k ± 0%  +0.57%  (p=0.000 n=590+589)
LinkCompiler                     538k ± 0%         538k ± 0%  -0.00%  (p=0.045 n=592+587)
ExternalLinkCompiler             593k ± 0%         593k ± 0%    ~     (p=0.171 n=588+587)
LinkWithoutDebugCompiler         172k ± 0%         172k ± 0%    ~     (p=0.996 n=590+585)
[Geo mean]                       685k              685k       -0.02%

name                      old maxRSS/op     new maxRSS/op     delta
Template                        53.7M ± 8%        53.8M ± 8%    ~     (p=0.666 n=576+574)
Unicode                         54.4M ±12%        55.0M ±10%  +1.15%  (p=0.000 n=591+588)
GoTypes                         95.1M ± 4%        95.1M ± 4%    ~     (p=0.948 n=589+591)
Compiler                         334M ± 6%         334M ± 6%    ~     (p=0.875 n=592+593)
SSA                              792M ± 5%         791M ± 5%    ~     (p=0.067 n=592+591)
Flate                           39.9M ±11%        40.0M ±10%    ~     (p=0.131 n=596+596)
GoParser                        45.2M ±11%        45.3M ±11%    ~     (p=0.353 n=592+590)
Reflect                         76.1M ± 5%        76.2M ± 5%    ~     (p=0.114 n=594+594)
Tar                             49.4M ±10%        49.6M ± 9%  +0.57%  (p=0.015 n=590+593)
XML                             57.4M ± 9%        57.7M ± 8%  +0.67%  (p=0.000 n=592+580)
LinkCompiler                     183M ± 2%         183M ± 2%    ~     (p=0.229 n=587+591)
ExternalLinkCompiler             187M ± 2%         187M ± 3%    ~     (p=0.362 n=571+562)
LinkWithoutDebugCompiler         143M ± 3%         143M ± 3%    ~     (p=0.350 n=584+586)
[Geo mean]                       103M              103M       +0.23%

Passes toolstash-check.

Fixes #4617.

Change-Id: Id4f6759b4afc5e002770091d0d4f6e272ee6cbdd
Reviewed-on: https://go-review.googlesource.com/c/go/+/272654
Reviewed-by: Robert Griesemer <gri@golang.org>
Trust: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Matthew Dempsky 2020-11-13 23:36:48 -08:00
parent 6826287c6b
commit 7d72951229
23 changed files with 597 additions and 1564 deletions

View file

@ -22,8 +22,6 @@ package main_test
var knownFormats = map[string]string{
"*bytes.Buffer %s": "",
"*cmd/compile/internal/gc.EscLocation %v": "",
"*cmd/compile/internal/gc.Mpflt %v": "",
"*cmd/compile/internal/gc.Mpint %v": "",
"*cmd/compile/internal/gc.Node %#v": "",
"*cmd/compile/internal/gc.Node %+S": "",
"*cmd/compile/internal/gc.Node %+v": "",
@ -60,9 +58,7 @@ var knownFormats = map[string]string{
"*cmd/internal/obj.Addr %v": "",
"*cmd/internal/obj.LSym %v": "",
"*math/big.Float %f": "",
"*math/big.Int %#x": "",
"*math/big.Int %s": "",
"*math/big.Int %v": "",
"[16]byte %x": "",
"[]*cmd/compile/internal/ssa.Block %v": "",
"[]*cmd/compile/internal/ssa.Value %v": "",
@ -91,9 +87,6 @@ var knownFormats = map[string]string{
"cmd/compile/internal/gc.Nodes %v": "",
"cmd/compile/internal/gc.Op %#v": "",
"cmd/compile/internal/gc.Op %v": "",
"cmd/compile/internal/gc.Val %#v": "",
"cmd/compile/internal/gc.Val %T": "",
"cmd/compile/internal/gc.Val %v": "",
"cmd/compile/internal/gc.fmtMode %d": "",
"cmd/compile/internal/gc.initKind %d": "",
"cmd/compile/internal/gc.itag %v": "",
@ -134,10 +127,10 @@ var knownFormats = map[string]string{
"error %v": "",
"float64 %.2f": "",
"float64 %.3f": "",
"float64 %.6g": "",
"float64 %g": "",
"go/constant.Kind %d": "",
"go/constant.Kind %v": "",
"go/constant.Value %#v": "",
"go/constant.Value %v": "",
"int %#x": "",
"int %-12d": "",
"int %-6d": "",
@ -155,7 +148,6 @@ var knownFormats = map[string]string{
"int32 %v": "",
"int32 %x": "",
"int64 %#x": "",
"int64 %+d": "",
"int64 %-10d": "",
"int64 %.5d": "",
"int64 %d": "",

File diff suppressed because it is too large Load diff

View file

@ -553,7 +553,7 @@ func structfield(n *Node) *types.Field {
f.Embedded = 1
}
if n.HasVal() {
f.Note = n.Val().U.(string)
f.Note = constant.StringVal(n.Val())
}
lineno = lno
@ -638,7 +638,7 @@ func interfacefield(n *Node) *types.Field {
Fatalf("interfacefield: oops %v\n", n)
}
if n.Val().Kind() != constant.Unknown {
if n.HasVal() {
yyerror("interface method cannot have annotation")
}

View file

@ -143,7 +143,7 @@ func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op Op, ctxt Class, t
// importconst declares symbol s as an imported constant with type t and value val.
// ipkg is the package being imported
func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val Val) {
func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val constant.Value) {
n := importobj(ipkg, pos, s, OLITERAL, PEXTERN, t)
if n == nil { // TODO: Check that value matches.
return

View file

@ -9,6 +9,7 @@ import (
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
"go/constant"
"io"
"strconv"
"strings"
@ -334,7 +335,7 @@ func (m fmtMode) prepareArgs(args []interface{}) {
args[i] = (*fmtSymErr)(arg)
case Nodes:
args[i] = fmtNodesErr(arg)
case Val, int32, int64, string, types.EType:
case int32, int64, string, types.EType, constant.Value:
// OK: printing these types doesn't depend on mode
default:
Fatalf("mode.prepareArgs type %T", arg)
@ -353,7 +354,7 @@ func (m fmtMode) prepareArgs(args []interface{}) {
args[i] = (*fmtSymDbg)(arg)
case Nodes:
args[i] = fmtNodesDbg(arg)
case Val, int32, int64, string, types.EType:
case int32, int64, string, types.EType, constant.Value:
// OK: printing these types doesn't depend on mode
default:
Fatalf("mode.prepareArgs type %T", arg)
@ -372,7 +373,7 @@ func (m fmtMode) prepareArgs(args []interface{}) {
args[i] = (*fmtSymTypeId)(arg)
case Nodes:
args[i] = fmtNodesTypeId(arg)
case Val, int32, int64, string, types.EType:
case int32, int64, string, types.EType, constant.Value:
// OK: printing these types doesn't depend on mode
default:
Fatalf("mode.prepareArgs type %T", arg)
@ -391,7 +392,7 @@ func (m fmtMode) prepareArgs(args []interface{}) {
args[i] = (*fmtSymTypeIdName)(arg)
case Nodes:
args[i] = fmtNodesTypeIdName(arg)
case Val, int32, int64, string, types.EType:
case int32, int64, string, types.EType, constant.Value:
// OK: printing these types doesn't depend on mode
default:
Fatalf("mode.prepareArgs type %T", arg)
@ -513,51 +514,37 @@ func (n *Node) jconv(s fmt.State, flag FmtFlag) {
}
}
func (v Val) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
v.vconv(s, fmtFlag(s, verb))
func vconv(v constant.Value, flag FmtFlag) string {
if flag&FmtSharp == 0 && v.Kind() == constant.Complex {
real, imag := constant.Real(v), constant.Imag(v)
default:
fmt.Fprintf(s, "%%!%c(Val=%T)", verb, v)
var re string
sre := constant.Sign(real)
if sre != 0 {
re = real.String()
}
var im string
sim := constant.Sign(imag)
if sim != 0 {
im = imag.String()
}
switch {
case sre == 0 && sim == 0:
return "0"
case sre == 0:
return im + "i"
case sim == 0:
return re
case sim < 0:
return fmt.Sprintf("(%s%si)", re, im)
default:
return fmt.Sprintf("(%s+%si)", re, im)
}
}
}
func (v Val) vconv(s fmt.State, flag FmtFlag) {
switch u := v.U.(type) {
case *Mpint:
if flag&FmtSharp != 0 {
fmt.Fprint(s, u.String())
return
}
fmt.Fprint(s, u.GoString())
return
case *Mpflt:
if flag&FmtSharp != 0 {
fmt.Fprint(s, u.String())
return
}
fmt.Fprint(s, u.GoString())
return
case *Mpcplx:
if flag&FmtSharp != 0 {
fmt.Fprint(s, u.String())
return
}
fmt.Fprint(s, u.GoString())
return
case string:
fmt.Fprint(s, strconv.Quote(u))
case bool:
fmt.Fprint(s, u)
default:
fmt.Fprintf(s, "<ctype=%d>", v.Kind())
}
return v.String()
}
/*
@ -1333,8 +1320,12 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
}
if n.Type == types.UntypedRune {
u := n.Val().U.(*Mpint)
switch x := u.Int64(); {
switch x, ok := constant.Int64Val(n.Val()); {
case !ok:
fallthrough
default:
fmt.Fprintf(s, "('\\x00' + %v)", n.Val())
case ' ' <= x && x < utf8.RuneSelf && x != '\\' && x != '\'':
fmt.Fprintf(s, "'%c'", int(x))
@ -1343,12 +1334,9 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
case 0 <= x && x <= utf8.MaxRune:
fmt.Fprintf(s, "'\\U%08x'", uint64(x))
default:
fmt.Fprintf(s, "('\\x00' + %v)", u)
}
} else {
mode.Fprintf(s, "%v", n.Val())
fmt.Fprint(s, vconv(n.Val(), fmtFlag(s, 'v')))
}
if needUnparen {

View file

@ -178,14 +178,6 @@ var (
iscmp [OEND]bool
)
var minintval [NTYPE]*Mpint
var maxintval [NTYPE]*Mpint
var minfltval [NTYPE]*Mpflt
var maxfltval [NTYPE]*Mpflt
var xtop []*Node
var exportlist []*Node

View file

@ -777,7 +777,7 @@ func constTypeOf(typ *types.Type) constant.Kind {
return 0
}
func (w *exportWriter) value(typ *types.Type, v Val) {
func (w *exportWriter) value(typ *types.Type, v constant.Value) {
assertRepresents(typ, v)
w.typ(typ)
@ -788,17 +788,16 @@ func (w *exportWriter) value(typ *types.Type, v Val) {
switch constTypeOf(typ) {
case constant.Bool:
w.bool(v.U.(bool))
w.bool(constant.BoolVal(v))
case constant.String:
w.string(v.U.(string))
w.string(constant.StringVal(v))
case constant.Int:
w.mpint(&v.U.(*Mpint).Val, typ)
w.mpint(v, typ)
case constant.Float:
w.mpfloat(&v.U.(*Mpflt).Val, typ)
w.mpfloat(v, typ)
case constant.Complex:
x := v.U.(*Mpcplx)
w.mpfloat(&x.Real.Val, typ)
w.mpfloat(&x.Imag.Val, typ)
w.mpfloat(constant.Real(v), typ)
w.mpfloat(constant.Imag(v), typ)
}
}
@ -847,15 +846,19 @@ func intSize(typ *types.Type) (signed bool, maxBytes uint) {
// single byte.
//
// TODO(mdempsky): Is this level of complexity really worthwhile?
func (w *exportWriter) mpint(x *big.Int, typ *types.Type) {
func (w *exportWriter) mpint(x constant.Value, typ *types.Type) {
signed, maxBytes := intSize(typ)
negative := x.Sign() < 0
negative := constant.Sign(x) < 0
if !signed && negative {
Fatalf("negative unsigned integer; type %v, value %v", typ, x)
}
b := x.Bytes()
b := constant.Bytes(x) // little endian
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
b[i], b[j] = b[j], b[i]
}
if len(b) > 0 && b[0] == 0 {
Fatalf("leading zeros")
}
@ -910,7 +913,8 @@ func (w *exportWriter) mpint(x *big.Int, typ *types.Type) {
// mantissa is an integer. The value is written out as mantissa (as a
// multi-precision integer) and then the exponent, except exponent is
// omitted if mantissa is zero.
func (w *exportWriter) mpfloat(f *big.Float, typ *types.Type) {
func (w *exportWriter) mpfloat(v constant.Value, typ *types.Type) {
f := bigFloatVal(v)
if f.IsInf() {
Fatalf("infinite constant")
}
@ -928,7 +932,7 @@ func (w *exportWriter) mpfloat(f *big.Float, typ *types.Type) {
if acc != big.Exact {
Fatalf("mantissa scaling failed for %f (%s)", f, acc)
}
w.mpint(manti, typ)
w.mpint(makeInt(manti), typ)
if manti.Sign() != 0 {
w.int64(exp)
}

View file

@ -356,27 +356,24 @@ func (r *importReader) doDecl(n *Node) {
}
}
func (p *importReader) value(typ *types.Type) (v Val) {
func (p *importReader) value(typ *types.Type) constant.Value {
switch constTypeOf(typ) {
case constant.Bool:
v.U = p.bool()
return constant.MakeBool(p.bool())
case constant.String:
v.U = p.string()
return constant.MakeString(p.string())
case constant.Int:
x := new(Mpint)
p.mpint(&x.Val, typ)
v.U = x
var i big.Int
p.mpint(&i, typ)
return makeInt(&i)
case constant.Float:
x := newMpflt()
p.float(x, typ)
v.U = x
return p.float(typ)
case constant.Complex:
x := newMpcmplx()
p.float(&x.Real, typ)
p.float(&x.Imag, typ)
v.U = x
return makeComplex(p.float(typ), p.float(typ))
}
return
Fatalf("unexpected value type: %v", typ)
panic("unreachable")
}
func (p *importReader) mpint(x *big.Int, typ *types.Type) {
@ -418,14 +415,15 @@ func (p *importReader) mpint(x *big.Int, typ *types.Type) {
}
}
func (p *importReader) float(x *Mpflt, typ *types.Type) {
func (p *importReader) float(typ *types.Type) constant.Value {
var mant big.Int
p.mpint(&mant, typ)
m := x.Val.SetInt(&mant)
if m.Sign() == 0 {
return
var f big.Float
f.SetInt(&mant)
if f.Sign() != 0 {
f.SetMantExp(&f, int(p.int64()))
}
m.SetMantExp(m, int(p.int64()))
return constant.Make(&f)
}
func (r *importReader) ident() *types.Sym {

View file

@ -21,6 +21,7 @@ import (
"cmd/internal/sys"
"flag"
"fmt"
"go/constant"
"internal/goversion"
"io"
"io/ioutil"
@ -1135,13 +1136,13 @@ func loadsys() {
// imported so far.
var myheight int
func importfile(f *Val) *types.Pkg {
path_, ok := f.U.(string)
if !ok {
func importfile(f constant.Value) *types.Pkg {
if f.Kind() != constant.String {
yyerror("import path must be a string")
return nil
}
path_ := constant.StringVal(f)
if len(path_) == 0 {
yyerror("import path is empty")
return nil

View file

@ -1,357 +0,0 @@
// 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 (
"fmt"
"math"
"math/big"
)
// implements float arithmetic
const (
// Maximum size in bits for Mpints before signalling
// overflow and also mantissa precision for Mpflts.
Mpprec = 512
// Turn on for constant arithmetic debugging output.
Mpdebug = false
)
// Mpflt represents a floating-point constant.
type Mpflt struct {
Val big.Float
}
// Mpcplx represents a complex constant.
type Mpcplx struct {
Real Mpflt
Imag Mpflt
}
// Use newMpflt (not new(Mpflt)!) to get the correct default precision.
func newMpflt() *Mpflt {
var a Mpflt
a.Val.SetPrec(Mpprec)
return &a
}
// Use newMpcmplx (not new(Mpcplx)!) to get the correct default precision.
func newMpcmplx() *Mpcplx {
var a Mpcplx
a.Real = *newMpflt()
a.Imag = *newMpflt()
return &a
}
func (a *Mpflt) SetInt(b *Mpint) {
if b.checkOverflow(0) {
// sign doesn't really matter but copy anyway
a.Val.SetInf(b.Val.Sign() < 0)
return
}
a.Val.SetInt(&b.Val)
}
func (a *Mpflt) Set(b *Mpflt) {
a.Val.Set(&b.Val)
}
func (a *Mpflt) Add(b *Mpflt) {
if Mpdebug {
fmt.Printf("\n%v + %v", a, b)
}
a.Val.Add(&a.Val, &b.Val)
if Mpdebug {
fmt.Printf(" = %v\n\n", a)
}
}
func (a *Mpflt) AddFloat64(c float64) {
var b Mpflt
b.SetFloat64(c)
a.Add(&b)
}
func (a *Mpflt) Sub(b *Mpflt) {
if Mpdebug {
fmt.Printf("\n%v - %v", a, b)
}
a.Val.Sub(&a.Val, &b.Val)
if Mpdebug {
fmt.Printf(" = %v\n\n", a)
}
}
func (a *Mpflt) Mul(b *Mpflt) {
if Mpdebug {
fmt.Printf("%v\n * %v\n", a, b)
}
a.Val.Mul(&a.Val, &b.Val)
if Mpdebug {
fmt.Printf(" = %v\n\n", a)
}
}
func (a *Mpflt) MulFloat64(c float64) {
var b Mpflt
b.SetFloat64(c)
a.Mul(&b)
}
func (a *Mpflt) Quo(b *Mpflt) {
if Mpdebug {
fmt.Printf("%v\n / %v\n", a, b)
}
a.Val.Quo(&a.Val, &b.Val)
if Mpdebug {
fmt.Printf(" = %v\n\n", a)
}
}
func (a *Mpflt) Cmp(b *Mpflt) int {
return a.Val.Cmp(&b.Val)
}
func (a *Mpflt) CmpFloat64(c float64) int {
if c == 0 {
return a.Val.Sign() // common case shortcut
}
return a.Val.Cmp(big.NewFloat(c))
}
func (a *Mpflt) Float64() float64 {
x, _ := a.Val.Float64()
// check for overflow
if math.IsInf(x, 0) && Errors() == 0 {
Fatalf("ovf in Mpflt Float64")
}
return x + 0 // avoid -0 (should not be needed, but be conservative)
}
func (a *Mpflt) Float32() float64 {
x32, _ := a.Val.Float32()
x := float64(x32)
// check for overflow
if math.IsInf(x, 0) && Errors() == 0 {
Fatalf("ovf in Mpflt Float32")
}
return x + 0 // avoid -0 (should not be needed, but be conservative)
}
func (a *Mpflt) SetFloat64(c float64) {
if Mpdebug {
fmt.Printf("\nconst %g", c)
}
// convert -0 to 0
if c == 0 {
c = 0
}
a.Val.SetFloat64(c)
if Mpdebug {
fmt.Printf(" = %v\n", a)
}
}
func (a *Mpflt) Neg() {
// avoid -0
if a.Val.Sign() != 0 {
a.Val.Neg(&a.Val)
}
}
func (a *Mpflt) SetString(as string) {
f, _, err := a.Val.Parse(as, 0)
if err != nil {
yyerror("malformed constant: %s (%v)", as, err)
a.Val.SetFloat64(0)
return
}
if f.IsInf() {
yyerror("constant too large: %s", as)
a.Val.SetFloat64(0)
return
}
// -0 becomes 0
if f.Sign() == 0 && f.Signbit() {
a.Val.SetFloat64(0)
}
}
func (f *Mpflt) String() string {
return f.Val.Text('b', 0)
}
func (fvp *Mpflt) GoString() string {
// determine sign
sign := ""
f := &fvp.Val
if f.Sign() < 0 {
sign = "-"
f = new(big.Float).Abs(f)
}
// Don't try to convert infinities (will not terminate).
if f.IsInf() {
return sign + "Inf"
}
// Use exact fmt formatting if in float64 range (common case):
// proceed if f doesn't underflow to 0 or overflow to inf.
if x, _ := f.Float64(); f.Sign() == 0 == (x == 0) && !math.IsInf(x, 0) {
return fmt.Sprintf("%s%.6g", sign, x)
}
// Out of float64 range. Do approximate manual to decimal
// conversion to avoid precise but possibly slow Float
// formatting.
// f = mant * 2**exp
var mant big.Float
exp := f.MantExp(&mant) // 0.5 <= mant < 1.0
// approximate float64 mantissa m and decimal exponent d
// f ~ m * 10**d
m, _ := mant.Float64() // 0.5 <= m < 1.0
d := float64(exp) * (math.Ln2 / math.Ln10) // log_10(2)
// adjust m for truncated (integer) decimal exponent e
e := int64(d)
m *= math.Pow(10, d-float64(e))
// ensure 1 <= m < 10
switch {
case m < 1-0.5e-6:
// The %.6g format below rounds m to 5 digits after the
// decimal point. Make sure that m*10 < 10 even after
// rounding up: m*10 + 0.5e-5 < 10 => m < 1 - 0.5e6.
m *= 10
e--
case m >= 10:
m /= 10
e++
}
return fmt.Sprintf("%s%.6ge%+d", sign, m, e)
}
// complex multiply v *= rv
// (a, b) * (c, d) = (a*c - b*d, b*c + a*d)
func (v *Mpcplx) Mul(rv *Mpcplx) {
var ac, ad, bc, bd 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 (v *Mpcplx) Div(rv *Mpcplx) bool {
if rv.Real.CmpFloat64(0) == 0 && rv.Imag.CmpFloat64(0) == 0 {
return false
}
var ac, ad, bc, bd, 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
}
func (v *Mpcplx) String() string {
return fmt.Sprintf("(%s+%si)", v.Real.String(), v.Imag.String())
}
func (v *Mpcplx) GoString() string {
var re string
sre := v.Real.CmpFloat64(0)
if sre != 0 {
re = v.Real.GoString()
}
var im string
sim := v.Imag.CmpFloat64(0)
if sim != 0 {
im = v.Imag.GoString()
}
switch {
case sre == 0 && sim == 0:
return "0"
case sre == 0:
return im + "i"
case sim == 0:
return re
case sim < 0:
return fmt.Sprintf("(%s%si)", re, im)
default:
return fmt.Sprintf("(%s+%si)", re, im)
}
}

View file

@ -1,303 +0,0 @@
// 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 (
"fmt"
"math/big"
)
// implements integer arithmetic
// Mpint represents an integer constant.
type Mpint struct {
Val big.Int
Ovf bool // set if Val overflowed compiler limit (sticky)
}
func (a *Mpint) SetOverflow() {
a.Val.SetUint64(1) // avoid spurious div-zero errors
a.Ovf = true
}
func (a *Mpint) checkOverflow(extra int) bool {
// We don't need to be precise here, any reasonable upper limit would do.
// For now, use existing limit so we pass all the tests unchanged.
if a.Val.BitLen()+extra > Mpprec {
a.SetOverflow()
}
return a.Ovf
}
func (a *Mpint) Set(b *Mpint) {
a.Val.Set(&b.Val)
}
func (a *Mpint) SetFloat(b *Mpflt) bool {
// avoid converting huge floating-point numbers to integers
// (2*Mpprec is large enough to permit all tests to pass)
if b.Val.MantExp(nil) > 2*Mpprec {
a.SetOverflow()
return false
}
if _, acc := b.Val.Int(&a.Val); acc == big.Exact {
return true
}
const delta = 16 // a reasonably small number of bits > 0
var t big.Float
t.SetPrec(Mpprec - delta)
// try rounding down a little
t.SetMode(big.ToZero)
t.Set(&b.Val)
if _, acc := t.Int(&a.Val); acc == big.Exact {
return true
}
// try rounding up a little
t.SetMode(big.AwayFromZero)
t.Set(&b.Val)
if _, acc := t.Int(&a.Val); acc == big.Exact {
return true
}
a.Ovf = false
return false
}
func (a *Mpint) Add(b *Mpint) {
if a.Ovf || b.Ovf {
if Errors() == 0 {
Fatalf("ovf in Mpint Add")
}
a.SetOverflow()
return
}
a.Val.Add(&a.Val, &b.Val)
if a.checkOverflow(0) {
yyerror("constant addition overflow")
}
}
func (a *Mpint) Sub(b *Mpint) {
if a.Ovf || b.Ovf {
if Errors() == 0 {
Fatalf("ovf in Mpint Sub")
}
a.SetOverflow()
return
}
a.Val.Sub(&a.Val, &b.Val)
if a.checkOverflow(0) {
yyerror("constant subtraction overflow")
}
}
func (a *Mpint) Mul(b *Mpint) {
if a.Ovf || b.Ovf {
if Errors() == 0 {
Fatalf("ovf in Mpint Mul")
}
a.SetOverflow()
return
}
a.Val.Mul(&a.Val, &b.Val)
if a.checkOverflow(0) {
yyerror("constant multiplication overflow")
}
}
func (a *Mpint) Quo(b *Mpint) {
if a.Ovf || b.Ovf {
if Errors() == 0 {
Fatalf("ovf in Mpint Quo")
}
a.SetOverflow()
return
}
a.Val.Quo(&a.Val, &b.Val)
if a.checkOverflow(0) {
// can only happen for div-0 which should be checked elsewhere
yyerror("constant division overflow")
}
}
func (a *Mpint) Rem(b *Mpint) {
if a.Ovf || b.Ovf {
if Errors() == 0 {
Fatalf("ovf in Mpint Rem")
}
a.SetOverflow()
return
}
a.Val.Rem(&a.Val, &b.Val)
if a.checkOverflow(0) {
// should never happen
yyerror("constant modulo overflow")
}
}
func (a *Mpint) Or(b *Mpint) {
if a.Ovf || b.Ovf {
if Errors() == 0 {
Fatalf("ovf in Mpint Or")
}
a.SetOverflow()
return
}
a.Val.Or(&a.Val, &b.Val)
}
func (a *Mpint) And(b *Mpint) {
if a.Ovf || b.Ovf {
if Errors() == 0 {
Fatalf("ovf in Mpint And")
}
a.SetOverflow()
return
}
a.Val.And(&a.Val, &b.Val)
}
func (a *Mpint) AndNot(b *Mpint) {
if a.Ovf || b.Ovf {
if Errors() == 0 {
Fatalf("ovf in Mpint AndNot")
}
a.SetOverflow()
return
}
a.Val.AndNot(&a.Val, &b.Val)
}
func (a *Mpint) Xor(b *Mpint) {
if a.Ovf || b.Ovf {
if Errors() == 0 {
Fatalf("ovf in Mpint Xor")
}
a.SetOverflow()
return
}
a.Val.Xor(&a.Val, &b.Val)
}
func (a *Mpint) Lsh(b *Mpint) {
if a.Ovf || b.Ovf {
if Errors() == 0 {
Fatalf("ovf in Mpint Lsh")
}
a.SetOverflow()
return
}
s := b.Int64()
if s < 0 || s >= Mpprec {
msg := "shift count too large"
if s < 0 {
msg = "invalid negative shift count"
}
yyerror("%s: %d", msg, s)
a.SetInt64(0)
return
}
if a.checkOverflow(int(s)) {
yyerror("constant shift overflow")
return
}
a.Val.Lsh(&a.Val, uint(s))
}
func (a *Mpint) Rsh(b *Mpint) {
if a.Ovf || b.Ovf {
if Errors() == 0 {
Fatalf("ovf in Mpint Rsh")
}
a.SetOverflow()
return
}
s := b.Int64()
if s < 0 {
yyerror("invalid negative shift count: %d", s)
if a.Val.Sign() < 0 {
a.SetInt64(-1)
} else {
a.SetInt64(0)
}
return
}
a.Val.Rsh(&a.Val, uint(s))
}
func (a *Mpint) Cmp(b *Mpint) int {
return a.Val.Cmp(&b.Val)
}
func (a *Mpint) CmpInt64(c int64) int {
if c == 0 {
return a.Val.Sign() // common case shortcut
}
return a.Val.Cmp(big.NewInt(c))
}
func (a *Mpint) Neg() {
a.Val.Neg(&a.Val)
}
func (a *Mpint) Int64() int64 {
if a.Ovf {
if Errors() == 0 {
Fatalf("constant overflow")
}
return 0
}
return a.Val.Int64()
}
func (a *Mpint) SetInt64(c int64) {
a.Val.SetInt64(c)
}
func (a *Mpint) SetString(as string) {
_, ok := a.Val.SetString(as, 0)
if !ok {
// The lexer checks for correct syntax of the literal
// and reports detailed errors. Thus SetString should
// never fail (in theory it might run out of memory,
// but that wouldn't be reported as an error here).
Fatalf("malformed integer constant: %s", as)
return
}
if a.checkOverflow(0) {
yyerror("constant too large: %s", as)
}
}
func (a *Mpint) GoString() string {
return a.Val.String()
}
func (a *Mpint) String() string {
return fmt.Sprintf("%#x", &a.Val)
}

View file

@ -7,6 +7,7 @@ package gc
import (
"fmt"
"go/constant"
"go/token"
"os"
"path/filepath"
"runtime"
@ -331,8 +332,7 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
p.checkUnused(pragma)
}
val := p.basicLit(imp.Path)
ipkg := importfile(&val)
ipkg := importfile(p.basicLit(imp.Path))
if ipkg == nil {
if Errors() == 0 {
Fatalf("phase error in import")
@ -824,7 +824,7 @@ func (p *noder) sum(x syntax.Expr) *Node {
chunks = append(chunks, nstr.StringVal())
} else {
if len(chunks) > 1 {
nstr.SetVal(Val{U: strings.Join(chunks, "")})
nstr.SetVal(constant.MakeString(strings.Join(chunks, "")))
}
nstr = nil
chunks = chunks[:0]
@ -832,7 +832,7 @@ func (p *noder) sum(x syntax.Expr) *Node {
n = p.nod(add, OADD, n, r)
}
if len(chunks) > 1 {
nstr.SetVal(Val{U: strings.Join(chunks, "")})
nstr.SetVal(constant.MakeString(strings.Join(chunks, "")))
}
return n
@ -1400,64 +1400,43 @@ func checkLangCompat(lit *syntax.BasicLit) {
}
}
func (p *noder) basicLit(lit *syntax.BasicLit) Val {
func (p *noder) basicLit(lit *syntax.BasicLit) constant.Value {
// We don't use the errors of the conversion routines to determine
// if a literal string is valid because the conversion routines may
// accept a wider syntax than the language permits. Rely on lit.Bad
// instead.
switch s := lit.Value; lit.Kind {
case syntax.IntLit:
checkLangCompat(lit)
x := new(Mpint)
if !lit.Bad {
x.SetString(s)
}
return Val{U: x}
case syntax.FloatLit:
checkLangCompat(lit)
x := newMpflt()
if !lit.Bad {
x.SetString(s)
}
return Val{U: x}
case syntax.ImagLit:
checkLangCompat(lit)
x := newMpcmplx()
if !lit.Bad {
x.Imag.SetString(strings.TrimSuffix(s, "i"))
}
return Val{U: x}
case syntax.RuneLit:
x := new(Mpint)
if !lit.Bad {
u, _ := strconv.Unquote(s)
var r rune
if len(u) == 1 {
r = rune(u[0])
} else {
r, _ = utf8.DecodeRuneInString(u)
}
x.SetInt64(int64(r))
}
return Val{U: x}
case syntax.StringLit:
var x string
if !lit.Bad {
if len(s) > 0 && s[0] == '`' {
// strip carriage returns from raw string
s = strings.Replace(s, "\r", "", -1)
}
x, _ = strconv.Unquote(s)
}
return Val{U: x}
default:
panic("unhandled BasicLit kind")
if lit.Bad {
return constant.MakeUnknown()
}
switch lit.Kind {
case syntax.IntLit, syntax.FloatLit, syntax.ImagLit:
checkLangCompat(lit)
}
v := constant.MakeFromLiteral(lit.Value, tokenForLitKind[lit.Kind], 0)
if v.Kind() == constant.Unknown {
// TODO(mdempsky): Better error message?
p.yyerrorpos(lit.Pos(), "malformed constant: %s", lit.Value)
}
// go/constant uses big.Rat by default, which is more precise, but
// causes toolstash -cmp and some tests to fail. For now, convert
// to big.Float to match cmd/compile's historical precision.
// TODO(mdempsky): Remove.
if v.Kind() == constant.Float {
v = constant.Make(bigFloatVal(v))
}
return v
}
var tokenForLitKind = [...]token.Token{
syntax.IntLit: token.INT,
syntax.RuneLit: token.CHAR,
syntax.FloatLit: token.FLOAT,
syntax.ImagLit: token.IMAG,
syntax.StringLit: token.STRING,
}
func (p *noder) name(name *syntax.Name) *types.Sym {

View file

@ -250,33 +250,18 @@ func dumpGlobalConst(n *Node) {
return
}
// only export integer constants for now
switch t.Etype {
case TINT8:
case TINT16:
case TINT32:
case TINT64:
case TINT:
case TUINT8:
case TUINT16:
case TUINT32:
case TUINT64:
case TUINT:
case TUINTPTR:
// ok
case TIDEAL:
if !Isconst(n, constant.Int) {
return
}
x := n.Val().U.(*Mpint)
if x.Cmp(minintval[TINT]) < 0 || x.Cmp(maxintval[TINT]) > 0 {
return
}
// Ideal integers we export as int (if they fit).
t = types.Types[TINT]
default:
if !t.IsInteger() {
return
}
Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), n.Int64Val())
v := n.Val()
if t.IsUntyped() {
// Export untyped integers as int (if they fit).
t = types.Types[TINT]
if doesoverflow(v, t) {
return
}
}
Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), int64Val(t, v))
}
func dumpglobls() {
@ -595,6 +580,9 @@ func litsym(n, c *Node, wid int) {
if n.Sym == nil {
Fatalf("litsym nil n sym")
}
if !types.Identical(n.Type, c.Type) {
Fatalf("litsym: type mismatch: %v has type %v, but %v has type %v", n, n.Type, c, c.Type)
}
if c.Op == ONIL {
return
}
@ -602,16 +590,16 @@ func litsym(n, c *Node, wid int) {
Fatalf("litsym c op %v", c.Op)
}
s := n.Sym.Linksym()
switch u := c.Val().U.(type) {
case bool:
i := int64(obj.Bool2int(u))
switch u := c.Val(); u.Kind() {
case constant.Bool:
i := int64(obj.Bool2int(constant.BoolVal(u)))
s.WriteInt(Ctxt, n.Xoffset, wid, i)
case *Mpint:
s.WriteInt(Ctxt, n.Xoffset, wid, u.Int64())
case constant.Int:
s.WriteInt(Ctxt, n.Xoffset, wid, int64Val(n.Type, u))
case *Mpflt:
f := u.Float64()
case constant.Float:
f, _ := constant.Float64Val(u)
switch n.Type.Etype {
case TFLOAT32:
s.WriteFloat32(Ctxt, n.Xoffset, float32(f))
@ -619,22 +607,23 @@ func litsym(n, c *Node, wid int) {
s.WriteFloat64(Ctxt, n.Xoffset, f)
}
case *Mpcplx:
r := u.Real.Float64()
i := u.Imag.Float64()
case constant.Complex:
re, _ := constant.Float64Val(constant.Real(u))
im, _ := constant.Float64Val(constant.Imag(u))
switch n.Type.Etype {
case TCOMPLEX64:
s.WriteFloat32(Ctxt, n.Xoffset, float32(r))
s.WriteFloat32(Ctxt, n.Xoffset+4, float32(i))
s.WriteFloat32(Ctxt, n.Xoffset, float32(re))
s.WriteFloat32(Ctxt, n.Xoffset+4, float32(im))
case TCOMPLEX128:
s.WriteFloat64(Ctxt, n.Xoffset, r)
s.WriteFloat64(Ctxt, n.Xoffset+8, i)
s.WriteFloat64(Ctxt, n.Xoffset, re)
s.WriteFloat64(Ctxt, n.Xoffset+8, im)
}
case string:
symdata := stringsym(n.Pos, u)
case constant.String:
i := constant.StringVal(u)
symdata := stringsym(n.Pos, i)
s.WriteAddr(Ctxt, n.Xoffset, Widthptr, symdata, 0)
s.WriteInt(Ctxt, n.Xoffset+int64(Widthptr), Widthptr, int64(len(u)))
s.WriteInt(Ctxt, n.Xoffset+int64(Widthptr), Widthptr, int64(len(i)))
default:
Fatalf("litsym unhandled OLITERAL %v", c)

View file

@ -8,6 +8,7 @@ import (
"cmd/compile/internal/types"
"cmd/internal/obj"
"fmt"
"go/constant"
)
type InitEntry struct {
@ -1116,20 +1117,13 @@ func isZero(n *Node) bool {
return true
case OLITERAL:
switch u := n.Val().U.(type) {
switch u := n.Val(); u.Kind() {
case constant.String:
return constant.StringVal(u) == ""
case constant.Bool:
return !constant.BoolVal(u)
default:
Dump("unexpected literal", n)
Fatalf("isZero")
case string:
return u == ""
case bool:
return !u
case *Mpint:
return u.CmpInt64(0) == 0
case *Mpflt:
return u.CmpFloat64(0) == 0
case *Mpcplx:
return u.Real.CmpFloat64(0) == 0 && u.Imag.CmpFloat64(0) == 0
return constant.Sign(u) == 0
}
case OARRAYLIT:

View file

@ -2044,9 +2044,9 @@ func (s *state) expr(n *Node) *ssa.Value {
return s.constNil(t)
}
case OLITERAL:
switch u := n.Val().U.(type) {
case *Mpint:
i := u.Int64()
switch u := n.Val(); u.Kind() {
case constant.Int:
i := int64Val(n.Type, u)
switch n.Type.Size() {
case 1:
return s.constInt8(n.Type, int8(i))
@ -2060,44 +2060,45 @@ func (s *state) expr(n *Node) *ssa.Value {
s.Fatalf("bad integer size %d", n.Type.Size())
return nil
}
case string:
if u == "" {
case constant.String:
i := constant.StringVal(u)
if i == "" {
return s.constEmptyString(n.Type)
}
return s.entryNewValue0A(ssa.OpConstString, n.Type, u)
case bool:
return s.constBool(u)
case *Mpflt:
return s.entryNewValue0A(ssa.OpConstString, n.Type, i)
case constant.Bool:
return s.constBool(constant.BoolVal(u))
case constant.Float:
f, _ := constant.Float64Val(u)
switch n.Type.Size() {
case 4:
return s.constFloat32(n.Type, u.Float32())
return s.constFloat32(n.Type, f)
case 8:
return s.constFloat64(n.Type, u.Float64())
return s.constFloat64(n.Type, f)
default:
s.Fatalf("bad float size %d", n.Type.Size())
return nil
}
case *Mpcplx:
r := &u.Real
i := &u.Imag
case constant.Complex:
re, _ := constant.Float64Val(constant.Real(u))
im, _ := constant.Float64Val(constant.Imag(u))
switch n.Type.Size() {
case 8:
pt := types.Types[TFLOAT32]
return s.newValue2(ssa.OpComplexMake, n.Type,
s.constFloat32(pt, r.Float32()),
s.constFloat32(pt, i.Float32()))
s.constFloat32(pt, re),
s.constFloat32(pt, im))
case 16:
pt := types.Types[TFLOAT64]
return s.newValue2(ssa.OpComplexMake, n.Type,
s.constFloat64(pt, r.Float64()),
s.constFloat64(pt, i.Float64()))
s.constFloat64(pt, re),
s.constFloat64(pt, im))
default:
s.Fatalf("bad float size %d", n.Type.Size())
s.Fatalf("bad complex size %d", n.Type.Size())
return nil
}
default:
s.Fatalf("unhandled OLITERAL %v", n.Val().Kind())
s.Fatalf("unhandled OLITERAL %v", u.Kind())
return nil
}
case OCONVNOP:

View file

@ -10,6 +10,7 @@ import (
"crypto/md5"
"encoding/binary"
"fmt"
"go/constant"
"sort"
"strconv"
"strings"
@ -252,9 +253,7 @@ func (x methcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x methcmp) Less(i, j int) bool { return x[i].Sym.Less(x[j].Sym) }
func nodintconst(v int64) *Node {
u := new(Mpint)
u.SetInt64(v)
return nodlit(Val{u})
return nodlit(constant.MakeInt64(v))
}
func nodnil() *Node {
@ -264,11 +263,11 @@ func nodnil() *Node {
}
func nodbool(b bool) *Node {
return nodlit(Val{b})
return nodlit(constant.MakeBool(b))
}
func nodstr(s string) *Node {
return nodlit(Val{s})
return nodlit(constant.MakeString(s))
}
// treecopy recursively copies n, with the exception of

View file

@ -8,6 +8,7 @@ import (
"cmd/compile/internal/types"
"cmd/internal/src"
"go/constant"
"go/token"
"sort"
)
@ -400,7 +401,7 @@ func (s *exprSwitch) flush() {
}
sort.Slice(cc, func(i, j int) bool {
return compareOp(cc[i].lo.Val(), OLT, cc[j].lo.Val())
return constant.Compare(cc[i].lo.Val(), token.LSS, cc[j].lo.Val())
})
// Merge consecutive integer cases.

View file

@ -12,6 +12,7 @@ import (
"cmd/internal/obj"
"cmd/internal/objabi"
"cmd/internal/src"
"go/constant"
"sort"
)
@ -236,16 +237,17 @@ func (n *Node) MarkReadonly() {
n.Sym.Linksym().Type = objabi.SRODATA
}
// Val returns the Val for the node.
func (n *Node) Val() Val {
// Val returns the constant.Value for the node.
func (n *Node) Val() constant.Value {
if !n.HasVal() {
return Val{}
return constant.MakeUnknown()
}
return Val{n.E}
return *n.E.(*constant.Value)
}
// SetVal sets the Val for the node, which must not have been used with SetOpt.
func (n *Node) SetVal(v Val) {
// SetVal sets the constant.Value for the node,
// which must not have been used with SetOpt.
func (n *Node) SetVal(v constant.Value) {
if n.HasOpt() {
Debug.h = 1
Dump("have Opt", n)
@ -255,7 +257,7 @@ func (n *Node) SetVal(v Val) {
assertRepresents(n.Type, v)
}
n.SetHasVal(true)
n.E = v.U
n.E = &v
}
// Opt returns the optimizer data for the node.

View file

@ -8,6 +8,7 @@ import (
"cmd/compile/internal/types"
"fmt"
"go/constant"
"go/token"
"strings"
)
@ -361,7 +362,7 @@ func typecheck1(n *Node, top int) (res *Node) {
ok |= ctxExpr
if n.Type == nil && n.Val().Kind() == constant.String {
n.Type = types.UntypedString
Fatalf("string literal missing type")
}
case ONIL, ONONAME:
@ -446,12 +447,13 @@ func typecheck1(n *Node, top int) (res *Node) {
return n
}
bound := v.U.(*Mpint).Int64()
if bound < 0 {
if constant.Sign(v) < 0 {
yyerror("array bound must be non-negative")
n.Type = nil
return n
}
bound, _ := constant.Int64Val(v)
t = types.NewArray(r.Type, bound)
}
@ -776,8 +778,9 @@ func typecheck1(n *Node, top int) (res *Node) {
}
if iscmp[n.Op] {
n = evalConst(n)
t = types.UntypedBool
n.Type = t
n = evalConst(n)
if n.Op != OLITERAL {
l, r = defaultlit2(l, r, true)
n.Left = l
@ -803,7 +806,7 @@ func typecheck1(n *Node, top int) (res *Node) {
}
if (op == ODIV || op == OMOD) && Isconst(r, constant.Int) {
if r.Val().U.(*Mpint).CmpInt64(0) == 0 {
if constant.Sign(r.Val()) == 0 {
yyerror("division by zero")
n.Type = nil
return n
@ -1045,14 +1048,14 @@ func typecheck1(n *Node, top int) (res *Node) {
}
if !n.Bounded() && Isconst(n.Right, constant.Int) {
x := n.Right.Int64Val()
if x < 0 {
x := n.Right.Val()
if constant.Sign(x) < 0 {
yyerror("invalid %s index %v (index must be non-negative)", why, n.Right)
} else if t.IsArray() && x >= t.NumElem() {
} else if t.IsArray() && constant.Compare(x, token.GEQ, constant.MakeInt64(t.NumElem())) {
yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.NumElem())
} else if Isconst(n.Left, constant.String) && x >= int64(len(n.Left.StringVal())) {
} else if Isconst(n.Left, constant.String) && constant.Compare(x, token.GEQ, constant.MakeInt64(int64(len(n.Left.StringVal())))) {
yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.StringVal()))
} else if doesoverflow(n.Right.Val(), types.Types[TINT]) {
} else if doesoverflow(x, types.Types[TINT]) {
yyerror("invalid %s index %v (index too large)", why, n.Right)
}
}
@ -1155,7 +1158,7 @@ func typecheck1(n *Node, top int) (res *Node) {
Fatalf("cap for OSLICEHEADER must be non-negative")
}
if Isconst(l, constant.Int) && Isconst(c, constant.Int) && compareOp(l.Val(), OGT, c.Val()) {
if Isconst(l, constant.Int) && Isconst(c, constant.Int) && constant.Compare(l.Val(), token.GTR, c.Val()) {
Fatalf("len larger than cap for OSLICEHEADER")
}
@ -1200,7 +1203,7 @@ func typecheck1(n *Node, top int) (res *Node) {
if doesoverflow(n.Left.Val(), types.Types[TINT]) {
Fatalf("len for OMAKESLICECOPY too large")
}
if n.Left.Int64Val() < 0 {
if constant.Sign(n.Left.Val()) < 0 {
Fatalf("len for OMAKESLICECOPY must be non-negative")
}
}
@ -1773,7 +1776,7 @@ func typecheck1(n *Node, top int) (res *Node) {
n.Type = nil
return n
}
if Isconst(l, constant.Int) && r != nil && Isconst(r, constant.Int) && compareOp(l.Val(), OGT, r.Val()) {
if Isconst(l, constant.Int) && r != nil && Isconst(r, constant.Int) && constant.Compare(l.Val(), token.GTR, r.Val()) {
yyerror("len larger than cap in make(%v)", t)
n.Type = nil
return n
@ -2181,16 +2184,17 @@ func checksliceindex(l *Node, r *Node, tp *types.Type) bool {
}
if r.Op == OLITERAL {
if r.Int64Val() < 0 {
x := r.Val()
if constant.Sign(x) < 0 {
yyerror("invalid slice index %v (index must be non-negative)", r)
return false
} else if tp != nil && tp.NumElem() >= 0 && r.Int64Val() > tp.NumElem() {
} else if tp != nil && tp.NumElem() >= 0 && constant.Compare(x, token.GTR, constant.MakeInt64(tp.NumElem())) {
yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.NumElem())
return false
} else if Isconst(l, constant.String) && r.Int64Val() > int64(len(l.StringVal())) {
} else if Isconst(l, constant.String) && constant.Compare(x, token.GTR, constant.MakeInt64(int64(len(l.StringVal())))) {
yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.StringVal()))
return false
} else if doesoverflow(r.Val(), types.Types[TINT]) {
} else if doesoverflow(x, types.Types[TINT]) {
yyerror("invalid slice index %v (index too large)", r)
return false
}
@ -2200,7 +2204,7 @@ func checksliceindex(l *Node, r *Node, tp *types.Type) bool {
}
func checksliceconst(lo *Node, hi *Node) bool {
if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && compareOp(lo.Val(), OGT, hi.Val()) {
if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && constant.Compare(lo.Val(), token.GTR, hi.Val()) {
yyerror("invalid slice index: %v > %v", lo, hi)
return false
}
@ -3192,7 +3196,7 @@ func samesafeexpr(l *Node, r *Node) bool {
return samesafeexpr(l.Left, r.Left) && samesafeexpr(l.Right, r.Right)
case OLITERAL:
return eqval(l.Val(), r.Val())
return constant.Compare(l.Val(), token.EQL, r.Val())
case ONIL:
return true
@ -3625,7 +3629,9 @@ func typecheckdef(n *Node) {
}
n.Type = e.Type
n.SetVal(e.Val())
if n.Type != nil {
n.SetVal(e.Val())
}
case ONAME:
if n.Name.Param.Ntype != nil {
@ -3723,14 +3729,13 @@ func checkmake(t *types.Type, arg string, np **Node) bool {
// Do range checks for constants before defaultlit
// to avoid redundant "constant NNN overflows int" errors.
switch consttype(n) {
case constant.Int, constant.Float, constant.Complex:
v := toint(n.Val()).U.(*Mpint)
if v.CmpInt64(0) < 0 {
if n.Op == OLITERAL {
v := toint(n.Val())
if constant.Sign(v) < 0 {
yyerror("negative %s argument in make(%v)", arg, t)
return false
}
if v.Cmp(maxintval[TINT]) > 0 {
if doesoverflow(v, types.Types[TINT]) {
yyerror("%s argument too large in make(%v)", arg, t)
return false
}

View file

@ -209,8 +209,6 @@ func typeinit() {
okforand[et] = true
okforconst[et] = true
issimple[et] = true
minintval[et] = new(Mpint)
maxintval[et] = new(Mpint)
}
if isFloat[et] {
@ -220,8 +218,6 @@ func typeinit() {
okforarith[et] = true
okforconst[et] = true
issimple[et] = true
minfltval[et] = newMpflt()
maxfltval[et] = newMpflt()
}
if isComplex[et] {
@ -310,31 +306,6 @@ func typeinit() {
iscmp[OEQ] = true
iscmp[ONE] = true
maxintval[TINT8].SetString("0x7f")
minintval[TINT8].SetString("-0x80")
maxintval[TINT16].SetString("0x7fff")
minintval[TINT16].SetString("-0x8000")
maxintval[TINT32].SetString("0x7fffffff")
minintval[TINT32].SetString("-0x80000000")
maxintval[TINT64].SetString("0x7fffffffffffffff")
minintval[TINT64].SetString("-0x8000000000000000")
maxintval[TUINT8].SetString("0xff")
maxintval[TUINT16].SetString("0xffff")
maxintval[TUINT32].SetString("0xffffffff")
maxintval[TUINT64].SetString("0xffffffffffffffff")
// f is valid float if min < f < max. (min and max are not themselves valid.)
maxfltval[TFLOAT32].SetString("33554431p103") // 2^24-1 p (127-23) + 1/2 ulp
minfltval[TFLOAT32].SetString("-33554431p103")
maxfltval[TFLOAT64].SetString("18014398509481983p970") // 2^53-1 p (1023-52) + 1/2 ulp
minfltval[TFLOAT64].SetString("-18014398509481983p970")
maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32]
minfltval[TCOMPLEX64] = minfltval[TFLOAT32]
maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64]
minfltval[TCOMPLEX128] = minfltval[TFLOAT64]
types.Types[TINTER] = types.New(TINTER) // empty interface
// simple aliases
@ -410,10 +381,6 @@ func lexinit1() {
}
simtype[s.etype] = sameas
minfltval[s.etype] = minfltval[sameas]
maxfltval[s.etype] = maxfltval[sameas]
minintval[s.etype] = minintval[sameas]
maxintval[s.etype] = maxintval[sameas]
t := types.New(s.etype)
t.Sym = s1

View file

@ -12,6 +12,7 @@ import (
"encoding/binary"
"fmt"
"go/constant"
"go/token"
"strings"
)
@ -1002,7 +1003,7 @@ opswitch:
break opswitch
}
case TUINT64:
c := uint64(n.Right.Int64Val())
c := n.Right.Uint64Val()
if c < 1<<16 {
break opswitch
}
@ -1062,7 +1063,7 @@ opswitch:
}
if Isconst(n.Right, constant.Int) {
if n.Right.Val().U.(*Mpint).CmpInt64(0) < 0 || doesoverflow(n.Right.Val(), types.Types[TINT]) {
if v := n.Right.Val(); constant.Sign(v) < 0 || doesoverflow(v, types.Types[TINT]) {
yyerror("index out of bounds")
}
}
@ -1223,7 +1224,7 @@ opswitch:
// Maximum key and elem size is 128 bytes, larger objects
// are stored with an indirection. So max bucket size is 2048+eps.
if !Isconst(hint, constant.Int) ||
hint.Val().U.(*Mpint).CmpInt64(BUCKETSIZE) <= 0 {
constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(BUCKETSIZE)) {
// In case hint is larger than BUCKETSIZE runtime.makemap
// will allocate the buckets on the heap, see #20184
@ -1256,7 +1257,7 @@ opswitch:
}
}
if Isconst(hint, constant.Int) && hint.Val().U.(*Mpint).CmpInt64(BUCKETSIZE) <= 0 {
if Isconst(hint, constant.Int) && constant.Compare(hint.Val(), token.LEQ, constant.MakeInt64(BUCKETSIZE)) {
// Handling make(map[any]any) and
// make(map[any]any, hint) where hint <= BUCKETSIZE
// special allows for faster map initialization and
@ -1588,8 +1589,8 @@ opswitch:
n = typecheck(n, ctxExpr)
// Emit string symbol now to avoid emitting
// any concurrently during the backend.
if s, ok := n.Val().U.(string); ok {
_ = stringsym(n.Pos, s)
if v := n.Val(); v.Kind() == constant.String {
_ = stringsym(n.Pos, constant.StringVal(v))
}
}
@ -3841,17 +3842,14 @@ func candiscard(n *Node) bool {
// Discardable as long as we know it's not division by zero.
case ODIV, OMOD:
if Isconst(n.Right, constant.Int) && n.Right.Val().U.(*Mpint).CmpInt64(0) != 0 {
break
}
if Isconst(n.Right, constant.Float) && n.Right.Val().U.(*Mpflt).CmpFloat64(0) != 0 {
if n.Right.Op == OLITERAL && constant.Sign(n.Right.Val()) != 0 {
break
}
return false
// Discardable as long as we know it won't fail because of a bad size.
case OMAKECHAN, OMAKEMAP:
if Isconst(n.Left, constant.Int) && n.Left.Val().U.(*Mpint).CmpInt64(0) == 0 {
if Isconst(n.Left, constant.Int) && constant.Sign(n.Left.Val()) == 0 {
break
}
return false

View file

@ -1212,7 +1212,7 @@ func (t *Type) IsInteger() bool {
case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TINT, TUINT, TUINTPTR:
return true
}
return false
return t == UntypedInt || t == UntypedRune
}
func (t *Type) IsSigned() bool {
@ -1223,12 +1223,20 @@ func (t *Type) IsSigned() bool {
return false
}
func (t *Type) IsUnsigned() bool {
switch t.Etype {
case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR:
return true
}
return false
}
func (t *Type) IsFloat() bool {
return t.Etype == TFLOAT32 || t.Etype == TFLOAT64
return t.Etype == TFLOAT32 || t.Etype == TFLOAT64 || t == UntypedFloat
}
func (t *Type) IsComplex() bool {
return t.Etype == TCOMPLEX64 || t.Etype == TCOMPLEX128
return t.Etype == TCOMPLEX64 || t.Etype == TCOMPLEX128 || t == UntypedComplex
}
// IsPtr reports whether t is a regular Go pointer type.

View file

@ -6,6 +6,6 @@
package main
const _ = 6e5518446744 // ERROR "malformed constant: 6e5518446744 \(exponent overflow\)"
const _ = 6e5518446744 // ERROR "malformed constant: 6e5518446744"
const _ = 1e-1000000000
const _ = 1e+1000000000 // ERROR "constant too large"
const _ = 1e+1000000000