@@ -13,27 +13,6 @@ import (
1313 "tinygo.org/x/go-llvm"
1414)
1515
16- // This is a compiler builtin, which reads the given register by name:
17- //
18- // func ReadRegister(name string) uintptr
19- //
20- // The register name must be a constant, for example "sp".
21- func (b * builder ) createReadRegister (name string , args []ssa.Value ) (llvm.Value , error ) {
22- fnType := llvm .FunctionType (b .uintptrType , []llvm.Type {}, false )
23- regname := constant .StringVal (args [0 ].(* ssa.Const ).Value )
24- var asm string
25- switch name {
26- case "device/arm.ReadRegister" :
27- asm = "mov $0, " + regname
28- case "device/riscv.ReadRegister" :
29- asm = "mv $0, " + regname
30- default :
31- panic ("unknown architecture" )
32- }
33- target := llvm .InlineAsm (fnType , asm , "=r" , false , false , 0 )
34- return b .CreateCall (target , nil , "" ), nil
35- }
36-
3716// This is a compiler builtin, which emits a piece of inline assembly with no
3817// operands or return values. It is useful for trivial instructions, like wfi in
3918// ARM or sleep in AVR.
@@ -52,7 +31,7 @@ func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
5231// This is a compiler builtin, which allows assembly to be called in a flexible
5332// way.
5433//
55- // func AsmFull(asm string, regs map[string]interface{})
34+ // func AsmFull(asm string, regs map[string]interface{}) uintptr
5635//
5736// The asm parameter must be a constant string. The regs parameter must be
5837// provided immediately. For example:
@@ -66,24 +45,24 @@ func (b *builder) createInlineAsm(args []ssa.Value) (llvm.Value, error) {
6645func (b * builder ) createInlineAsmFull (instr * ssa.CallCommon ) (llvm.Value , error ) {
6746 asmString := constant .StringVal (instr .Args [0 ].(* ssa.Const ).Value )
6847 registers := map [string ]llvm.Value {}
69- registerMap := instr .Args [1 ].(* ssa.MakeMap )
70- for _ , r := range * registerMap .Referrers () {
71- switch r := r .(type ) {
72- case * ssa.DebugRef :
73- // ignore
74- case * ssa.MapUpdate :
75- if r .Block () != registerMap .Block () {
76- return llvm.Value {}, b .makeError (instr .Pos (), "register value map must be created in the same basic block" )
77- }
78- key := constant .StringVal (r .Key .(* ssa.Const ).Value )
79- //println("value:", r.Value.(*ssa.MakeInterface).X.String())
80- registers [key ] = b .getValue (r .Value .(* ssa.MakeInterface ).X )
81- case * ssa.Call :
82- if r .Common () == instr {
83- break
48+ if registerMap , ok := instr .Args [1 ].(* ssa.MakeMap ); ok {
49+ for _ , r := range * registerMap .Referrers () {
50+ switch r := r .(type ) {
51+ case * ssa.DebugRef :
52+ // ignore
53+ case * ssa.MapUpdate :
54+ if r .Block () != registerMap .Block () {
55+ return llvm.Value {}, b .makeError (instr .Pos (), "register value map must be created in the same basic block" )
56+ }
57+ key := constant .StringVal (r .Key .(* ssa.Const ).Value )
58+ registers [key ] = b .getValue (r .Value .(* ssa.MakeInterface ).X )
59+ case * ssa.Call :
60+ if r .Common () == instr {
61+ break
62+ }
63+ default :
64+ return llvm.Value {}, b .makeError (instr .Pos (), "don't know how to handle argument to inline assembly: " + r .String ())
8465 }
85- default :
86- return llvm.Value {}, b .makeError (instr .Pos (), "don't know how to handle argument to inline assembly: " + r .String ())
8766 }
8867 }
8968 // TODO: handle dollar signs in asm string
@@ -92,6 +71,15 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
9271 argTypes := []llvm.Type {}
9372 args := []llvm.Value {}
9473 constraints := []string {}
74+ hasOutput := false
75+ asmString = regexp .MustCompile ("\\ {\\ }" ).ReplaceAllStringFunc (asmString , func (s string ) string {
76+ hasOutput = true
77+ return "$0"
78+ })
79+ if hasOutput {
80+ constraints = append (constraints , "=&r" )
81+ registerNumbers ["" ] = 0
82+ }
9583 asmString = regexp .MustCompile ("\\ {[a-zA-Z]+\\ }" ).ReplaceAllStringFunc (asmString , func (s string ) string {
9684 // TODO: skip strings like {r4} etc. that look like ARM push/pop
9785 // instructions.
@@ -121,9 +109,21 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
121109 if err != nil {
122110 return llvm.Value {}, err
123111 }
124- fnType := llvm .FunctionType (b .ctx .VoidType (), argTypes , false )
112+ var outputType llvm.Type
113+ if hasOutput {
114+ outputType = b .uintptrType
115+ } else {
116+ outputType = b .ctx .VoidType ()
117+ }
118+ fnType := llvm .FunctionType (outputType , argTypes , false )
125119 target := llvm .InlineAsm (fnType , asmString , strings .Join (constraints , "," ), true , false , 0 )
126- return b .CreateCall (target , args , "" ), nil
120+ result := b .CreateCall (target , args , "" )
121+ if hasOutput {
122+ return result , nil
123+ } else {
124+ // Make sure we return something valid.
125+ return llvm .ConstInt (b .uintptrType , 0 , false ), nil
126+ }
127127}
128128
129129// This is a compiler builtin which emits an inline SVCall instruction. It can
0 commit comments