Skip to content

the JIT parks a statement after a terminator in its own dead block; the dim-expr folding fixture halves by a multiply - #3964

Merged
borisbat merged 1 commit into
masterfrom
bbatkin/nightly-jit-terminator
Sep 8, 2026
Merged

the JIT parks a statement after a terminator in its own dead block; the dim-expr folding fixture halves by a multiply#3964
borisbat merged 1 commit into
masterfrom
bbatkin/nightly-jit-terminator

Conversation

@borisbat

@borisbat borisbat commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Why. The JIT rejected any function that has a statement after a terminator inside one block list: a nested block's return / break / continue, or the constant-condition if the compiler unfolds even unoptimized. The tail was appended after the ret in the same basic block and LLVM's verifier failed the function ("Terminator found in the middle of a basic block"). The new fast-math nightly lane hit it first, through test_step_smoothstep.das's if (HOST_FAST_MATH) { skip; return } arm under options optimize = false. The same lane showed tests/lint/test_dim_expr_folding.das asserting an exact float4 / 2.0 fold that a gcc -ffast-math host answers one ULP off.

What changes.

  • preVisitExprBlockExpression parks the builder in a fresh dead basic block when the current block already terminates, so the tail becomes unreachable IR instead of an invalid block.
  • tests/jit_tests/terminated_block_tail.das pins every shape (bare-block return, constant-if return, break and continue inside a nested block, void bare-block return, the skip-then-return shape) under options optimize = false.
  • The dim-expr folding fixture halves its vector by * 0.5 instead of / 2.0: a -ffast-math host lowers a vector division by a runtime splat to rcpps plus one Newton step, while a multiply by 0.5 is exact on every host.
  • LLVM_JIT_CODEGEN_VERSION 0x76, emitter pin re-hashed.

Observable behavior.

  • options optimize = false + a terminated nested block + a following statement: JIT panic Failed to get IR of '<fn> implementation' -> compiles and runs, the tail never executes.
  • fastmath nightly lane: test_step_smoothstep.das (1 error) and test_dim_expr_folding.das (1 failed) -> green.

Where to look. The one new branch in llvm_jit.das preVisitExprBlockExpression; the dead block is the same device visitExprIfThenElse already uses for a fully-terminating if/else.

Validation, claims, ledger

Validation

  • Both failures reproduced on a gcc -DDAS_FAST_MATH=ON Release build (zen4, g++ 12, HOST_FAST_MATH true): VEC_HALF answered 0.49999997, 0.99999994, 1.4999999, 1.9999999 in interpreter and JIT; the rcpps lowering confirmed from the assembly of _mm_div_ps(a, _mm_set1_ps(b)) under -O2 -ffast-math. The terminator bug reproduces on any host with -jit.
  • At this tip on a clean fast-math build of the same box: test_dim_expr_folding.das, test_step_smoothstep.das and the new test green under both tiers, the smoothstep vector arm skipping as designed.
  • Targeted gates instead of the full preflight: the change is confined to the JIT block emitter and two test files. Run at this tip: the tests/jit_tests sweep under -jit (389 passed, 1 skipped), the dasLLVM module-owned suite under -jit (84 passed), make-pr jit-smoke, lint and format on the changed files. The TDD audit's negative controls: the new test fails at every pinned shape with the emitter change reverted.
  • Not run locally: the full AOT sweep (tests/jit_tests is gated off under --use-aot; the fixture change is exercised by the AOT'd test_dim_expr_folding.das on the nightly).

Claims - stated, not tested

  • A -ffast-math host's vector division by a runtime splat is one ULP off in the interpreter tier. Measured on zen4, pinned by no test after this change; whether it is ledgered as an accepted host property is a separate ruling.

Not done

  • The other nightly reds are separate: the Windows AOT-host tests/module_cache/test_default_cache_path.das children (empty output, rc 0, every nightly since 2026-09-04), the Windows watchdog string-heap bound, the MinGW isolated-mode sharing violation, the tsan test_tray Quit exit code.

… nested block's return / break / continue, or the constant-condition if the compiler unfolds even unoptimized, left the tail after the ret in the same basic block (LLVM "Terminator found in the middle of a basic block", surfaced by test_step_smoothstep's HOST_FAST_MATH skip arm under options optimize = false); tests/jit_tests/terminated_block_tail.das pins every shape; the dim-expr folding fixture halves its vector by a multiply, since a -ffast-math host divides by a runtime splat through rcpps one ULP off; codegen version 0x76, emitter pin re-hashed

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 8, 2026 04:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The JIT fix is localized, follows an existing dead-block pattern already used in the emitter, and is backed by targeted regression tests plus the necessary codegen cache invalidation.

Pull request overview

This PR fixes an LLVM IR validity bug in the dasLLVM JIT emitter where code generation could append instructions after a terminator inside the same basic block (triggering LLVM verifier failures). It also hardens fast-math test stability by adjusting a dim-expr folding fixture to avoid an imprecise vector-division lowering under -ffast-math.

Changes:

  • Park the LLVM IR builder in a fresh “dead” basic block when a block already terminates, so subsequently visited (unreachable) statements don’t land after a terminator in the same block.
  • Add a JIT regression test covering multiple “statement-after-terminator” shapes under options optimize = false.
  • Update the dim-expr folding fixture to use * 0.5 instead of / 2.0, and bump JIT codegen version + emitter hash.
File summaries
File Description
tests/lint/_fixture_dim_expr_folding.das Makes the “half vector” fixture stable under fast-math by using an exact multiply-by-0.5 form.
tests/jit_tests/terminated_block_tail.das Adds coverage for unreachable tail statements after return/break/continue and skip+return shapes.
modules/dasLLVM/daslib/llvm_jit.das Adjusts block-expression visitation to relocate emission to a dead block when the current block already has a terminator.
modules/dasLLVM/daslib/llvm_jit_run.das Bumps LLVM_JIT_CODEGEN_VERSION and updates the emitter hash to invalidate cached artifacts.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@borisbat
borisbat merged commit 8e23bbf into master Sep 8, 2026
30 checks passed
@borisbat
borisbat deleted the bbatkin/nightly-jit-terminator branch September 8, 2026 05:26
@borisbat borisbat changed the title the JIT parks a statement after a terminator in its own dead block; the dim-expr folding fixture halves by a multiply four nightly reds: the JIT's terminated-block tail, the fast-math fold fixture, the no-LLVM lint lane's umbrella requires and LLVM-only programs, the playground's dastest start line Sep 8, 2026
@borisbat
borisbat requested a lite review from Copilot September 8, 2026 05:56
@borisbat borisbat changed the title four nightly reds: the JIT's terminated-block tail, the fast-math fold fixture, the no-LLVM lint lane's umbrella requires and LLVM-only programs, the playground's dastest start line the JIT parks a statement after a terminator in its own dead block; the dim-expr folding fixture halves by a multiply Sep 8, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The PR description claims several additional fixes/files that do not appear to be included in the presented changes, so the PR metadata must be aligned with the actual diff (or the missing commits added) before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment on lines +1073 to +1077
if (current_block_terminates()) {
//! a statement after a terminator - a nested block's return / break / continue, or the
//! constant-condition if the compiler unfolds even unoptimized - lands in its own dead block
LLVMPositionBuilderAtEnd(g_builder, append_basic_block("dead_at_line_{int(expr.at.line)}_"))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants