github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/builder.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 `sort` 22 23 `github.com/cloudwego/frugal/internal/atm/hir` 24 ) 25 26 var ( 27 _GenericRegs []hir.GenericRegister 28 _PointerRegs []hir.PointerRegister 29 ) 30 31 func init() { 32 _GenericRegs = make([]hir.GenericRegister, 0, len(hir.GenericRegisters)) 33 _PointerRegs = make([]hir.PointerRegister, 0, len(hir.PointerRegisters)) 34 35 /* extract all generic registers */ 36 for i := range hir.GenericRegisters { 37 if i != hir.Rz { 38 _GenericRegs = append(_GenericRegs, i) 39 } 40 } 41 42 /* extract all pointer registers */ 43 for m := range hir.PointerRegisters { 44 if m != hir.Pn { 45 _PointerRegs = append(_PointerRegs, m) 46 } 47 } 48 49 /* sort by register ID */ 50 sort.Slice(_GenericRegs, func(i int, j int) bool { return _GenericRegs[i] < _GenericRegs[j] }) 51 sort.Slice(_PointerRegs, func(i int, j int) bool { return _PointerRegs[i] < _PointerRegs[j] }) 52 } 53 54 type _GraphBuilder struct { 55 p map[*hir.Ir]bool 56 g map[*hir.Ir]*BasicBlock 57 } 58 59 func newGraphBuilder() *_GraphBuilder { 60 return &_GraphBuilder { 61 p: make(map[*hir.Ir]bool), 62 g: make(map[*hir.Ir]*BasicBlock), 63 } 64 } 65 66 func (self *_GraphBuilder) build(p hir.Program) *CFG { 67 ret := &CFG { 68 Depth : make(map[int]int), 69 DominatedBy : make(map[int]*BasicBlock), 70 DominatorOf : make(map[int][]*BasicBlock), 71 DominanceFrontier : make(map[int][]*BasicBlock), 72 } 73 74 /* create the root block */ 75 ret.Root = ret.CreateBlock() 76 ret.Root.Ins = make([]IrNode, 0, len(_GenericRegs) + len(_PointerRegs) + N_size) 77 78 /* implicit defination of all generic registers */ 79 for _, v := range _GenericRegs { 80 ret.Root.Ins = append(ret.Root.Ins, &IrConstInt { R: Rv(v), V: 0 }) 81 } 82 83 /* implicit defination of all pointer registers */ 84 for _, v := range _PointerRegs { 85 ret.Root.Ins = append(ret.Root.Ins, &IrConstPtr { R: Rv(v), P: nil, M: Volatile }) 86 } 87 88 /* implicitly define all the temporary registers */ 89 for i := 0; i < N_size; i++ { 90 ret.Root.Ins = append( 91 ret.Root.Ins, 92 &IrConstInt { R: Tr(i), V: 0 }, 93 &IrConstPtr { R: Pr(i), P: nil, M: Volatile }, 94 ) 95 } 96 97 /* mark all the branch targets */ 98 for v := p.Head; v != nil; v = v.Ln { 99 if v.IsBranch() { 100 if v.Op != hir.OP_bsw { 101 self.p[v.Br] = true 102 } else { 103 for _, lb := range v.Switch() { 104 self.p[lb] = true 105 } 106 } 107 } 108 } 109 110 /* process the root block */ 111 self.g[p.Head] = ret.Root 112 self.block(ret, p.Head, ret.Root) 113 114 /* build the CFG */ 115 ret.Rebuild() 116 return ret 117 } 118 119 func (self *_GraphBuilder) block(cfg *CFG, p *hir.Ir, bb *BasicBlock) { 120 bb.Phi = nil 121 bb.Term = nil 122 123 /* traverse down until it hits a branch instruction */ 124 for p != nil && !p.IsBranch() && p.Op != hir.OP_ret { 125 bb.addInstr(p) 126 p = p.Ln 127 128 /* hit a merge point, merge with existing block */ 129 if self.p[p] { 130 bb.termBranch(self.branch(cfg, p)) 131 return 132 } 133 } 134 135 /* basic block must terminate */ 136 if p == nil { 137 panic(fmt.Sprintf("basic block %d does not terminate", bb.Id)) 138 } 139 140 /* add terminators */ 141 switch p.Op { 142 case hir.OP_bsw : self.termbsw(cfg, p, bb) 143 case hir.OP_ret : bb.termReturn(p) 144 case hir.OP_jmp : bb.termBranch(self.branch(cfg, p.Br)) 145 default : bb.termCondition(p, self.branch(cfg, p.Br), self.branch(cfg, p.Ln)) 146 } 147 } 148 149 func (self *_GraphBuilder) branch(cfg *CFG, p *hir.Ir) *BasicBlock { 150 var ok bool 151 var bb *BasicBlock 152 153 /* check for existing basic blocks */ 154 if bb, ok = self.g[p]; ok { 155 return bb 156 } 157 158 /* create and process the new block */ 159 bb = cfg.CreateBlock() 160 self.g[p] = bb 161 self.block(cfg, p, bb) 162 return bb 163 } 164 165 func (self *_GraphBuilder) termbsw(cfg *CFG, p *hir.Ir, bb *BasicBlock) { 166 sw := new(IrSwitch) 167 sw.Br = make(map[int32]*IrBranch, p.Iv) 168 bb.Term = sw 169 170 /* add every branch of the switch instruction */ 171 for i, br := range p.Switch() { 172 if br != nil { 173 to := self.branch(cfg, br) 174 to.addPred(bb) 175 sw.Br[int32(i)] = IrLikely(to) 176 } 177 } 178 179 /* add the default branch */ 180 sw.Ln = IrUnlikely(self.branch(cfg, p.Ln)) 181 sw.Ln.To.addPred(bb) 182 }