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
|
|
|
|
|
|
2015-03-26 18:07:19 -07:00
|
|
|
import (
|
|
|
|
|
"fmt"
|
2016-10-13 15:13:41 -04:00
|
|
|
"math/big"
|
2015-03-26 18:07:19 -07:00
|
|
|
)
|
2015-03-18 14:10:22 -07:00
|
|
|
|
2016-02-29 20:20:13 -08:00
|
|
|
// implements integer arithmetic
|
|
|
|
|
|
|
|
|
|
// Mpint represents an integer constant.
|
|
|
|
|
type Mpint struct {
|
|
|
|
|
Val big.Int
|
|
|
|
|
Ovf bool // set if Val overflowed compiler limit (sticky)
|
|
|
|
|
Rune bool // set if syntax indicates default type rune
|
|
|
|
|
}
|
2015-03-18 14:10:22 -07:00
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) SetOverflow() {
|
2015-04-21 10:39:21 -07:00
|
|
|
a.Val.SetUint64(1) // avoid spurious div-zero errors
|
2015-03-18 14:10:22 -07:00
|
|
|
a.Ovf = true
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) checkOverflow(extra int) bool {
|
2015-03-18 14:10:22 -07:00
|
|
|
// 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.
|
2015-03-26 18:07:19 -07:00
|
|
|
if a.Val.BitLen()+extra > Mpprec {
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetOverflow()
|
2015-03-18 14:10:22 -07:00
|
|
|
}
|
|
|
|
|
return a.Ovf
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) Set(b *Mpint) {
|
2015-03-26 18:07:19 -07:00
|
|
|
a.Val.Set(&b.Val)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) SetFloat(b *Mpflt) int {
|
2015-12-03 15:51:03 -08:00
|
|
|
// 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 {
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-26 18:07:19 -07:00
|
|
|
if _, acc := b.Val.Int(&a.Val); acc == big.Exact {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-02 16:34:48 -07:00
|
|
|
const delta = 16 // a reasonably small number of bits > 0
|
2015-03-26 18:07:19 -07:00
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-23 11:07:20 -07:00
|
|
|
func (a *Mpint) Add(b *Mpint) {
|
2015-03-18 14:10:22 -07:00
|
|
|
if a.Ovf || b.Ovf {
|
|
|
|
|
if nsavederrors+nerrors == 0 {
|
2016-09-30 11:27:52 +02:00
|
|
|
yyerror("ovf in Mpint Add")
|
2015-03-18 14:10:22 -07:00
|
|
|
}
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetOverflow()
|
2015-03-18 14:10:22 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.Val.Add(&a.Val, &b.Val)
|
|
|
|
|
|
2016-03-23 11:07:20 -07:00
|
|
|
if a.checkOverflow(0) {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("constant addition overflow")
|
2015-03-18 14:10:22 -07:00
|
|
|
}
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) Sub(b *Mpint) {
|
2015-03-26 18:07:19 -07:00
|
|
|
if a.Ovf || b.Ovf {
|
|
|
|
|
if nsavederrors+nerrors == 0 {
|
2016-09-30 11:27:52 +02:00
|
|
|
yyerror("ovf in Mpint Sub")
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetOverflow()
|
2015-03-26 18:07:19 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.Val.Sub(&a.Val, &b.Val)
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
if a.checkOverflow(0) {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("constant subtraction overflow")
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) Mul(b *Mpint) {
|
2015-03-18 14:10:22 -07:00
|
|
|
if a.Ovf || b.Ovf {
|
|
|
|
|
if nsavederrors+nerrors == 0 {
|
2016-09-30 11:27:52 +02:00
|
|
|
yyerror("ovf in Mpint Mul")
|
2015-03-18 14:10:22 -07:00
|
|
|
}
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetOverflow()
|
2015-03-18 14:10:22 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.Val.Mul(&a.Val, &b.Val)
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
if a.checkOverflow(0) {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("constant multiplication overflow")
|
2015-03-18 14:10:22 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) Quo(b *Mpint) {
|
2015-03-26 18:07:19 -07:00
|
|
|
if a.Ovf || b.Ovf {
|
|
|
|
|
if nsavederrors+nerrors == 0 {
|
2016-09-30 11:27:52 +02:00
|
|
|
yyerror("ovf in Mpint Quo")
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetOverflow()
|
2015-03-26 18:07:19 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.Val.Quo(&a.Val, &b.Val)
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
if a.checkOverflow(0) {
|
2015-03-26 18:07:19 -07:00
|
|
|
// can only happen for div-0 which should be checked elsewhere
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("constant division overflow")
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) Rem(b *Mpint) {
|
2015-03-26 18:07:19 -07:00
|
|
|
if a.Ovf || b.Ovf {
|
|
|
|
|
if nsavederrors+nerrors == 0 {
|
2016-09-30 11:27:52 +02:00
|
|
|
yyerror("ovf in Mpint Rem")
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetOverflow()
|
2015-03-26 18:07:19 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.Val.Rem(&a.Val, &b.Val)
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
if a.checkOverflow(0) {
|
2015-03-26 18:07:19 -07:00
|
|
|
// should never happen
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("constant modulo overflow")
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) Or(b *Mpint) {
|
2015-03-18 14:10:22 -07:00
|
|
|
if a.Ovf || b.Ovf {
|
|
|
|
|
if nsavederrors+nerrors == 0 {
|
2016-09-30 11:27:52 +02:00
|
|
|
yyerror("ovf in Mpint Or")
|
2015-03-18 14:10:22 -07:00
|
|
|
}
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetOverflow()
|
2015-03-18 14:10:22 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.Val.Or(&a.Val, &b.Val)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) And(b *Mpint) {
|
2015-03-18 14:10:22 -07:00
|
|
|
if a.Ovf || b.Ovf {
|
|
|
|
|
if nsavederrors+nerrors == 0 {
|
2016-09-30 11:27:52 +02:00
|
|
|
yyerror("ovf in Mpint And")
|
2015-03-18 14:10:22 -07:00
|
|
|
}
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetOverflow()
|
2015-03-18 14:10:22 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.Val.And(&a.Val, &b.Val)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) AndNot(b *Mpint) {
|
2015-03-18 14:10:22 -07:00
|
|
|
if a.Ovf || b.Ovf {
|
|
|
|
|
if nsavederrors+nerrors == 0 {
|
2016-09-30 11:27:52 +02:00
|
|
|
yyerror("ovf in Mpint AndNot")
|
2015-03-18 14:10:22 -07:00
|
|
|
}
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetOverflow()
|
2015-03-18 14:10:22 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.Val.AndNot(&a.Val, &b.Val)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) Xor(b *Mpint) {
|
2015-03-18 14:10:22 -07:00
|
|
|
if a.Ovf || b.Ovf {
|
|
|
|
|
if nsavederrors+nerrors == 0 {
|
2016-09-30 11:27:52 +02:00
|
|
|
yyerror("ovf in Mpint Xor")
|
2015-03-18 14:10:22 -07:00
|
|
|
}
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetOverflow()
|
2015-03-18 14:10:22 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
a.Val.Xor(&a.Val, &b.Val)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) Lsh(b *Mpint) {
|
2015-03-18 14:10:22 -07:00
|
|
|
if a.Ovf || b.Ovf {
|
2015-02-13 14:40:36 -05:00
|
|
|
if nsavederrors+nerrors == 0 {
|
2016-09-30 11:27:52 +02:00
|
|
|
yyerror("ovf in Mpint Lsh")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetOverflow()
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
s := b.Int64()
|
2015-03-26 18:07:19 -07:00
|
|
|
if s < 0 || s >= Mpprec {
|
2016-02-23 13:35:12 -08:00
|
|
|
msg := "shift count too large"
|
|
|
|
|
if s < 0 {
|
|
|
|
|
msg = "invalid negative shift count"
|
|
|
|
|
}
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("%s: %d", msg, s)
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetInt64(0)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-23 11:07:20 -07:00
|
|
|
if a.checkOverflow(int(s)) {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("constant shift overflow")
|
2016-03-23 11:07:20 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
a.Val.Lsh(&a.Val, uint(s))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) Rsh(b *Mpint) {
|
2015-03-18 14:10:22 -07:00
|
|
|
if a.Ovf || b.Ovf {
|
|
|
|
|
if nsavederrors+nerrors == 0 {
|
2016-09-30 11:27:52 +02:00
|
|
|
yyerror("ovf in Mpint Rsh")
|
2015-03-18 14:10:22 -07:00
|
|
|
}
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetOverflow()
|
2015-03-18 14:10:22 -07:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
s := b.Int64()
|
2015-08-20 17:53:41 +02:00
|
|
|
if s < 0 {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("invalid negative shift count: %d", s)
|
2015-03-18 14:10:22 -07:00
|
|
|
if a.Val.Sign() < 0 {
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetInt64(-1)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2016-03-20 13:55:42 -07:00
|
|
|
a.SetInt64(0)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-23 11:07:20 -07:00
|
|
|
a.Val.Rsh(&a.Val, uint(s))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) Cmp(b *Mpint) int {
|
2015-03-26 18:07:19 -07:00
|
|
|
return a.Val.Cmp(&b.Val)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-21 10:52:03 -07:00
|
|
|
func (a *Mpint) CmpInt64(c int64) int {
|
|
|
|
|
if c == 0 {
|
|
|
|
|
return a.Val.Sign() // common case shortcut
|
|
|
|
|
}
|
|
|
|
|
return a.Val.Cmp(big.NewInt(c))
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) Neg() {
|
2015-03-18 14:10:22 -07:00
|
|
|
a.Val.Neg(&a.Val)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) Int64() int64 {
|
2015-03-18 14:10:22 -07:00
|
|
|
if a.Ovf {
|
|
|
|
|
if nsavederrors+nerrors == 0 {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("constant overflow")
|
2015-03-18 14:10:22 -07:00
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return a.Val.Int64()
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) SetInt64(c int64) {
|
2015-03-18 14:10:22 -07:00
|
|
|
a.Val.SetInt64(c)
|
|
|
|
|
}
|
2015-03-26 18:07:19 -07:00
|
|
|
|
2016-03-20 13:55:42 -07:00
|
|
|
func (a *Mpint) SetString(as string) {
|
2015-03-26 18:07:19 -07:00
|
|
|
_, 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
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("malformed integer constant: %s", as)
|
2015-03-26 18:07:19 -07:00
|
|
|
a.Val.SetUint64(0)
|
|
|
|
|
return
|
|
|
|
|
}
|
2016-03-20 13:55:42 -07:00
|
|
|
if a.checkOverflow(0) {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("constant too large: %s", as)
|
2015-03-26 18:07:19 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-17 11:56:29 -04:00
|
|
|
func (x *Mpint) String() string {
|
cmd/compile/internal/gc: unexport {J,S,F,H,B,V}conv
Updates #15462
Unexport Jconv, Sconv, Fconv, Hconv, Bconv, and VConv as they are
not referenced outside internal/gc.
Econv was only called by EType.String, so merge it into that method.
Change-Id: Iad9b06078eb513b85a03a43cd9eb9366477643d1
Reviewed-on: https://go-review.googlesource.com/22531
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Dave Cheney <dave@cheney.net>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-04-27 15:15:47 +10:00
|
|
|
return bconv(x, 0)
|
2015-04-17 11:56:29 -04:00
|
|
|
}
|
|
|
|
|
|
cmd/compile/internal/gc: unexport {J,S,F,H,B,V}conv
Updates #15462
Unexport Jconv, Sconv, Fconv, Hconv, Bconv, and VConv as they are
not referenced outside internal/gc.
Econv was only called by EType.String, so merge it into that method.
Change-Id: Iad9b06078eb513b85a03a43cd9eb9366477643d1
Reviewed-on: https://go-review.googlesource.com/22531
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Dave Cheney <dave@cheney.net>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-04-27 15:15:47 +10:00
|
|
|
func bconv(xval *Mpint, flag FmtFlag) string {
|
2016-03-15 13:06:58 -07:00
|
|
|
if flag&FmtSharp != 0 {
|
2015-03-26 18:07:19 -07:00
|
|
|
return fmt.Sprintf("%#x", &xval.Val)
|
|
|
|
|
}
|
|
|
|
|
return xval.Val.String()
|
|
|
|
|
}
|