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 }