---
generated: true
model: claude-fable-5
generated_at: 2026-07-08T15:12:37+00:00
source_commit: 5f0e613fdd3c2890bb087d9ff76154e2605a14d2
watched_paths_digest: 37d40d6faa1f92d8e35b6cc828752b61f477cec57399105ffa0243bf29abd8ce
source_doc: docs/generated/design/ir-reference/differentiation.md
source_doc_digest: 6e279be87ce710694f4992c25f87c0813ef33ef71662c600601e8c83f7b3ae5e
warning: "Auto-generated. May drift from source. Do not edit by hand."
---

# Tests for ir-reference/differentiation

## Intent

Tests verify the per-opcode catalog of the IR differentiation family
described in
[`docs/generated/design/ir-reference/differentiation.md`](../../../design/ir-reference/differentiation.md):
that each user-observable differentiation opcode appears in
`-dump-ir` output for the obvious AST surface that produces it
(`__fwd_diff(f)` / `fwd_diff(f)`, `__bwd_diff(f)` / `bwd_diff(f)`,
`DifferentialPair<T>(p, d)`, `.p` / `.d` projections, `detach(x)`,
`no_diff T x` parameter markers), and that the lowering-produced
built-in requirement keys of the `IDifferentiable` family
(`BuiltinRequirementKey` plus its `BuiltinRequirementDecoration`
role tag) are visible at the same stage.

The primary observation mechanism is `-target spirv-asm -dump-ir -o
/dev/null -entry main -stage compute` followed by a FileCheck
against the LOWER-TO-IR section. Anchors are user-named symbols
(`func %main`, `func %f`, `func %helperFunc`, `func %blockDeriv`,
`func %scale`, `let %fwdx5Fdiff`) — the IR-dump preamble for
autodiff is very large (every `IDifferentiable` /
`IForwardDifferentiable` / `IBackwardDifferentiable` interface,
every key, every builtin float-family witness) and any
unanchored pattern risks false positives. The two
builtin-requirement-key tests are the exception: their bare
opcode-name substrings can only match the key definitions
themselves, so they match inside the preamble deliberately.

The angle distinguishing this bundle from `ir-reference/structure`
(which anchors `func`/`interface`/`witness_table` opcodes) and
`ir-reference/types` (which anchors the differential-pair _type_
family) is: **the differentiation-operator and pair-construction/
projection axis** — every test observes either an autodiff opcode,
the `no_diff` / `detach` markers that participate in the autodiff
system, or the built-in requirement keys the autodiff passes look
requirements up by. The internal autodiff-pass opcodes
(`BackwardDifferentiate`, `BackwardDifferentiatePropagate`,
`checkpointObj`, `loopExitValue`, `PrimalParamRef`, etc.) are not
user-observable at LOWER-TO-IR and are recorded as out of scope.

## Functional coverage

| Claim                                                                                                                                                                  | Intent     | Anchor                                                                                                        | Tests                                                                                        |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| Each built-in requirement key is tagged with a BuiltinRequirementDecoration recording the BuiltinRequirementKind role it represents.                                   | functional | [#built-in-requirement-keys](../../../design/ir-reference/differentiation.md#built-in-requirement-keys)       | [`builtin-requirement-decoration.slang`](builtin-requirement-decoration.slang)               |
| Lowering assigns hoistable BuiltinRequirementKey insts as the requirement keys of the built-in IDifferentiable-family interfaces, visible in the LOWER-TO-IR dump.     | functional | [#built-in-requirement-keys](../../../design/ir-reference/differentiation.md#built-in-requirement-keys)       | [`builtin-requirement-key.slang`](builtin-requirement-key.slang)                             |
| detach(x) inside a differentiable function lowers to detachDerivative(%x).                                                                                             | functional | [#detachderivative](../../../design/ir-reference/differentiation.md#detachderivative)                         | [`detach-derivative.slang`](detach-derivative.slang)                                         |
| detachDerivative returns its operand unchanged with the same scalar result type at LOWER-TO-IR.                                                                        | functional | [#detachderivative](../../../design/ir-reference/differentiation.md#detachderivative)                         | [`detach-derivative-result-type.slang`](detach-derivative-result-type.slang)                 |
| Reading .d off a returned DifferentialPair lowers to GetDifferential(%pair).                                                                                           | functional | [#differential-pair-projection](../../../design/ir-reference/differentiation.md#differential-pair-projection) | [`get-differential.slang`](get-differential.slang)                                           |
| Reading .p off a returned DifferentialPair lowers to GetPrimal(%pair).                                                                                                 | functional | [#differential-pair-projection](../../../design/ir-reference/differentiation.md#differential-pair-projection) | [`get-primal.slang`](get-primal.slang)                                                       |
| ForwardDifferentiate has exactly one operand (baseFn): the user-named func value to differentiate.                                                                     | functional | [#forward-mode](../../../design/ir-reference/differentiation.md#forward-mode)                                 | [`forward-differentiate-base-fn-operand.slang`](forward-differentiate-base-fn-operand.slang) |
| ForwardDifferentiate is hoistable so two syntactic \_\_fwd_diff(f) occurrences on the same base function dedupe to one ForwardDifferentiate(%f) IR value.              | functional | [#forwarddifferentiate](../../../design/ir-reference/differentiation.md#forwarddifferentiate)                 | [`forward-differentiate-dedupes.slang`](forward-differentiate-dedupes.slang)                 |
| The unprefixed fwd_diff(f) form also lowers to ForwardDifferentiate(%f), same as \_\_fwd_diff.                                                                         | functional | [#forwarddifferentiate](../../../design/ir-reference/differentiation.md#forwarddifferentiate)                 | [`fwd-diff-alias.slang`](fwd-diff-alias.slang)                                               |
| \_\_fwd_diff(f) on a [ForwardDifferentiable] function lowers to a ForwardDifferentiate(%f) IR value whose result type is the JVP signature Func(DiffPair, DiffPair).   | functional | [#forwarddifferentiate](../../../design/ir-reference/differentiation.md#forwarddifferentiate)                 | [`forward-differentiate.slang`](forward-differentiate.slang)                                 |
| The unprefixed bwd_diff(f) form also lowers to LegacyBackwardDifferentiate at LOWER-TO-IR, same as \_\_bwd_diff.                                                       | functional | [#legacy-bridge](../../../design/ir-reference/differentiation.md#legacy-bridge)                               | [`bwd-diff-alias.slang`](bwd-diff-alias.slang)                                               |
| \_\_bwd_diff(f) on a [BackwardDifferentiable] function lowers at LOWER-TO-IR to LegacyBackwardDifferentiate(%apply_bwd, %remat, %ctx_t), not to BackwardDifferentiate. | functional | [#legacy-bridge](../../../design/ir-reference/differentiation.md#legacy-bridge)                               | [`legacy-backward-differentiate.slang`](legacy-backward-differentiate.slang)                 |
| DifferentialPair<T>(primal, diff) constructor at a \_\_fwd_diff call site lowers to MakeDiffPair(%primal, %diff).                                                      | functional | [#makediffpair](../../../design/ir-reference/differentiation.md#makediffpair)                                 | [`make-diff-pair.slang`](make-diff-pair.slang)                                               |
| MakeDiffPair produces a value of type DiffPair(T, witness); the witness operand is the IDifferentiable witness for T.                                                  | functional | [#makediffpair](../../../design/ir-reference/differentiation.md#makediffpair)                                 | [`diff-pair-result-type.slang`](diff-pair-result-type.slang)                                 |
| MakeDiffPair works on vector primal/differential types; result type is DiffPair(Vec(...), witness).                                                                    | functional | [#makediffpair](../../../design/ir-reference/differentiation.md#makediffpair)                                 | [`make-diff-pair-vector.slang`](make-diff-pair-vector.slang)                                 |
| A no_diff parameter surfaces as Attributed(T, %no_diff) on the function entry block at LOWER-TO-IR.                                                                    | functional | [#opcodes](../../../design/ir-reference/differentiation.md#opcodes)                                           | [`no-diff-parameter-marker.slang`](no-diff-parameter-marker.slang)                           |
| A single entry point that constructs a DifferentialPair then reads both .p and .d exercises MakeDiffPair, GetPrimal, and GetDifferential in one IR dump.               | functional | [#opcodes](../../../design/ir-reference/differentiation.md#opcodes)                                           | [`make-diff-pair-and-projections.slang`](make-diff-pair-and-projections.slang)               |
| The no_diff parameter marker is implemented by a unique module-scope let %k : Void = no_diff value that all Attributed(T, %k) wrappers reference.                      | functional | [#opcodes](../../../design/ir-reference/differentiation.md#opcodes)                                           | [`no-diff-module-scope-marker.slang`](no-diff-module-scope-marker.slang)                     |

## Untested claims

| Claim                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  | Reason                | Anchor                                                                                                              | Why untested                                                                                                                                                                                                                                              |
|   | --------------------- | ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`checkpointObj`**, **`loopExitValue`**, **`ReportCheckpointStore`** — checkpointing markers inserted by the reverse-mode pass; no natural surface form at LOWER-TO-IR.                                                                                                                                                                                                                                                                                                                                                                                                                                                               | link-stage-only       | [#checkpointobj](../../../design/ir-reference/differentiation.md#checkpointobj)                                     | `(synthesized)` inside the reverse-mode checkpointing pass, later than this bundle's `pipeline_stage`; no user surface produces them at LOWER-TO-IR.                                                                                                      |
| **`LoadReverseGradient`**, **`ReverseGradientDiffPairRef`**, **`PrimalParamRef`**, **`DiffParamRef`** — autodiff temporaries that do not survive past the splitting / back-prop pass.                                                                                                                                                                                                                                                                                                                                                                                                                                                  | link-stage-only       | [#loadreversegradient](../../../design/ir-reference/differentiation.md#loadreversegradient)                         | Placeholders created and consumed inside the reverse-mode splitting passes; they exist only between two internal pass points and never at LOWER-TO-IR.                                                                                                    |
| **`BackwardDifferentiate`** — listed as `(synthesized)`; the doc's Source section says `visitBackwardDifferentiateVal` emits it only when lowering differentiation `Val`s stored in witness tables, while the `__bwd_diff` expression form is resolved before IR lowering (its `visit*` calls `SLANG_UNEXPECTED`) and surfaces as `LegacyBackwardDifferentiate` instead (see `legacy-backward-differentiate.slang`).                                                                                                                                                                                                                    | internal-source-fact  | [#backwarddifferentiate](../../../design/ir-reference/differentiation.md#backwarddifferentiate)                     | The doc names the lowering callback but no user-level construct that stores a differentiation `Val` in a witness table, so an observation test would have to guess its surface. See the `#source` doc-gap row.                                            |
| **`BackwardDifferentiatePrimal`**, **`BackwardDifferentiatePropagate`**, **`BackwardRemat`**, **`TrivialBackwardDifferentiate*`** — `(synthesized)` by the unzip pass.                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | link-stage-only       | [#backwarddifferentiateprimal](../../../design/ir-reference/differentiation.md#backwarddifferentiateprimal)         | Synthesized at a later IR pass than this bundle's `pipeline_stage` observes; the test belongs in the bundle whose pipeline stage matches.                                                                                                                 |
| **`BackwardFromLegacyBwdDiffFunc`** / `BackwardPrimalFromLegacyBwdDiffFunc` / `BackwardRematFromLegacyBwdDiffFunc` / `BackwardPropagateFromLegacyBwdDiffFunc` — `(synthesized)` legacy-bridge extraction opcodes.                                                                                                                                                                                                                                                                                                                                                                                                                      | link-stage-only       | [#backwardfromlegacybwddifffunc](../../../design/ir-reference/differentiation.md#backwardfromlegacybwddifffunc)     | Synthesized at a later IR pass than this bundle's `pipeline_stage` observes; the test belongs in the bundle whose pipeline stage matches.                                                                                                                 |
| **`DiffTypeInfo`** — `(synthesized)` type-info container, internal.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    | link-stage-only       | [#difftypeinfo](../../../design/ir-reference/differentiation.md#difftypeinfo)                                       | Synthesized at a later IR pass than this bundle's `pipeline_stage` observes; the test belongs in the bundle whose pipeline stage matches.                                                                                                                 |
| **`ForwardDifferentiatePropagate`**, **`TrivialForwardDifferentiate`** — `(synthesized)`; produced by the unzip / transcribe pipeline.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 | link-stage-only       | [#forwarddifferentiatepropagate](../../../design/ir-reference/differentiation.md#forwarddifferentiatepropagate)     | Synthesized at a later IR pass than this bundle's `pipeline_stage` observes; the test belongs in the bundle whose pipeline stage matches.                                                                                                                 |
| **`FunctionCopy`**, **`SynthesizedForwardDerivativeWitnessTable`**, **`SynthesizedBackwardDerivativeWitnessTable`**, **`MakeIDifferentiableWitness`**, **`SynthesizedBackwardDerivativeWitnessTableFromLegacyBwdDiffFunc`** — derivative-witness synthesis, internal. (Note: `SynthesizedForwardDerivativeWitnessTable` and `SynthesizedBackwardDerivativeWitnessTable` do happen to appear near the LOWER-TO-IR output for every user `[Forward/Backward Differentiable]` function, but the doc lists them as `(synthesized)` with no AST origin; their presence is a side-effect of the lowering, not a documented surface mapping.) | link-stage-only       | [#functioncopy](../../../design/ir-reference/differentiation.md#functioncopy)                                       | Synthesized at a later IR pass than this bundle's `pipeline_stage` observes; the test belongs in the bundle whose pipeline stage matches.                                                                                                                 |
| **`GetDifferentialPtr`**, **`GetPrimalRef`** — `(synthesized)` pointer-projection counterparts; no natural user surface.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               | link-stage-only       | [#getdifferentialptr](../../../design/ir-reference/differentiation.md#getdifferentialptr)                           | Synthesized at a later IR pass than this bundle's `pipeline_stage` observes; the test belongs in the bundle whose pipeline stage matches.                                                                                                                 |
| The autodiff simplification passes fold a `GetPrimal`/`GetDifferential` applied directly to a `MakeDiffPair` back to the original operand.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | link-stage-only       | [#getdifferential--getprimal](../../../design/ir-reference/differentiation.md#getdifferential--getprimal)           | The fold runs in the autodiff simplification passes, later than the LOWER-TO-IR snapshot this bundle observes; at this stage the unfolded projection is the expected shape (see `make-diff-pair-and-projections.slang`).                                  |
| **`MakeDiffRefPair`** — `(synthesized)`; pointer-typed primal/ differential pair used inside autodiff-pass plumbing.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   | link-stage-only       | [#makediffrefpair](../../../design/ir-reference/differentiation.md#makediffrefpair)                                 | Synthesized at a later IR pass than this bundle's `pipeline_stage` observes; the test belongs in the bundle whose pipeline stage matches.                                                                                                                 |
| **`IdentityRemat`** — `(synthesized)` identity-remat marker for user-provided `__func_extension __apply` when `MinimalContext == BwdCallable`, making the user's apply result the recomputable context.                                                                                                                                                                                                                                                                                                                                                                                                                                | link-stage-only       | [#synthesized-derivative-witnesses](../../../design/ir-reference/differentiation.md#synthesized-derivative-witnesses) | Synthesized by the backward-pass machinery, later than this bundle's `pipeline_stage`; the doc names no LOWER-TO-IR surface for it.                                                                                                                       |
| The reverse-mode primal context is carried by type opcodes (`BackwardDiffIntermediateContextType`, `BackwardDiffMinimalContextType`, and their trivial / legacy variants); no opcode spelled `BackwardDiffPropagateContext` exists — the context plumbing is the result type of `BackwardDifferentiatePropagate`.                                                                                                                                                                                                                                                                                                                      | out-of-bundle         | [#reverse-mode-context](../../../design/ir-reference/differentiation.md#reverse-mode-context)                       | The context claims are about the `TranslatedTypeBase` type family documented in `types.md` and belong to `ir-reference/types`; the no-such-opcode statement is a negative claim with no directive that could observe it.                                  |
| The hoistable `BuiltinRequirementKey` dedupes by construction from its `kind` operand, so one key inst serves the canonical interface constraint, constraints synthesized while building a type's `Differential`, and references across the precompiled-core-module boundary, with no linkage decoration.                                                                                                                                                                                                                                                                                                                              | implementation-detail | [#builtinrequirementkey](../../../design/ir-reference/differentiation.md#builtinrequirementkey)                     | The dump legitimately contains one key per `BuiltinRequirementKind`, and the doc does not document the kind operand's values or dump rendering, so per-kind uniqueness cannot be pinned by FileCheck. Presence is covered by `builtin-requirement-key.slang`. |
| Because a built-in requirement may be reached through dynamic dispatch, the `lookupKey` operand of `GetDispatcher` is typed as a plain `IRInst` rather than `IRStructKey`.                                                                                                                                                                                                                                                                                                                                                                                                                                                             | internal-source-fact  | [#builtinrequirementkey](../../../design/ir-reference/differentiation.md#builtinrequirementkey)                     | An operand-typing fact about the C++ wrapper with no observable consequence in the textual IR dump at this stage.                                                                                                                                         |

## Doc gaps observed

| Anchor                                                                                                            | Kind                  | Gap                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        | Suggested addition                                                                                                                                                                                                                                                |
| ----------------------------------------------------------------------------------------------------------------- | --------------------- |   | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [#built-in-requirement-keys](../../../design/ir-reference/differentiation.md#built-in-requirement-keys)           | missing-example       | The section names the `BuiltinRequirementKey` / `BuiltinRequirementDecoration` opcodes and their lowering origin, but shows neither the `-dump-ir` form of the key definition nor the documented values of the `kind` operand. Tests had to fall back to loose opcode-name substrings and could not pin per-kind deduplication.                                                                                                                                                                                                                             | Add a one-line dump example of a decorated key definition (decoration line plus `let %N : _ = BuiltinRequirementKey(<kind>)`) and enumerate the `BuiltinRequirementKind` operand values so tests can pin one key per kind.                                        |
| [#source](../../../design/ir-reference/differentiation.md#source)                                                 | missing-surface       | The Source section says `visitBackwardDifferentiateVal` emits `BackwardDifferentiate` "when lowering the differentiation `Val`s stored in witness tables", but does not name any user-level construct that places such a `Val` in a witness table, so a test cannot anchor the claim without guessing a surface.                                                                                                                                                                                                                                            | Name one concrete user-level program shape (attribute, conformance, or generic pattern) whose witness table stores a `BackwardDifferentiate` `Val`, or state explicitly that no user surface reaches `visitBackwardDifferentiateVal`.                             |
| [#differential-pair-construction](../../../design/ir-reference/differentiation.md#differential-pair-construction) | undocumented-behavior | The `### Differential-pair construction` and `### Differential-pair projection` tables list every opcode's AST origin as `(synthesized)`, but `MakeDiffPair`, `GetPrimal`, and `GetDifferential` are all routinely produced from user-written surface code (`DifferentialPair<T>(p, d)` constructor calls and `.p`/`.d` field accesses). The AST-origin column should distinguish "synthesized by autodiff passes" from "naturally produced from user surface at LOWER-TO-IR". (See `make-diff-pair.slang`, `get-primal.slang`, `get-differential.slang`.) | Change the AST-origin cells of `MakeDiffPair`, `GetPrimal`, and `GetDifferential` to name the user surface (`DifferentialPair<T>(p, d)` constructor, `.p` / `.d` accesses) alongside the autodiff-pass producers.                                                 |
| [#nodiff](../../../design/ir-reference/differentiation.md#nodiff)                                                 | undocumented-behavior | The doc nowhere documents the **`no_diff`** parameter marker as an IR opcode. At LOWER-TO-IR, `no_diff T x` parameters surface as `param %x : Attributed(T, %no_diff)` where `%no_diff` is a module-scope `let %k : Void = no_diff` IR value. The `no_diff` opcode should appear in the catalog (alongside or in the `Autodiff temporaries` table) with its `Attributed(...)` parameter-wrapper role spelled out. (See `no-diff-parameter-marker.slang`, `no-diff-module-scope-marker.slang`.)                                                             | Add a catalog row for the `no_diff` opcode describing its module-scope `let %k : Void = no_diff` binding and its `Attributed(T, %k)` parameter-wrapper role.                                                                                                      |
| [#forwarddifferentiate](../../../design/ir-reference/differentiation.md#forwarddifferentiate)                     | undocumented-behavior | The `### ForwardDifferentiate` discussion says "Specialization replaces the opcode with the actual JVP function once `baseFn` is fully known" but does not document the LOWER-TO-IR form before specialization (`let %fwd_diff : Func(DiffPair(T, %w), DiffPair(T, %w)) = ForwardDifferentiate(%f)`).                                                                                                                                                                                                                                                      | A one-line example showing the pre-specialization shape would anchor reference tests. (See `forward-differentiate.slang`.)                                                                                                                                        |
| [#detachderivative](../../../design/ir-reference/differentiation.md#detachderivative)                             | undocumented-behavior | The `### detachDerivative` discussion describes the semantic (returns operand unchanged, blocks derivative) but does not show the LOWER-TO-IR form (`let %N : T = detachDerivative(%x)` with operand and result type equal).                                                                                                                                                                                                                                                                                                                               | A one-line example would prevent over-specific pattern construction. (See `detach-derivative.slang`, `detach-derivative-result-type.slang`.)                                                                                                                      |
| [#fwddiff](../../../design/ir-reference/differentiation.md#fwddiff)                                               | undocumented-behavior | The doc does not describe the **`fwd_diff` / `bwd_diff` unprefixed aliases**. The parser accepts both `__fwd_diff(f)` and `fwd_diff(f)` (similarly for `bwd_diff`); both lower identically.                                                                                                                                                                                                                                                                                                                                                                | A note that the unprefixed aliases exist would clarify the surface. (See `fwd-diff-alias.slang`, `bwd-diff-alias.slang`.)                                                                                                                                         |
