Skip to content

Commit

Permalink
arm64: Add support for system calls (SVC)
Browse files Browse the repository at this point in the history
  • Loading branch information
racerxdl authored and aykevl committed Oct 3, 2020
1 parent 9a015f4 commit c2bfe6b
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 2 deletions.
6 changes: 4 additions & 2 deletions compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1336,12 +1336,14 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
return b.createMemoryCopyCall(fn, instr.Args)
case name == "runtime.memzero":
return b.createMemoryZeroCall(instr.Args)
case name == "device.Asm" || name == "device/arm.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm":
case name == "device.Asm" || name == "device/arm.Asm" || name == "device/arm64.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm":
return b.createInlineAsm(instr.Args)
case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull":
case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/arm64.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull":
return b.createInlineAsmFull(instr)
case strings.HasPrefix(name, "device/arm.SVCall"):
return b.emitSVCall(instr.Args)
case strings.HasPrefix(name, "device/arm64.SVCall"):
return b.emitSV64Call(instr.Args)
case strings.HasPrefix(name, "(device/riscv.CSR)."):
return b.emitCSROperation(instr)
case strings.HasPrefix(name, "syscall.Syscall"):
Expand Down
38 changes: 38 additions & 0 deletions compiler/inlineasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,44 @@ func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
return b.CreateCall(target, llvmArgs, ""), nil
}

// This is a compiler builtin which emits an inline SVCall instruction. It can
// be one of:
//
// func SVCall0(num uintptr) uintptr
// func SVCall1(num uintptr, a1 interface{}) uintptr
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
// func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
//
// The num parameter must be a constant. All other parameters may be any scalar
// value supported by LLVM inline assembly.
// Same as emitSVCall but for AArch64
func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
num, _ := constant.Uint64Val(args[0].(*ssa.Const).Value)
llvmArgs := []llvm.Value{}
argTypes := []llvm.Type{}
asm := "svc #" + strconv.FormatUint(num, 10)
constraints := "={x0}"
for i, arg := range args[1:] {
arg = arg.(*ssa.MakeInterface).X
if i == 0 {
constraints += ",0"
} else {
constraints += ",{x" + strconv.Itoa(i) + "}"
}
llvmValue := b.getValue(arg)
llvmArgs = append(llvmArgs, llvmValue)
argTypes = append(argTypes, llvmValue.Type())
}
// Implement the ARM64 calling convention by marking x1-x7 as
// clobbered. x0 is used as an output register so doesn't have to be
// marked as clobbered.
constraints += ",~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7}"
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0)
return b.CreateCall(target, llvmArgs, ""), nil
}

// This is a compiler builtin which emits CSR instructions. It can be one of:
//
// func (csr CSR) Get() uintptr
Expand Down
36 changes: 36 additions & 0 deletions src/device/arm64/arm64.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package arm64

// Run the given assembly code. The code will be marked as having side effects,
// as it doesn't produce output and thus would normally be eliminated by the
// optimizer.
func Asm(asm string)

// Run the given inline assembly. The code will be marked as having side
// effects, as it would otherwise be optimized away. The inline assembly string
// recognizes template values in the form {name}, like so:
//
// arm.AsmFull(
// "str {value}, {result}",
// map[string]interface{}{
// "value": 1
// "result": &dest,
// })
//
// You can use {} in the asm string (which expands to a register) to set the
// return value.
func AsmFull(asm string, regs map[string]interface{}) uintptr

// Run the following system call (SVCall) with 0 arguments.
func SVCall0(num uintptr) uintptr

// Run the following system call (SVCall) with 1 argument.
func SVCall1(num uintptr, a1 interface{}) uintptr

// Run the following system call (SVCall) with 2 arguments.
func SVCall2(num uintptr, a1, a2 interface{}) uintptr

// Run the following system call (SVCall) with 3 arguments.
func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr

// Run the following system call (SVCall) with 4 arguments.
func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr

0 comments on commit c2bfe6b

Please sign in to comment.