github.com/aclements/go-misc@v0.0.0-20240129233631-2f6ede80790c/rtcheck/live.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 main 6 7 import ( 8 "log" 9 "os" 10 11 "golang.org/x/tools/go/ssa" 12 ) 13 14 // livenessFor computes which values must be live in each basic block 15 // in f in order to compute each value in vals. Note that a given 16 // value may be may be marked live in the same block it's defined in, 17 // so it may not yet exist upon entry to the block. deps is indexed by 18 // basic block number in f. 19 // 20 // TODO: This doesn't account for control flow dependencies. For 21 // example if a value depends on a phi, this will add all of the 22 // values that go into that phi, but not the values necessary to 23 // determine the control flow into that phi. In effect, the phi has an 24 // implicit dependency on which predecessor it came from, and we don't 25 // model that. 26 func livenessFor(f *ssa.Function, vals []ssa.Instruction) (deps []map[ssa.Value]struct{}) { 27 deps = make([]map[ssa.Value]struct{}, len(f.Blocks)) 28 29 // For each operand to def, keep the operand live in all 30 // blocks between the operand's definition and here. 31 var walk func(def ssa.Value, use *ssa.BasicBlock) 32 walk = func(def ssa.Value, use *ssa.BasicBlock) { 33 if _, ok := deps[use.Index][def]; ok { 34 return 35 } 36 37 if deps[use.Index] == nil { 38 deps[use.Index] = make(map[ssa.Value]struct{}) 39 } 40 deps[use.Index][def] = struct{}{} 41 42 switch def := def.(type) { 43 case *ssa.Const, *ssa.Global, *ssa.Function, *ssa.Builtin: 44 // There are never defined. 45 return 46 case *ssa.Parameter, *ssa.FreeVar: 47 // These are defined at function entry, so 48 // flood to function entry. 49 if len(use.Preds) == 0 { 50 return 51 } 52 case ssa.Instruction: 53 if def.Block() == use { 54 // We've reached the defining block. 55 return 56 } 57 default: 58 log.Fatalf("unexpected value definition type %s (%T)", def, def) 59 } 60 61 if len(use.Preds) == 0 { 62 f.WriteTo(os.Stderr) 63 log.Fatalf("failed to find definition of %v", def) 64 } 65 for _, pred := range use.Preds { 66 walk(def, pred) 67 } 68 } 69 70 visited := make(map[ssa.Instruction]struct{}) 71 var doInstr func(val ssa.Instruction) 72 doInstr = func(val ssa.Instruction) { 73 if _, ok := visited[val]; ok { 74 return 75 } 76 visited[val] = struct{}{} 77 78 if phi, ok := val.(*ssa.Phi); ok { 79 // A phi is special, as usual. It only uses 80 // each operand if it came from the 81 // corresponding predecessor. 82 if deps[phi.Block().Index] == nil { 83 deps[phi.Block().Index] = make(map[ssa.Value]struct{}) 84 } 85 for i, rand := range phi.Edges { 86 deps[phi.Block().Index][rand] = struct{}{} 87 walk(rand, phi.Block().Preds[i]) 88 89 // Recursively depend on the inputs to 90 // this operand. 91 if instr, ok := val.(ssa.Instruction); ok { 92 doInstr(instr) 93 } 94 } 95 } else { 96 // Regular instruction uses all of their operands. 97 rands := val.Operands(nil) 98 for _, rand := range rands { 99 if *rand == nil { 100 continue 101 } 102 walk(*rand, val.Block()) 103 104 // Recursively depend on the inputs to 105 // the operands. 106 if instr, ok := (*rand).(ssa.Instruction); ok { 107 doInstr(instr) 108 } 109 } 110 } 111 } 112 113 for _, val := range vals { 114 doInstr(val) 115 } 116 return deps 117 }