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