github.com/golangci/go-tools@v0.0.0-20190318060251-af6baa5dc196/functions/loops.go (about)

     1  package functions
     2  
     3  import "github.com/golangci/go-tools/ssa"
     4  
     5  type Loop map[*ssa.BasicBlock]bool
     6  
     7  func findLoops(fn *ssa.Function) []Loop {
     8  	if fn.Blocks == nil {
     9  		return nil
    10  	}
    11  	tree := fn.DomPreorder()
    12  	var sets []Loop
    13  	for _, h := range tree {
    14  		for _, n := range h.Preds {
    15  			if !h.Dominates(n) {
    16  				continue
    17  			}
    18  			// n is a back-edge to h
    19  			// h is the loop header
    20  			if n == h {
    21  				sets = append(sets, Loop{n: true})
    22  				continue
    23  			}
    24  			set := Loop{h: true, n: true}
    25  			for _, b := range allPredsBut(n, h, nil) {
    26  				set[b] = true
    27  			}
    28  			sets = append(sets, set)
    29  		}
    30  	}
    31  	return sets
    32  }
    33  
    34  func allPredsBut(b, but *ssa.BasicBlock, list []*ssa.BasicBlock) []*ssa.BasicBlock {
    35  outer:
    36  	for _, pred := range b.Preds {
    37  		if pred == but {
    38  			continue
    39  		}
    40  		for _, p := range list {
    41  			// TODO improve big-o complexity of this function
    42  			if pred == p {
    43  				continue outer
    44  			}
    45  		}
    46  		list = append(list, pred)
    47  		list = allPredsBut(pred, but, list)
    48  	}
    49  	return list
    50  }