a function address answers the function in every tier; a module-qualified builtin call stops crashing JIT codegen - #3974
Merged
Conversation
aleksisch
force-pushed
the
aleksisch/fix-reported-bugs
branch
3 times, most recently
from
September 8, 2026 21:10
f62385c to
79fe945
Compare
7 tasks
aleksisch
force-pushed
the
aleksisch/fix-reported-bugs
branch
from
September 8, 2026 21:26
79fe945 to
26a7d76
Compare
…value casts through its { ptr } aggregate
Ten intrinsic handlers keyed on `expr.name`, the call-site spelling, while the dispatch tables
key on the declaration. A module-qualified call kept its qualifier: as an intrinsic-name
fragment that built `llvm.math::sqrt.f32`, which LLVM does not know and the C API dereferenced
anyway; as a branch key it picked the other arm, so `math::min` emitted max. They read
`expr.func.name` now, and the wrapper refuses intrinsic id 0.
A missing intrinsic is no state to return: `LLVMLookupIntrinsicID` answers 0 only for a name
that is no intrinsic, and LLVM's table is target-independent, so a foreign target's names
resolve on any host built with it. It means the emitter built the name wrongly, and no caller
can recover. The twenty-two lookups of a name the emitter builds go through `intrinsic_id`,
which panics naming the string; the nineteen target-specific literals keep the raw lookup and
their own fallback, since a trimmed LLVM can genuinely lack those. Three handlers also stop using the null the intrinsic builder returns for
an operand type it does not serve, which is a different and reachable path.
`visitExprCast` had no arm for `Type.tFunction`, so a function-address reinterpret emitted a
bitcast between the `{ ptr }` aggregate and a scalar and the program failed to simulate. Two
arms go through element 0 instead.
Fixes #3968
Fixes #3969
…a silent 0 The two `@@fn` const nodes left every typed slot as `DAS_ASSERT(0); return 0;`, and `DAS_NO_ASSERTIONS` is on in Release - so `reinterpret<uint64>(@@fn)` read a silent 0 in every store position, while the same cast through a parameter, and the JIT and AOT tiers, answered the address. `evalPtr`, `evalInt64` and `evalUInt64` compute it; the narrower slots keep the assert. `tests/language/func_addr.das` covers the store positions and the handle round-trip, and `func_addr_solid.das` covers the solid-context node, which no test in the tree reached. This folder's checklist gets three fixes its own audit of this change found. Fixes #3970
…y's address `das_cast<TT*>` bound a `Func` to its catch-all `cast(const QQ &)`, which returns `&expr`. The emitter spells `@@fn` as a `Func(...)` temporary, so `reinterpret<void?>(@@fn)` answered a stack address where the interpreter and the JIT answer the function. A `Func` overload reads `PTR`, the way the smart-pointer overloads beside it read `get()`. The two function-address tests gain their `void?` cells, which could not be green before this.
aleksisch
force-pushed
the
aleksisch/fix-reported-bugs
branch
from
September 8, 2026 21:47
26a7d76 to
42a8e9e
Compare
This was referenced Sep 9, 2026
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.
Behavior change:
reinterpreton a function address answers the function in every tier. The JIT caches invalidate once (codegen 0x78).Why. A function's address kept as an opaque handle answered
0in the interpreter once stored, would not JIT, and was a stack address under AOT. A module-qualified builtin call -math::sqrt- killed JIT codegen or emitted the wrong function.What changes.
intrinsic_id, which panics naming it; three handlers stop using the builder's null.visitExprCastgains function <-> pointer / int64 arms through the{ ptr }aggregate.das_cast<TT*>reads aFunc's target, not the temporary's address.Observable behavior.
reinterpret<uint64>(@@fn)once stored ->0-> the address.-jit:math::sqrt(x)-> SIGSEGV -> runs;math::min-> max -> min.-jit: that cast ->Invalid bitcast-> compiles.reinterpret<void?>(@@fn)-> a stack address -> the function.no LLVM intrinsic named '<name>'.Where to look.
llvm_jit_intrin.das's ten key sites and thevisitExprCastarms.Fixes #3968
Fixes #3969
Fixes #3970
Validation, claims, ledger
Validation
tests-interp,tests-jit,tests-aot(the fulltest_aotbuild and sweep, which per-PR CI does not run),docs,utils-tests,tests-cpp,compile-sweep(759 roots).math::minreturned 7 formin(3, 7),llvm.math::sqrt.f32was reported as no intrinsic. The AOT overload was controlled by buildingtest_aot_subsetat the base, wherefunc_addr.dasfails exactly one assert, with a stack address.modules/dasLLVM/testsis 83/84. The failure istest_vector_log_special_values, which fails identically onorigin/master: it pins the aarch64 inline rail's non-IEEE log2 specials and this host is x86_64.codexon this box.untrackedgate is red on 1803 files, all pre-existing scratch in the working tree, none of it staged.Claims - stated, not tested
cos,coshortanhselected a neighbouring arm before this change -build_vector_hyperdispatches on the name, so a qualifiedtanhemitted sinh. This host is x86_64, so that path never ran here. Verified by reading the dispatch, and pinned by asserting each arm against the value its named function has at zero, where the neighbouring arm answers a different number. The emitted-vs-interpreted cell over every vector width thatmodules/dasLLVM/REVIEW.mdasks for needs an ARM box. A break shows astest_qualified_vector_arm_identityfailing on aarch64.intrinsic_idpanic. No committed test reaches it, because after the name fix no call site builds a name LLVM has none of. Verified by reverting the name fix alone, which turns the SIGSEGV intono LLVM intrinsic named 'llvm.math::sqrt.f32'at the panic's own line, with exit 1. A break returns to a hard crash with no line. The 19 target-specific literals keep the raw lookup and their fallbacks: a trimmedLLVM_TARGETS_TO_BUILDis the one case where a missing intrinsic is not an emitter defect, and on a full LLVM every buildable name resolves (probed: 84 of 84, foreign targets included).cond ? "a" : "b"passed as thenameargument ofLLVMBuildInsertValuecrashes codegen with a SIGSEGV at 0x50, while a literal, or the same ternary hoisted into alet, is fine. A standalonedef take(s : string)does not reproduce it, so it needs the extern string-substitution path. The emitter uses theletspelling; the defect is unreported and unfixed.Not done
daslib/REVIEW.md's pair rules only trigger from the daslib side, so a C++-side change routed there has no receiving rule. Merging them into one side-agnostic rule, and recording thedas_cast/Funcpair indaslib/ARCHITECTURE_EMIT.mdsec. 5, is queued rather than done here.modules/dasLLVM/REVIEW.md's two platform rules trigger onget_platform_name()and on the target triple, while the emitters branch on the resolvedg_target_*globals a step later. A property-shaped criterion covering that gap is queued.tests/math/nortests/language/has a checklist today, and creating the first one there is not this change's call.expr.name-as-key check is mechanically decidable from the tree and belongs inmodules/dasLLVM/REVIEW.dasas a gate. Not written here.failed_Erecords and the visit continues; the error list is read only after the whole function. Making a reported failure stop emission is a separate change.