aboutsummaryrefslogtreecommitdiffhomepage
path: root/compiler/inlineasm.go
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2020-01-06 19:57:48 +0100
committerRon Evans <[email protected]>2020-01-10 08:04:13 +0100
commit360923abbf35a5c51f041a9a1f0ba854d3d83295 (patch)
treea655732b735c3af8399be9f7c66c28995591b843 /compiler/inlineasm.go
parented9b2dbc03b49cdeecd937a05fa6b62f554ad5b3 (diff)
downloadtinygo-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.go45
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)
+ }
+}