transform, compiler: support LLVM 21's captures(none) attribute; add …#5505
Open
dgryski wants to merge 3 commits into
Open
transform, compiler: support LLVM 21's captures(none) attribute; add …#5505dgryski wants to merge 3 commits into
dgryski wants to merge 3 commits into
Conversation
…LLVM 22 build support Written entirely by Claude (Anthropic's Claude Code), at the request of and under the direction of dgryski, as part of an effort to get TinyGo building against upcoming LLVM releases (this branch currently targets LLVM 22, verified against real LLVM 22.1.8; a corresponding go-llvm branch of the same name adds the matching binding support). LLVM 21 replaced the boolean 'nocapture' enum attribute with the more expressive 'captures' int attribute, where captures(none) (value 0) is the equivalent of the old nocapture. This matters for transform.OptimizeAllocs, which relies on reading this attribute for its interprocedural escape analysis, and for compiler/symbol.go, which emits it on a number of runtime/generated functions. Confirmed empirically (via `opt -passes=function-attrs`) that the cutoff is LLVM 20 emits/expects nocapture, LLVM 21+ emits/expects captures(none). Since TinyGo must keep working with LLVM 20, both sites now go through new version-gated helpers in compiler/llvmutil (NoCaptureAttrName/IsNoCapture) rather than switching unconditionally. Also fixes a second, unrelated but load-bearing break found while testing against LLVM 22: llvm.lifetime.start/end dropped their i64 size argument (confirmed via `opt -passes=verify`, the cutoff here is one version later, at LLVM 22). compiler/llvmutil now builds the right call signature based on version. Adds llvm21 and llvm22 build-tag config files to the cgo package, which parses cgo fragments via libclang and had never been updated past LLVM 20 even though the compiler package itself already gained LLVM 21 support previously -- a latent gap that would have caused a version mismatch between the cgo preprocessor and the rest of the compiler when building with -tags llvm21 or llvm22. Finally, updates the golden-IR test comparators in transform/transform_test.go and compiler/compiler_test.go to normalize a few cosmetic LLVM 21/22 output differences (the captures(none) rename/reordering, a new 'nocreateundeforpoison' intrinsic attribute, and the lifetime intrinsic arity change) so a single golden file continues to match output from either LLVM version. Verified by building a full (non-byollvm) tinygo binary against real LLVM 22.1.8 and running a compiled Go program end-to-end (exercising OptimizeAllocs' stack-allocation path), and by running the transform/compiler/cgo test suites against both LLVM 20 (default) and LLVM 22. Not yet addressed: the byollvm embedded-clang/lld build path hits separate, unrelated Clang C++ API breakage against LLVM 22 (DiagnosticOptions reference-to-pointer change, missing headers) -- that is a larger follow-up effort.
Member
Author
|
Depends on tinygo-org/go-llvm#75, then we can update go.mod and test directly against llvm 22. |
Written entirely by Claude (Anthropic's Claude Code), at the request of and under the direction of dgryski, on the dgryski/llvm23 branch (LLVM 22 support, in preparation for the eventual LLVM 23 release; the corresponding go-llvm branch of the same name adds the matching binding support this depends on). Found while running real-world Go test suites through a tinygo built against LLVM 22 (as a smoke test of the earlier captures(none)/ nocapture and lifetime-intrinsic fixes on this branch): `tinygo test` on github.com/dgryski/go-rc5 panicked at compile time with "unknown value" inside interp.(*runner).getValue, while compiling (*sync.Once).Do. Bisecting against LLVM 21 (unaffected) narrowed it to a change introduced in LLVM 22 specifically, unrelated to the earlier captures/lifetime work. Root cause: LLVM 22 stopped exposing switch-instruction case values as regular instruction operands -- only the condition and destination-block operands remain. interp/compiler.go's `case llvm.Switch:` handling walked raw operands assuming the old alternating (value, label) layout, so under LLVM 22 it read a destination *block* where it expected an integer case value, eventually panicking deep inside a getValue call it couldn't resolve. This only manifested on functions actually compiled by the interp package (TinyGo's compile-time evaluator for global initializers) that happen to reach a switch-based dispatch, such as sync.Once's defer-based Do method -- hence it needed a real, moderately complex package (crypto/cipher via go-rc5) to surface, and never showed up in smaller smoke tests. Fix: use the new version-independent Value.SuccessorsCount()/ Value.Successor(i) and Value.GetSwitchCaseValue(i) helpers just added to go-llvm, instead of raw Operand() indexing. Also applies the same captures(none)/nocapture golden-IR normalization already used in transform/transform_test.go and compiler/compiler_test.go to interp/interp_test.go's separate copy of the same comparator helper, which was missed in the earlier pass and started failing two of its subtests once actually run against LLVM 22. Verified: `tinygo test` on go-rc5 now passes reliably (repeated runs) against both LLVM 20 (default) and LLVM 22; full transform/compiler/ interp/cgo/goenv test suites pass on both versions. The `builder` package has pre-existing, environment-related test failures (stale GOROOT cache, local clang/target-feature drift) confirmed identical against an unmodified LLVM 20 build, so unrelated to this change.
Member
Author
|
When this is merged, I can add (by hand :) the rest of the math functions we missed for wasip2 from #5354 |
Member
Author
|
Probably need to add llvm 22 to various CI yml versions. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
…LLVM 22 build support
Written entirely by Claude (Anthropic's Claude Code), at the request of and under the direction of dgryski, as part of an effort to get TinyGo building against upcoming LLVM releases (this branch currently targets LLVM 22, verified against real LLVM 22.1.8; a corresponding go-llvm branch of the same name adds the matching binding support).
LLVM 21 replaced the boolean 'nocapture' enum attribute with the more expressive 'captures' int attribute, where captures(none) (value 0) is the equivalent of the old nocapture. This matters for transform.OptimizeAllocs, which relies on reading this attribute for its interprocedural escape analysis, and for compiler/symbol.go, which emits it on a number of runtime/generated functions. Confirmed empirically (via
opt -passes=function-attrs) that the cutoff is LLVM 20 emits/expects nocapture, LLVM 21+ emits/expects captures(none). Since TinyGo must keep working with LLVM 20, both sites now go through new version-gated helpers incompiler/llvmutil (NoCaptureAttrName/IsNoCapture) rather than switching unconditionally.
Also fixes a second, unrelated but load-bearing break found while testing against LLVM 22: llvm.lifetime.start/end dropped their i64 size argument (confirmed via
opt -passes=verify, the cutoff here is one version later, at LLVM 22). compiler/llvmutil now builds the right call signature based on version.Adds llvm21 and llvm22 build-tag config files to the cgo package, which parses cgo fragments via libclang and had never been updated past LLVM 20 even though the compiler package itself already gained LLVM 21 support previously -- a latent gap that would have caused a version mismatch between the cgo preprocessor and the rest of the compiler when building with -tags llvm21 or llvm22.
Finally, updates the golden-IR test comparators in transform/transform_test.go and compiler/compiler_test.go to normalize a few cosmetic LLVM 21/22 output differences (the captures(none) rename/reordering, a new 'nocreateundeforpoison' intrinsic attribute, and the lifetime intrinsic arity change) so a single golden file continues to match output from either LLVM version.
Verified by building a full (non-byollvm) tinygo binary against real LLVM 22.1.8 and running a compiled Go program end-to-end (exercising OptimizeAllocs' stack-allocation path), and by running the transform/compiler/cgo test suites against both LLVM 20 (default) and LLVM 22.
Not yet addressed: the byollvm embedded-clang/lld build path hits separate, unrelated Clang C++ API breakage against LLVM 22 (DiagnosticOptions reference-to-pointer change, missing headers) -- that is a larger follow-up effort.