Files
LLVMParty-llvm-nanobind/devdocs/api-ux-cleanup/progress.md
T
2026-05-13 16:58:02 +02:00

5.7 KiB

API UX Cleanup Progress

Status

Implemented and tested the active UX work:

  1. generic intrinsic helper,
  2. explicit module optimization helper,
  3. object/assembly emission convenience,
  4. JIT through LLVM-C ORC LLJIT,
  5. metadata/debug-info cleanup.

Implemented APIs

Phase 1: Generic intrinsic helper

  • Added Builder.intrinsic(name, args, *, overloaded_types=..., name_hint="").
  • Added no-overload form Builder.intrinsic(name, args, *, name_hint="").
  • Internally looks up the intrinsic ID by name.
  • Uses overloaded_types as LLVM's overload-disambiguation type list.
  • Raises a clear error for unknown intrinsic names.
  • Raises a clear error when an overloaded intrinsic needs overloaded_types.
  • Keeps existing lower-level intrinsic APIs public.
  • Tests cover non-overloaded, overloaded, and memory intrinsics.

Phase 2: Module optimization helper

  • Added Module.optimize(pipeline, *, target_machine=None, options=None).
  • Uses LLVM PassBuilder pipeline strings directly.
  • Mutates the module in place.
  • Includes the failed pipeline string in error messages.
  • Keeps existing lower-level pass APIs public.
  • Fixed optional pass options by creating a default PassBuilderOptions internally when none is provided.
  • Tests cover success and failure paths.

Phase 3: Object/assembly emission convenience

  • Added TargetMachine.host(...).
  • Added Module.emit_object(*, target_machine=None).
  • Added Module.emit_assembly(*, target_machine=None).
  • If target_machine is omitted, creates a host target machine internally.
  • Emission methods do not run optimization passes.
  • Keeps TargetMachine.emit_to_memory_buffer public.
  • Tests cover object, assembly, host target, explicit target machine, and BinaryManager parsing.

Phase 4: JIT through LLVM-C

  • Inspected available LLVM-C headers and chose ORC LLJIT C API.
  • Added llvm.JIT.host() context manager.
  • Implemented module ownership transfer for jit.add_module(mod).
  • jit.add_module(mod) invalidates the Python Module wrapper on success.
  • Added jit.lookup(name) -> int.
  • Added jit.ctypes_function(...) callable wrapper.
  • jit.ctypes_function(...) keeps the JIT object alive while the returned callable wrapper is alive.
  • Added jit.add_symbol(...) for integer addresses and ctypes callbacks.
  • ctypes callback objects are pinned while the JIT is alive and released on dispose.
  • Unsupported host target/JIT setup raises LLVMError; tests skip target-dependent checks cleanly when unavailable.

Phase 5: Metadata/debug-info cleanup

  • Added Value.metadata mapping view by metadata kind name.
  • Added Metadata.kind, is_string, is_node, is_value, string, operands, and value accessors.
  • Stubbed Metadata.value with NotImplementedError because LLVM-C cannot unwrap ValueAsMetadata to Value.
  • Added MetadataMap.copy_to(target, include_debug_location=False) so transforms can copy arbitrary attached metadata without exposing kind IDs.
  • Added support for detached instruction metadata by deriving the context from the value type.
  • Added Module.named_metadata mapping/list view.
  • Added NamedMetadataMap.keys() and iteration.
  • Added Module.module_flags view.
  • Added Context.debug_location(...).
  • Added Builder.debug_location(...) context manager.
  • Added DIBuilder recipes: file, compile_unit, function, local_variable.
  • Removed redundant public low-level metadata APIs: raw metadata kind lookup, raw Value.set_metadata, public ValueMetadataEntries, public NamedMDNode, Metadata.as_value, raw named-metadata methods, and raw module-flag methods.
  • Removed redundant DIBuilder aliases covered by recipes: create_file, create_compile_unit.
  • Kept advanced DIBuilder create_* methods where the recipes do not provide full coverage.

Tests added

  • tests/regressions/test_api_ux_cleanup.py
  • tests/regressions/test_metadata_ux_cleanup.py

Coverage:

  • non-overloaded intrinsic call,
  • overloaded floating-point intrinsic call,
  • memory intrinsic call,
  • unknown intrinsic error,
  • missing overload types error,
  • module optimization success and invalid-pipeline failure,
  • optimization with target machine,
  • object and assembly emission,
  • emitted object opens with BinaryManager,
  • JIT integer function lookup and ctypes call,
  • module invalidation after JIT transfer,
  • missing JIT symbol error,
  • JIT ctypes callable keeps the JIT alive,
  • JIT callback symbol registration and callback lifetime pinning.

Documentation and examples updated

  • README.md current capabilities, known limitations, and example links.
  • devdocs/api-reference.md high-level UX helper examples.
  • devdocs/api-ux-cleanup/plan.md remains the task design reference.
  • examples/intrinsic_memcpy.py shows Builder.intrinsic(...).
  • examples/optimize_module.py shows Module.optimize(...).
  • examples/emit_object_assembly.py shows TargetMachine.host(), emit_object(), and emit_assembly().
  • examples/jit_add.py shows JIT.host(), add_module(), lookup via ctypes_function(), and add_symbol().

Validation performed

cmake --build build
uv run tests/regressions/test_api_ux_cleanup.py
uv run pytest tests/regressions/test_api_ux_cleanup.py -q
uv run tests/regressions/test_metadata_ux_cleanup.py
uv run pytest tests/regressions/test_metadata_ux_cleanup.py tests/test_examples.py -q
uv run run_tests.py --regressions
uv run run_tests.py
uv run run_llvm_c_tests.py --use-python
uvx ty check

All commands passed.