github.com/cloudwego/frugal@v0.1.15/internal/atm/ssa/pass_abispec.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  // ABILowering lowers ABI-specific instructions to machine specific instructions.
    24  type ABILowering struct{}
    25  
    26  func (self ABILowering) Apply(cfg *CFG) {
    27      rr := make([]Reg, len(cfg.Layout.Args))
    28      rb := rr[:0]
    29  
    30      /* map each argument load to register alias or stack load */
    31      for i, v := range cfg.Root.Ins {
    32          if iv, ok := v.(*IrLoadArg); !ok {
    33              break
    34          } else if iv.I < 0 || iv.I >= len(cfg.Layout.Args) {
    35              panic("abi: argument load out of bound: " + v.String())
    36          } else if rr[iv.I] != 0 {
    37              panic("abi: second load of the same argument: " + v.String())
    38          } else if a := cfg.Layout.Args[iv.I]; a.InRegister {
    39              rr[iv.I] = IrSetArch(Rz, a.Reg)
    40              cfg.Root.Ins[i] = &IrAlias { R: iv.R, V: rr[iv.I] }
    41          } else {
    42              rr[iv.I] = Rz
    43              cfg.Root.Ins[i] = IrArchLoadStack(iv.R, a.Mem, IrSlotArgs)
    44          }
    45      }
    46  
    47      /* extract all the registers */
    48      for _, r := range rr {
    49          if r != 0 && r != Rz {
    50              rb = append(rb, r)
    51          }
    52      }
    53  
    54      /* insert an entry point node to hold all the register arguments */
    55      if len(rb) != 0 {
    56          cfg.Root.Ins = append(
    57              []IrNode { &IrEntry { rb } },
    58              cfg.Root.Ins...
    59          )
    60      }
    61  
    62      /* lower the entire program */
    63      cfg.PostOrder().ForEach(func(bb *BasicBlock) {
    64          ins := bb.Ins
    65          bb.Ins = make([]IrNode, 0, len(ins))
    66  
    67          /* scan every instruction */
    68          for _, v := range ins {
    69              switch p := v.(type) {
    70                  case *IrLoadArg    : panic(fmt.Sprintf("abi: argument load in the middle of CFG: bb_%d: %s", bb.Id, v))
    71                  case *IrCallFunc   : self.abiCallFunc(cfg, bb, p)
    72                  case *IrCallNative : self.abiCallNative(cfg, bb, p)
    73                  case *IrCallMethod : self.abiCallMethod(cfg, bb, p)
    74                  default            : bb.Ins = append(bb.Ins, p)
    75              }
    76          }
    77  
    78          /* scan the terminator */
    79          if p, ok := bb.Term.(*IrReturn); ok {
    80              rr = make([]Reg, len(p.R))
    81              rb = rr[:0]
    82  
    83              /* check for return value count */
    84              if len(p.R) != len(cfg.Layout.Rets) {
    85                  panic("abi: return value store size mismatch: " + p.String())
    86              }
    87  
    88              /* copy return values */
    89              for i, rv := range p.R {
    90                  if r := cfg.Layout.Rets[i]; r.InRegister {
    91                      rr[i] = IrSetArch(cfg.CreateRegister(rv.Ptr()), r.Reg)
    92                      bb.Ins = append(bb.Ins, IrArchCopy(rr[i], rv))
    93                  } else {
    94                      rr[i] = Rz
    95                      bb.Ins = append(bb.Ins, IrArchStoreStack(rv, r.Mem, IrSlotArgs))
    96                  }
    97              }
    98  
    99              /* extract all the registers */
   100              for _, r := range rr {
   101                  if r != 0 && r != Rz {
   102                      rb = append(rb, r)
   103                  }
   104              }
   105  
   106              /* replace the terminator */
   107              if len(rb) != 0 {
   108                  bb.Term = IrArchReturn(rb)
   109              } else {
   110                  bb.Term = IrArchReturn(nil)
   111              }
   112          }
   113      })
   114  }