Skip to content
This repository was archived by the owner on Apr 29, 2026. It is now read-only.

⏺ Summary#205

Merged
navicore merged 1 commit intomainfrom
fix-virt-var-spill
Jan 9, 2026
Merged

⏺ Summary#205
navicore merged 1 commit intomainfrom
fix-virt-var-spill

Conversation

@navicore
Copy link
Copy Markdown
Owner

@navicore navicore commented Jan 9, 2026

Fixed 8 operations that were missing virtual register spills:
┌─────────────────────────────────┬──────────────────────┐
│ Operation │ Type │
├─────────────────────────────────┼──────────────────────┤
│ and │ Boolean │
├─────────────────────────────────┼──────────────────────┤
│ or │ Boolean │
├─────────────────────────────────┼──────────────────────┤
│ not │ Boolean │
├─────────────────────────────────┼──────────────────────┤
│ tuck │ Stack │
├─────────────────────────────────┼──────────────────────┤
│ 2dup │ Stack │
├─────────────────────────────────┼──────────────────────┤
│ nip │ Stack (runtime call) │
├─────────────────────────────────┼──────────────────────┤
│ f.+, f.-, f.*, f./ │ Float arithmetic │
├─────────────────────────────────┼──────────────────────┤
│ f.=, f.<>, f.<, f.>, f.<=, f.>= │ Float comparison │
└─────────────────────────────────┴──────────────────────┘
Added 22 new integration tests in tests/integration/src/test-virtual-register-spill.seq that specifically test integer literals followed by each operation. These tests would have caught the bug - they verify that 3 4 2dup produces 3 4 3 4 (not 0 0 3 4).

All 199 tests pass (177 original + 22 new).

  Fixed 8 operations that were missing virtual register spills:
  ┌─────────────────────────────────┬──────────────────────┐
  │            Operation            │         Type         │
  ├─────────────────────────────────┼──────────────────────┤
  │ and                             │ Boolean              │
  ├─────────────────────────────────┼──────────────────────┤
  │ or                              │ Boolean              │
  ├─────────────────────────────────┼──────────────────────┤
  │ not                             │ Boolean              │
  ├─────────────────────────────────┼──────────────────────┤
  │ tuck                            │ Stack                │
  ├─────────────────────────────────┼──────────────────────┤
  │ 2dup                            │ Stack                │
  ├─────────────────────────────────┼──────────────────────┤
  │ nip                             │ Stack (runtime call) │
  ├─────────────────────────────────┼──────────────────────┤
  │ f.+, f.-, f.*, f./              │ Float arithmetic     │
  ├─────────────────────────────────┼──────────────────────┤
  │ f.=, f.<>, f.<, f.>, f.<=, f.>= │ Float comparison     │
  └─────────────────────────────────┴──────────────────────┘
  Added 22 new integration tests in tests/integration/src/test-virtual-register-spill.seq that specifically test integer literals followed by each operation. These tests would have caught the bug - they verify that 3 4 2dup produces 3 4 3 4 (not 0 0 3 4).

  All 199 tests pass (177 original + 22 new).
@claude
Copy link
Copy Markdown

claude Bot commented Jan 9, 2026

PR Review - Virtual Register Spill Fix

Summary

This PR fixes a critical code generation bug where 8 operations were missing virtual register spills before accessing memory. The fix correctly adds spill_virtual_stack() calls to ensure LLVM virtual registers are written to memory before operations that need to access the stack. The PR includes comprehensive test coverage with 22 new integration tests.

Code Quality - ✅ Excellent

Strengths:

  1. Consistent Pattern: All fixes follow the same correct pattern:

    // Spill virtual registers (Issue #189)
    let stack_var = self.spill_virtual_stack(stack_var)?;
    let stack_var = stack_var.as_str();
  2. Clear Documentation: Each fix includes a comment referencing Issue Optimization: Use LLVM registers for stack-top values #189, making it easy to trace the reasoning.

  3. Proper Placement: Spills happen at the right time - immediately before any memory access operations (getelementptr, load, store).

  4. Comprehensive Coverage: All 8 problematic operations identified in the issue are fixed:

    • Boolean ops: and, or, not
    • Stack ops: tuck, 2dup, nip
    • Float arithmetic: f.+, f.-, f.*, f./
    • Float comparisons: f.=, f.<>, f.<, f.>, f.<=, f.>=

Code Organization:

  • Changes are localized to crates/compiler/src/codegen.rs:3103-4302
  • Helper functions codegen_inline_float_binary_op and codegen_inline_float_comparison properly handle the spill for all float operations

Test Coverage - ✅ Excellent

The new test file tests/integration/src/test-virtual-register-spill.seq provides thorough coverage:

Test Categories:

  1. Stack operations (3 tests): 2dup, tuck, nip
  2. Boolean operations (4 tests): Basic and, or, not, plus combined with comparisons
  3. Float arithmetic (4 tests): All four operations
  4. Float comparisons (6 tests): All six comparison operators
  5. Combined operations (3 tests): Complex scenarios testing interactions

Test Quality:

  • Tests are regression tests that would have caught the original bug
  • Each test uses integer/float literals (which trigger virtual registers) followed by the operation
  • Good documentation explaining what each test verifies
  • Tests check actual correctness, not just "doesn't crash"

Total: 22 new tests, all passing (177 + 22 = 199 tests)

Potential Issues - ⚠️ Minor

1. Test Discovery

The test file test-virtual-register-spill.seq is placed in tests/integration/src/ and will be discovered by seqc test tests/integration/src/ (called by just test-integration). However, I couldn't verify it's explicitly referenced anywhere.

Recommendation: Verify the test file is being run by the test runner. Run:

just test-integration 2>&1 | grep -i "virtual-register-spill"

2. Benchmark File Update

The benchmarks/LATEST_RUN.txt update is cosmetic (timestamp change) and unrelated to the fix itself. This is fine, but worth noting.

Performance Considerations - ✅ Good

  • No Performance Regression: The spill operation was already needed; this fix just ensures it happens when required
  • The spill is efficient - it only writes virtual registers that exist and clears the virtual stack
  • No unnecessary spills added - only operations that access memory need the spill

Security Concerns - ✅ None

  • Fix prevents undefined behavior (reading uninitialized/garbage memory)
  • No security implications beyond correctness

Best Practices - ✅ Followed

  1. Issue Reference: Clear reference to Issue Optimization: Use LLVM registers for stack-top values #189 in all comments
  2. Atomic Fix: All related operations fixed in one PR
  3. Test First Mindset: Tests demonstrate the bug would have been caught
  4. Documentation: Commit message and PR description are excellent with clear table of affected operations

Suggestions for Improvement

Optional Enhancements:

  1. Consider adding a test that would fail if the spill is removed (to ensure tests are actually catching the bug)
  2. Could add a comment in the spill_virtual_stack method doc string mentioning these operations as use cases

Final Verdict - ✅ LGTM

This is a high-quality bug fix that:

  • Correctly addresses the root cause
  • Includes comprehensive test coverage
  • Follows consistent patterns
  • Has excellent documentation

Recommendation: Approve and merge

The fix is critical for correctness and should be merged promptly. All 199 tests pass, and the implementation is sound.


Review completed by Claude Code - checking code quality, security, performance, and best practices

@navicore navicore merged commit e1823f8 into main Jan 9, 2026
2 checks passed
@navicore navicore deleted the fix-virt-var-spill branch January 9, 2026 03:17
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant