github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_copyelim.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  // CopyElim removes unnessecery register copies.
    20  type CopyElim struct{}
    21  
    22  func (CopyElim) Apply(cfg *CFG) {
    23      regs := make(map[Reg]Reg)
    24      consts := make(map[Reg]_ConstData)
    25  
    26      /* constant zero registers */
    27      consts[Rz] = constint(0)
    28      consts[Pn] = constptr(nil, Const)
    29  
    30      /* register replacement func */
    31      replacereg := func(rr *Reg) {
    32          var rv Reg
    33          var ok bool
    34          var cc _ConstData
    35  
    36          /* substitute registers */
    37          for {
    38              if rv, ok = regs[*rr]; ok {
    39                  *rr = rv
    40              } else {
    41                  break
    42              }
    43          }
    44  
    45          /* substitute zero registers */
    46          if cc, ok = consts[*rr]; ok {
    47              if cc.i && cc.v == 0 {
    48                  *rr = Rz
    49              } else if !cc.i && cc.p == nil {
    50                  *rr = Pn
    51              }
    52          }
    53      }
    54  
    55      /* Phase 1: Find all the constants */
    56      cfg.PostOrder().ForEach(func(bb *BasicBlock) {
    57          for _, v := range bb.Ins {
    58              switch p := v.(type) {
    59                  case *IrConstInt: consts[p.R] = constint(p.V)
    60                  case *IrConstPtr: consts[p.R] = constptr(p.P, p.M)
    61              }
    62          }
    63      })
    64  
    65      /* Phase 2: Identify all the identity operations */
    66      for _, bb := range cfg.PostOrder().Reversed() {
    67          for _, v := range bb.Ins {
    68              switch p := v.(type) {
    69                  default: {
    70                      continue
    71                  }
    72  
    73                  /* pointer arithmetic */
    74                  case *IrLEA: {
    75                      if cc, ok := consts[p.Off]; ok && cc.i && cc.v == 0 {
    76                          regs[p.R] = p.Mem
    77                      }
    78                  }
    79  
    80                  /* integer arithmetic */
    81                  case *IrBinaryExpr: {
    82                      var c bool
    83                      var i int64
    84                      var x _ConstData
    85                      var y _ConstData
    86  
    87                      /* calculate mathematical identities */
    88                      switch p.Op {
    89                          case IrOpAdd : i = 0
    90                          case IrOpSub : i = 0
    91                          case IrOpMul : i = 1
    92                          case IrOpAnd : i = -1
    93                          case IrOpOr  : i = 0
    94                          case IrOpXor : i = 0
    95                          case IrOpShr : i = 0
    96                          default      : continue
    97                      }
    98  
    99                      /* check for identity operations */
   100                      if x, c = consts[p.X]; c && x.i && x.v == i {
   101                          regs[p.R] = p.Y
   102                      } else if y, c = consts[p.Y]; c && y.i && y.v == i {
   103                          regs[p.R] = p.X
   104                      }
   105                  }
   106              }
   107          }
   108      }
   109  
   110      /* Phase 3: Replace all the register references */
   111      cfg.PostOrder().ForEach(func(bb *BasicBlock) {
   112          var ok bool
   113          var use IrUsages
   114  
   115          /* replace in Phi nodes */
   116          for _, v := range bb.Phi {
   117              for _, u := range v.Usages() {
   118                  replacereg(u)
   119              }
   120          }
   121  
   122          /* replace in instructions */
   123          for _, v := range bb.Ins {
   124              if use, ok = v.(IrUsages); ok {
   125                  for _, u := range use.Usages() {
   126                      replacereg(u)
   127                  }
   128              }
   129          }
   130  
   131          /* replace in terminators */
   132          if use, ok = bb.Term.(IrUsages); ok {
   133              for _, u := range use.Usages() {
   134                  replacereg(u)
   135              }
   136          }
   137      })
   138  }