0%

Section 05: LLVM Codegen Internal DRY

Status: Not Started Goal: Eliminate algorithmic duplication within ori_llvm: 19 identical iterator dispatch stanzas, COW list mutation protocol duplication, 75-entry trait method Cartesian product, manually mirrored JIT runtime mappings, and duplicate debug helpers. Context: The LLVM codegen backend has significant internal duplication, particularly in the declare_builtins! macro invocations and runtime mapping code. The iterator dispatch has 19 stanzas that all check TypeInfo::Iterator { element } and delegate to emitter.emit_iterator_method(). The COW list mutations repeat a multi-step protocol. The runtime_mappings.rs file has a TODO acknowledging it manually mirrors RT_FUNCTIONS.

05.1 Consolidate Iterator Builtin Dispatch

File(s): compiler/ori_llvm/src/codegen/arc_emitter/builtins/iterator.rs

19 iterator method dispatch stanzas all follow the same pattern: check TypeInfo::Iterator, delegate to emitter.emit_iterator_method().

  • Replace the 19 individual declare_builtins! entries with a single ("Iterator", _) catch-all handler that checks if the method name is a known iterator method

  • Use the existing is_iterator_method() function (which queries ori_registry) to validate method names

  • Keep the declare_builtins! registration entries for discoverability, but make them point to the single handler

  • Verify: all iterator method tests pass unchanged

  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (05.1) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-05.1 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 05.1: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.


05.2 Extract COW List Mutation Helper

File(s): compiler/ori_llvm/src/codegen/arc_emitter/builtins/collections/mod.rs, compiler/ori_llvm/src/codegen/arc_emitter/builtins/collections/list_cow.rs 9 COW list mutation functions in list_cow.rs (push, pop, set, insert, remove, concat, reverse, sort, sort_stable) share the same protocol: extract element type, get cow_mode, call the runtime function, conditionally call mark_cow_data_noalias_if_unique. The dispatch stanzas in collections/mod.rs also repeat the same TypeInfo::List { element } extraction pattern.

  • Create emit_cow_list_op() higher-order function:

    fn emit_cow_list_op<F>(
        emitter: &mut ArcEmitter,
        ctx: &BuiltinContext,
        op: F,
    ) -> Option<BasicValueEnum>
    where F: FnOnce(&mut ArcEmitter, ...) -> BasicValueEnum
  • Refactor push, pop, set, insert, remove, concat, reverse, sort, sort_stable to use emit_cow_list_op()

  • Verify: timeout 150 cargo test -p ori_llvm passes

  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (05.2) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-05.2 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 05.2: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.


05.3 Collapse Trait Method Cartesian Product

File(s): compiler/ori_llvm/src/codegen/arc_emitter/builtins/traits.rs, compiler/ori_llvm/src/codegen/arc_emitter/builtins/primitives.rs

The declare_builtins! in traits.rs lists ~80 entries all calling emitter.emit_trait_method() with identical arguments. The primitives.rs file has ~38 entries calling emitter.emit_primitive_method() identically.

  • Generate the Cartesian product programmatically from two lists: types and trait methods

  • Keep the explicit registration (needed for the declare_builtins! macro’s map construction) but generate it from arrays/slices

  • For primitives.rs: same approach — generate from PRIMITIVE_TYPES x PRIMITIVE_METHODS arrays

  • WARNING: declare_builtins! is a proc-macro or macro_rules that constructs a HashMap at build time. Understand the macro’s expansion before modifying — the generated dispatch map is consumed by emit_builtin_method(). Changing the macro signature or its output format will break all builtin dispatch.

  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (05.3) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-05.3 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 05.3: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.


05.4 Generate JIT Runtime Mappings from RT_FUNCTIONS

File(s): compiler/ori_llvm/src/evaluator/runtime_mappings.rs, compiler/ori_llvm/src/codegen/runtime_decl/runtime_functions.rs

The lookup_jit_address() function (260 lines) manually mirrors the RT_FUNCTIONS table. The file has a TODO at line 65: “Generate this mapping from RT_FUNCTIONS data.” The struct is RtFn (not RuntimeFunction), and it already has a jit_allowed: bool field — jit_symbol_mappings() already filters by it. The duplication is purely in lookup_jit_address() which maintains a manual match-arm-per-function mapping. Implementation note: Function pointers (fn as *const () as usize) are NOT const-evaluable in stable Rust, so storing them directly in the static RT_FUNCTIONS array is not possible. The approach must use runtime initialization.

  • Create a LazyLock<HashMap<&'static str, usize>> that iterates RT_FUNCTIONS (filtering by jit_allowed: true) and resolves each name to its function pointer at first access. Use a module-level fn resolve_fn_ptr(name: &str) -> usize with the existing match arms, or use a registration macro that pairs each RtFn entry with its function pointer at initialization time.

  • Alternatively, use a build.rs or proc macro to generate the match statement from the RT_FUNCTIONS data, keeping the match but auto-generating it from the canonical source.

  • Replace lookup_jit_address() body with a HashMap lookup from the lazy-initialized mapping.

  • Verify: JIT tests pass unchanged (timeout 150 cargo test -p ori_llvm -- jit)

  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (05.4) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-05.4 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 05.4: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.


05.5 Merge Duplicate Debug Helpers

File(s): compiler/ori_llvm/src/codegen/arc_emitter/builtins/debug_helpers.rs

emit_result_debug (lines 254-312) and emit_nested_result_debug (lines 322-377) have the same structure: extract tag, branch on Ok/Err, format payload, merge via phi.

  • Have emit_result_debug (line 254) delegate to emit_nested_result_debug (line 322) — or extract the shared Ok/Err branch+phi pattern into a parameterized helper that both call- [ ] Verify: debug formatting tests pass unchanged

  • [BLOAT] compiler/ori_llvm/src/codegen/arc_emitter/builtins/debug_helpers.rs — currently 534 lines, exceeds 500-line limit. After merging duplicate helpers, verify it drops below 500; if not, split into debug_helpers/mod.rs + debug_helpers/result.rs

  • /tpr-review passed — independent review found no critical or major issues (or all findings triaged)

  • /impl-hygiene-review passed — hygiene review clean. MUST run AFTER /tpr-review is clean.

  • Subsection close-out (05.5) — MANDATORY before starting the next subsection. Run /improve-tooling retrospectively on THIS subsection’s debugging journey (per .claude/skills/improve-tooling/SKILL.md “Per-Subsection Workflow”): which diagnostics/ scripts you ran, where you added dbg!/tracing calls, where output was hard to interpret, where test failures gave unhelpful messages, where you ran the same command sequence repeatedly. Forward-look: what tool/log/diagnostic would shorten the next regression in this code path by 10 minutes? Implement improvements NOW (zero deferral) and commit each via SEPARATE /commit-push using a valid conventional-commit type (build(diagnostics): ... — surfaced by section-05.5 retrospectivebuild/test/chore/ci/docs are valid; tools(...) is rejected by the lefthook commit-msg hook). Mandatory even when nothing felt painful. If genuinely no gaps, document briefly: “Retrospective 05.5: no tooling gaps”. Update this subsection’s status in section frontmatter to complete.

  • /sync-claude section-close doc sync — verify Claude artifacts across all section commits. Map changed crates to rules files, check CLAUDE.md, canon.md. Fix drift NOW.

  • Repo hygiene check — run diagnostics/repo-hygiene.sh --check and clean any detected temp files.


Cleanup (fix while touching these files)

  • [WASTE] compiler/ori_llvm/src/evaluator/runtime_mappings.rs:65 — TODO comment “Generate this mapping from RT_FUNCTIONS data” is exactly what Section 05.4 implements. Remove the TODO after implementing 05.4.
  • [BLOAT] compiler/ori_llvm/src/codegen/arc_emitter/builtins/collections/mod.rs — currently 566 lines, exceeds 500-line limit. After COW helper extraction in 05.2, verify it drops below 500; if not, split iterator consumers into a submodule.

05.R Third Party Review Findings

  • None.

05.T Test Strategy

This section refactors LLVM codegen internals. Zero behavioral change, but high risk due to generated code.

  • Add enforcement test: the consolidated iterator handler dispatches all methods listed in ori_registry for Iterator type
  • Add enforcement test: all RT_FUNCTIONS entries with jit_allowed: true are resolvable via the generated JIT mapping
  • Add unit test for emit_cow_list_op(): verify it produces the same IR structure as the original per-function implementations (compare LLVM IR output for at least push and sort)
  • Verify timeout 150 cargo test -p ori_llvm passes after each sub-section (05.1-05.5)
  • Verify debug AND release builds: timeout 150 cargo test -p ori_llvm and timeout 150 cargo test -p ori_llvm --release
  • Verify timeout 150 ./test-all.sh passes after all sub-sections complete

05.N Completion Checklist

  • Iterator dispatch consolidated to single handler
  • COW list mutation helper extracted
  • Trait method Cartesian product generated programmatically
  • JIT runtime mappings generated from RT_FUNCTIONS
  • Duplicate debug helpers merged
  • Enforcement tests for iterator dispatch and JIT mappings
  • timeout 150 cargo test -p ori_llvm passes (debug and release)
  • timeout 150 ./test-all.sh passes
  • ./clippy-all.sh clean
  • /tpr-review covering Section 05
  • /impl-hygiene-review
  • /improve-tooling retrospective completed — MANDATORY at section close, after both reviews are clean. Reflect on the section’s debugging journey (which diagnostics/ scripts you ran, which command sequences you repeated, where you added ad-hoc dbg!/tracing calls, where output was hard to interpret) and identify any tool/log/diagnostic improvement that would have made this section materially easier OR that would help the next section touching this area. Implement every accepted improvement NOW (zero deferral) and commit each via SEPARATE /commit-push. The retrospective is mandatory even when nothing felt painful — that is exactly when blind spots accumulate. See .claude/skills/improve-tooling/SKILL.md “Retrospective Mode” for the full protocol.