diff options
author | Ayke van Laethem <[email protected]> | 2020-01-06 19:57:48 +0100 |
---|---|---|
committer | Ron Evans <[email protected]> | 2020-01-10 08:04:13 +0100 |
commit | 360923abbf35a5c51f041a9a1f0ba854d3d83295 (patch) | |
tree | a655732b735c3af8399be9f7c66c28995591b843 /compiler/inlineasm.go | |
parent | ed9b2dbc03b49cdeecd937a05fa6b62f554ad5b3 (diff) | |
download | tinygo-360923abbf35a5c51f041a9a1f0ba854d3d83295.tar.gz tinygo-360923abbf35a5c51f041a9a1f0ba854d3d83295.zip |
compiler,riscv: implement CSR operations as intrinsics
CSR operations must be implemented in assembly. The easiest way to
implement them is with some custom intrinsics in the compiler.
Diffstat (limited to 'compiler/inlineasm.go')
-rw-r--r-- | compiler/inlineasm.go | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/compiler/inlineasm.go b/compiler/inlineasm.go index f5dbc9f8a..e9f093a7b 100644 --- a/compiler/inlineasm.go +++ b/compiler/inlineasm.go @@ -162,3 +162,48 @@ func (c *Compiler) emitSVCall(frame *Frame, args []ssa.Value) (llvm.Value, error target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0) return c.builder.CreateCall(target, llvmArgs, ""), nil } + +// This is a compiler builtin which emits CSR instructions. It can be one of: +// +// func (csr CSR) Get() uintptr +// func (csr CSR) Set(uintptr) +// func (csr CSR) SetBits(uintptr) uintptr +// func (csr CSR) ClearBits(uintptr) uintptr +// +// The csr parameter (method receiver) must be a constant. Other parameter can +// be any value. +func (c *Compiler) emitCSROperation(frame *Frame, call *ssa.CallCommon) (llvm.Value, error) { + csrConst, ok := call.Args[0].(*ssa.Const) + if !ok { + return llvm.Value{}, c.makeError(call.Pos(), "CSR must be constant") + } + csr := csrConst.Uint64() + switch name := call.StaticCallee().Name(); name { + case "Get": + // Note that this instruction may have side effects, and thus must be + // marked as such. + fnType := llvm.FunctionType(c.uintptrType, nil, false) + asm := fmt.Sprintf("csrr $0, %d", csr) + target := llvm.InlineAsm(fnType, asm, "=r", true, false, 0) + return c.builder.CreateCall(target, nil, ""), nil + case "Set": + fnType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.uintptrType}, false) + asm := fmt.Sprintf("csrw %d, $0", csr) + target := llvm.InlineAsm(fnType, asm, "r", true, false, 0) + return c.builder.CreateCall(target, []llvm.Value{c.getValue(frame, call.Args[1])}, ""), nil + case "SetBits": + // Note: it may be possible to optimize this to csrrsi in many cases. + fnType := llvm.FunctionType(c.uintptrType, []llvm.Type{c.uintptrType}, false) + asm := fmt.Sprintf("csrrs $0, %d, $1", csr) + target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0) + return c.builder.CreateCall(target, []llvm.Value{c.getValue(frame, call.Args[1])}, ""), nil + case "ClearBits": + // Note: it may be possible to optimize this to csrrci in many cases. + fnType := llvm.FunctionType(c.uintptrType, []llvm.Type{c.uintptrType}, false) + asm := fmt.Sprintf("csrrc $0, %d, $1", csr) + target := llvm.InlineAsm(fnType, asm, "=r,r", true, false, 0) + return c.builder.CreateCall(target, []llvm.Value{c.getValue(frame, call.Args[1])}, ""), nil + default: + return llvm.Value{}, c.makeError(call.Pos(), "unknown CSR operation: "+name) + } +} |