github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_phielim.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      `github.com/cloudwego/frugal/internal/rt`
    21  )
    22  
    23  type _RegSrc struct {
    24      r Reg
    25      p IrNode
    26  }
    27  
    28  // PhiElim transforms Phi nodes into copies if possible.
    29  type PhiElim struct{}
    30  
    31  func (self PhiElim) addSource(src map[_RegSrc]struct{}, phi *IrPhi, defs map[Reg]IrNode, visited map[*IrPhi]struct{}) {
    32      var ok bool
    33      var pp *IrPhi
    34      var def IrNode
    35  
    36      /* circles back to itself */
    37      if _, ok = visited[phi]; ok {
    38          return
    39      } else {
    40          visited[phi] = struct{}{}
    41      }
    42  
    43      /* add definitions for this node */
    44      for _, r := range phi.V {
    45          if r.Kind() == K_zero {
    46              src[_RegSrc { r: *r, p: nil }] = struct{}{}
    47          } else if def, ok = defs[*r]; !ok {
    48              panic("phixform: undefined register: " + r.String())
    49          } else if pp, ok = def.(*IrPhi); ok {
    50              self.addSource(src, pp, defs, visited)
    51          } else {
    52              src[_RegSrc { r: *r, p: def }] = struct{}{}
    53          }
    54      }
    55  }
    56  
    57  func (self PhiElim) Apply(cfg *CFG) {
    58      buf := make(map[Reg]IrNode)
    59      vis := make(map[*IrPhi]struct{})
    60      src := make(map[_RegSrc]struct{})
    61  
    62      /* scan for all instruction usages and register definitions */
    63      cfg.PostOrder().ForEach(func(bb *BasicBlock) {
    64          var ok bool
    65          var def IrDefinitions
    66  
    67          /* mark all Phi definitions */
    68          for _, v := range bb.Phi {
    69              buf[v.R] = v
    70          }
    71  
    72          /* scan instructions */
    73          for _, v := range bb.Ins {
    74              if def, ok = v.(IrDefinitions); ok {
    75                  for _, r := range def.Definitions() {
    76                      buf[*r] = v
    77                  }
    78              }
    79          }
    80      })
    81  
    82      /* scan for unused Phi nodes */
    83      cfg.PostOrder().ForEach(func(bb *BasicBlock) {
    84          var p *IrPhi
    85          var ins []IrNode
    86  
    87          /* filter the Phi nodes */
    88          phi := bb.Phi
    89          bb.Phi = bb.Phi[:0]
    90  
    91          /* check all Phi nodes */
    92          for _, p = range phi {
    93              rt.MapClear(src)
    94              rt.MapClear(vis)
    95  
    96              /* resolve all the value sources */
    97              if self.addSource(src, p, buf, vis); len(src) != 1 {
    98                  bb.Phi = append(bb.Phi, p)
    99                  continue
   100              }
   101  
   102              /* all values come from a single source */
   103              for s := range src {
   104                  ins = append(ins, IrCopy(p.R, s.r))
   105                  break
   106              }
   107          }
   108  
   109          /* patch instructions if needed */
   110          if len(ins) != 0 {
   111              bb.Ins = append(ins, bb.Ins...)
   112          }
   113      })
   114  }