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