github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/phi.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      `github.com/oleiade/lane`
    23  )
    24  
    25  type _PhiDesc struct {
    26      r Reg
    27      b []*BasicBlock
    28  }
    29  
    30  func appendReg(buf map[Reg]bool, r Reg) map[Reg]bool {
    31      if buf == nil {
    32          return map[Reg]bool { r: true }
    33      } else {
    34          buf[r] = true
    35          return buf
    36      }
    37  }
    38  
    39  func appendBlock(buf map[int]*BasicBlock, bb *BasicBlock) map[int]*BasicBlock {
    40      if buf == nil {
    41          return map[int]*BasicBlock { bb.Id: bb }
    42      } else {
    43          buf[bb.Id] = bb
    44          return buf
    45      }
    46  }
    47  
    48  func insertPhiNodes(cfg *CFG) {
    49      q := lane.NewQueue()
    50      phi := make(map[Reg]map[int]bool)
    51      orig := make(map[int]map[Reg]bool)
    52      defs := make(map[Reg]map[int]*BasicBlock)
    53  
    54      /* find out all the variable origins */
    55      for q.Enqueue(cfg.Root); !q.Empty(); {
    56          p := q.Dequeue().(*BasicBlock)
    57          addImmediateDominated(cfg.DominatorOf, p, q)
    58  
    59          /* mark all the definition sites */
    60          for _, ins := range p.Ins {
    61              if def, ok := ins.(IrDefinitions); ok {
    62                  for _, d := range def.Definitions() {
    63                      if k := d.Kind(); k != K_zero {
    64                          orig[p.Id] = appendReg(orig[p.Id], *d)
    65                      }
    66                  }
    67              }
    68          }
    69      }
    70  
    71      /* find out all the variable defination sites */
    72      for q.Enqueue(cfg.Root); !q.Empty(); {
    73          p := q.Dequeue().(*BasicBlock)
    74          addImmediateDominated(cfg.DominatorOf, p, q)
    75  
    76          /* mark all the defination sites */
    77          for def := range orig[p.Id] {
    78              defs[def] = appendBlock(defs[def], p)
    79          }
    80      }
    81  
    82      /* reserve buffer for Phi descriptors */
    83      nb := len(defs)
    84      pd := make([]_PhiDesc, nb)
    85  
    86      /* dump the descriptors */
    87      for r, v := range defs {
    88          n := len(v)
    89          b := make([]*BasicBlock, 0, n)
    90  
    91          /* dump the blocks */
    92          for _, p := range v {
    93              b = append(b, p)
    94          }
    95  
    96          /* sort blocks by ID */
    97          sort.Slice(b, func(i int, j int) bool {
    98              return b[i].Id < b[j].Id
    99          })
   100  
   101          /* add the descriptor */
   102          pd = append(pd, _PhiDesc {
   103              r: r,
   104              b: b,
   105          })
   106      }
   107  
   108      /* sort descriptors by register */
   109      sort.Slice(pd, func(i int, j int) bool {
   110          return pd[i].r < pd[j].r
   111      })
   112  
   113      /* insert Phi node for every variable */
   114      for _, p := range pd {
   115          for len(p.b) != 0 {
   116              n := p.b[0]
   117              p.b = p.b[1:]
   118  
   119              /* insert Phi nodes */
   120              for _, y := range cfg.DominanceFrontier[n.Id] {
   121                  if rem := phi[p.r]; !rem[y.Id] {
   122                      id := y.Id
   123                      src := make(map[*BasicBlock]*Reg)
   124  
   125                      /* mark as processed */
   126                      if rem != nil {
   127                          rem[id] = true
   128                      } else {
   129                          phi[p.r] = map[int]bool { id: true }
   130                      }
   131  
   132                      /* build the Phi node args */
   133                      for _, pred := range y.Pred {
   134                          src[pred] = new(Reg)
   135                          *src[pred] = p.r
   136                      }
   137  
   138                      /* insert a new Phi node */
   139                      y.Phi = append(y.Phi, &IrPhi {
   140                          R: p.r,
   141                          V: src,
   142                      })
   143  
   144                      /* a node may contain both an ordinary definition and a
   145                       * Phi node for the same variable */
   146                      if !orig[y.Id][p.r] {
   147                          p.b = append(p.b, y)
   148                      }
   149                  }
   150              }
   151          }
   152      }
   153  }