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