// 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/compile/internal/big"
"cmd/internal/obj"
"fmt"
)
/// implements fix arithmetic
func mpsetovf(a *Mpint) {
a.Val.SetUint64(1) // avoid spurious div-zero errors
a.Ovf = true
}
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.
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
}
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 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 mpaddfixfix")
}
mpsetovf(a)
return
}
a.Val.Add(&a.Val, &b.Val)
if mptestovf(a, 0) && quiet == 0 {
Yyerror("constant addition overflow")
}
}
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 {
Yyerror("ovf in mpmulfixfix")
}
mpsetovf(a)
return
}
a.Val.Mul(&a.Val, &b.Val)
if mptestovf(a, 0) {
Yyerror("constant multiplication overflow")
}
}
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 {
Yyerror("ovf in mporfixfix")
}
mpsetovf(a)
return
}
a.Val.Or(&a.Val, &b.Val)
}
func mpandfixfix(a, b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
Yyerror("ovf in mpandfixfix")
}
mpsetovf(a)
return
}
a.Val.And(&a.Val, &b.Val)
}
func mpandnotfixfix(a, b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
Yyerror("ovf in mpandnotfixfix")
}
mpsetovf(a)
return
}
a.Val.AndNot(&a.Val, &b.Val)
}
func mpxorfixfix(a, b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
Yyerror("ovf in mpxorfixfix")
}
mpsetovf(a)
return
}
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 {
Yyerror("ovf in mplshfixfix")
}
mpsetovf(a)
return
}
s := Mpgetfix(b)
if s < 0 || s >= Mpprec {
Yyerror("stupid shift: %d", s)
Mpmovecfix(a, 0)
return
}
Mpshiftfix(a, int(s))
}
func mprshfixfix(a, b *Mpint) {
if a.Ovf || b.Ovf {
if nsavederrors+nerrors == 0 {
Yyerror("ovf in mprshfixfix")
}
mpsetovf(a)
return
}
s := Mpgetfix(b)
if s < 0 || s >= Mpprec {
Yyerror("stupid shift: %d", s)
if a.Val.Sign() < 0 {
Mpmovecfix(a, -1)
} else {
Mpmovecfix(a, 0)
}
return
}
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)
}
func Mpgetfix(a *Mpint) int64 {
if a.Ovf {
if nsavederrors+nerrors == 0 {
Yyerror("constant overflow")
}
return 0
}
return a.Val.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 (x *Mpint) String() string {
return Bconv(x, 0)
}
func Bconv(xval *Mpint, flag int) string {
if flag&obj.FmtSharp != 0 {
return fmt.Sprintf("%#x", &xval.Val)
}
return xval.Val.String()
}