github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_layout.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 23 type _Successor struct { 24 bb *BasicBlock 25 prob Likeliness 26 } 27 28 // Layout flattens the CFG into a linear FuncLayout 29 type Layout struct{} 30 31 func (self Layout) flatten(fn *FuncLayout, bb *BasicBlock) { 32 var ok bool 33 var nx []_Successor 34 35 /* check for visited blocks */ 36 if _, ok = fn.Start[bb.Id]; ok { 37 return 38 } 39 40 /* mark the starting position, and the corresponding block */ 41 fn.Start[bb.Id] = len(fn.Ins) 42 fn.Block[len(fn.Ins)] = bb 43 44 /* add instructions and the terminator */ 45 fn.Ins = append(fn.Ins, bb.Ins...) 46 fn.Ins = append(fn.Ins, bb.Term) 47 48 /* get all it's successors */ 49 for it := bb.Term.Successors(); it.Next(); { 50 nx = append(nx, _Successor { 51 bb : it.Block(), 52 prob : it.Likeliness(), 53 }) 54 } 55 56 /* sort the likely blocks at front */ 57 sort.Slice(nx, func(i int, j int) bool { 58 return nx[i].prob == Likely && nx[j].prob == Unlikely 59 }) 60 61 /* visit all the successors */ 62 for _, v := range nx { 63 self.flatten(fn, v.bb) 64 } 65 } 66 67 func (self Layout) Apply(cfg *CFG) { 68 cfg.Func.Layout = new(FuncLayout) 69 cfg.Func.Layout.Start = make(map[int]int, cfg.MaxBlock()) 70 cfg.Func.Layout.Block = make(map[int]*BasicBlock, cfg.MaxBlock()) 71 72 /* remove all virtual instructions */ 73 cfg.PostOrder().ForEach(func(bb *BasicBlock) { 74 ins := bb.Ins 75 bb.Ins = bb.Ins[:0] 76 77 /* filter the instructions */ 78 for _, v := range ins { 79 if _, ok := v.(*IrEntry) ; ok { continue } 80 if _, ok := v.(*IrClobberList) ; ok { continue } 81 bb.Ins = append(bb.Ins, v) 82 } 83 }) 84 85 /* retry until no more intermediate blocks found */ 86 for { 87 var rt bool 88 var nb *BasicBlock 89 90 /* collapse all the intermediate blocks */ 91 cfg.PostOrder().ForEach(func(bb *BasicBlock) { 92 tr := bb.Term 93 it := tr.Successors() 94 95 /* scan every successors */ 96 for it.Next() { 97 nx := it.Block() 98 st := nx.Term.Successors() 99 100 /* must have exactly 1 predecessor, exactly 1 successor, and no instructions 101 * if so, update the successor to skip the intermediate block */ 102 if st.Next() && len(nx.Ins) == 0 && len(nx.Pred) == 1 { 103 if nb = st.Block(); !st.Next() { 104 rt = true 105 it.UpdateBlock(nb) 106 } 107 } 108 } 109 }) 110 111 /* rebuild the CFG if needed */ 112 if !rt { 113 break 114 } else { 115 cfg.Rebuild() 116 } 117 } 118 119 /* flatten the CFG */ 120 root := cfg.Root 121 self.flatten(cfg.Func.Layout, root) 122 }