github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/ssa/lca.go (about)

     1  // Copyright 2016 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 ssa
     6  
     7  // Code to compute lowest common ancestors in the dominator tree.
     8  // https://en.wikipedia.org/wiki/Lowest_common_ancestor
     9  // https://en.wikipedia.org/wiki/Range_minimum_query#Solution_using_constant_time_and_linearithmic_space
    10  
    11  // lcaRange is a data structure that can compute lowest common ancestor queries
    12  // in O(n lg n) precomputed space and O(1) time per query.
    13  type lcaRange struct {
    14  	// Additional information about each block (indexed by block ID).
    15  	blocks []lcaRangeBlock
    16  
    17  	// Data structure for range minimum queries.
    18  	// rangeMin[k][i] contains the ID of the minimum depth block
    19  	// in the Euler tour from positions i to i+1<<k-1, inclusive.
    20  	rangeMin [][]ID
    21  }
    22  
    23  type lcaRangeBlock struct {
    24  	b          *Block
    25  	parent     ID    // parent in dominator tree.  0 = no parent (entry or unreachable)
    26  	firstChild ID    // first child in dominator tree
    27  	sibling    ID    // next child of parent
    28  	pos        int32 // an index in the Euler tour where this block appears (any one of its occurrences)
    29  	depth      int32 // depth in dominator tree (root=0, its children=1, etc.)
    30  }
    31  
    32  func makeLCArange(f *Func) *lcaRange {
    33  	dom := f.Idom()
    34  
    35  	// Build tree
    36  	blocks := make([]lcaRangeBlock, f.NumBlocks())
    37  	for _, b := range f.Blocks {
    38  		blocks[b.ID].b = b
    39  		if dom[b.ID] == nil {
    40  			continue // entry or unreachable
    41  		}
    42  		parent := dom[b.ID].ID
    43  		blocks[b.ID].parent = parent
    44  		blocks[b.ID].sibling = blocks[parent].firstChild
    45  		blocks[parent].firstChild = b.ID
    46  	}
    47  
    48  	// Compute euler tour ordering.
    49  	// Each reachable block will appear #children+1 times in the tour.
    50  	tour := make([]ID, 0, f.NumBlocks()*2-1)
    51  	type queueEntry struct {
    52  		bid ID // block to work on
    53  		cid ID // child we're already working on (0 = haven't started yet)
    54  	}
    55  	q := []queueEntry{{f.Entry.ID, 0}}
    56  	for len(q) > 0 {
    57  		n := len(q) - 1
    58  		bid := q[n].bid
    59  		cid := q[n].cid
    60  		q = q[:n]
    61  
    62  		// Add block to tour.
    63  		blocks[bid].pos = int32(len(tour))
    64  		tour = append(tour, bid)
    65  
    66  		// Proceed down next child edge (if any).
    67  		if cid == 0 {
    68  			// This is our first visit to b. Set its depth.
    69  			blocks[bid].depth = blocks[blocks[bid].parent].depth + 1
    70  			// Then explore its first child.
    71  			cid = blocks[bid].firstChild
    72  		} else {
    73  			// We've seen b before. Explore the next child.
    74  			cid = blocks[cid].sibling
    75  		}
    76  		if cid != 0 {
    77  			q = append(q, queueEntry{bid, cid}, queueEntry{cid, 0})
    78  		}
    79  	}
    80  
    81  	// Compute fast range-minimum query data structure
    82  	var rangeMin [][]ID
    83  	rangeMin = append(rangeMin, tour) // 1-size windows are just the tour itself.
    84  	for logS, s := 1, 2; s < len(tour); logS, s = logS+1, s*2 {
    85  		r := make([]ID, len(tour)-s+1)
    86  		for i := 0; i < len(tour)-s+1; i++ {
    87  			bid := rangeMin[logS-1][i]
    88  			bid2 := rangeMin[logS-1][i+s/2]
    89  			if blocks[bid2].depth < blocks[bid].depth {
    90  				bid = bid2
    91  			}
    92  			r[i] = bid
    93  		}
    94  		rangeMin = append(rangeMin, r)
    95  	}
    96  
    97  	return &lcaRange{blocks: blocks, rangeMin: rangeMin}
    98  }
    99  
   100  // find returns the lowest common ancestor of a and b.
   101  func (lca *lcaRange) find(a, b *Block) *Block {
   102  	if a == b {
   103  		return a
   104  	}
   105  	// Find the positions of a and bin the Euler tour.
   106  	p1 := lca.blocks[a.ID].pos
   107  	p2 := lca.blocks[b.ID].pos
   108  	if p1 > p2 {
   109  		p1, p2 = p2, p1
   110  	}
   111  
   112  	// The lowest common ancestor is the minimum depth block
   113  	// on the tour from p1 to p2.  We've precomputed minimum
   114  	// depth blocks for powers-of-two subsequences of the tour.
   115  	// Combine the right two precomputed values to get the answer.
   116  	logS := uint(log2(int64(p2 - p1)))
   117  	bid1 := lca.rangeMin[logS][p1]
   118  	bid2 := lca.rangeMin[logS][p2-1<<logS+1]
   119  	if lca.blocks[bid1].depth < lca.blocks[bid2].depth {
   120  		return lca.blocks[bid1].b
   121  	}
   122  	return lca.blocks[bid2].b
   123  }