From e65592599cb6c3a0ffd73d5a021b9aa4e00959ae Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 25 Jun 2021 15:00:32 +0200 Subject: [PATCH] compiler: implement syscall.rawSyscallNoError in inline assembly This makes it possible to call syscall.Getpid() on Linux, for example. These syscalls never return an error so don't need any error checking. --- compiler/compiler.go | 4 +++- compiler/syscall.go | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/compiler/compiler.go b/compiler/compiler.go index cc696d5b..7841cd65 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -23,7 +23,7 @@ import ( // Version of the compiler pacakge. Must be incremented each time the compiler // package changes in a way that affects the generated LLVM module. // This version is independent of the TinyGo version number. -const Version = 11 // last change: change method name globals +const Version = 12 // last change: implement syscall.rawSyscallNoError func init() { llvm.InitializeAllTargets() @@ -1310,6 +1310,8 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error) return b.emitCSROperation(instr) case strings.HasPrefix(name, "syscall.Syscall"): return b.createSyscall(instr) + case strings.HasPrefix(name, "syscall.rawSyscallNoError"): + return b.createRawSyscallNoError(instr) case strings.HasPrefix(name, "runtime/volatile.Load"): return b.createVolatileLoad(instr) case strings.HasPrefix(name, "runtime/volatile.Store"): diff --git a/compiler/syscall.go b/compiler/syscall.go index 5b93e9ec..6a0bd328 100644 --- a/compiler/syscall.go +++ b/compiler/syscall.go @@ -10,11 +10,11 @@ import ( "tinygo.org/x/go-llvm" ) -// createSyscall emits an inline system call instruction, depending on the -// target OS/arch. -func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { +// createRawSyscall creates a system call with the provided system call number +// and returns the result as a single integer (the system call result). The +// result is not further interpreted. +func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) { num := b.getValue(call.Args[0]) - var syscallResult llvm.Value switch { case b.GOARCH == "amd64": if b.GOOS == "darwin" { @@ -57,7 +57,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { constraints += ",~{rcx},~{r11}" fnType := llvm.FunctionType(b.uintptrType, argTypes, false) target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel) - syscallResult = b.CreateCall(target, args, "") + return b.CreateCall(target, args, ""), nil case b.GOARCH == "386" && b.GOOS == "linux": // Sources: // syscall(2) man page @@ -83,7 +83,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { } fnType := llvm.FunctionType(b.uintptrType, argTypes, false) target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel) - syscallResult = b.CreateCall(target, args, "") + return b.CreateCall(target, args, ""), nil case b.GOARCH == "arm" && b.GOOS == "linux": // Implement the EABI system call convention for Linux. // Source: syscall(2) man page. @@ -115,7 +115,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { } fnType := llvm.FunctionType(b.uintptrType, argTypes, false) target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0) - syscallResult = b.CreateCall(target, args, "") + return b.CreateCall(target, args, ""), nil case b.GOARCH == "arm64" && b.GOOS == "linux": // Source: syscall(2) man page. args := []llvm.Value{} @@ -147,10 +147,19 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { constraints += ",~{x16},~{x17}" // scratch registers fnType := llvm.FunctionType(b.uintptrType, argTypes, false) target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0) - syscallResult = b.CreateCall(target, args, "") + return b.CreateCall(target, args, ""), nil default: return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH) } +} + +// createSyscall emits instructions for the syscall.Syscall* family of +// functions, depending on the target OS/arch. +func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { + syscallResult, err := b.createRawSyscall(call) + if err != nil { + return syscallResult, err + } switch b.GOOS { case "linux", "freebsd": // Return values: r0, r1 uintptr, err Errno @@ -190,3 +199,16 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH) } } + +// createRawSyscallNoError emits instructions for the Linux-specific +// syscall.rawSyscallNoError function. +func (b *builder) createRawSyscallNoError(call *ssa.CallCommon) (llvm.Value, error) { + syscallResult, err := b.createRawSyscall(call) + if err != nil { + return syscallResult, err + } + retval := llvm.ConstNull(b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType}, false)) + retval = b.CreateInsertValue(retval, syscallResult, 0, "") + retval = b.CreateInsertValue(retval, llvm.ConstInt(b.uintptrType, 0, false), 1, "") + return retval, nil +}