github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_stack_liveness.go (about) 1 /* 2 * Copyright 2022 ByteDance Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package ssa 18 19 import ( 20 `fmt` 21 ) 22 23 // StackLiveness calculates the liveness of each stack slot. 24 type StackLiveness struct{} 25 26 func (self StackLiveness) livein(lr map[Pos]SlotSet, bb *BasicBlock, in map[int]SlotSet, out map[int]SlotSet) SlotSet { 27 var ok bool 28 var ss SlotSet 29 var sp *IrSpill 30 31 /* check for cached live-in sets */ 32 if ss, ok = in[bb.Id]; ok { 33 return ss.clone() 34 } 35 36 /* calculate the live-out set of current block */ 37 tr := bb.Term 38 sl := self.liveout(lr, bb, in, out).clone() 39 40 /* assume all terminators are non-definitive */ 41 if _, ok = tr.(IrDefinitions); ok { 42 panic("regalloc: definitions within terminators") 43 } 44 45 /* mark live range of the terminator */ 46 rr := sl.clone() 47 lr[pos(bb, _P_term)] = rr 48 49 /* live(i-1) = use(i) ∪ (live(i) - { def(i) }) */ 50 for i := len(bb.Ins) - 1; i >= 0; i-- { 51 ins := bb.Ins[i] 52 sp, ok = ins.(*IrSpill) 53 54 /* only account for pointer slots */ 55 if !ok || !sp.S.IsPtr() { 56 lr[pos(bb, i)] = sl.clone() 57 continue 58 } 59 60 /* handle spill operations */ 61 switch sp.Op { 62 default: { 63 panic("stackmap: invalid spill Op") 64 } 65 66 /* store operaion marks the value is alive since here */ 67 case IrSpillStore: { 68 if sl.remove(sp.S) { 69 lr[pos(bb, i)] = sl.clone() 70 } else { 71 panic(fmt.Sprintf("stackmap: killing non-existing value %s at %s:%d. ins = %s", sp.S, bb, i, bb.Ins[i])) 72 } 73 } 74 75 /* load operaion marks the value is alive until here */ 76 case IrSpillReload: { 77 if sl.add(sp.S) { 78 lr[pos(bb, i)] = sl.clone() 79 } 80 } 81 } 82 } 83 84 /* should not have any Phi nodes */ 85 if len(bb.Phi) != 0 { 86 panic("regalloc: unexpected Phi nodes") 87 } 88 89 /* update the cache */ 90 in[bb.Id] = sl.clone() 91 return sl 92 } 93 94 func (self StackLiveness) liveout(lr map[Pos]SlotSet, bb *BasicBlock, in map[int]SlotSet, out map[int]SlotSet) SlotSet { 95 var ok bool 96 var ss SlotSet 97 var it IrSuccessors 98 99 /* check for cached live-out sets */ 100 if ss, ok = out[bb.Id]; ok { 101 return ss 102 } 103 104 /* check for return blocks */ 105 if _, ok = IrTryIntoArchReturn(bb.Term); ok { 106 out[bb.Id] = make(SlotSet) 107 return ss 108 } 109 110 /* create a new register set */ 111 ss = make(SlotSet) 112 it = bb.Term.Successors() 113 114 /* live-out(p) = ∑(live-in(succ(p))) */ 115 for out[bb.Id] = nil; it.Next(); { 116 for sl := range self.livein(lr, it.Block(), in, out) { 117 ss.add(sl) 118 } 119 } 120 121 /* update cache */ 122 out[bb.Id] = ss 123 return ss 124 } 125 126 func (self StackLiveness) liveness(cfg *CFG) { 127 for ss := range self.livein(cfg.Func.Liveness, cfg.Root, make(map[int]SlotSet), make(map[int]SlotSet)) { 128 panic("stackliveness: live slot at entry: " + ss.String()) 129 } 130 } 131 132 func (self StackLiveness) Apply(cfg *CFG) { 133 cfg.Func.Liveness = make(map[Pos]SlotSet) 134 self.liveness(cfg) 135 }