github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_blockmerge.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  // BlockMerge merges redundant intermediate blocks (blocks with a single
    20  // outgoing edge which goes to another block with a single incoming edge).
    21  type BlockMerge struct{}
    22  
    23  func (BlockMerge) Apply(cfg *CFG) {
    24      for {
    25          var rt bool
    26          var nx *BasicBlock
    27          var it IrSuccessors
    28          var tr IrTerminator
    29  
    30          /* check every block */
    31          cfg.PostOrder().ForEach(func(bb *BasicBlock) {
    32              tr = bb.Term
    33              it = tr.Successors()
    34  
    35              /* it must have successors */
    36              if !it.Next() {
    37                  return
    38              }
    39  
    40              /* it must have exactly 1 successor, and the successor must have exactly 1 predecessor */
    41              if nx = it.Block(); it.Next() || len(nx.Pred) != 1 {
    42                  return
    43              }
    44  
    45              /* merge the two blocks */
    46              rt = true
    47              bb.Ins = append(bb.Ins, nx.Ins...)
    48              bb.Term = nx.Term
    49  
    50              /* must not have Phi nodes */
    51              if len(nx.Phi) != 0 {
    52                  panic("invalid Phi node found in intermediate blocks")
    53              }
    54  
    55              /* get the successor iterator */
    56              tr = nx.Term
    57              it = tr.Successors()
    58  
    59              /* update all predecessors references */
    60              for it.Next() {
    61                  rb := it.Block()
    62                  pp := rb.Pred
    63  
    64                  /* update predecessor list */
    65                  for i, p := range pp {
    66                      if p == nx {
    67                          pp[i] = bb
    68                      }
    69                  }
    70  
    71                  /* update in Phi nodes */
    72                  for _, v := range rb.Phi {
    73                      v.V[bb] = v.V[nx]
    74                      delete(v.V, nx)
    75                  }
    76              }
    77          })
    78  
    79          /* rebuild the dominator tree, and retry if needed */
    80          if cfg.Rebuild(); !rt {
    81              break
    82          }
    83      }
    84  }
    85