Source file src/cmd/compile/internal/ssacompile/lca.go

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

View as plain text