Skip to content

feat: control flow — :cond (where-chain) + honest deferrals (CM4) - #151

Merged
ausimian merged 3 commits into
feat/expr-compilerfrom
feat/expr-compiler-cm4
Jun 4, 2026
Merged

feat: control flow — :cond (where-chain) + honest deferrals (CM4)#151
ausimian merged 3 commits into
feat/expr-compilerfrom
feat/expr-compiler-cm4

Conversation

@ausimian

@ausimian ausimian commented Jun 4, 2026

Copy link
Copy Markdown
Owner

CM4 — Nx.Defn control flow in the Expr→MLX compiler. Targets
feat/expr-compiler.

What this adds

  • :cond / if → a where-chain where(p1, b1, where(p2, b2, … last)), so a defn cond compiles single-NIF bit-identical to the
    Evaluator. First matching predicate wins (matches Nx semantics). All
    branches are evaluated (Nx branches are side-effect-free + shape-
    compatible) and the select picks the right one — only the not-taken
    branches' compute is wasted (documented).
  • :attach_token → pass-through to the inner expr when there are no
    active hooks; raises clearly if hooks are present (a mid-graph Elixir
    callback isn't expressible in the single-NIF replay).
  • Honest no-fallback errors for the deferred constructs:
    reduce/window_reduce with an arbitrary BEAM reducer (the fixed
    aggregates lower natively); while and its :elem tuple projection
    (the replay has no loop construct — a focused follow-up; defn while
    isn't used by the core transformer forwards, whose loops run in Elixir).

Gate

compiler_control_flow_test — two-branch if, multi-clause cond,
nested conds (each bit-identical to the Evaluator), plus assertions that
arbitrary reduce and while raise clearly. mix precommit green:
40 doctests, 79 properties, 615 tests, 0 failures; credo --strict
clean. Reviewed (focused); findings addressed.

Next

:while (static-unroll / worker-synced loop) as a follow-up; then CM5
(no-fallback conformance) and CM6 (mx::compile secondary).

ausimian added 3 commits June 5, 2026 01:29
- :cond — raw args [clauses, last]; lower to a select chain
  where(p1, b1, where(p2, b2, ... last)). All branches are evaluated
  (Nx branches are side-effect-free and shape-compatible) and the result
  matches the Evaluator's chosen branch exactly; only the not-taken
  branches' compute is wasted. The whole-tensor scalar predicate selects
  a branch wholesale.
- :attach_token — pass through to the inner expr when there are no active
  hooks; raise clearly if hooks are present (a mid-graph Elixir callback
  isn't expressible in the single-NIF replay; program-split is deferred).

Tests: compiler_control_flow — two-branch if, multi-clause cond, and
nested conds, each bit-identical to the Evaluator. :while is next.
- reduce / window_reduce with an arbitrary BEAM reducer raise a clear
  error (no silent fallback); the fixed-identity aggregates (sum/product/
  reduce_max/reduce_min) lower natively as their own ops.
- while and its :elem tuple projection raise a clear "deferred" error —
  the single-NIF replay has no loop construct, so a data-dependent while
  needs static-trip unrolling or a worker-side synced loop (a focused
  follow-up). defn while is not used by the core transformer forwards;
  decode/generation loops run in Elixir.

Tests assert both raise clearly under the native compiler.
- Split :elem out of the :while raise with an accurate message — :elem is
  a generic tuple projection (defn while AND multi-output ops), not while-
  specific, so the old "while loops" diagnostic could mislead.
- Caveat the cond comment: a not-taken branch is still computed; on MLX an
  out-of-bounds gather there clamps (so the discarded value never changes
  the result), but a hard-faulting op on a not-taken path would diverge
  from the Evaluator's lazy single-branch eval.
@ausimian
ausimian merged commit e2bf3f8 into feat/expr-compiler Jun 4, 2026
3 checks passed
@ausimian
ausimian deleted the feat/expr-compiler-cm4 branch June 4, 2026 15:43
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