github.com/golangci/go-tools@v0.0.0-20190318060251-af6baa5dc196/staticcheck/vrp/int.go (about) 1 package vrp 2 3 import ( 4 "fmt" 5 "go/token" 6 "go/types" 7 "math/big" 8 9 "github.com/golangci/go-tools/ssa" 10 ) 11 12 type Zs []Z 13 14 func (zs Zs) Len() int { 15 return len(zs) 16 } 17 18 func (zs Zs) Less(i int, j int) bool { 19 return zs[i].Cmp(zs[j]) == -1 20 } 21 22 func (zs Zs) Swap(i int, j int) { 23 zs[i], zs[j] = zs[j], zs[i] 24 } 25 26 type Z struct { 27 infinity int8 28 integer *big.Int 29 } 30 31 func NewZ(n int64) Z { 32 return NewBigZ(big.NewInt(n)) 33 } 34 35 func NewBigZ(n *big.Int) Z { 36 return Z{integer: n} 37 } 38 39 func (z1 Z) Infinite() bool { 40 return z1.infinity != 0 41 } 42 43 func (z1 Z) Add(z2 Z) Z { 44 if z2.Sign() == -1 { 45 return z1.Sub(z2.Negate()) 46 } 47 if z1 == NInfinity { 48 return NInfinity 49 } 50 if z1 == PInfinity { 51 return PInfinity 52 } 53 if z2 == PInfinity { 54 return PInfinity 55 } 56 57 if !z1.Infinite() && !z2.Infinite() { 58 n := &big.Int{} 59 n.Add(z1.integer, z2.integer) 60 return NewBigZ(n) 61 } 62 63 panic(fmt.Sprintf("%s + %s is not defined", z1, z2)) 64 } 65 66 func (z1 Z) Sub(z2 Z) Z { 67 if z2.Sign() == -1 { 68 return z1.Add(z2.Negate()) 69 } 70 if !z1.Infinite() && !z2.Infinite() { 71 n := &big.Int{} 72 n.Sub(z1.integer, z2.integer) 73 return NewBigZ(n) 74 } 75 76 if z1 != PInfinity && z2 == PInfinity { 77 return NInfinity 78 } 79 if z1.Infinite() && !z2.Infinite() { 80 return Z{infinity: z1.infinity} 81 } 82 if z1 == PInfinity && z2 == PInfinity { 83 return PInfinity 84 } 85 panic(fmt.Sprintf("%s - %s is not defined", z1, z2)) 86 } 87 88 func (z1 Z) Mul(z2 Z) Z { 89 if (z1.integer != nil && z1.integer.Sign() == 0) || 90 (z2.integer != nil && z2.integer.Sign() == 0) { 91 return NewBigZ(&big.Int{}) 92 } 93 94 if z1.infinity != 0 || z2.infinity != 0 { 95 return Z{infinity: int8(z1.Sign() * z2.Sign())} 96 } 97 98 n := &big.Int{} 99 n.Mul(z1.integer, z2.integer) 100 return NewBigZ(n) 101 } 102 103 func (z1 Z) Negate() Z { 104 if z1.infinity == 1 { 105 return NInfinity 106 } 107 if z1.infinity == -1 { 108 return PInfinity 109 } 110 n := &big.Int{} 111 n.Neg(z1.integer) 112 return NewBigZ(n) 113 } 114 115 func (z1 Z) Sign() int { 116 if z1.infinity != 0 { 117 return int(z1.infinity) 118 } 119 return z1.integer.Sign() 120 } 121 122 func (z1 Z) String() string { 123 if z1 == NInfinity { 124 return "-∞" 125 } 126 if z1 == PInfinity { 127 return "∞" 128 } 129 return fmt.Sprintf("%d", z1.integer) 130 } 131 132 func (z1 Z) Cmp(z2 Z) int { 133 if z1.infinity == z2.infinity && z1.infinity != 0 { 134 return 0 135 } 136 if z1 == PInfinity { 137 return 1 138 } 139 if z1 == NInfinity { 140 return -1 141 } 142 if z2 == NInfinity { 143 return 1 144 } 145 if z2 == PInfinity { 146 return -1 147 } 148 return z1.integer.Cmp(z2.integer) 149 } 150 151 func MaxZ(zs ...Z) Z { 152 if len(zs) == 0 { 153 panic("Max called with no arguments") 154 } 155 if len(zs) == 1 { 156 return zs[0] 157 } 158 ret := zs[0] 159 for _, z := range zs[1:] { 160 if z.Cmp(ret) == 1 { 161 ret = z 162 } 163 } 164 return ret 165 } 166 167 func MinZ(zs ...Z) Z { 168 if len(zs) == 0 { 169 panic("Min called with no arguments") 170 } 171 if len(zs) == 1 { 172 return zs[0] 173 } 174 ret := zs[0] 175 for _, z := range zs[1:] { 176 if z.Cmp(ret) == -1 { 177 ret = z 178 } 179 } 180 return ret 181 } 182 183 var NInfinity = Z{infinity: -1} 184 var PInfinity = Z{infinity: 1} 185 var EmptyIntInterval = IntInterval{true, PInfinity, NInfinity} 186 187 func InfinityFor(v ssa.Value) IntInterval { 188 if b, ok := v.Type().Underlying().(*types.Basic); ok { 189 if (b.Info() & types.IsUnsigned) != 0 { 190 return NewIntInterval(NewZ(0), PInfinity) 191 } 192 } 193 return NewIntInterval(NInfinity, PInfinity) 194 } 195 196 type IntInterval struct { 197 known bool 198 Lower Z 199 Upper Z 200 } 201 202 func NewIntInterval(l, u Z) IntInterval { 203 if u.Cmp(l) == -1 { 204 return EmptyIntInterval 205 } 206 return IntInterval{known: true, Lower: l, Upper: u} 207 } 208 209 func (i IntInterval) IsKnown() bool { 210 return i.known 211 } 212 213 func (i IntInterval) Empty() bool { 214 return i.Lower == PInfinity && i.Upper == NInfinity 215 } 216 217 func (i IntInterval) IsMaxRange() bool { 218 return i.Lower == NInfinity && i.Upper == PInfinity 219 } 220 221 func (i1 IntInterval) Intersection(i2 IntInterval) IntInterval { 222 if !i1.IsKnown() { 223 return i2 224 } 225 if !i2.IsKnown() { 226 return i1 227 } 228 if i1.Empty() || i2.Empty() { 229 return EmptyIntInterval 230 } 231 i3 := NewIntInterval(MaxZ(i1.Lower, i2.Lower), MinZ(i1.Upper, i2.Upper)) 232 if i3.Lower.Cmp(i3.Upper) == 1 { 233 return EmptyIntInterval 234 } 235 return i3 236 } 237 238 func (i1 IntInterval) Union(other Range) Range { 239 i2, ok := other.(IntInterval) 240 if !ok { 241 i2 = EmptyIntInterval 242 } 243 if i1.Empty() || !i1.IsKnown() { 244 return i2 245 } 246 if i2.Empty() || !i2.IsKnown() { 247 return i1 248 } 249 return NewIntInterval(MinZ(i1.Lower, i2.Lower), MaxZ(i1.Upper, i2.Upper)) 250 } 251 252 func (i1 IntInterval) Add(i2 IntInterval) IntInterval { 253 if i1.Empty() || i2.Empty() { 254 return EmptyIntInterval 255 } 256 l1, u1, l2, u2 := i1.Lower, i1.Upper, i2.Lower, i2.Upper 257 return NewIntInterval(l1.Add(l2), u1.Add(u2)) 258 } 259 260 func (i1 IntInterval) Sub(i2 IntInterval) IntInterval { 261 if i1.Empty() || i2.Empty() { 262 return EmptyIntInterval 263 } 264 l1, u1, l2, u2 := i1.Lower, i1.Upper, i2.Lower, i2.Upper 265 return NewIntInterval(l1.Sub(u2), u1.Sub(l2)) 266 } 267 268 func (i1 IntInterval) Mul(i2 IntInterval) IntInterval { 269 if i1.Empty() || i2.Empty() { 270 return EmptyIntInterval 271 } 272 x1, x2 := i1.Lower, i1.Upper 273 y1, y2 := i2.Lower, i2.Upper 274 return NewIntInterval( 275 MinZ(x1.Mul(y1), x1.Mul(y2), x2.Mul(y1), x2.Mul(y2)), 276 MaxZ(x1.Mul(y1), x1.Mul(y2), x2.Mul(y1), x2.Mul(y2)), 277 ) 278 } 279 280 func (i1 IntInterval) String() string { 281 if !i1.IsKnown() { 282 return "[⊥, ⊥]" 283 } 284 if i1.Empty() { 285 return "{}" 286 } 287 return fmt.Sprintf("[%s, %s]", i1.Lower, i1.Upper) 288 } 289 290 type IntArithmeticConstraint struct { 291 aConstraint 292 A ssa.Value 293 B ssa.Value 294 Op token.Token 295 Fn func(IntInterval, IntInterval) IntInterval 296 } 297 298 type IntAddConstraint struct{ *IntArithmeticConstraint } 299 type IntSubConstraint struct{ *IntArithmeticConstraint } 300 type IntMulConstraint struct{ *IntArithmeticConstraint } 301 302 type IntConversionConstraint struct { 303 aConstraint 304 X ssa.Value 305 } 306 307 type IntIntersectionConstraint struct { 308 aConstraint 309 ranges Ranges 310 A ssa.Value 311 B ssa.Value 312 Op token.Token 313 I IntInterval 314 resolved bool 315 } 316 317 type IntIntervalConstraint struct { 318 aConstraint 319 I IntInterval 320 } 321 322 func NewIntArithmeticConstraint(a, b, y ssa.Value, op token.Token, fn func(IntInterval, IntInterval) IntInterval) *IntArithmeticConstraint { 323 return &IntArithmeticConstraint{NewConstraint(y), a, b, op, fn} 324 } 325 func NewIntAddConstraint(a, b, y ssa.Value) Constraint { 326 return &IntAddConstraint{NewIntArithmeticConstraint(a, b, y, token.ADD, IntInterval.Add)} 327 } 328 func NewIntSubConstraint(a, b, y ssa.Value) Constraint { 329 return &IntSubConstraint{NewIntArithmeticConstraint(a, b, y, token.SUB, IntInterval.Sub)} 330 } 331 func NewIntMulConstraint(a, b, y ssa.Value) Constraint { 332 return &IntMulConstraint{NewIntArithmeticConstraint(a, b, y, token.MUL, IntInterval.Mul)} 333 } 334 func NewIntConversionConstraint(x, y ssa.Value) Constraint { 335 return &IntConversionConstraint{NewConstraint(y), x} 336 } 337 func NewIntIntersectionConstraint(a, b ssa.Value, op token.Token, ranges Ranges, y ssa.Value) Constraint { 338 return &IntIntersectionConstraint{ 339 aConstraint: NewConstraint(y), 340 ranges: ranges, 341 A: a, 342 B: b, 343 Op: op, 344 } 345 } 346 func NewIntIntervalConstraint(i IntInterval, y ssa.Value) Constraint { 347 return &IntIntervalConstraint{NewConstraint(y), i} 348 } 349 350 func (c *IntArithmeticConstraint) Operands() []ssa.Value { return []ssa.Value{c.A, c.B} } 351 func (c *IntConversionConstraint) Operands() []ssa.Value { return []ssa.Value{c.X} } 352 func (c *IntIntersectionConstraint) Operands() []ssa.Value { return []ssa.Value{c.A} } 353 func (s *IntIntervalConstraint) Operands() []ssa.Value { return nil } 354 355 func (c *IntArithmeticConstraint) String() string { 356 return fmt.Sprintf("%s = %s %s %s", c.Y().Name(), c.A.Name(), c.Op, c.B.Name()) 357 } 358 func (c *IntConversionConstraint) String() string { 359 return fmt.Sprintf("%s = %s(%s)", c.Y().Name(), c.Y().Type(), c.X.Name()) 360 } 361 func (c *IntIntersectionConstraint) String() string { 362 return fmt.Sprintf("%s = %s %s %s (%t branch)", c.Y().Name(), c.A.Name(), c.Op, c.B.Name(), c.Y().(*ssa.Sigma).Branch) 363 } 364 func (c *IntIntervalConstraint) String() string { return fmt.Sprintf("%s = %s", c.Y().Name(), c.I) } 365 366 func (c *IntArithmeticConstraint) Eval(g *Graph) Range { 367 i1, i2 := g.Range(c.A).(IntInterval), g.Range(c.B).(IntInterval) 368 if !i1.IsKnown() || !i2.IsKnown() { 369 return IntInterval{} 370 } 371 return c.Fn(i1, i2) 372 } 373 func (c *IntConversionConstraint) Eval(g *Graph) Range { 374 s := &types.StdSizes{ 375 // XXX is it okay to assume the largest word size, or do we 376 // need to be platform specific? 377 WordSize: 8, 378 MaxAlign: 1, 379 } 380 fromI := g.Range(c.X).(IntInterval) 381 toI := g.Range(c.Y()).(IntInterval) 382 fromT := c.X.Type().Underlying().(*types.Basic) 383 toT := c.Y().Type().Underlying().(*types.Basic) 384 fromB := s.Sizeof(c.X.Type()) 385 toB := s.Sizeof(c.Y().Type()) 386 387 if !fromI.IsKnown() { 388 return toI 389 } 390 if !toI.IsKnown() { 391 return fromI 392 } 393 394 // uint<N> -> sint/uint<M>, M > N: [max(0, l1), min(2**N-1, u2)] 395 if (fromT.Info()&types.IsUnsigned != 0) && 396 toB > fromB { 397 398 n := big.NewInt(1) 399 n.Lsh(n, uint(fromB*8)) 400 n.Sub(n, big.NewInt(1)) 401 return NewIntInterval( 402 MaxZ(NewZ(0), fromI.Lower), 403 MinZ(NewBigZ(n), toI.Upper), 404 ) 405 } 406 407 // sint<N> -> sint<M>, M > N; [max(-∞, l1), min(2**N-1, u2)] 408 if (fromT.Info()&types.IsUnsigned == 0) && 409 (toT.Info()&types.IsUnsigned == 0) && 410 toB > fromB { 411 412 n := big.NewInt(1) 413 n.Lsh(n, uint(fromB*8)) 414 n.Sub(n, big.NewInt(1)) 415 return NewIntInterval( 416 MaxZ(NInfinity, fromI.Lower), 417 MinZ(NewBigZ(n), toI.Upper), 418 ) 419 } 420 421 return fromI 422 } 423 func (c *IntIntersectionConstraint) Eval(g *Graph) Range { 424 xi := g.Range(c.A).(IntInterval) 425 if !xi.IsKnown() { 426 return c.I 427 } 428 return xi.Intersection(c.I) 429 } 430 func (c *IntIntervalConstraint) Eval(*Graph) Range { return c.I } 431 432 func (c *IntIntersectionConstraint) Futures() []ssa.Value { 433 return []ssa.Value{c.B} 434 } 435 436 func (c *IntIntersectionConstraint) Resolve() { 437 r, ok := c.ranges[c.B].(IntInterval) 438 if !ok { 439 c.I = InfinityFor(c.Y()) 440 return 441 } 442 443 switch c.Op { 444 case token.EQL: 445 c.I = r 446 case token.GTR: 447 c.I = NewIntInterval(r.Lower.Add(NewZ(1)), PInfinity) 448 case token.GEQ: 449 c.I = NewIntInterval(r.Lower, PInfinity) 450 case token.LSS: 451 // TODO(dh): do we need 0 instead of NInfinity for uints? 452 c.I = NewIntInterval(NInfinity, r.Upper.Sub(NewZ(1))) 453 case token.LEQ: 454 c.I = NewIntInterval(NInfinity, r.Upper) 455 case token.NEQ: 456 c.I = InfinityFor(c.Y()) 457 default: 458 panic("unsupported op " + c.Op.String()) 459 } 460 } 461 462 func (c *IntIntersectionConstraint) IsKnown() bool { 463 return c.I.IsKnown() 464 } 465 466 func (c *IntIntersectionConstraint) MarkUnresolved() { 467 c.resolved = false 468 } 469 470 func (c *IntIntersectionConstraint) MarkResolved() { 471 c.resolved = true 472 } 473 474 func (c *IntIntersectionConstraint) IsResolved() bool { 475 return c.resolved 476 }