github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_comsubexpr.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      `fmt`
    21  )
    22  
    23  type _Vid interface {
    24      IrDefinitions
    25      vid() []string
    26  }
    27  
    28  func (self *IrLoadArg) vid() []string {
    29      return []string {
    30          fmt.Sprintf("#%d", self.I),
    31      }
    32  }
    33  
    34  func (self *IrConstInt) vid() []string {
    35      return []string {
    36          fmt.Sprintf("$%d", self.V),
    37      }
    38  }
    39  
    40  func (self *IrConstPtr) vid() []string {
    41      return []string {
    42          fmt.Sprintf("$%p", self.P),
    43      }
    44  }
    45  
    46  func (self *IrLEA) vid() []string {
    47      return []string {
    48          fmt.Sprintf("(& %s %s)", self.Mem, self.Off),
    49      }
    50  }
    51  
    52  func (self *IrUnaryExpr) vid() []string {
    53      return []string {
    54          fmt.Sprintf("(%s %s)", self.Op, self.V),
    55      }
    56  }
    57  
    58  func (self *IrBinaryExpr) vid() []string {
    59      x := self.X
    60      y := self.Y
    61  
    62      /* commutative operations, sort the operands */
    63      switch self.Op {
    64          case IrOpAdd : fallthrough
    65          case IrOpMul : fallthrough
    66          case IrOpAnd : fallthrough
    67          case IrOpOr  : fallthrough
    68          case IrOpXor : fallthrough
    69          case IrCmpEq : fallthrough
    70          case IrCmpNe : if x > y { x, y = y, x }
    71      }
    72  
    73      /* build the value ID */
    74      return []string {
    75          fmt.Sprintf("(%s %s %s)", self.Op, x, y),
    76      }
    77  }
    78  
    79  func (self *IrBitTestSet) vid() []string {
    80      return []string {
    81          fmt.Sprintf("(&# %s %s)", self.X, self.Y),
    82          fmt.Sprintf("(|# %s %s)", self.X, self.Y),
    83      }
    84  }
    85  
    86  type _VidMap struct {
    87      p *_VidMap
    88      m map[string]Reg
    89  }
    90  
    91  func (self *_VidMap) derive() *_VidMap {
    92      return &_VidMap {
    93          p: self,
    94          m: make(map[string]Reg),
    95      }
    96  }
    97  
    98  func (self *_VidMap) lookup(vid string) (Reg, bool) {
    99      if r, ok := self.m[vid]; ok {
   100          return r, true
   101      } else if self.p == nil {
   102          return 0, false
   103      } else {
   104          return self.p.lookup(vid)
   105      }
   106  }
   107  
   108  func (self *_VidMap) define(vid string, reg Reg) {
   109      self.m[vid] = reg
   110  }
   111  
   112  // CSE performs the Common Sub-expression Elimintation optimization.
   113  type CSE struct{}
   114  
   115  func (self CSE) dfs(cfg *CFG, bb *BasicBlock, vm *_VidMap) {
   116      ins := bb.Ins
   117      vals := vm.derive()
   118  
   119      /* scan every instructions */
   120      for i, v := range ins {
   121          var r Reg
   122          var d _Vid
   123          var ok bool
   124  
   125          /* check if the instruction have VIDs */
   126          if d, ok = v.(_Vid); !ok {
   127              continue
   128          }
   129  
   130          /* calculate the VIDs */
   131          repc := i
   132          vids := d.vid()
   133          defs := d.Definitions()
   134  
   135          /* replace each VID with a copy instruction */
   136          for j, vid := range vids {
   137              s := defs[j]
   138              r, ok = vals.lookup(vid)
   139  
   140              /* skip zero registers */
   141              if s.Kind() == K_zero {
   142                  continue
   143              }
   144  
   145              /* add to definations if not found */
   146              if !ok {
   147                  vals.define(vid, *s)
   148                  continue
   149              }
   150  
   151              /* allocate one slot for the new instruction */
   152              repc++
   153              bb.Ins = append(bb.Ins, nil)
   154              copy(bb.Ins[repc + 1:], bb.Ins[repc:])
   155  
   156              /* insert a new copy instruction */
   157              bb.Ins[repc] = IrCopy(*s, r)
   158              *s = s.Zero()
   159          }
   160  
   161          /* all the definations are been replaced */
   162          if repc == i + len(defs) {
   163              bb.Ins = append(bb.Ins[:i], bb.Ins[i + 1:]...)
   164          }
   165      }
   166  
   167      /* DFS the dominator tree */
   168      for _, v := range cfg.DominatorOf[bb.Id] {
   169          self.dfs(cfg, v, vals)
   170      }
   171  }
   172  
   173  func (self CSE) Apply(cfg *CFG) {
   174      self.dfs(cfg, cfg.Root, nil)
   175  }