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 }