mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-09 21:43:40 +00:00
compiler: refactor function calling
This commit is contained in:
committed by
Ron Evans
parent
d46934d1f1
commit
d752e66be5
+45
-45
@@ -10,14 +10,14 @@ import (
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// emitSyscall emits an inline system call instruction, depending on the target
|
||||
// OS/arch.
|
||||
func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value, error) {
|
||||
num := frame.getValue(call.Args[0])
|
||||
// createSyscall emits an inline system call instruction, depending on the
|
||||
// target OS/arch.
|
||||
func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
num := b.getValue(call.Args[0])
|
||||
var syscallResult llvm.Value
|
||||
switch {
|
||||
case c.GOARCH() == "amd64":
|
||||
if c.GOOS() == "darwin" {
|
||||
case b.GOARCH() == "amd64":
|
||||
if b.GOOS() == "darwin" {
|
||||
// Darwin adds this magic number to system call numbers:
|
||||
//
|
||||
// > Syscall classes for 64-bit system call entry.
|
||||
@@ -28,13 +28,13 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
||||
// > All system classes enter the kernel via the syscall instruction.
|
||||
//
|
||||
// Source: https://opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/mach/i386/syscall_sw.h
|
||||
num = c.builder.CreateOr(num, llvm.ConstInt(c.uintptrType, 0x2000000, false), "")
|
||||
num = b.CreateOr(num, llvm.ConstInt(b.uintptrType, 0x2000000, false), "")
|
||||
}
|
||||
// Sources:
|
||||
// https://stackoverflow.com/a/2538212
|
||||
// https://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux#syscall
|
||||
args := []llvm.Value{num}
|
||||
argTypes := []llvm.Type{c.uintptrType}
|
||||
argTypes := []llvm.Type{b.uintptrType}
|
||||
// Constraints will look something like:
|
||||
// "={rax},0,{rdi},{rsi},{rdx},{r10},{r8},{r9},~{rcx},~{r11}"
|
||||
constraints := "={rax},0"
|
||||
@@ -50,21 +50,21 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
||||
"{r12}",
|
||||
"{r13}",
|
||||
}[i]
|
||||
llvmValue := frame.getValue(arg)
|
||||
llvmValue := b.getValue(arg)
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
constraints += ",~{rcx},~{r11}"
|
||||
fnType := llvm.FunctionType(c.uintptrType, argTypes, false)
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel)
|
||||
syscallResult = c.builder.CreateCall(target, args, "")
|
||||
case c.GOARCH() == "386" && c.GOOS() == "linux":
|
||||
syscallResult = b.CreateCall(target, args, "")
|
||||
case b.GOARCH() == "386" && b.GOOS() == "linux":
|
||||
// Sources:
|
||||
// syscall(2) man page
|
||||
// https://stackoverflow.com/a/2538212
|
||||
// https://en.wikibooks.org/wiki/X86_Assembly/Interfacing_with_Linux#int_0x80
|
||||
args := []llvm.Value{num}
|
||||
argTypes := []llvm.Type{c.uintptrType}
|
||||
argTypes := []llvm.Type{b.uintptrType}
|
||||
// Constraints will look something like:
|
||||
// "={eax},0,{ebx},{ecx},{edx},{esi},{edi},{ebp}"
|
||||
constraints := "={eax},0"
|
||||
@@ -77,14 +77,14 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
||||
"{edi}",
|
||||
"{ebp}",
|
||||
}[i]
|
||||
llvmValue := frame.getValue(arg)
|
||||
llvmValue := b.getValue(arg)
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
fnType := llvm.FunctionType(c.uintptrType, argTypes, false)
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel)
|
||||
syscallResult = c.builder.CreateCall(target, args, "")
|
||||
case c.GOARCH() == "arm" && c.GOOS() == "linux":
|
||||
syscallResult = b.CreateCall(target, args, "")
|
||||
case b.GOARCH() == "arm" && b.GOOS() == "linux":
|
||||
// Implement the EABI system call convention for Linux.
|
||||
// Source: syscall(2) man page.
|
||||
args := []llvm.Value{}
|
||||
@@ -102,21 +102,21 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
||||
"{r5}",
|
||||
"{r6}",
|
||||
}[i]
|
||||
llvmValue := frame.getValue(arg)
|
||||
llvmValue := b.getValue(arg)
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
args = append(args, num)
|
||||
argTypes = append(argTypes, c.uintptrType)
|
||||
argTypes = append(argTypes, b.uintptrType)
|
||||
constraints += ",{r7}" // syscall number
|
||||
for i := len(call.Args) - 1; i < 4; i++ {
|
||||
// r0-r3 get clobbered after the syscall returns
|
||||
constraints += ",~{r" + strconv.Itoa(i) + "}"
|
||||
}
|
||||
fnType := llvm.FunctionType(c.uintptrType, argTypes, false)
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
|
||||
syscallResult = c.builder.CreateCall(target, args, "")
|
||||
case c.GOARCH() == "arm64" && c.GOOS() == "linux":
|
||||
syscallResult = b.CreateCall(target, args, "")
|
||||
case b.GOARCH() == "arm64" && b.GOOS() == "linux":
|
||||
// Source: syscall(2) man page.
|
||||
args := []llvm.Value{}
|
||||
argTypes := []llvm.Type{}
|
||||
@@ -132,12 +132,12 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
||||
"{x4}",
|
||||
"{x5}",
|
||||
}[i]
|
||||
llvmValue := frame.getValue(arg)
|
||||
llvmValue := b.getValue(arg)
|
||||
args = append(args, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
args = append(args, num)
|
||||
argTypes = append(argTypes, c.uintptrType)
|
||||
argTypes = append(argTypes, b.uintptrType)
|
||||
constraints += ",{x8}" // syscall number
|
||||
for i := len(call.Args) - 1; i < 8; i++ {
|
||||
// x0-x7 may get clobbered during the syscall following the aarch64
|
||||
@@ -145,13 +145,13 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
||||
constraints += ",~{x" + strconv.Itoa(i) + "}"
|
||||
}
|
||||
constraints += ",~{x16},~{x17}" // scratch registers
|
||||
fnType := llvm.FunctionType(c.uintptrType, argTypes, false)
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
|
||||
syscallResult = c.builder.CreateCall(target, args, "")
|
||||
syscallResult = b.CreateCall(target, args, "")
|
||||
default:
|
||||
return llvm.Value{}, c.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+c.GOOS()+"/"+c.GOARCH())
|
||||
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS()+"/"+b.GOARCH())
|
||||
}
|
||||
switch c.GOOS() {
|
||||
switch b.GOOS() {
|
||||
case "linux", "freebsd":
|
||||
// Return values: r0, r1 uintptr, err Errno
|
||||
// Pseudocode:
|
||||
@@ -160,15 +160,15 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
||||
// err = -syscallResult
|
||||
// }
|
||||
// return syscallResult, 0, err
|
||||
zero := llvm.ConstInt(c.uintptrType, 0, false)
|
||||
inrange1 := c.builder.CreateICmp(llvm.IntSLT, syscallResult, llvm.ConstInt(c.uintptrType, 0, false), "")
|
||||
inrange2 := c.builder.CreateICmp(llvm.IntSGT, syscallResult, llvm.ConstInt(c.uintptrType, 0xfffffffffffff000, true), "") // -4096
|
||||
hasError := c.builder.CreateAnd(inrange1, inrange2, "")
|
||||
errResult := c.builder.CreateSelect(hasError, c.builder.CreateSub(zero, syscallResult, ""), zero, "syscallError")
|
||||
retval := llvm.Undef(c.ctx.StructType([]llvm.Type{c.uintptrType, c.uintptrType, c.uintptrType}, false))
|
||||
retval = c.builder.CreateInsertValue(retval, syscallResult, 0, "")
|
||||
retval = c.builder.CreateInsertValue(retval, zero, 1, "")
|
||||
retval = c.builder.CreateInsertValue(retval, errResult, 2, "")
|
||||
zero := llvm.ConstInt(b.uintptrType, 0, false)
|
||||
inrange1 := b.CreateICmp(llvm.IntSLT, syscallResult, llvm.ConstInt(b.uintptrType, 0, false), "")
|
||||
inrange2 := b.CreateICmp(llvm.IntSGT, syscallResult, llvm.ConstInt(b.uintptrType, 0xfffffffffffff000, true), "") // -4096
|
||||
hasError := b.CreateAnd(inrange1, inrange2, "")
|
||||
errResult := b.CreateSelect(hasError, b.CreateSub(zero, syscallResult, ""), zero, "syscallError")
|
||||
retval := llvm.Undef(b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType, b.uintptrType}, false))
|
||||
retval = b.CreateInsertValue(retval, syscallResult, 0, "")
|
||||
retval = b.CreateInsertValue(retval, zero, 1, "")
|
||||
retval = b.CreateInsertValue(retval, errResult, 2, "")
|
||||
return retval, nil
|
||||
case "darwin":
|
||||
// Return values: r0, r1 uintptr, err Errno
|
||||
@@ -178,15 +178,15 @@ func (c *Compiler) emitSyscall(frame *Frame, call *ssa.CallCommon) (llvm.Value,
|
||||
// err = syscallResult
|
||||
// }
|
||||
// return syscallResult, 0, err
|
||||
zero := llvm.ConstInt(c.uintptrType, 0, false)
|
||||
hasError := c.builder.CreateICmp(llvm.IntNE, syscallResult, llvm.ConstInt(c.uintptrType, 0, false), "")
|
||||
errResult := c.builder.CreateSelect(hasError, syscallResult, zero, "syscallError")
|
||||
retval := llvm.Undef(c.ctx.StructType([]llvm.Type{c.uintptrType, c.uintptrType, c.uintptrType}, false))
|
||||
retval = c.builder.CreateInsertValue(retval, syscallResult, 0, "")
|
||||
retval = c.builder.CreateInsertValue(retval, zero, 1, "")
|
||||
retval = c.builder.CreateInsertValue(retval, errResult, 2, "")
|
||||
zero := llvm.ConstInt(b.uintptrType, 0, false)
|
||||
hasError := b.CreateICmp(llvm.IntNE, syscallResult, llvm.ConstInt(b.uintptrType, 0, false), "")
|
||||
errResult := b.CreateSelect(hasError, syscallResult, zero, "syscallError")
|
||||
retval := llvm.Undef(b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType, b.uintptrType}, false))
|
||||
retval = b.CreateInsertValue(retval, syscallResult, 0, "")
|
||||
retval = b.CreateInsertValue(retval, zero, 1, "")
|
||||
retval = b.CreateInsertValue(retval, errResult, 2, "")
|
||||
return retval, nil
|
||||
default:
|
||||
return llvm.Value{}, c.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+c.GOOS()+"/"+c.GOARCH())
|
||||
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS()+"/"+b.GOARCH())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user