github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/internal/abi/abi_amd64.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 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  func (self *Frame) emitDebug(p *Program) {
   280  	p.INT(3)
   281  }