github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/phi.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 `sort` 21 22 `github.com/oleiade/lane` 23 ) 24 25 type _PhiDesc struct { 26 r Reg 27 b []*BasicBlock 28 } 29 30 func appendReg(buf map[Reg]bool, r Reg) map[Reg]bool { 31 if buf == nil { 32 return map[Reg]bool { r: true } 33 } else { 34 buf[r] = true 35 return buf 36 } 37 } 38 39 func appendBlock(buf map[int]*BasicBlock, bb *BasicBlock) map[int]*BasicBlock { 40 if buf == nil { 41 return map[int]*BasicBlock { bb.Id: bb } 42 } else { 43 buf[bb.Id] = bb 44 return buf 45 } 46 } 47 48 func insertPhiNodes(cfg *CFG) { 49 q := lane.NewQueue() 50 phi := make(map[Reg]map[int]bool) 51 orig := make(map[int]map[Reg]bool) 52 defs := make(map[Reg]map[int]*BasicBlock) 53 54 /* find out all the variable origins */ 55 for q.Enqueue(cfg.Root); !q.Empty(); { 56 p := q.Dequeue().(*BasicBlock) 57 addImmediateDominated(cfg.DominatorOf, p, q) 58 59 /* mark all the definition sites */ 60 for _, ins := range p.Ins { 61 if def, ok := ins.(IrDefinitions); ok { 62 for _, d := range def.Definitions() { 63 if k := d.Kind(); k != K_zero { 64 orig[p.Id] = appendReg(orig[p.Id], *d) 65 } 66 } 67 } 68 } 69 } 70 71 /* find out all the variable defination sites */ 72 for q.Enqueue(cfg.Root); !q.Empty(); { 73 p := q.Dequeue().(*BasicBlock) 74 addImmediateDominated(cfg.DominatorOf, p, q) 75 76 /* mark all the defination sites */ 77 for def := range orig[p.Id] { 78 defs[def] = appendBlock(defs[def], p) 79 } 80 } 81 82 /* reserve buffer for Phi descriptors */ 83 nb := len(defs) 84 pd := make([]_PhiDesc, nb) 85 86 /* dump the descriptors */ 87 for r, v := range defs { 88 n := len(v) 89 b := make([]*BasicBlock, 0, n) 90 91 /* dump the blocks */ 92 for _, p := range v { 93 b = append(b, p) 94 } 95 96 /* sort blocks by ID */ 97 sort.Slice(b, func(i int, j int) bool { 98 return b[i].Id < b[j].Id 99 }) 100 101 /* add the descriptor */ 102 pd = append(pd, _PhiDesc { 103 r: r, 104 b: b, 105 }) 106 } 107 108 /* sort descriptors by register */ 109 sort.Slice(pd, func(i int, j int) bool { 110 return pd[i].r < pd[j].r 111 }) 112 113 /* insert Phi node for every variable */ 114 for _, p := range pd { 115 for len(p.b) != 0 { 116 n := p.b[0] 117 p.b = p.b[1:] 118 119 /* insert Phi nodes */ 120 for _, y := range cfg.DominanceFrontier[n.Id] { 121 if rem := phi[p.r]; !rem[y.Id] { 122 id := y.Id 123 src := make(map[*BasicBlock]*Reg) 124 125 /* mark as processed */ 126 if rem != nil { 127 rem[id] = true 128 } else { 129 phi[p.r] = map[int]bool { id: true } 130 } 131 132 /* build the Phi node args */ 133 for _, pred := range y.Pred { 134 src[pred] = new(Reg) 135 *src[pred] = p.r 136 } 137 138 /* insert a new Phi node */ 139 y.Phi = append(y.Phi, &IrPhi { 140 R: p.r, 141 V: src, 142 }) 143 144 /* a node may contain both an ordinary definition and a 145 * Phi node for the same variable */ 146 if !orig[y.Id][p.r] { 147 p.b = append(p.b, y) 148 } 149 } 150 } 151 } 152 } 153 }