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  }