github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/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 }