cl(feat): llgo.asm implement tinygo.AsmFull#1224
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1224 +/- ##
==========================================
+ Coverage 88.15% 88.19% +0.03%
==========================================
Files 34 34
Lines 8470 8539 +69
==========================================
+ Hits 7467 7531 +64
- Misses 934 937 +3
- Partials 69 71 +2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
763cb8a to
29bd0c4
Compare
22a0445 to
b31ef79
Compare
ef5b21a to
8b9f2c6
Compare
dbf7ead to
0d2655e
Compare
cl/instr.go
Outdated
| hasOutput = true | ||
| } | ||
|
|
||
| finalAsm = regexp.MustCompile(`\{[a-zA-Z]+\}`).ReplaceAllStringFunc(finalAsm, func(s string) string { |
There was a problem hiding this comment.
NOTE(MeteorsLiu): MustCompile can be optimized by once.Do() to avoid compiling regexp repeatedly.
There was a problem hiding this comment.
Done in 068253d but once.Do() maybe isn't necessary here since Go runtime already guarantees package-level variables are initialized only once during package initialization
fcda0ea to
812fa38
Compare
73c3bc8 to
a272b5a
Compare
f2f2f7c to
e085873
Compare
e085873 to
d9dc4d5
Compare
| %0 = load ptr, ptr @_llgo_string, align 8 | ||
| %1 = load ptr, ptr @_llgo_any, align 8 | ||
| %2 = load ptr, ptr @"map[_llgo_string]_llgo_any", align 8 | ||
| %3 = call ptr @"github.com/goplus/llgo/runtime/internal/runtime.MakeMap"(ptr %2, i64 1) |
There was a problem hiding this comment.
Remove runtime dependency in another PR
| case *ssa.DebugRef, *ssa.Call: | ||
| // ignore | ||
| case *ssa.MapUpdate: | ||
| if r.Block() != registerMap.Block() { |
There was a problem hiding this comment.
this panic logic is fully consistent with current TinyGo behavior, and tracing back to the earliest commit of this code (tinygo-org/tinygo@392bba8), no reasoning was provided.
However, I believe the fundamental technical reason is that LLVM inline assembly requires all call information to be determined at compile time - parameter types, constraint strings, and parameter counts cannot change dynamically at runtime.
call i64 asm sideeffect "mov $0, ${1}", "=&r,r"(i64 42)This is essentially the same requirement as any function call needing determined function signatures and parameter types at compile time.
If cross-basic-block map construction were allowed, the compiler couldn't determine what parameters are needed for the call:
regs := make(map[string]interface{})
if condition {
regs["value"] = 42
}
res1 := asmFull("mov {}, {value}", regs) // Compiler can't determine if value exists There was a problem hiding this comment.
at this case *ssa.MapUpdate: we actually can't know if this value needs collecting at compile time.
| asmFull("nop", nil) | ||
|
|
||
| // 0 output & 1 input with memory address | ||
| addr := uintptr(unsafe.Pointer(&testVar)) |
There was a problem hiding this comment.
Why pointer type is not supported?
There was a problem hiding this comment.
Current logic is fully corespoding with Tinygo,so panic with same case.
And the reason TinyGo currently doesn't support pointer operands in inline assembly is due to LLVM's transition from typed pointers to opaque pointers starting with LLVM 14 (https://llvm.org/docs/OpaquePointers.html). This change requires inline assembly to explicitly declare pointer element types using the elementtype attribute (https://reviews.llvm.org/D116531). Rather than implementing the additional complexity, TinyGo chose to remove pointer support entirely (tinygo-org/tinygo@cad6a57).
However, I believe it's possible to add back this pointer type support. As TinyGo's comment indicates, it would require modifying the go-llvm API. I think we should make this functionality available first, and then support this feature in a separate PR (after all, going from uintptr(unsafe.Pointer(&val)) to &val wouldn't introduce breaking changes).
| } else { | ||
| retType = b.Prog.Void() | ||
| } | ||
|
|
There was a problem hiding this comment.
Is retType matched with the func return type?
There was a problem hiding this comment.
fixed at 49b9b92, Now when hasOutput is false, we return a valid uintptr(0) value that matches the Go function signature, rather than returning a void-typed inline assembly call.
|
@xushiwei need review |
resolved #1218
This PR fully adapts TinyGo's device.AsmFull implementation to provide LLGo with the same inline assembly capabilities, identical semantics, and constraint rules.
logic from tinygo/compiler/inlineasm
usage
Parameters
instruction: Assembly template with placeholders ({}for output,{name}for inputs)regs: Register mapping (nilfor simple instructions,map[string]anyfor register values)Example
asm("nop")from cl(feat):llgo.asm implement tinygo.Asm #1217.also is aims to provide TinyGo memory operations for embedded systems. Enables precise hardware register access and memory control, similar to TinyGo's
device.AsmFullused in GPIO and peripheral programming.like follow operatetasks
test
Maps used solely at compile time (like those for instruction signature compilation) currently still introduce runtime map dependencies, causing failures on embedded boards. we maybe can implement compile-time analysis to detect when programs only use compile-time function signatures, and exclude runtime capabilities in such cases.