...

Source file src/github.com/bytedance/sonic/internal/abi/abi_amd64.go

Documentation: github.com/bytedance/sonic/internal/abi

     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 abi
    18  
    19  import (
    20      `fmt`
    21      `reflect`
    22      `unsafe`
    23  
    24      . `github.com/chenzhuoyu/iasm/x86_64`
    25  )
    26  
    27  const (
    28      PtrSize  = 8    // pointer size
    29      PtrAlign = 8    // pointer alignment
    30  )
    31  
    32  var iregOrderC = []Register{
    33      RDI, 
    34      RSI, 
    35      RDX, 
    36      RCX,
    37      R8, 
    38      R9,
    39  }
    40  
    41  var xregOrderC = []Register{
    42      XMM0,
    43      XMM1,
    44      XMM2,
    45      XMM3,
    46      XMM4,
    47      XMM5,
    48      XMM6,
    49      XMM7,
    50  }
    51  
    52  var (
    53      intType = reflect.TypeOf(0)
    54      ptrType = reflect.TypeOf(unsafe.Pointer(nil))
    55  )
    56  
    57  func (self *Frame) argv(i int) *MemoryOperand {
    58      return Ptr(RSP, int32(self.Prev() + self.desc.Args[i].Mem))
    59  }
    60  
    61  // spillv is used for growstack spill registers
    62  func (self *Frame) spillv(i int) *MemoryOperand {
    63      // remain one slot for caller return pc
    64      return Ptr(RSP, PtrSize + int32(self.desc.Args[i].Mem))
    65  }
    66  
    67  func (self *Frame) retv(i int) *MemoryOperand {
    68      return Ptr(RSP, int32(self.Prev() + self.desc.Rets[i].Mem))
    69  }
    70  
    71  func (self *Frame) resv(i int) *MemoryOperand {
    72      return Ptr(RSP, int32(self.Offs() - uint32((i+1) * PtrSize)))
    73  }
    74  
    75  func (self *Frame) emitGrowStack(p *Program, entry *Label) {
    76      // spill all register arguments
    77      for i, v := range self.desc.Args {
    78          if v.InRegister {
    79              if v.IsFloat == floatKind64 {
    80                  p.MOVSD(v.Reg, self.spillv(i))
    81              } else if v.IsFloat == floatKind32 {
    82                  p.MOVSS(v.Reg, self.spillv(i))
    83              }else {
    84                  p.MOVQ(v.Reg, self.spillv(i))
    85              }
    86          }
    87      }
    88  
    89      // call runtime.morestack_noctxt
    90      p.MOVQ(F_morestack_noctxt, R12)
    91      p.CALLQ(R12)
    92      // load all register arguments
    93      for i, v := range self.desc.Args {
    94          if v.InRegister {
    95              if v.IsFloat == floatKind64 {
    96                  p.MOVSD(self.spillv(i), v.Reg)
    97              } else if v.IsFloat == floatKind32 {
    98                  p.MOVSS(self.spillv(i), v.Reg)
    99              }else {
   100                  p.MOVQ(self.spillv(i), v.Reg)
   101              }
   102          }
   103      }
   104  
   105      // jump back to the function entry
   106      p.JMP(entry)
   107  }
   108  
   109  func (self *Frame) GrowStackTextSize() uint32 {
   110      p := DefaultArch.CreateProgram()
   111      // spill all register arguments
   112      for i, v := range self.desc.Args {
   113          if v.InRegister {
   114              if v.IsFloat == floatKind64 {
   115                  p.MOVSD(v.Reg, self.spillv(i))
   116              } else if v.IsFloat == floatKind32 {
   117                  p.MOVSS(v.Reg, self.spillv(i))
   118              }else {
   119                  p.MOVQ(v.Reg, self.spillv(i))
   120              }
   121          }
   122      }
   123  
   124      // call runtime.morestack_noctxt
   125      p.MOVQ(F_morestack_noctxt, R12)
   126      p.CALLQ(R12)
   127      // load all register arguments
   128      for i, v := range self.desc.Args {
   129          if v.InRegister {
   130              if v.IsFloat == floatKind64 {
   131                  p.MOVSD(self.spillv(i), v.Reg)
   132              } else if v.IsFloat == floatKind32 {
   133                  p.MOVSS(self.spillv(i), v.Reg)
   134              } else {
   135                  p.MOVQ(self.spillv(i), v.Reg)
   136              }
   137          }
   138      }
   139  
   140      // jump back to the function entry
   141      l := CreateLabel("")
   142      p.Link(l)
   143      p.JMP(l)
   144  
   145      return uint32(len(p.Assemble(0)))
   146  }
   147  
   148  func (self *Frame) emitPrologue(p *Program) {
   149      p.SUBQ(self.Size(), RSP)
   150      p.MOVQ(RBP, Ptr(RSP, int32(self.Offs())))
   151      p.LEAQ(Ptr(RSP, int32(self.Offs())), RBP)
   152  }
   153  
   154  func (self *Frame) emitEpilogue(p *Program) {
   155      p.MOVQ(Ptr(RSP, int32(self.Offs())), RBP)
   156      p.ADDQ(self.Size(), RSP)
   157      p.RET()
   158  }
   159  
   160  func (self *Frame) emitReserveRegs(p *Program) {
   161      // spill reserved registers
   162      for i, r := range ReservedRegs(self.ccall) {
   163          switch r.(type) {
   164          case Register64:
   165              p.MOVQ(r, self.resv(i))
   166          case XMMRegister:
   167              p.MOVSD(r, self.resv(i))
   168          default:
   169              panic(fmt.Sprintf("unsupported register type %t to reserve", r))
   170          }
   171      }
   172  }
   173  
   174  func (self *Frame) emitSpillPtrs(p *Program) {
   175      // spill pointer argument registers
   176      for i, r := range self.desc.Args {
   177          if r.InRegister && r.IsPointer {
   178              p.MOVQ(r.Reg, self.argv(i))
   179          }
   180      }
   181  }
   182  
   183  func (self *Frame) emitClearPtrs(p *Program) {
   184      // spill pointer argument registers
   185      for i, r := range self.desc.Args {
   186          if r.InRegister && r.IsPointer {
   187              p.MOVQ(int64(0), self.argv(i))
   188          }
   189      }
   190  }
   191  
   192  func (self *Frame) emitCallC(p *Program, addr uintptr) {
   193      p.MOVQ(addr, RAX)
   194      p.CALLQ(RAX)
   195  }
   196  
   197  type floatKind uint8
   198  
   199  const (
   200      notFloatKind floatKind = iota
   201      floatKind32
   202      floatKind64
   203  )
   204  
   205  type Parameter struct {
   206      InRegister bool
   207      IsPointer  bool
   208      IsFloat    floatKind
   209      Reg        Register
   210      Mem        uint32
   211      Type       reflect.Type
   212  }
   213  
   214  func mkIReg(vt reflect.Type, reg Register64) (p Parameter) {
   215      p.Reg = reg
   216      p.Type = vt
   217      p.InRegister = true
   218      p.IsPointer = isPointer(vt)
   219      return
   220  }
   221  
   222  func isFloat(vt reflect.Type) floatKind {
   223      switch vt.Kind() {
   224      case reflect.Float32:
   225          return floatKind32
   226      case reflect.Float64:
   227          return floatKind64
   228      default:
   229          return notFloatKind
   230      }
   231  }
   232  
   233  func mkXReg(vt reflect.Type, reg XMMRegister) (p Parameter) {
   234      p.Reg = reg
   235      p.Type = vt
   236      p.InRegister = true
   237      p.IsFloat = isFloat(vt)
   238      return
   239  }
   240  
   241  func mkStack(vt reflect.Type, mem uint32) (p Parameter) {
   242      p.Mem = mem
   243      p.Type = vt
   244      p.InRegister = false
   245      p.IsPointer = isPointer(vt)
   246      p.IsFloat = isFloat(vt)
   247      return
   248  }
   249  
   250  func (self Parameter) String() string {
   251      if self.InRegister {
   252          return fmt.Sprintf("[%%%s, Pointer(%v), Float(%v)]", self.Reg, self.IsPointer, self.IsFloat)
   253      } else {
   254          return fmt.Sprintf("[%d(FP), Pointer(%v), Float(%v)]", self.Mem, self.IsPointer, self.IsFloat)
   255      }
   256  }
   257  
   258  func CallC(addr uintptr, fr Frame, maxStack uintptr) []byte {
   259      p := DefaultArch.CreateProgram()
   260  
   261      stack := CreateLabel("_stack_grow")
   262      entry := CreateLabel("_entry")
   263      p.Link(entry)
   264      fr.emitStackCheck(p, stack, maxStack)
   265      fr.emitPrologue(p)
   266      fr.emitReserveRegs(p)
   267      fr.emitSpillPtrs(p)
   268      fr.emitExchangeArgs(p)
   269      fr.emitCallC(p, addr)
   270      fr.emitExchangeRets(p)
   271      fr.emitRestoreRegs(p)
   272      fr.emitEpilogue(p)
   273      p.Link(stack)
   274      fr.emitGrowStack(p, entry)
   275  
   276      return p.Assemble(0)
   277  }
   278  
   279  
   280  func (self *Frame) emitDebug(p *Program) {
   281      p.INT(3)
   282  }

View as plain text