github.com/golangci/go-tools@v0.0.0-20190318060251-af6baa5dc196/staticcheck/vrp/vrp.go (about) 1 package vrp 2 3 // TODO(dh) widening and narrowing have a lot of code in common. Make 4 // it reusable. 5 6 import ( 7 "fmt" 8 "go/constant" 9 "go/token" 10 "go/types" 11 "math/big" 12 "sort" 13 "strings" 14 15 "github.com/golangci/go-tools/ssa" 16 ) 17 18 type Future interface { 19 Constraint 20 Futures() []ssa.Value 21 Resolve() 22 IsKnown() bool 23 MarkUnresolved() 24 MarkResolved() 25 IsResolved() bool 26 } 27 28 type Range interface { 29 Union(other Range) Range 30 IsKnown() bool 31 } 32 33 type Constraint interface { 34 Y() ssa.Value 35 isConstraint() 36 String() string 37 Eval(*Graph) Range 38 Operands() []ssa.Value 39 } 40 41 type aConstraint struct { 42 y ssa.Value 43 } 44 45 func NewConstraint(y ssa.Value) aConstraint { 46 return aConstraint{y} 47 } 48 49 func (aConstraint) isConstraint() {} 50 func (c aConstraint) Y() ssa.Value { return c.y } 51 52 type PhiConstraint struct { 53 aConstraint 54 Vars []ssa.Value 55 } 56 57 func NewPhiConstraint(vars []ssa.Value, y ssa.Value) Constraint { 58 uniqm := map[ssa.Value]struct{}{} 59 for _, v := range vars { 60 uniqm[v] = struct{}{} 61 } 62 var uniq []ssa.Value 63 for v := range uniqm { 64 uniq = append(uniq, v) 65 } 66 return &PhiConstraint{ 67 aConstraint: NewConstraint(y), 68 Vars: uniq, 69 } 70 } 71 72 func (c *PhiConstraint) Operands() []ssa.Value { 73 return c.Vars 74 } 75 76 func (c *PhiConstraint) Eval(g *Graph) Range { 77 i := Range(nil) 78 for _, v := range c.Vars { 79 i = g.Range(v).Union(i) 80 } 81 return i 82 } 83 84 func (c *PhiConstraint) String() string { 85 names := make([]string, len(c.Vars)) 86 for i, v := range c.Vars { 87 names[i] = v.Name() 88 } 89 return fmt.Sprintf("%s = φ(%s)", c.Y().Name(), strings.Join(names, ", ")) 90 } 91 92 func isSupportedType(typ types.Type) bool { 93 switch typ := typ.Underlying().(type) { 94 case *types.Basic: 95 switch typ.Kind() { 96 case types.String, types.UntypedString: 97 return true 98 default: 99 if (typ.Info() & types.IsInteger) == 0 { 100 return false 101 } 102 } 103 case *types.Chan: 104 return true 105 case *types.Slice: 106 return true 107 default: 108 return false 109 } 110 return true 111 } 112 113 func ConstantToZ(c constant.Value) Z { 114 s := constant.ToInt(c).ExactString() 115 n := &big.Int{} 116 n.SetString(s, 10) 117 return NewBigZ(n) 118 } 119 120 func sigmaInteger(g *Graph, ins *ssa.Sigma, cond *ssa.BinOp, ops []*ssa.Value) Constraint { 121 op := cond.Op 122 if !ins.Branch { 123 op = (invertToken(op)) 124 } 125 126 switch op { 127 case token.EQL, token.GTR, token.GEQ, token.LSS, token.LEQ: 128 default: 129 return nil 130 } 131 var a, b ssa.Value 132 if (*ops[0]) == ins.X { 133 a = *ops[0] 134 b = *ops[1] 135 } else { 136 a = *ops[1] 137 b = *ops[0] 138 op = flipToken(op) 139 } 140 return NewIntIntersectionConstraint(a, b, op, g.ranges, ins) 141 } 142 143 func sigmaString(g *Graph, ins *ssa.Sigma, cond *ssa.BinOp, ops []*ssa.Value) Constraint { 144 op := cond.Op 145 if !ins.Branch { 146 op = (invertToken(op)) 147 } 148 149 switch op { 150 case token.EQL, token.GTR, token.GEQ, token.LSS, token.LEQ: 151 default: 152 return nil 153 } 154 155 if ((*ops[0]).Type().Underlying().(*types.Basic).Info() & types.IsString) == 0 { 156 var a, b ssa.Value 157 call, ok := (*ops[0]).(*ssa.Call) 158 if ok && call.Common().Args[0] == ins.X { 159 a = *ops[0] 160 b = *ops[1] 161 } else { 162 a = *ops[1] 163 b = *ops[0] 164 op = flipToken(op) 165 } 166 return NewStringIntersectionConstraint(a, b, op, g.ranges, ins) 167 } 168 var a, b ssa.Value 169 if (*ops[0]) == ins.X { 170 a = *ops[0] 171 b = *ops[1] 172 } else { 173 a = *ops[1] 174 b = *ops[0] 175 op = flipToken(op) 176 } 177 return NewStringIntersectionConstraint(a, b, op, g.ranges, ins) 178 } 179 180 func sigmaSlice(g *Graph, ins *ssa.Sigma, cond *ssa.BinOp, ops []*ssa.Value) Constraint { 181 // TODO(dh) sigmaSlice and sigmaString are a lot alike. Can they 182 // be merged? 183 // 184 // XXX support futures 185 186 op := cond.Op 187 if !ins.Branch { 188 op = (invertToken(op)) 189 } 190 191 k, ok := (*ops[1]).(*ssa.Const) 192 // XXX investigate in what cases this wouldn't be a Const 193 // 194 // XXX what if left and right are swapped? 195 if !ok { 196 return nil 197 } 198 199 call, ok := (*ops[0]).(*ssa.Call) 200 if !ok { 201 return nil 202 } 203 builtin, ok := call.Common().Value.(*ssa.Builtin) 204 if !ok { 205 return nil 206 } 207 if builtin.Name() != "len" { 208 return nil 209 } 210 callops := call.Operands(nil) 211 212 v := ConstantToZ(k.Value) 213 c := NewSliceIntersectionConstraint(*callops[1], IntInterval{}, ins).(*SliceIntersectionConstraint) 214 switch op { 215 case token.EQL: 216 c.I = NewIntInterval(v, v) 217 case token.GTR, token.GEQ: 218 off := int64(0) 219 if cond.Op == token.GTR { 220 off = 1 221 } 222 c.I = NewIntInterval( 223 v.Add(NewZ(off)), 224 PInfinity, 225 ) 226 case token.LSS, token.LEQ: 227 off := int64(0) 228 if cond.Op == token.LSS { 229 off = -1 230 } 231 c.I = NewIntInterval( 232 NInfinity, 233 v.Add(NewZ(off)), 234 ) 235 default: 236 return nil 237 } 238 return c 239 } 240 241 func BuildGraph(f *ssa.Function) *Graph { 242 g := &Graph{ 243 Vertices: map[interface{}]*Vertex{}, 244 ranges: Ranges{}, 245 } 246 247 var cs []Constraint 248 249 ops := make([]*ssa.Value, 16) 250 seen := map[ssa.Value]bool{} 251 for _, block := range f.Blocks { 252 for _, ins := range block.Instrs { 253 ops = ins.Operands(ops[:0]) 254 for _, op := range ops { 255 if c, ok := (*op).(*ssa.Const); ok { 256 if seen[c] { 257 continue 258 } 259 seen[c] = true 260 if c.Value == nil { 261 switch c.Type().Underlying().(type) { 262 case *types.Slice: 263 cs = append(cs, NewSliceIntervalConstraint(NewIntInterval(NewZ(0), NewZ(0)), c)) 264 } 265 continue 266 } 267 switch c.Value.Kind() { 268 case constant.Int: 269 v := ConstantToZ(c.Value) 270 cs = append(cs, NewIntIntervalConstraint(NewIntInterval(v, v), c)) 271 case constant.String: 272 s := constant.StringVal(c.Value) 273 n := NewZ(int64(len(s))) 274 cs = append(cs, NewStringIntervalConstraint(NewIntInterval(n, n), c)) 275 } 276 } 277 } 278 } 279 } 280 for _, block := range f.Blocks { 281 for _, ins := range block.Instrs { 282 switch ins := ins.(type) { 283 case *ssa.Convert: 284 switch v := ins.Type().Underlying().(type) { 285 case *types.Basic: 286 if (v.Info() & types.IsInteger) == 0 { 287 continue 288 } 289 cs = append(cs, NewIntConversionConstraint(ins.X, ins)) 290 } 291 case *ssa.Call: 292 if static := ins.Common().StaticCallee(); static != nil { 293 if fn, ok := static.Object().(*types.Func); ok { 294 switch fn.FullName() { 295 case "bytes.Index", "bytes.IndexAny", "bytes.IndexByte", 296 "bytes.IndexFunc", "bytes.IndexRune", "bytes.LastIndex", 297 "bytes.LastIndexAny", "bytes.LastIndexByte", "bytes.LastIndexFunc", 298 "strings.Index", "strings.IndexAny", "strings.IndexByte", 299 "strings.IndexFunc", "strings.IndexRune", "strings.LastIndex", 300 "strings.LastIndexAny", "strings.LastIndexByte", "strings.LastIndexFunc": 301 // TODO(dh): instead of limiting by +∞, 302 // limit by the upper bound of the passed 303 // string 304 cs = append(cs, NewIntIntervalConstraint(NewIntInterval(NewZ(-1), PInfinity), ins)) 305 case "bytes.Title", "bytes.ToLower", "bytes.ToTitle", "bytes.ToUpper", 306 "strings.Title", "strings.ToLower", "strings.ToTitle", "strings.ToUpper": 307 cs = append(cs, NewCopyConstraint(ins.Common().Args[0], ins)) 308 case "bytes.ToLowerSpecial", "bytes.ToTitleSpecial", "bytes.ToUpperSpecial", 309 "strings.ToLowerSpecial", "strings.ToTitleSpecial", "strings.ToUpperSpecial": 310 cs = append(cs, NewCopyConstraint(ins.Common().Args[1], ins)) 311 case "bytes.Compare", "strings.Compare": 312 cs = append(cs, NewIntIntervalConstraint(NewIntInterval(NewZ(-1), NewZ(1)), ins)) 313 case "bytes.Count", "strings.Count": 314 // TODO(dh): instead of limiting by +∞, 315 // limit by the upper bound of the passed 316 // string. 317 cs = append(cs, NewIntIntervalConstraint(NewIntInterval(NewZ(0), PInfinity), ins)) 318 case "bytes.Map", "bytes.TrimFunc", "bytes.TrimLeft", "bytes.TrimLeftFunc", 319 "bytes.TrimRight", "bytes.TrimRightFunc", "bytes.TrimSpace", 320 "strings.Map", "strings.TrimFunc", "strings.TrimLeft", "strings.TrimLeftFunc", 321 "strings.TrimRight", "strings.TrimRightFunc", "strings.TrimSpace": 322 // TODO(dh): lower = 0, upper = upper of passed string 323 case "bytes.TrimPrefix", "bytes.TrimSuffix", 324 "strings.TrimPrefix", "strings.TrimSuffix": 325 // TODO(dh) range between "unmodified" and len(cutset) removed 326 case "(*bytes.Buffer).Cap", "(*bytes.Buffer).Len", "(*bytes.Reader).Len", "(*bytes.Reader).Size": 327 cs = append(cs, NewIntIntervalConstraint(NewIntInterval(NewZ(0), PInfinity), ins)) 328 } 329 } 330 } 331 builtin, ok := ins.Common().Value.(*ssa.Builtin) 332 ops := ins.Operands(nil) 333 if !ok { 334 continue 335 } 336 switch builtin.Name() { 337 case "len": 338 switch op1 := (*ops[1]).Type().Underlying().(type) { 339 case *types.Basic: 340 if op1.Kind() == types.String || op1.Kind() == types.UntypedString { 341 cs = append(cs, NewStringLengthConstraint(*ops[1], ins)) 342 } 343 case *types.Slice: 344 cs = append(cs, NewSliceLengthConstraint(*ops[1], ins)) 345 } 346 347 case "append": 348 cs = append(cs, NewSliceAppendConstraint(ins.Common().Args[0], ins.Common().Args[1], ins)) 349 } 350 case *ssa.BinOp: 351 ops := ins.Operands(nil) 352 basic, ok := (*ops[0]).Type().Underlying().(*types.Basic) 353 if !ok { 354 continue 355 } 356 switch basic.Kind() { 357 case types.Int, types.Int8, types.Int16, types.Int32, types.Int64, 358 types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.UntypedInt: 359 fns := map[token.Token]func(ssa.Value, ssa.Value, ssa.Value) Constraint{ 360 token.ADD: NewIntAddConstraint, 361 token.SUB: NewIntSubConstraint, 362 token.MUL: NewIntMulConstraint, 363 // XXX support QUO, REM, SHL, SHR 364 } 365 fn, ok := fns[ins.Op] 366 if ok { 367 cs = append(cs, fn(*ops[0], *ops[1], ins)) 368 } 369 case types.String, types.UntypedString: 370 if ins.Op == token.ADD { 371 cs = append(cs, NewStringConcatConstraint(*ops[0], *ops[1], ins)) 372 } 373 } 374 case *ssa.Slice: 375 typ := ins.X.Type().Underlying() 376 switch typ := typ.(type) { 377 case *types.Basic: 378 cs = append(cs, NewStringSliceConstraint(ins.X, ins.Low, ins.High, ins)) 379 case *types.Slice: 380 cs = append(cs, NewSliceSliceConstraint(ins.X, ins.Low, ins.High, ins)) 381 case *types.Array: 382 cs = append(cs, NewArraySliceConstraint(ins.X, ins.Low, ins.High, ins)) 383 case *types.Pointer: 384 if _, ok := typ.Elem().(*types.Array); !ok { 385 continue 386 } 387 cs = append(cs, NewArraySliceConstraint(ins.X, ins.Low, ins.High, ins)) 388 } 389 case *ssa.Phi: 390 if !isSupportedType(ins.Type()) { 391 continue 392 } 393 ops := ins.Operands(nil) 394 dops := make([]ssa.Value, len(ops)) 395 for i, op := range ops { 396 dops[i] = *op 397 } 398 cs = append(cs, NewPhiConstraint(dops, ins)) 399 case *ssa.Sigma: 400 pred := ins.Block().Preds[0] 401 instrs := pred.Instrs 402 cond, ok := instrs[len(instrs)-1].(*ssa.If).Cond.(*ssa.BinOp) 403 ops := cond.Operands(nil) 404 if !ok { 405 continue 406 } 407 switch typ := ins.Type().Underlying().(type) { 408 case *types.Basic: 409 var c Constraint 410 switch typ.Kind() { 411 case types.Int, types.Int8, types.Int16, types.Int32, types.Int64, 412 types.Uint, types.Uint8, types.Uint16, types.Uint32, types.Uint64, types.UntypedInt: 413 c = sigmaInteger(g, ins, cond, ops) 414 case types.String, types.UntypedString: 415 c = sigmaString(g, ins, cond, ops) 416 } 417 if c != nil { 418 cs = append(cs, c) 419 } 420 case *types.Slice: 421 c := sigmaSlice(g, ins, cond, ops) 422 if c != nil { 423 cs = append(cs, c) 424 } 425 default: 426 //log.Printf("unsupported sigma type %T", typ) // XXX 427 } 428 case *ssa.MakeChan: 429 cs = append(cs, NewMakeChannelConstraint(ins.Size, ins)) 430 case *ssa.MakeSlice: 431 cs = append(cs, NewMakeSliceConstraint(ins.Len, ins)) 432 case *ssa.ChangeType: 433 switch ins.X.Type().Underlying().(type) { 434 case *types.Chan: 435 cs = append(cs, NewChannelChangeTypeConstraint(ins.X, ins)) 436 } 437 } 438 } 439 } 440 441 for _, c := range cs { 442 if c == nil { 443 panic("nil constraint") 444 } 445 // If V is used in constraint C, then we create an edge V->C 446 for _, op := range c.Operands() { 447 g.AddEdge(op, c, false) 448 } 449 if c, ok := c.(Future); ok { 450 for _, op := range c.Futures() { 451 g.AddEdge(op, c, true) 452 } 453 } 454 // If constraint C defines variable V, then we create an edge 455 // C->V 456 g.AddEdge(c, c.Y(), false) 457 } 458 459 g.FindSCCs() 460 g.sccEdges = make([][]Edge, len(g.SCCs)) 461 g.futures = make([][]Future, len(g.SCCs)) 462 for _, e := range g.Edges { 463 g.sccEdges[e.From.SCC] = append(g.sccEdges[e.From.SCC], e) 464 if !e.control { 465 continue 466 } 467 if c, ok := e.To.Value.(Future); ok { 468 g.futures[e.From.SCC] = append(g.futures[e.From.SCC], c) 469 } 470 } 471 return g 472 } 473 474 func (g *Graph) Solve() Ranges { 475 var consts []Z 476 off := NewZ(1) 477 for _, n := range g.Vertices { 478 if c, ok := n.Value.(*ssa.Const); ok { 479 basic, ok := c.Type().Underlying().(*types.Basic) 480 if !ok { 481 continue 482 } 483 if (basic.Info() & types.IsInteger) != 0 { 484 z := ConstantToZ(c.Value) 485 consts = append(consts, z) 486 consts = append(consts, z.Add(off)) 487 consts = append(consts, z.Sub(off)) 488 } 489 } 490 491 } 492 sort.Sort(Zs(consts)) 493 494 for scc, vertices := range g.SCCs { 495 n := 0 496 n = len(vertices) 497 if n == 1 { 498 g.resolveFutures(scc) 499 v := vertices[0] 500 if v, ok := v.Value.(ssa.Value); ok { 501 switch typ := v.Type().Underlying().(type) { 502 case *types.Basic: 503 switch typ.Kind() { 504 case types.String, types.UntypedString: 505 if !g.Range(v).(StringInterval).IsKnown() { 506 g.SetRange(v, StringInterval{NewIntInterval(NewZ(0), PInfinity)}) 507 } 508 default: 509 if !g.Range(v).(IntInterval).IsKnown() { 510 g.SetRange(v, InfinityFor(v)) 511 } 512 } 513 case *types.Chan: 514 if !g.Range(v).(ChannelInterval).IsKnown() { 515 g.SetRange(v, ChannelInterval{NewIntInterval(NewZ(0), PInfinity)}) 516 } 517 case *types.Slice: 518 if !g.Range(v).(SliceInterval).IsKnown() { 519 g.SetRange(v, SliceInterval{NewIntInterval(NewZ(0), PInfinity)}) 520 } 521 } 522 } 523 if c, ok := v.Value.(Constraint); ok { 524 g.SetRange(c.Y(), c.Eval(g)) 525 } 526 } else { 527 uses := g.uses(scc) 528 entries := g.entries(scc) 529 for len(entries) > 0 { 530 v := entries[len(entries)-1] 531 entries = entries[:len(entries)-1] 532 for _, use := range uses[v] { 533 if g.widen(use, consts) { 534 entries = append(entries, use.Y()) 535 } 536 } 537 } 538 539 g.resolveFutures(scc) 540 541 // XXX this seems to be necessary, but shouldn't be. 542 // removing it leads to nil pointer derefs; investigate 543 // where we're not setting values correctly. 544 for _, n := range vertices { 545 if v, ok := n.Value.(ssa.Value); ok { 546 i, ok := g.Range(v).(IntInterval) 547 if !ok { 548 continue 549 } 550 if !i.IsKnown() { 551 g.SetRange(v, InfinityFor(v)) 552 } 553 } 554 } 555 556 actives := g.actives(scc) 557 for len(actives) > 0 { 558 v := actives[len(actives)-1] 559 actives = actives[:len(actives)-1] 560 for _, use := range uses[v] { 561 if g.narrow(use) { 562 actives = append(actives, use.Y()) 563 } 564 } 565 } 566 } 567 // propagate scc 568 for _, edge := range g.sccEdges[scc] { 569 if edge.control { 570 continue 571 } 572 if edge.From.SCC == edge.To.SCC { 573 continue 574 } 575 if c, ok := edge.To.Value.(Constraint); ok { 576 g.SetRange(c.Y(), c.Eval(g)) 577 } 578 if c, ok := edge.To.Value.(Future); ok { 579 if !c.IsKnown() { 580 c.MarkUnresolved() 581 } 582 } 583 } 584 } 585 586 for v, r := range g.ranges { 587 i, ok := r.(IntInterval) 588 if !ok { 589 continue 590 } 591 if (v.Type().Underlying().(*types.Basic).Info() & types.IsUnsigned) == 0 { 592 if i.Upper != PInfinity { 593 s := &types.StdSizes{ 594 // XXX is it okay to assume the largest word size, or do we 595 // need to be platform specific? 596 WordSize: 8, 597 MaxAlign: 1, 598 } 599 bits := (s.Sizeof(v.Type()) * 8) - 1 600 n := big.NewInt(1) 601 n = n.Lsh(n, uint(bits)) 602 upper, lower := &big.Int{}, &big.Int{} 603 upper.Sub(n, big.NewInt(1)) 604 lower.Neg(n) 605 606 if i.Upper.Cmp(NewBigZ(upper)) == 1 { 607 i = NewIntInterval(NInfinity, PInfinity) 608 } else if i.Lower.Cmp(NewBigZ(lower)) == -1 { 609 i = NewIntInterval(NInfinity, PInfinity) 610 } 611 } 612 } 613 614 g.ranges[v] = i 615 } 616 617 return g.ranges 618 } 619 620 func VertexString(v *Vertex) string { 621 switch v := v.Value.(type) { 622 case Constraint: 623 return v.String() 624 case ssa.Value: 625 return v.Name() 626 case nil: 627 return "BUG: nil vertex value" 628 default: 629 panic(fmt.Sprintf("unexpected type %T", v)) 630 } 631 } 632 633 type Vertex struct { 634 Value interface{} // one of Constraint or ssa.Value 635 SCC int 636 index int 637 lowlink int 638 stack bool 639 640 Succs []Edge 641 } 642 643 type Ranges map[ssa.Value]Range 644 645 func (r Ranges) Get(x ssa.Value) Range { 646 if x == nil { 647 return nil 648 } 649 i, ok := r[x] 650 if !ok { 651 switch x := x.Type().Underlying().(type) { 652 case *types.Basic: 653 switch x.Kind() { 654 case types.String, types.UntypedString: 655 return StringInterval{} 656 default: 657 return IntInterval{} 658 } 659 case *types.Chan: 660 return ChannelInterval{} 661 case *types.Slice: 662 return SliceInterval{} 663 } 664 } 665 return i 666 } 667 668 type Graph struct { 669 Vertices map[interface{}]*Vertex 670 Edges []Edge 671 SCCs [][]*Vertex 672 ranges Ranges 673 674 // map SCCs to futures 675 futures [][]Future 676 // map SCCs to edges 677 sccEdges [][]Edge 678 } 679 680 func (g Graph) Graphviz() string { 681 var lines []string 682 lines = append(lines, "digraph{") 683 ids := map[interface{}]int{} 684 i := 1 685 for _, v := range g.Vertices { 686 ids[v] = i 687 shape := "box" 688 if _, ok := v.Value.(ssa.Value); ok { 689 shape = "oval" 690 } 691 lines = append(lines, fmt.Sprintf(`n%d [shape="%s", label=%q, colorscheme=spectral11, style="filled", fillcolor="%d"]`, 692 i, shape, VertexString(v), (v.SCC%11)+1)) 693 i++ 694 } 695 for _, e := range g.Edges { 696 style := "solid" 697 if e.control { 698 style = "dashed" 699 } 700 lines = append(lines, fmt.Sprintf(`n%d -> n%d [style="%s"]`, ids[e.From], ids[e.To], style)) 701 } 702 lines = append(lines, "}") 703 return strings.Join(lines, "\n") 704 } 705 706 func (g *Graph) SetRange(x ssa.Value, r Range) { 707 g.ranges[x] = r 708 } 709 710 func (g *Graph) Range(x ssa.Value) Range { 711 return g.ranges.Get(x) 712 } 713 714 func (g *Graph) widen(c Constraint, consts []Z) bool { 715 setRange := func(i Range) { 716 g.SetRange(c.Y(), i) 717 } 718 widenIntInterval := func(oi, ni IntInterval) (IntInterval, bool) { 719 if !ni.IsKnown() { 720 return oi, false 721 } 722 nlc := NInfinity 723 nuc := PInfinity 724 for _, co := range consts { 725 if co.Cmp(ni.Lower) <= 0 { 726 nlc = co 727 break 728 } 729 } 730 for _, co := range consts { 731 if co.Cmp(ni.Upper) >= 0 { 732 nuc = co 733 break 734 } 735 } 736 737 if !oi.IsKnown() { 738 return ni, true 739 } 740 if ni.Lower.Cmp(oi.Lower) == -1 && ni.Upper.Cmp(oi.Upper) == 1 { 741 return NewIntInterval(nlc, nuc), true 742 } 743 if ni.Lower.Cmp(oi.Lower) == -1 { 744 return NewIntInterval(nlc, oi.Upper), true 745 } 746 if ni.Upper.Cmp(oi.Upper) == 1 { 747 return NewIntInterval(oi.Lower, nuc), true 748 } 749 return oi, false 750 } 751 switch oi := g.Range(c.Y()).(type) { 752 case IntInterval: 753 ni := c.Eval(g).(IntInterval) 754 si, changed := widenIntInterval(oi, ni) 755 if changed { 756 setRange(si) 757 return true 758 } 759 return false 760 case StringInterval: 761 ni := c.Eval(g).(StringInterval) 762 si, changed := widenIntInterval(oi.Length, ni.Length) 763 if changed { 764 setRange(StringInterval{si}) 765 return true 766 } 767 return false 768 case SliceInterval: 769 ni := c.Eval(g).(SliceInterval) 770 si, changed := widenIntInterval(oi.Length, ni.Length) 771 if changed { 772 setRange(SliceInterval{si}) 773 return true 774 } 775 return false 776 default: 777 return false 778 } 779 } 780 781 func (g *Graph) narrow(c Constraint) bool { 782 narrowIntInterval := func(oi, ni IntInterval) (IntInterval, bool) { 783 oLower := oi.Lower 784 oUpper := oi.Upper 785 nLower := ni.Lower 786 nUpper := ni.Upper 787 788 if oLower == NInfinity && nLower != NInfinity { 789 return NewIntInterval(nLower, oUpper), true 790 } 791 if oUpper == PInfinity && nUpper != PInfinity { 792 return NewIntInterval(oLower, nUpper), true 793 } 794 if oLower.Cmp(nLower) == 1 { 795 return NewIntInterval(nLower, oUpper), true 796 } 797 if oUpper.Cmp(nUpper) == -1 { 798 return NewIntInterval(oLower, nUpper), true 799 } 800 return oi, false 801 } 802 switch oi := g.Range(c.Y()).(type) { 803 case IntInterval: 804 ni := c.Eval(g).(IntInterval) 805 si, changed := narrowIntInterval(oi, ni) 806 if changed { 807 g.SetRange(c.Y(), si) 808 return true 809 } 810 return false 811 case StringInterval: 812 ni := c.Eval(g).(StringInterval) 813 si, changed := narrowIntInterval(oi.Length, ni.Length) 814 if changed { 815 g.SetRange(c.Y(), StringInterval{si}) 816 return true 817 } 818 return false 819 case SliceInterval: 820 ni := c.Eval(g).(SliceInterval) 821 si, changed := narrowIntInterval(oi.Length, ni.Length) 822 if changed { 823 g.SetRange(c.Y(), SliceInterval{si}) 824 return true 825 } 826 return false 827 default: 828 return false 829 } 830 } 831 832 func (g *Graph) resolveFutures(scc int) { 833 for _, c := range g.futures[scc] { 834 c.Resolve() 835 } 836 } 837 838 func (g *Graph) entries(scc int) []ssa.Value { 839 var entries []ssa.Value 840 for _, n := range g.Vertices { 841 if n.SCC != scc { 842 continue 843 } 844 if v, ok := n.Value.(ssa.Value); ok { 845 // XXX avoid quadratic runtime 846 // 847 // XXX I cannot think of any code where the future and its 848 // variables aren't in the same SCC, in which case this 849 // code isn't very useful (the variables won't be resolved 850 // yet). Before we have a cross-SCC example, however, we 851 // can't really verify that this code is working 852 // correctly, or indeed doing anything useful. 853 for _, on := range g.Vertices { 854 if c, ok := on.Value.(Future); ok { 855 if c.Y() == v { 856 if !c.IsResolved() { 857 g.SetRange(c.Y(), c.Eval(g)) 858 c.MarkResolved() 859 } 860 break 861 } 862 } 863 } 864 if g.Range(v).IsKnown() { 865 entries = append(entries, v) 866 } 867 } 868 } 869 return entries 870 } 871 872 func (g *Graph) uses(scc int) map[ssa.Value][]Constraint { 873 m := map[ssa.Value][]Constraint{} 874 for _, e := range g.sccEdges[scc] { 875 if e.control { 876 continue 877 } 878 if v, ok := e.From.Value.(ssa.Value); ok { 879 c := e.To.Value.(Constraint) 880 sink := c.Y() 881 if g.Vertices[sink].SCC == scc { 882 m[v] = append(m[v], c) 883 } 884 } 885 } 886 return m 887 } 888 889 func (g *Graph) actives(scc int) []ssa.Value { 890 var actives []ssa.Value 891 for _, n := range g.Vertices { 892 if n.SCC != scc { 893 continue 894 } 895 if v, ok := n.Value.(ssa.Value); ok { 896 if _, ok := v.(*ssa.Const); !ok { 897 actives = append(actives, v) 898 } 899 } 900 } 901 return actives 902 } 903 904 func (g *Graph) AddEdge(from, to interface{}, ctrl bool) { 905 vf, ok := g.Vertices[from] 906 if !ok { 907 vf = &Vertex{Value: from} 908 g.Vertices[from] = vf 909 } 910 vt, ok := g.Vertices[to] 911 if !ok { 912 vt = &Vertex{Value: to} 913 g.Vertices[to] = vt 914 } 915 e := Edge{From: vf, To: vt, control: ctrl} 916 g.Edges = append(g.Edges, e) 917 vf.Succs = append(vf.Succs, e) 918 } 919 920 type Edge struct { 921 From, To *Vertex 922 control bool 923 } 924 925 func (e Edge) String() string { 926 return fmt.Sprintf("%s -> %s", VertexString(e.From), VertexString(e.To)) 927 } 928 929 func (g *Graph) FindSCCs() { 930 // use Tarjan to find the SCCs 931 932 index := 1 933 var s []*Vertex 934 935 scc := 0 936 var strongconnect func(v *Vertex) 937 strongconnect = func(v *Vertex) { 938 // set the depth index for v to the smallest unused index 939 v.index = index 940 v.lowlink = index 941 index++ 942 s = append(s, v) 943 v.stack = true 944 945 for _, e := range v.Succs { 946 w := e.To 947 if w.index == 0 { 948 // successor w has not yet been visited; recurse on it 949 strongconnect(w) 950 if w.lowlink < v.lowlink { 951 v.lowlink = w.lowlink 952 } 953 } else if w.stack { 954 // successor w is in stack s and hence in the current scc 955 if w.index < v.lowlink { 956 v.lowlink = w.index 957 } 958 } 959 } 960 961 if v.lowlink == v.index { 962 for { 963 w := s[len(s)-1] 964 s = s[:len(s)-1] 965 w.stack = false 966 w.SCC = scc 967 if w == v { 968 break 969 } 970 } 971 scc++ 972 } 973 } 974 for _, v := range g.Vertices { 975 if v.index == 0 { 976 strongconnect(v) 977 } 978 } 979 980 g.SCCs = make([][]*Vertex, scc) 981 for _, n := range g.Vertices { 982 n.SCC = scc - n.SCC - 1 983 g.SCCs[n.SCC] = append(g.SCCs[n.SCC], n) 984 } 985 } 986 987 func invertToken(tok token.Token) token.Token { 988 switch tok { 989 case token.LSS: 990 return token.GEQ 991 case token.GTR: 992 return token.LEQ 993 case token.EQL: 994 return token.NEQ 995 case token.NEQ: 996 return token.EQL 997 case token.GEQ: 998 return token.LSS 999 case token.LEQ: 1000 return token.GTR 1001 default: 1002 panic(fmt.Sprintf("unsupported token %s", tok)) 1003 } 1004 } 1005 1006 func flipToken(tok token.Token) token.Token { 1007 switch tok { 1008 case token.LSS: 1009 return token.GTR 1010 case token.GTR: 1011 return token.LSS 1012 case token.EQL: 1013 return token.EQL 1014 case token.NEQ: 1015 return token.NEQ 1016 case token.GEQ: 1017 return token.LEQ 1018 case token.LEQ: 1019 return token.GEQ 1020 default: 1021 panic(fmt.Sprintf("unsupported token %s", tok)) 1022 } 1023 } 1024 1025 type CopyConstraint struct { 1026 aConstraint 1027 X ssa.Value 1028 } 1029 1030 func (c *CopyConstraint) String() string { 1031 return fmt.Sprintf("%s = copy(%s)", c.Y().Name(), c.X.Name()) 1032 } 1033 1034 func (c *CopyConstraint) Eval(g *Graph) Range { 1035 return g.Range(c.X) 1036 } 1037 1038 func (c *CopyConstraint) Operands() []ssa.Value { 1039 return []ssa.Value{c.X} 1040 } 1041 1042 func NewCopyConstraint(x, y ssa.Value) Constraint { 1043 return &CopyConstraint{ 1044 aConstraint: aConstraint{ 1045 y: y, 1046 }, 1047 X: x, 1048 } 1049 }