Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Review: word-sized struct ABI translation
Solid, well-scoped change. goWordStructParts is deliberately conservative — it only accepts flat structs whose fields are each exactly one integer/pointer word in both the Go value layout and the assembly FP frame, and requires the value/frame word sizes to match (rejecting the wasm32-on-64-bit-frame case). Anything else falls through to a hard unsupported struct ... error rather than a silent miscompile, which is the right fail-closed behavior at an ABI boundary. The GO_ARGS no-op is consistent with the other Go metadata directives already grouped in that case, and the accompanying comments accurately describe the code.
Reviewed for correctness, security, performance, and doc accuracy across all three changed files. No blocking issues. Two minor, non-blocking suggestions are inline.
There was a problem hiding this comment.
Review: word-sized flat struct ABI translation
Solid, well-guarded change. goWordStructParts is intentionally conservative — it flattens only flat structs whose fields are each exactly one integer/pointer word in both the Go value layout and the assembly FP frame, and fails closed to an unsupported struct error rather than emitting incorrect IR. The guard-test matrix (TestGoTranslateWordStructGuards) and the end-to-end ABI test (TestGoTranslateWordStructABI, verifying arg types, frame slot offsets/indices, and actual extractvalue/call IR) give strong coverage.
Verified clean:
- Security: No memory-safety or overflow concerns — offsets/sizes come from trusted
go/types.Sizes, and the flatten path is defensively gated. Dependency bumps (klauspost/compress v1.20.1,pierrec/lz4/v4 v4.1.31) havego.sumhashes consistent with upstream. - Docs:
doc/plan9asm-corpus.md,go.mod, andreported-libraries.jsonversions are consistent; the newgoWordStructPartsandGO_ARGScomments accurately describe behavior.
One finding (inline): the non-flatten struct argument path recomputes goWordStructParts and re-lowers each field type, when the parts (which already carry .Type) are available in hand.
Minor / optional (not inline):
- In
goWordStructParts,sz.OffsetsofandframeSz.Offsetsofare computed separately even whensz == frameSz(the common case, e.g. the value-type call at the struct case passessz, sz). Reusing the value offsets when the twoSizesare identical avoids a redundant allocation. - The doc comment could note that word-sized floats are deliberately excluded (they need FP register classification) — currently the least obvious rejection.
- The flatten branch sets
Field: -1, dropping the field index the non-flatten branch preserves; a one-line note on why results don't need per-field mapping would prevent future confusion.
| if tt.NumFields() == 0 { | ||
| return LLVMType("[0 x i8]"), nil | ||
| } | ||
| if parts, ok := goWordStructParts(tt, goarch, sz, sz); ok { |
There was a problem hiding this comment.
The aggregate LLVM type here is derived from a second, value-only goWordStructParts call. But on the non-flatten argument path in goLLVMArgsAndFrameSlotsForTuple, goFramePartsForTypeWithSizes has already run goWordStructParts and produced parts whose .Type fields are exactly these element types — so the struct type is classified and each field re-lowered twice per struct argument.
Beyond the duplicate compile-time work, this creates an implicit coupling: the arg path stays correct only because goWordStructParts requires word(sz) == word(frameSz), so the value-only call agrees with the frame-aware one. If that guard is ever relaxed (e.g. to allow value-word != frame-word structs), the aggregate type and the frame layout could silently diverge. Consider building the LLVM aggregate string from the already-computed parts in the non-flatten branch instead of recomputing via a separate value-only call.
Draft investigation for xgo-dev/llgo#2691; not yet a complete or mergeable ABI0 fix.
Changes
GO_ARGSmetadata.klauspost/compress v1.20.1andpierrec/lz4/v4 v4.1.31, including lz4's new amd64internal/xxh32assembly inventory. Keep latest-version and exact-inventory checks enabled.Validation
go test ./... -coverprofile=...passes;goWordStructPartshas 100% statement coverage locally.Remaining blocker
Tracked in #44: the generated
modernc.org/libcABI0 wrappers pass outgoing arguments through SP slots, while current amd64CALLlowering reads registers. Successful LLVM translation can therefore still produce incorrect calls. The same 1,875-function file also contains complex values, other structured arguments, and 37 callback-trampoline wrappers. Correct ABI0 stack-call lowering and end-to-end Linux/amd64 execution are required before merge.