Skip to content

feat(codegen,runtime): emit the unary kinds the DSL already exposes - #72

Open
bigSheep123 wants to merge 1 commit into
tile-ai:mainfrom
bigSheep123:fix/exp-codegen
Open

feat(codegen,runtime): emit the unary kinds the DSL already exposes#72
bigSheep123 wants to merge 1 commit into
tile-ai:mainfrom
bigSheep123:fix/exp-codegen

Conversation

@bigSheep123

Copy link
Copy Markdown
Contributor

feat(codegen,runtime): emit the unary kinds the DSL already exposes

Fixes #71.

What was wrong

tf.exp, tf.exp2, tf.log, tf.log2, tf.abs, tf.ceil and tf.round are
all reachable from the DSL and all type-infer and evaluate, but _UNARY_TAG
carried rows for only RSQRT, NEG, RELU and SQUARE. Everything else
failed at emission with a bare KeyError: <UnaryKind.LOG: 'log'> — writable and
checkable, but not compilable.

The change

The seven missing runtime functors and their tag rows, following the existing
pattern in unary.cuh.

Two choices worth calling out:

  • The transcendentals use the precise <math.h> entries (expf, logf,
    exp2f, log2f) rather than the __-prefixed intrinsics, so a compiled
    kernel agrees with the evaluator's torch oracle instead of being slightly
    faster and slightly different. A kernel that would rather have the intrinsic
    can still reach for it explicitly.
  • round uses rintf, which breaks halfway cases to even, matching
    torch.round. roundf rounds them away from zero and would disagree at every
    .5.

CAST and NOT stay absent deliberately, and the table now says so rather than
leaving them looking pending: CAST has its own handler, and NOT is a boolean
operation rather than the float path these functors assume.

Tests

tests/integration/test_unary_codegen.py compiles one kernel per op and
compares against the torch oracle on GPU. Verified to fail on main first —
all seven raise KeyError at emission — and pass after.

The inputs are chosen per op rather than shared: log / log2 get a strictly
positive domain, and round gets a grid landing exactly on .5 boundaries so
the rounding-mode choice above is actually exercised instead of assumed.

Each kernel is a separate top-level function because the compiled artifact is
cached per function — a factory emitting several same-named kernels hands every
op whichever one compiled first.

Verification

pytest tests/ -q     644 passed (main @ e55e4b0)  ->  651 passed (+7 new)

Every .pre-commit-config.yaml hook clean: ruff, spec-rules, spec-refs,
spec-entropy, forward-references, comment-hygiene, no-machine-paths,
english-only, and clang-format over all C++ files.

`tf.exp`, `tf.exp2`, `tf.log`, `tf.log2`, `tf.abs`, `tf.ceil` and `tf.round` are
all reachable from the DSL and all type-infer and evaluate, but `_UNARY_TAG`
carried rows for only `RSQRT`, `NEG`, `RELU` and `SQUARE`. Everything else
failed at emission with a bare `KeyError: <UnaryKind.LOG: 'log'>` -- writable
and checkable, but not compilable.

Add the seven missing functors and their tag rows, following the existing
pattern.

Two choices worth stating:

- The transcendentals use the precise `<math.h>` entries (`expf`, `logf`, ...)
  rather than the `__`-prefixed intrinsics, so a compiled kernel agrees with the
  evaluator's torch oracle instead of being a little faster and a little
  different. A kernel that would rather have the intrinsic can still reach for
  it explicitly.
- `round` uses `rintf`, which breaks halfway cases to even, matching torch.
  `roundf` rounds them away from zero and would disagree at every `.5`; the test
  input lands exactly on those boundaries so the distinction is covered rather
  than assumed.

`CAST` and `NOT` stay absent on purpose, and the table now says so: `CAST` has
its own handler, and `NOT` is a boolean operation rather than the float path
these functors assume.

Each test kernel is a separate top-level function because the compiled artifact
is cached per function -- a factory emitting several same-named kernels hands
every op whichever one compiled first.

pytest tests/ -q: 644 passed before, 651 after (+7 new, no regressions).
Verified failing on main first: all seven raise `KeyError` at emission.
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.

Most unary kinds the DSL exposes cannot be emitted

1 participant