github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_phielim.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 `github.com/cloudwego/frugal/internal/rt` 21 ) 22 23 type _RegSrc struct { 24 r Reg 25 p IrNode 26 } 27 28 // PhiElim transforms Phi nodes into copies if possible. 29 type PhiElim struct{} 30 31 func (self PhiElim) addSource(src map[_RegSrc]struct{}, phi *IrPhi, defs map[Reg]IrNode, visited map[*IrPhi]struct{}) { 32 var ok bool 33 var pp *IrPhi 34 var def IrNode 35 36 /* circles back to itself */ 37 if _, ok = visited[phi]; ok { 38 return 39 } else { 40 visited[phi] = struct{}{} 41 } 42 43 /* add definitions for this node */ 44 for _, r := range phi.V { 45 if r.Kind() == K_zero { 46 src[_RegSrc { r: *r, p: nil }] = struct{}{} 47 } else if def, ok = defs[*r]; !ok { 48 panic("phixform: undefined register: " + r.String()) 49 } else if pp, ok = def.(*IrPhi); ok { 50 self.addSource(src, pp, defs, visited) 51 } else { 52 src[_RegSrc { r: *r, p: def }] = struct{}{} 53 } 54 } 55 } 56 57 func (self PhiElim) Apply(cfg *CFG) { 58 buf := make(map[Reg]IrNode) 59 vis := make(map[*IrPhi]struct{}) 60 src := make(map[_RegSrc]struct{}) 61 62 /* scan for all instruction usages and register definitions */ 63 cfg.PostOrder().ForEach(func(bb *BasicBlock) { 64 var ok bool 65 var def IrDefinitions 66 67 /* mark all Phi definitions */ 68 for _, v := range bb.Phi { 69 buf[v.R] = v 70 } 71 72 /* scan instructions */ 73 for _, v := range bb.Ins { 74 if def, ok = v.(IrDefinitions); ok { 75 for _, r := range def.Definitions() { 76 buf[*r] = v 77 } 78 } 79 } 80 }) 81 82 /* scan for unused Phi nodes */ 83 cfg.PostOrder().ForEach(func(bb *BasicBlock) { 84 var p *IrPhi 85 var ins []IrNode 86 87 /* filter the Phi nodes */ 88 phi := bb.Phi 89 bb.Phi = bb.Phi[:0] 90 91 /* check all Phi nodes */ 92 for _, p = range phi { 93 rt.MapClear(src) 94 rt.MapClear(vis) 95 96 /* resolve all the value sources */ 97 if self.addSource(src, p, buf, vis); len(src) != 1 { 98 bb.Phi = append(bb.Phi, p) 99 continue 100 } 101 102 /* all values come from a single source */ 103 for s := range src { 104 ins = append(ins, IrCopy(p.R, s.r)) 105 break 106 } 107 } 108 109 /* patch instructions if needed */ 110 if len(ins) != 0 { 111 bb.Ins = append(ins, bb.Ins...) 112 } 113 }) 114 }