Home | History | Annotate | Download | only in gc
      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 	"fmt"
      9 	"math/big"
     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) bool {
     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 		a.SetOverflow()
     44 		return false
     45 	}
     46 
     47 	if _, acc := b.Val.Int(&a.Val); acc == big.Exact {
     48 		return true
     49 	}
     50 
     51 	const delta = 16 // a reasonably small number of bits > 0
     52 	var t big.Float
     53 	t.SetPrec(Mpprec - delta)
     54 
     55 	// try rounding down a little
     56 	t.SetMode(big.ToZero)
     57 	t.Set(&b.Val)
     58 	if _, acc := t.Int(&a.Val); acc == big.Exact {
     59 		return true
     60 	}
     61 
     62 	// try rounding up a little
     63 	t.SetMode(big.AwayFromZero)
     64 	t.Set(&b.Val)
     65 	if _, acc := t.Int(&a.Val); acc == big.Exact {
     66 		return true
     67 	}
     68 
     69 	a.Ovf = false
     70 	return false
     71 }
     72 
     73 func (a *Mpint) Add(b *Mpint) {
     74 	if a.Ovf || b.Ovf {
     75 		if nsavederrors+nerrors == 0 {
     76 			Fatalf("ovf in Mpint Add")
     77 		}
     78 		a.SetOverflow()
     79 		return
     80 	}
     81 
     82 	a.Val.Add(&a.Val, &b.Val)
     83 
     84 	if a.checkOverflow(0) {
     85 		yyerror("constant addition overflow")
     86 	}
     87 }
     88 
     89 func (a *Mpint) Sub(b *Mpint) {
     90 	if a.Ovf || b.Ovf {
     91 		if nsavederrors+nerrors == 0 {
     92 			Fatalf("ovf in Mpint Sub")
     93 		}
     94 		a.SetOverflow()
     95 		return
     96 	}
     97 
     98 	a.Val.Sub(&a.Val, &b.Val)
     99 
    100 	if a.checkOverflow(0) {
    101 		yyerror("constant subtraction overflow")
    102 	}
    103 }
    104 
    105 func (a *Mpint) Mul(b *Mpint) {
    106 	if a.Ovf || b.Ovf {
    107 		if nsavederrors+nerrors == 0 {
    108 			Fatalf("ovf in Mpint Mul")
    109 		}
    110 		a.SetOverflow()
    111 		return
    112 	}
    113 
    114 	a.Val.Mul(&a.Val, &b.Val)
    115 
    116 	if a.checkOverflow(0) {
    117 		yyerror("constant multiplication overflow")
    118 	}
    119 }
    120 
    121 func (a *Mpint) Quo(b *Mpint) {
    122 	if a.Ovf || b.Ovf {
    123 		if nsavederrors+nerrors == 0 {
    124 			Fatalf("ovf in Mpint Quo")
    125 		}
    126 		a.SetOverflow()
    127 		return
    128 	}
    129 
    130 	a.Val.Quo(&a.Val, &b.Val)
    131 
    132 	if a.checkOverflow(0) {
    133 		// can only happen for div-0 which should be checked elsewhere
    134 		yyerror("constant division overflow")
    135 	}
    136 }
    137 
    138 func (a *Mpint) Rem(b *Mpint) {
    139 	if a.Ovf || b.Ovf {
    140 		if nsavederrors+nerrors == 0 {
    141 			Fatalf("ovf in Mpint Rem")
    142 		}
    143 		a.SetOverflow()
    144 		return
    145 	}
    146 
    147 	a.Val.Rem(&a.Val, &b.Val)
    148 
    149 	if a.checkOverflow(0) {
    150 		// should never happen
    151 		yyerror("constant modulo overflow")
    152 	}
    153 }
    154 
    155 func (a *Mpint) Or(b *Mpint) {
    156 	if a.Ovf || b.Ovf {
    157 		if nsavederrors+nerrors == 0 {
    158 			Fatalf("ovf in Mpint Or")
    159 		}
    160 		a.SetOverflow()
    161 		return
    162 	}
    163 
    164 	a.Val.Or(&a.Val, &b.Val)
    165 }
    166 
    167 func (a *Mpint) And(b *Mpint) {
    168 	if a.Ovf || b.Ovf {
    169 		if nsavederrors+nerrors == 0 {
    170 			Fatalf("ovf in Mpint And")
    171 		}
    172 		a.SetOverflow()
    173 		return
    174 	}
    175 
    176 	a.Val.And(&a.Val, &b.Val)
    177 }
    178 
    179 func (a *Mpint) AndNot(b *Mpint) {
    180 	if a.Ovf || b.Ovf {
    181 		if nsavederrors+nerrors == 0 {
    182 			Fatalf("ovf in Mpint AndNot")
    183 		}
    184 		a.SetOverflow()
    185 		return
    186 	}
    187 
    188 	a.Val.AndNot(&a.Val, &b.Val)
    189 }
    190 
    191 func (a *Mpint) Xor(b *Mpint) {
    192 	if a.Ovf || b.Ovf {
    193 		if nsavederrors+nerrors == 0 {
    194 			Fatalf("ovf in Mpint Xor")
    195 		}
    196 		a.SetOverflow()
    197 		return
    198 	}
    199 
    200 	a.Val.Xor(&a.Val, &b.Val)
    201 }
    202 
    203 func (a *Mpint) Lsh(b *Mpint) {
    204 	if a.Ovf || b.Ovf {
    205 		if nsavederrors+nerrors == 0 {
    206 			Fatalf("ovf in Mpint Lsh")
    207 		}
    208 		a.SetOverflow()
    209 		return
    210 	}
    211 
    212 	s := b.Int64()
    213 	if s < 0 || s >= Mpprec {
    214 		msg := "shift count too large"
    215 		if s < 0 {
    216 			msg = "invalid negative shift count"
    217 		}
    218 		yyerror("%s: %d", msg, s)
    219 		a.SetInt64(0)
    220 		return
    221 	}
    222 
    223 	if a.checkOverflow(int(s)) {
    224 		yyerror("constant shift overflow")
    225 		return
    226 	}
    227 	a.Val.Lsh(&a.Val, uint(s))
    228 }
    229 
    230 func (a *Mpint) Rsh(b *Mpint) {
    231 	if a.Ovf || b.Ovf {
    232 		if nsavederrors+nerrors == 0 {
    233 			Fatalf("ovf in Mpint Rsh")
    234 		}
    235 		a.SetOverflow()
    236 		return
    237 	}
    238 
    239 	s := b.Int64()
    240 	if s < 0 {
    241 		yyerror("invalid negative shift count: %d", s)
    242 		if a.Val.Sign() < 0 {
    243 			a.SetInt64(-1)
    244 		} else {
    245 			a.SetInt64(0)
    246 		}
    247 		return
    248 	}
    249 
    250 	a.Val.Rsh(&a.Val, uint(s))
    251 }
    252 
    253 func (a *Mpint) Cmp(b *Mpint) int {
    254 	return a.Val.Cmp(&b.Val)
    255 }
    256 
    257 func (a *Mpint) CmpInt64(c int64) int {
    258 	if c == 0 {
    259 		return a.Val.Sign() // common case shortcut
    260 	}
    261 	return a.Val.Cmp(big.NewInt(c))
    262 }
    263 
    264 func (a *Mpint) Neg() {
    265 	a.Val.Neg(&a.Val)
    266 }
    267 
    268 func (a *Mpint) Int64() int64 {
    269 	if a.Ovf {
    270 		if nsavederrors+nerrors == 0 {
    271 			Fatalf("constant overflow")
    272 		}
    273 		return 0
    274 	}
    275 
    276 	return a.Val.Int64()
    277 }
    278 
    279 func (a *Mpint) SetInt64(c int64) {
    280 	a.Val.SetInt64(c)
    281 }
    282 
    283 func (a *Mpint) SetString(as string) {
    284 	_, ok := a.Val.SetString(as, 0)
    285 	if !ok {
    286 		// required syntax is [+-][0[x]]d*
    287 		// At the moment we lose precise error cause;
    288 		// the old code distinguished between:
    289 		// - malformed hex constant
    290 		// - malformed octal constant
    291 		// - malformed decimal constant
    292 		// TODO(gri) use different conversion function
    293 		yyerror("malformed integer constant: %s", as)
    294 		a.Val.SetUint64(0)
    295 		return
    296 	}
    297 	if a.checkOverflow(0) {
    298 		yyerror("constant too large: %s", as)
    299 	}
    300 }
    301 
    302 func (x *Mpint) String() string {
    303 	return bconv(x, 0)
    304 }
    305 
    306 func bconv(xval *Mpint, flag FmtFlag) string {
    307 	if flag&FmtSharp != 0 {
    308 		return fmt.Sprintf("%#x", &xval.Val)
    309 	}
    310 	return xval.Val.String()
    311 }
    312