github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_zeroreg.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      `runtime`
    21  )
    22  
    23  // ZeroReg replaces read to %z or %nil to a register that was
    24  // initialized to zero for architectures that does not have constant
    25  // zero registers, such as `x86_64`.
    26  type ZeroReg struct{}
    27  
    28  func (ZeroReg) replace(cfg *CFG) {
    29      cfg.PostOrder().ForEach(func(bb *BasicBlock) {
    30          var ok bool
    31          var rr *Reg
    32          var use IrUsages
    33  
    34          /* create the instruction buffer */
    35          ins := bb.Ins
    36          bb.Ins = make([]IrNode, 0, len(ins))
    37  
    38          /* zero register replacer */
    39          replacez := func(v IrUsages, ins *[]IrNode, tail IrNode) {
    40              var z Reg
    41              var r *Reg
    42  
    43              /* insert an zeroing instruction if needed */
    44              for _, r = range v.Usages() {
    45                  if r.Kind() == K_zero {
    46                      z = cfg.CreateRegister(false)
    47                      *ins = append(*ins, IrArchZero(z))
    48                      break
    49                  }
    50              }
    51  
    52              /* substitute all the zero register usages */
    53              for _, r = range v.Usages() {
    54                  if r.Kind() == K_zero {
    55                      *r = z
    56                  }
    57              }
    58  
    59              /* add the instruction if needed */
    60              if tail != nil {
    61                  *ins = append(*ins, tail)
    62              }
    63          }
    64  
    65          /* scan all the Phi nodes */
    66          for _, p := range bb.Pred {
    67              var z Reg
    68              var v *IrPhi
    69  
    70              /* insert an zeroing instruction to it's predecessor if needed */
    71              for _, v = range bb.Phi {
    72                  if v.V[p].Kind() == K_zero {
    73                      z = cfg.CreateRegister(false)
    74                      p.Ins = append(p.Ins, IrArchZero(z))
    75                      break
    76                  }
    77              }
    78  
    79              /* substitute all the zero register usages */
    80              for _, v = range bb.Phi {
    81                  if rr = v.V[p]; rr.Kind() == K_zero {
    82                      *rr = z
    83                  }
    84              }
    85          }
    86  
    87          /* scan all the instructions */
    88          for _, v := range ins {
    89              if use, ok = v.(IrUsages); ok {
    90                  replacez(use, &bb.Ins, v)
    91              } else {
    92                  bb.Ins = append(bb.Ins, v)
    93              }
    94          }
    95  
    96          /* scan the terminator */
    97          if use, ok = bb.Term.(IrUsages); ok {
    98              replacez(use, &bb.Ins, nil)
    99          }
   100      })
   101  }
   102  
   103  //goland:noinspection GoBoolExpressions
   104  func (self ZeroReg) Apply(cfg *CFG) {
   105      if runtime.GOARCH == "amd64" {
   106          self.replace(cfg)
   107      }
   108  }