diff --git a/src/cmd/internal/gc/const.go b/src/cmd/internal/gc/const.go index 8d4ebe12fa..e81db1da9c 100644 --- a/src/cmd/internal/gc/const.go +++ b/src/cmd/internal/gc/const.go @@ -24,8 +24,6 @@ func truncfltlit(oldv *Mpflt, t *Type) *Mpflt { overflow(v, t) fv := newMpflt() - - // *fv = *oldv mpmovefltflt(fv, oldv) // convert large precision literal floating diff --git a/src/cmd/internal/gc/go.go b/src/cmd/internal/gc/go.go index 13b36efae0..e4305961a0 100644 --- a/src/cmd/internal/gc/go.go +++ b/src/cmd/internal/gc/go.go @@ -57,9 +57,9 @@ const ( ) const ( - // TODO(gri) replace these with a single precision constant. - Mpscale = 29 // safely smaller than bits in a long - Mpprec = 16 // Mpscale*Mpprec is max number of bits + // TODO(gri) consider increasing Mpprec to 512 or perhaps 1024 + // (this would permit enabling additional tests). + Mpprec = 16 * 29 // == 464, to match original value Mpdebug = 0 ) diff --git a/src/cmd/internal/gc/mparith1.go b/src/cmd/internal/gc/mparith1.go deleted file mode 100644 index b31da8e323..0000000000 --- a/src/cmd/internal/gc/mparith1.go +++ /dev/null @@ -1,172 +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 ( - "cmd/internal/gc/big" - "cmd/internal/obj" - "fmt" -) - -func Mpcmpfixfix(a, b *Mpint) int { - return a.Val.Cmp(&b.Val) -} - -func mpcmpfixc(b *Mpint, c int64) int { - return b.Val.Cmp(big.NewInt(c)) -} - -func mpcmpfltflt(a *Mpflt, b *Mpflt) int { - return a.Val.Cmp(&b.Val) -} - -func mpcmpfltc(b *Mpflt, c float64) int { - var a Mpflt - - Mpmovecflt(&a, c) - return mpcmpfltflt(b, &a) -} - -func mpsubfixfix(a, b *Mpint) { - a.Val.Sub(&a.Val, &b.Val) -} - -func mpsubfltflt(a *Mpflt, b *Mpflt) { - if Mpdebug != 0 { - fmt.Printf("\n%v - %v", Fconv(a, 0), Fconv(b, 0)) - } - - a.Val.Sub(&a.Val, &b.Val) - - if Mpdebug != 0 { - fmt.Printf(" = %v\n\n", Fconv(a, 0)) - } -} - -func mpaddcflt(a *Mpflt, c float64) { - var b Mpflt - - Mpmovecflt(&b, c) - mpaddfltflt(a, &b) -} - -func mpmulcflt(a *Mpflt, c float64) { - var b Mpflt - - Mpmovecflt(&b, c) - mpmulfltflt(a, &b) -} - -func mpdivfixfix(a, b *Mpint) { - a.Val.Quo(&a.Val, &b.Val) -} - -func mpmodfixfix(a, b *Mpint) { - a.Val.Rem(&a.Val, &b.Val) -} - -func Mpmovefixflt(a *Mpflt, b *Mpint) { - if b.Ovf { - // sign doesn't really matter but copy anyway - a.Val.SetInf(b.Val.Sign() < 0) - return - } - a.Val.SetInt(&b.Val) -} - -func mpmovefltfix(a *Mpint, b *Mpflt) int { - if _, acc := b.Val.Int(&a.Val); acc == big.Exact { - return 0 - } - - const delta = Mpscale // a reasonably small number of bits > 0 - var t big.Float - t.SetPrec(Mpscale*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 0 - } - - // try rounding up a little - t.SetMode(big.AwayFromZero) - t.Set(&b.Val) - if _, acc := t.Int(&a.Val); acc == big.Exact { - return 0 - } - - return -1 -} - -func mpmovefixfix(a, b *Mpint) { - a.Val.Set(&b.Val) -} - -func mpmovefltflt(a *Mpflt, b *Mpflt) { - a.Val.Set(&b.Val) -} - -// -// floating point input -// required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*] -// -func mpatoflt(a *Mpflt, as string) { - for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') { - as = as[1:] - } - - f, ok := a.Val.SetString(as) - if !ok { - // At the moment we lose precise error cause; - // the old code additionally distinguished between: - // - malformed hex constant - // - decimal point in hex constant - // - constant exponent out of range - // - decimal point and binary point in constant - // TODO(gri) use different conversion function or check separately - Yyerror("malformed constant: %s", as) - a.Val.SetUint64(0) - } - - if f.IsInf() { - Yyerror("constant too large: %s", as) - a.Val.SetUint64(0) - } -} - -func mpatofix(a *Mpint, as string) { - _, ok := a.Val.SetString(as, 0) - if !ok { - // required syntax is [+-][0[x]]d* - // At the moment we lose precise error cause; - // the old code distinguished between: - // - malformed hex constant - // - malformed octal constant - // - malformed decimal constant - // TODO(gri) use different conversion function - Yyerror("malformed integer constant: %s", as) - a.Val.SetUint64(0) - return - } - if mptestovf(a, 0) { - Yyerror("constant too large: %s", as) - } -} - -func Bconv(xval *Mpint, flag int) string { - if flag&obj.FmtSharp != 0 { - return fmt.Sprintf("%#x", &xval.Val) - } - return xval.Val.String() -} - -func Fconv(fvp *Mpflt, flag int) string { - if flag&obj.FmtSharp != 0 { - return fvp.Val.Format('g', 6) - } - return fvp.Val.Format('b', 0) -} diff --git a/src/cmd/internal/gc/mparith2.go b/src/cmd/internal/gc/mparith2.go index 807f7337b0..a4b870eb67 100644 --- a/src/cmd/internal/gc/mparith2.go +++ b/src/cmd/internal/gc/mparith2.go @@ -4,19 +4,11 @@ package gc -// shift left by s (or right by -s) -func Mpshiftfix(a *Mpint, s int) { - switch { - case s > 0: - if mptestovf(a, s) { - Yyerror("constant shift overflow") - return - } - a.Val.Lsh(&a.Val, uint(s)) - case s < 0: - a.Val.Rsh(&a.Val, uint(-s)) - } -} +import ( + "cmd/internal/gc/big" + "cmd/internal/obj" + "fmt" +) /// implements fix arithmetic @@ -28,17 +20,49 @@ func mpsetovf(a *Mpint) { func mptestovf(a *Mpint, 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. - const limit = Mpscale * Mpprec - if a.Val.BitLen()+extra > limit { + if a.Val.BitLen()+extra > Mpprec { mpsetovf(a) } return a.Ovf } +func mpmovefixfix(a, b *Mpint) { + a.Val.Set(&b.Val) +} + +func mpmovefltfix(a *Mpint, b *Mpflt) int { + if _, acc := b.Val.Int(&a.Val); acc == big.Exact { + return 0 + } + + // TODO(gri) reduce the value of delta - currently + // we use the size of a mp-word of the old implementation + // for approximately similar behavior. + const delta = 29 // 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 0 + } + + // try rounding up a little + t.SetMode(big.AwayFromZero) + t.Set(&b.Val) + if _, acc := t.Int(&a.Val); acc == big.Exact { + return 0 + } + + return -1 +} + func mpaddfixfix(a, b *Mpint, quiet int) { if a.Ovf || b.Ovf { if nsavederrors+nerrors == 0 { - Yyerror("ovf in mpaddxx") + Yyerror("ovf in mpaddfixfix") } mpsetovf(a) return @@ -51,6 +75,22 @@ func mpaddfixfix(a, b *Mpint, quiet int) { } } +func mpsubfixfix(a, b *Mpint) { + if a.Ovf || b.Ovf { + if nsavederrors+nerrors == 0 { + Yyerror("ovf in mpsubfixfix") + } + mpsetovf(a) + return + } + + a.Val.Sub(&a.Val, &b.Val) + + if mptestovf(a, 0) { + Yyerror("constant subtraction overflow") + } +} + func mpmulfixfix(a, b *Mpint) { if a.Ovf || b.Ovf { if nsavederrors+nerrors == 0 { @@ -67,6 +107,40 @@ func mpmulfixfix(a, b *Mpint) { } } +func mpdivfixfix(a, b *Mpint) { + if a.Ovf || b.Ovf { + if nsavederrors+nerrors == 0 { + Yyerror("ovf in mpdivfixfix") + } + mpsetovf(a) + return + } + + a.Val.Quo(&a.Val, &b.Val) + + if mptestovf(a, 0) { + // can only happen for div-0 which should be checked elsewhere + Yyerror("constant division overflow") + } +} + +func mpmodfixfix(a, b *Mpint) { + if a.Ovf || b.Ovf { + if nsavederrors+nerrors == 0 { + Yyerror("ovf in mpmodfixfix") + } + mpsetovf(a) + return + } + + a.Val.Rem(&a.Val, &b.Val) + + if mptestovf(a, 0) { + // should never happen + Yyerror("constant modulo overflow") + } +} + func mporfixfix(a, b *Mpint) { if a.Ovf || b.Ovf { if nsavederrors+nerrors == 0 { @@ -115,6 +189,20 @@ func mpxorfixfix(a, b *Mpint) { a.Val.Xor(&a.Val, &b.Val) } +// shift left by s (or right by -s) +func Mpshiftfix(a *Mpint, s int) { + switch { + case s > 0: + if mptestovf(a, s) { + Yyerror("constant shift overflow") + return + } + a.Val.Lsh(&a.Val, uint(s)) + case s < 0: + a.Val.Rsh(&a.Val, uint(-s)) + } +} + func mplshfixfix(a, b *Mpint) { if a.Ovf || b.Ovf { if nsavederrors+nerrors == 0 { @@ -125,7 +213,7 @@ func mplshfixfix(a, b *Mpint) { } s := Mpgetfix(b) - if s < 0 || s >= Mpprec*Mpscale { + if s < 0 || s >= Mpprec { Yyerror("stupid shift: %d", s) Mpmovecfix(a, 0) return @@ -144,7 +232,7 @@ func mprshfixfix(a, b *Mpint) { } s := Mpgetfix(b) - if s < 0 || s >= Mpprec*Mpscale { + if s < 0 || s >= Mpprec { Yyerror("stupid shift: %d", s) if a.Val.Sign() < 0 { Mpmovecfix(a, -1) @@ -157,6 +245,14 @@ func mprshfixfix(a, b *Mpint) { Mpshiftfix(a, int(-s)) } +func Mpcmpfixfix(a, b *Mpint) int { + return a.Val.Cmp(&b.Val) +} + +func mpcmpfixc(b *Mpint, c int64) int { + return b.Val.Cmp(big.NewInt(c)) +} + func mpnegfix(a *Mpint) { a.Val.Neg(&a.Val) } @@ -175,3 +271,29 @@ func Mpgetfix(a *Mpint) int64 { func Mpmovecfix(a *Mpint, c int64) { a.Val.SetInt64(c) } + +func mpatofix(a *Mpint, as string) { + _, ok := a.Val.SetString(as, 0) + if !ok { + // required syntax is [+-][0[x]]d* + // At the moment we lose precise error cause; + // the old code distinguished between: + // - malformed hex constant + // - malformed octal constant + // - malformed decimal constant + // TODO(gri) use different conversion function + Yyerror("malformed integer constant: %s", as) + a.Val.SetUint64(0) + return + } + if mptestovf(a, 0) { + Yyerror("constant too large: %s", as) + } +} + +func Bconv(xval *Mpint, flag int) string { + if flag&obj.FmtSharp != 0 { + return fmt.Sprintf("%#x", &xval.Val) + } + return xval.Val.String() +} diff --git a/src/cmd/internal/gc/mparith3.go b/src/cmd/internal/gc/mparith3.go index 73658c4a1f..b2424df92a 100644 --- a/src/cmd/internal/gc/mparith3.go +++ b/src/cmd/internal/gc/mparith3.go @@ -5,17 +5,31 @@ package gc import ( + "cmd/internal/obj" "fmt" "math" ) +/// implements float arihmetic + func newMpflt() *Mpflt { var a Mpflt - a.Val.SetPrec(Mpscale * Mpprec) + a.Val.SetPrec(Mpprec) return &a } -/// implements float arihmetic +func Mpmovefixflt(a *Mpflt, b *Mpint) { + if b.Ovf { + // sign doesn't really matter but copy anyway + a.Val.SetInf(b.Val.Sign() < 0) + return + } + a.Val.SetInt(&b.Val) +} + +func mpmovefltflt(a *Mpflt, b *Mpflt) { + a.Val.Set(&b.Val) +} func mpaddfltflt(a *Mpflt, b *Mpflt) { if Mpdebug != 0 { @@ -29,6 +43,25 @@ func mpaddfltflt(a *Mpflt, b *Mpflt) { } } +func mpaddcflt(a *Mpflt, c float64) { + var b Mpflt + + Mpmovecflt(&b, c) + mpaddfltflt(a, &b) +} + +func mpsubfltflt(a *Mpflt, b *Mpflt) { + if Mpdebug != 0 { + fmt.Printf("\n%v - %v", Fconv(a, 0), Fconv(b, 0)) + } + + a.Val.Sub(&a.Val, &b.Val) + + if Mpdebug != 0 { + fmt.Printf(" = %v\n\n", Fconv(a, 0)) + } +} + func mpmulfltflt(a *Mpflt, b *Mpflt) { if Mpdebug != 0 { fmt.Printf("%v\n * %v\n", Fconv(a, 0), Fconv(b, 0)) @@ -41,6 +74,13 @@ func mpmulfltflt(a *Mpflt, b *Mpflt) { } } +func mpmulcflt(a *Mpflt, c float64) { + var b Mpflt + + Mpmovecflt(&b, c) + mpmulfltflt(a, &b) +} + func mpdivfltflt(a *Mpflt, b *Mpflt) { if Mpdebug != 0 { fmt.Printf("%v\n / %v\n", Fconv(a, 0), Fconv(b, 0)) @@ -53,6 +93,17 @@ func mpdivfltflt(a *Mpflt, b *Mpflt) { } } +func mpcmpfltflt(a *Mpflt, b *Mpflt) int { + return a.Val.Cmp(&b.Val) +} + +func mpcmpfltc(b *Mpflt, c float64) int { + var a Mpflt + + Mpmovecflt(&a, c) + return mpcmpfltflt(b, &a) +} + func mpgetfltN(a *Mpflt, prec int, bias int) float64 { var x float64 switch prec { @@ -103,3 +154,38 @@ func Mpmovecflt(a *Mpflt, c float64) { func mpnegflt(a *Mpflt) { a.Val.Neg(&a.Val) } + +// +// floating point input +// required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*] +// +func mpatoflt(a *Mpflt, as string) { + for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') { + as = as[1:] + } + + f, ok := a.Val.SetString(as) + if !ok { + // At the moment we lose precise error cause; + // the old code additionally distinguished between: + // - malformed hex constant + // - decimal point in hex constant + // - constant exponent out of range + // - decimal point and binary point in constant + // TODO(gri) use different conversion function or check separately + Yyerror("malformed constant: %s", as) + a.Val.SetUint64(0) + } + + if f.IsInf() { + Yyerror("constant too large: %s", as) + a.Val.SetUint64(0) + } +} + +func Fconv(fvp *Mpflt, flag int) string { + if flag&obj.FmtSharp != 0 { + return fvp.Val.Format('g', 6) + } + return fvp.Val.Format('b', 0) +}