Skip to content

Remove is_placed flag from JIT decorator #2957

Draft
hunhoffe wants to merge 12 commits intomainfrom
fix/jit-remove-is-placed
Draft

Remove is_placed flag from JIT decorator #2957
hunhoffe wants to merge 12 commits intomainfrom
fix/jit-remove-is-placed

Conversation

@hunhoffe
Copy link
Collaborator

Remove is_placed flag from JIT decorator

⚠️ Depends on fix/jit-preexisting-bugs (PR #2948) — merge that first.

Summary

  • Removes the is_placed parameter from jit(). The mode (placed vs. unplaced) is now auto-detected from the decorated function's return value: if it
    returns None, the module was built implicitly via @device/@core/@runtime_sequence context managers (placed style); if it returns a module object, that
    module is used directly (unplaced style via Program.resolve_program).
  • Removes is_placed=False from all call sites across tests, programming examples, and mini-tutorial files (~40 files).
  • Removes stale is_placed parameter documentation from example file comments and programming_examples/algorithms/README.md.
  • Adds test/python/npu-xrt/test_jit_placed_style.py, a new test covering the placed-style JIT code path (function returns None), which previously had no
    automated test coverage.

Test plan

  • All existing JIT tests pass: test_jit_compilation, test_jit_utils, test_jit_extern_functions, test_jit_extern_functions_inside_jit, test_jit_trace,
    test_algorithms
  • New placed-style test passes: test_jit_placed_style (both num_elements=16 and num_elements=64)
  • programming_examples/basic/vector_vector_add/vector_vector_add_placed.py runs correctly (exercises @iron.jit bare decorator with placed style on NPU)

🤖 Generated with https://claude.com/claude-code

hunhoffe and others added 12 commits March 11, 2026 16:35
jit.py: "|".join(running_hash) iterated over characters of the
concatenated string instead of per-kernel hash values, causing cache
key collisions between different ExternalFunction configurations.

utils.py: compile_external_kernel silently returned when source_file
did not exist, producing a confusing downstream linker error. Now
raises FileNotFoundError with the missing path in the message.

Regression tests added in test/python/test_jit_utils_bugs.py; they
run without hardware or XRT.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…lar import

- Delete test/python/test_jit_utils_bugs.py (tested local reimplementations
  of hash_module and compile_external_kernel rather than the real functions)
- Add test/python/npu-xrt/test_jit_utils.py with 12 tests against the real
  hash_module and compile_external_kernel using real MLIR modules built via
  iron and real Peano compilation; all 12 pass on hardware
- Fix circular import in python/utils/jit.py: top-level
  `from aie.iron.kernel import ExternalFunction` triggered aie.iron.__init__
  which imports jit, causing ImportError when jit.py was the first module
  loaded; move the import inside decorator() and _filter_tensor_args(),
  matching the existing deferred-import pattern in that file

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…und (#2879)

Closures differing only in captured value produced identical in-memory
cache keys because _create_function_cache_key hashed only co_code,
co_consts, co_names, and defaults — none of which change when a free
variable changes.

Add _closure_key() to extract cell_contents from a callable's closure
and include it in the hash tuple, with fallbacks for unhashable values
(repr()) and deleted cells (ValueError). Apply to both the args and
kwargs branches of _create_function_cache_key.

Remove the has_closures / effective_use_cache workaround from jit.py
and the now-unused _has_closure helper. The workaround was disabling
the in-memory cache for all closures and forcing a full disk recompile
on every call, even when a valid cached artifact already existed.

Add two tests to test_jit_utils.py:
- test_closure_cache_key_distinguishes_captured_values: unit test
  verifying different captured values produce different cache keys
- test_jit_closure_parametrize: parametrized hardware test confirming
  correct output for add_value in {1, 2, 3}

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Replace identity-based hash() fallback in _closure_key with a
_cell_val_to_key helper that uses a priority chain:

1. value-hash   — O(1) for types with a proper value-based __hash__
                  (int, str, float, tuple, frozenset, custom immutables)
2. pickle       — SHA-256 of pickle.dumps(val) captures full __dict__
                  state for mutable objects regardless of whether
                  __eq__ / __hash__ / __repr__ are defined
3. pickle_dict  — fallback for locally-defined classes (not picklable
                  by qualified name); pickle __dict__ directly instead
4. repr         — last resort for non-picklable identity-hashable objects

Also include variable names in closure key tuples for precision.

Adds four new unit tests covering: mutable object with no __repr__,
in-place list mutation, key stability without mutation, and the
no-closure fast path.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
The jit() decorator previously had an is_placed parameter to select
between two execution modes. This removes the flag and auto-detects
the mode from the decorated function's return value:

- If the function returns None the module was built implicitly via
  @device/@core/@runtime_sequence context managers (placed style).
- If the function returns a module it is used directly (unplaced style,
  Program.resolve_program).

All call sites that passed is_placed=False explicitly are updated to
use the simpler @iron.jit() / @iron.jit form. Comments referencing
the is_placed parameter are removed from example files.

A new test (test_jit_placed_style.py) is added to cover the placed-
style JIT code path, which had no automated test coverage.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Comment on lines +187 to +188
f.write(
"""extern "C" {
Copy link
Contributor

Choose a reason for hiding this comment

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

[black] reported by reviewdog 🐶

Suggested change
f.write(
"""extern "C" {
f.write("""extern "C" {

Comment on lines +192 to +193
}"""
)
Copy link
Contributor

Choose a reason for hiding this comment

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

[black] reported by reviewdog 🐶

Suggested change
}"""
)
}""")

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.

1 participant