mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-16 02:33:28 +00:00
interp: fix switch-instruction handling for LLVM 22's new case-value API
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.
This commit is contained in:
+17
-5
@@ -140,13 +140,25 @@ func (r *runner) compileFunction(llvmFn llvm.Value) *function {
|
||||
panic("unknown number of operands")
|
||||
}
|
||||
case llvm.Switch:
|
||||
// A switch is an array of (value, label) pairs, of which the
|
||||
// Compile to an array of (value, label) pairs, of which the
|
||||
// first one indicates the to-switch value and the default
|
||||
// label.
|
||||
numOperands := llvmInst.OperandsCount()
|
||||
for i := 0; i < numOperands; i += 2 {
|
||||
inst.operands = append(inst.operands, r.getValue(llvmInst.Operand(i)))
|
||||
inst.operands = append(inst.operands, literalValue{uint32(blockIndices[llvmInst.Operand(i+1)])})
|
||||
//
|
||||
// Successor 0 is always the default destination; successors
|
||||
// 1..N-1 are the individual cases. This must be read via
|
||||
// GetSwitchCaseValue/Successor rather than raw operands,
|
||||
// because LLVM 22 stopped exposing switch case values as
|
||||
// regular instruction operands (only the condition and
|
||||
// destination-block operands remain).
|
||||
inst.operands = append(inst.operands,
|
||||
r.getValue(llvmInst.Operand(0)),
|
||||
literalValue{uint32(blockIndices[llvmInst.Successor(0).AsValue()])},
|
||||
)
|
||||
for i := 1; i < llvmInst.SuccessorsCount(); i++ {
|
||||
inst.operands = append(inst.operands,
|
||||
r.getValue(llvmInst.GetSwitchCaseValue(i)),
|
||||
literalValue{uint32(blockIndices[llvmInst.Successor(i).AsValue()])},
|
||||
)
|
||||
}
|
||||
case llvm.PHI:
|
||||
inst.name = llvmInst.Name()
|
||||
|
||||
Reference in New Issue
Block a user