Skip to content

Commit c2bfe6b

Browse files
racerxdlaykevl
authored andcommitted
arm64: Add support for system calls (SVC)
1 parent 9a015f4 commit c2bfe6b

File tree

3 files changed

+78
-2
lines changed

3 files changed

+78
-2
lines changed

compiler/compiler.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,12 +1336,14 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
13361336
return b.createMemoryCopyCall(fn, instr.Args)
13371337
case name == "runtime.memzero":
13381338
return b.createMemoryZeroCall(instr.Args)
1339-
case name == "device.Asm" || name == "device/arm.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm":
1339+
case name == "device.Asm" || name == "device/arm.Asm" || name == "device/arm64.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm":
13401340
return b.createInlineAsm(instr.Args)
1341-
case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull":
1341+
case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/arm64.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull":
13421342
return b.createInlineAsmFull(instr)
13431343
case strings.HasPrefix(name, "device/arm.SVCall"):
13441344
return b.emitSVCall(instr.Args)
1345+
case strings.HasPrefix(name, "device/arm64.SVCall"):
1346+
return b.emitSV64Call(instr.Args)
13451347
case strings.HasPrefix(name, "(device/riscv.CSR)."):
13461348
return b.emitCSROperation(instr)
13471349
case strings.HasPrefix(name, "syscall.Syscall"):

compiler/inlineasm.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,44 @@ func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
163163
return b.CreateCall(target, llvmArgs, ""), nil
164164
}
165165

166+
// This is a compiler builtin which emits an inline SVCall instruction. It can
167+
// be one of:
168+
//
169+
// func SVCall0(num uintptr) uintptr
170+
// func SVCall1(num uintptr, a1 interface{}) uintptr
171+
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr
172+
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
173+
// func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
174+
//
175+
// The num parameter must be a constant. All other parameters may be any scalar
176+
// value supported by LLVM inline assembly.
177+
// Same as emitSVCall but for AArch64
178+
func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
179+
num, _ := constant.Uint64Val(args[0].(*ssa.Const).Value)
180+
llvmArgs := []llvm.Value{}
181+
argTypes := []llvm.Type{}
182+
asm := "svc #" + strconv.FormatUint(num, 10)
183+
constraints := "={x0}"
184+
for i, arg := range args[1:] {
185+
arg = arg.(*ssa.MakeInterface).X
186+
if i == 0 {
187+
constraints += ",0"
188+
} else {
189+
constraints += ",{x" + strconv.Itoa(i) + "}"
190+
}
191+
llvmValue := b.getValue(arg)
192+
llvmArgs = append(llvmArgs, llvmValue)
193+
argTypes = append(argTypes, llvmValue.Type())
194+
}
195+
// Implement the ARM64 calling convention by marking x1-x7 as
196+
// clobbered. x0 is used as an output register so doesn't have to be
197+
// marked as clobbered.
198+
constraints += ",~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7}"
199+
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
200+
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0)
201+
return b.CreateCall(target, llvmArgs, ""), nil
202+
}
203+
166204
// This is a compiler builtin which emits CSR instructions. It can be one of:
167205
//
168206
// func (csr CSR) Get() uintptr

src/device/arm64/arm64.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package arm64
2+
3+
// Run the given assembly code. The code will be marked as having side effects,
4+
// as it doesn't produce output and thus would normally be eliminated by the
5+
// optimizer.
6+
func Asm(asm string)
7+
8+
// Run the given inline assembly. The code will be marked as having side
9+
// effects, as it would otherwise be optimized away. The inline assembly string
10+
// recognizes template values in the form {name}, like so:
11+
//
12+
// arm.AsmFull(
13+
// "str {value}, {result}",
14+
// map[string]interface{}{
15+
// "value": 1
16+
// "result": &dest,
17+
// })
18+
//
19+
// You can use {} in the asm string (which expands to a register) to set the
20+
// return value.
21+
func AsmFull(asm string, regs map[string]interface{}) uintptr
22+
23+
// Run the following system call (SVCall) with 0 arguments.
24+
func SVCall0(num uintptr) uintptr
25+
26+
// Run the following system call (SVCall) with 1 argument.
27+
func SVCall1(num uintptr, a1 interface{}) uintptr
28+
29+
// Run the following system call (SVCall) with 2 arguments.
30+
func SVCall2(num uintptr, a1, a2 interface{}) uintptr
31+
32+
// Run the following system call (SVCall) with 3 arguments.
33+
func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
34+
35+
// Run the following system call (SVCall) with 4 arguments.
36+
func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr

0 commit comments

Comments
 (0)