github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_splitcritical.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 type _CrEdge struct { 20 to *BasicBlock 21 from *BasicBlock 22 } 23 24 // SplitCritical splits critical edges (those that go from a block with 25 // more than one outedge to a block with more than one inedge) by inserting 26 // an empty block. 27 // 28 // PhiProp wants a critical-edge-free CFG so it can safely remove Phi nodes 29 // for RegAlloc. 30 type SplitCritical struct{} 31 32 func (SplitCritical) Apply(cfg *CFG) { 33 var nb int 34 var edges []_CrEdge 35 36 /* find all critical edges */ 37 cfg.PostOrder().ForEach(func(bb *BasicBlock) { 38 if len(bb.Pred) > 1 { 39 for _, p := range bb.Pred { 40 nb = 0 41 tr := p.Term.Successors() 42 43 /* check for successors */ 44 for nb < 2 && tr.Next() { 45 nb++ 46 } 47 48 /* the predecessor have more than 1 successors, this is a critcal edge */ 49 if nb > 1 { 50 edges = append(edges, _CrEdge { 51 to : bb, 52 from : p, 53 }) 54 } 55 } 56 } 57 }) 58 59 /* insert empty block between the edges */ 60 for _, e := range edges { 61 bb := cfg.CreateBlock() 62 bb.Term = IrArchJump(e.to) 63 bb.Pred = []*BasicBlock { e.from } 64 65 /* update the successor */ 66 for it := e.from.Term.Successors(); it.Next(); { 67 if it.Block() == e.to { 68 it.UpdateBlock(bb) 69 break 70 } 71 } 72 73 /* update the predecessor */ 74 for i, p := range e.to.Pred { 75 if p == e.from { 76 e.to.Pred[i] = bb 77 break 78 } 79 } 80 81 /* update the Phi nodes */ 82 for _, p := range e.to.Phi { 83 for b, r := range p.V { 84 if b == e.from { 85 p.V[bb] = r 86 delete(p.V, b) 87 break 88 } 89 } 90 } 91 } 92 93 /* rebuild the CFG if needed */ 94 if len(edges) != 0 { 95 cfg.Rebuild() 96 } 97 }