github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/gc/mpint.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package gc
     6  
     7  import (
     8  	"cmd/compile/internal/big"
     9  	"fmt"
    10  )
    11  
    12  // implements integer arithmetic
    13  
    14  // Mpint represents an integer constant.
    15  type Mpint struct {
    16  	Val  big.Int
    17  	Ovf  bool // set if Val overflowed compiler limit (sticky)
    18  	Rune bool // set if syntax indicates default type rune
    19  }
    20  
    21  func (a *Mpint) SetOverflow() {
    22  	a.Val.SetUint64(1) // avoid spurious div-zero errors
    23  	a.Ovf = true
    24  }
    25  
    26  func (a *Mpint) checkOverflow(extra int) bool {
    27  	// We don't need to be precise here, any reasonable upper limit would do.
    28  	// For now, use existing limit so we pass all the tests unchanged.
    29  	if a.Val.BitLen()+extra > Mpprec {
    30  		a.SetOverflow()
    31  	}
    32  	return a.Ovf
    33  }
    34  
    35  func (a *Mpint) Set(b *Mpint) {
    36  	a.Val.Set(&b.Val)
    37  }
    38  
    39  func (a *Mpint) SetFloat(b *Mpflt) int {
    40  	// avoid converting huge floating-point numbers to integers
    41  	// (2*Mpprec is large enough to permit all tests to pass)
    42  	if b.Val.MantExp(nil) > 2*Mpprec {
    43  		return -1
    44  	}
    45  
    46  	if _, acc := b.Val.Int(&a.Val); acc == big.Exact {
    47  		return 0
    48  	}
    49  
    50  	const delta = 16 // a reasonably small number of bits > 0
    51  	var t big.Float
    52  	t.SetPrec(Mpprec - delta)
    53  
    54  	// try rounding down a little
    55  	t.SetMode(big.ToZero)
    56  	t.Set(&b.Val)
    57  	if _, acc := t.Int(&a.Val); acc == big.Exact {
    58  		return 0
    59  	}
    60  
    61  	// try rounding up a little
    62  	t.SetMode(big.AwayFromZero)
    63  	t.Set(&b.Val)
    64  	if _, acc := t.Int(&a.Val); acc == big.Exact {
    65  		return 0
    66  	}
    67  
    68  	return -1
    69  }
    70  
    71  func (a *Mpint) Add(b *Mpint) {
    72  	if a.Ovf || b.Ovf {
    73  		if nsavederrors+nerrors == 0 {
    74  			Yyerror("ovf in mpaddfixfix")
    75  		}
    76  		a.SetOverflow()
    77  		return
    78  	}
    79  
    80  	a.Val.Add(&a.Val, &b.Val)
    81  
    82  	if a.checkOverflow(0) {
    83  		Yyerror("constant addition overflow")
    84  	}
    85  }
    86  
    87  func (a *Mpint) Sub(b *Mpint) {
    88  	if a.Ovf || b.Ovf {
    89  		if nsavederrors+nerrors == 0 {
    90  			Yyerror("ovf in mpsubfixfix")
    91  		}
    92  		a.SetOverflow()
    93  		return
    94  	}
    95  
    96  	a.Val.Sub(&a.Val, &b.Val)
    97  
    98  	if a.checkOverflow(0) {
    99  		Yyerror("constant subtraction overflow")
   100  	}
   101  }
   102  
   103  func (a *Mpint) Mul(b *Mpint) {
   104  	if a.Ovf || b.Ovf {
   105  		if nsavederrors+nerrors == 0 {
   106  			Yyerror("ovf in mpmulfixfix")
   107  		}
   108  		a.SetOverflow()
   109  		return
   110  	}
   111  
   112  	a.Val.Mul(&a.Val, &b.Val)
   113  
   114  	if a.checkOverflow(0) {
   115  		Yyerror("constant multiplication overflow")
   116  	}
   117  }
   118  
   119  func (a *Mpint) Quo(b *Mpint) {
   120  	if a.Ovf || b.Ovf {
   121  		if nsavederrors+nerrors == 0 {
   122  			Yyerror("ovf in mpdivfixfix")
   123  		}
   124  		a.SetOverflow()
   125  		return
   126  	}
   127  
   128  	a.Val.Quo(&a.Val, &b.Val)
   129  
   130  	if a.checkOverflow(0) {
   131  		// can only happen for div-0 which should be checked elsewhere
   132  		Yyerror("constant division overflow")
   133  	}
   134  }
   135  
   136  func (a *Mpint) Rem(b *Mpint) {
   137  	if a.Ovf || b.Ovf {
   138  		if nsavederrors+nerrors == 0 {
   139  			Yyerror("ovf in mpmodfixfix")
   140  		}
   141  		a.SetOverflow()
   142  		return
   143  	}
   144  
   145  	a.Val.Rem(&a.Val, &b.Val)
   146  
   147  	if a.checkOverflow(0) {
   148  		// should never happen
   149  		Yyerror("constant modulo overflow")
   150  	}
   151  }
   152  
   153  func (a *Mpint) Or(b *Mpint) {
   154  	if a.Ovf || b.Ovf {
   155  		if nsavederrors+nerrors == 0 {
   156  			Yyerror("ovf in mporfixfix")
   157  		}
   158  		a.SetOverflow()
   159  		return
   160  	}
   161  
   162  	a.Val.Or(&a.Val, &b.Val)
   163  }
   164  
   165  func (a *Mpint) And(b *Mpint) {
   166  	if a.Ovf || b.Ovf {
   167  		if nsavederrors+nerrors == 0 {
   168  			Yyerror("ovf in mpandfixfix")
   169  		}
   170  		a.SetOverflow()
   171  		return
   172  	}
   173  
   174  	a.Val.And(&a.Val, &b.Val)
   175  }
   176  
   177  func (a *Mpint) AndNot(b *Mpint) {
   178  	if a.Ovf || b.Ovf {
   179  		if nsavederrors+nerrors == 0 {
   180  			Yyerror("ovf in mpandnotfixfix")
   181  		}
   182  		a.SetOverflow()
   183  		return
   184  	}
   185  
   186  	a.Val.AndNot(&a.Val, &b.Val)
   187  }
   188  
   189  func (a *Mpint) Xor(b *Mpint) {
   190  	if a.Ovf || b.Ovf {
   191  		if nsavederrors+nerrors == 0 {
   192  			Yyerror("ovf in mpxorfixfix")
   193  		}
   194  		a.SetOverflow()
   195  		return
   196  	}
   197  
   198  	a.Val.Xor(&a.Val, &b.Val)
   199  }
   200  
   201  func (a *Mpint) Lsh(b *Mpint) {
   202  	if a.Ovf || b.Ovf {
   203  		if nsavederrors+nerrors == 0 {
   204  			Yyerror("ovf in mplshfixfix")
   205  		}
   206  		a.SetOverflow()
   207  		return
   208  	}
   209  
   210  	s := b.Int64()
   211  	if s < 0 || s >= Mpprec {
   212  		msg := "shift count too large"
   213  		if s < 0 {
   214  			msg = "invalid negative shift count"
   215  		}
   216  		Yyerror("%s: %d", msg, s)
   217  		a.SetInt64(0)
   218  		return
   219  	}
   220  
   221  	if a.checkOverflow(int(s)) {
   222  		Yyerror("constant shift overflow")
   223  		return
   224  	}
   225  	a.Val.Lsh(&a.Val, uint(s))
   226  }
   227  
   228  func (a *Mpint) Rsh(b *Mpint) {
   229  	if a.Ovf || b.Ovf {
   230  		if nsavederrors+nerrors == 0 {
   231  			Yyerror("ovf in mprshfixfix")
   232  		}
   233  		a.SetOverflow()
   234  		return
   235  	}
   236  
   237  	s := b.Int64()
   238  	if s < 0 {
   239  		Yyerror("invalid negative shift count: %d", s)
   240  		if a.Val.Sign() < 0 {
   241  			a.SetInt64(-1)
   242  		} else {
   243  			a.SetInt64(0)
   244  		}
   245  		return
   246  	}
   247  
   248  	a.Val.Rsh(&a.Val, uint(s))
   249  }
   250  
   251  func (a *Mpint) Cmp(b *Mpint) int {
   252  	return a.Val.Cmp(&b.Val)
   253  }
   254  
   255  func (a *Mpint) CmpInt64(c int64) int {
   256  	if c == 0 {
   257  		return a.Val.Sign() // common case shortcut
   258  	}
   259  	return a.Val.Cmp(big.NewInt(c))
   260  }
   261  
   262  func (a *Mpint) Neg() {
   263  	a.Val.Neg(&a.Val)
   264  }
   265  
   266  func (a *Mpint) Int64() int64 {
   267  	if a.Ovf {
   268  		if nsavederrors+nerrors == 0 {
   269  			Yyerror("constant overflow")
   270  		}
   271  		return 0
   272  	}
   273  
   274  	return a.Val.Int64()
   275  }
   276  
   277  func (a *Mpint) SetInt64(c int64) {
   278  	a.Val.SetInt64(c)
   279  }
   280  
   281  func (a *Mpint) SetString(as string) {
   282  	_, ok := a.Val.SetString(as, 0)
   283  	if !ok {
   284  		// required syntax is [+-][0[x]]d*
   285  		// At the moment we lose precise error cause;
   286  		// the old code distinguished between:
   287  		// - malformed hex constant
   288  		// - malformed octal constant
   289  		// - malformed decimal constant
   290  		// TODO(gri) use different conversion function
   291  		Yyerror("malformed integer constant: %s", as)
   292  		a.Val.SetUint64(0)
   293  		return
   294  	}
   295  	if a.checkOverflow(0) {
   296  		Yyerror("constant too large: %s", as)
   297  	}
   298  }
   299  
   300  func (x *Mpint) String() string {
   301  	return bconv(x, 0)
   302  }
   303  
   304  func bconv(xval *Mpint, flag FmtFlag) string {
   305  	if flag&FmtSharp != 0 {
   306  		return fmt.Sprintf("%#x", &xval.Val)
   307  	}
   308  	return xval.Val.String()
   309  }