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  }