MCPcopy
hub / github.com/tinygo-org/tinygo / createSyscall

Method createSyscall

compiler/syscall.go:248–350  ·  view source on GitHub ↗

createSyscall emits instructions for the syscall.Syscall* family of functions, depending on the target OS/arch.

(call *ssa.CallCommon)

Source from the content-addressed store, hash-verified

246// createSyscall emits instructions for the syscall.Syscall* family of
247// functions, depending on the target OS/arch.
248func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
249 switch b.GOOS {
250 case "linux":
251 syscallResult, err := b.createRawSyscall(call)
252 if err != nil {
253 return syscallResult, err
254 }
255 // Return values: r0, r1 uintptr, err Errno
256 // Pseudocode:
257 // var err uintptr
258 // if syscallResult < 0 && syscallResult > -4096 {
259 // err = -syscallResult
260 // }
261 // return syscallResult, 0, err
262 zero := llvm.ConstInt(b.uintptrType, 0, false)
263 inrange1 := b.CreateICmp(llvm.IntSLT, syscallResult, llvm.ConstInt(b.uintptrType, 0, false), "")
264 inrange2 := b.CreateICmp(llvm.IntSGT, syscallResult, llvm.ConstInt(b.uintptrType, 0xfffffffffffff000, true), "") // -4096
265 hasError := b.CreateAnd(inrange1, inrange2, "")
266 errResult := b.CreateSelect(hasError, b.CreateSub(zero, syscallResult, ""), zero, "syscallError")
267 retval := llvm.Undef(b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType, b.uintptrType}, false))
268 retval = b.CreateInsertValue(retval, syscallResult, 0, "")
269 retval = b.CreateInsertValue(retval, zero, 1, "")
270 retval = b.CreateInsertValue(retval, errResult, 2, "")
271 return retval, nil
272 case "windows":
273 // On Windows, syscall.Syscall* is basically just a function pointer
274 // call. This is complicated in gc because of stack switching and the
275 // different ABI, but easy in TinyGo: just call the function pointer.
276 // The signature looks like this:
277 // func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
278
279 isI386 := strings.HasPrefix(b.Triple, "i386-")
280
281 // Prepare input values.
282 var paramTypes []llvm.Type
283 var params []llvm.Value
284 for _, val := range call.Args[2:] {
285 param := b.getValue(val, getPos(call))
286 params = append(params, param)
287 paramTypes = append(paramTypes, param.Type())
288 }
289 llvmType := llvm.FunctionType(b.uintptrType, paramTypes, false)
290 fn := b.getValue(call.Args[0], getPos(call))
291 fnPtr := b.CreateIntToPtr(fn, b.dataPtrType, "")
292
293 // Prepare some functions that will be called later.
294 setLastError := b.mod.NamedFunction("SetLastError")
295 if setLastError.IsNil() {
296 llvmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.ctx.Int32Type()}, false)
297 setLastError = llvm.AddFunction(b.mod, "SetLastError", llvmType)
298 if isI386 {
299 setLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
300 }
301 }
302 getLastError := b.mod.NamedFunction("GetLastError")
303 if getLastError.IsNil() {
304 llvmType := llvm.FunctionType(b.ctx.Int32Type(), nil, false)
305 getLastError = llvm.AddFunction(b.mod, "GetLastError", llvmType)

Callers 1

createFunctionCallMethod · 0.95

Calls 9

createRawSyscallMethod · 0.95
getValueMethod · 0.95
readStackPointerMethod · 0.95
writeStackPointerMethod · 0.95
IsNilMethod · 0.80
makeErrorMethod · 0.80
getPosFunction · 0.70
PosMethod · 0.65
TypeMethod · 0.45

Tested by

no test coverage detected