[Fix] Restore the fx.maxnumf contract, and keep ninf off the score reductions - #1050
[Fix] Restore the fx.maxnumf contract, and keep ninf off the score reductions#1050JohnQinAMD wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Restores fx.maxnumf’s stable return-type/shape contract and updates attention score-reduction call sites to use a fastmath flag that preserves -inf mask semantics (i.e., keep ninf off score reductions while still allowing nnan-driven lowering).
Changes:
- Re-introduce a hand-wrapped
fx.maxnumfimplementation so it returns the DSL type/shape of operanda(including logical vector shape and generic vector dtype). - Introduce
_MAX_FASTMATH = FastMathFlags.nnanfor attention score reductions and thread it through allfx.maxnumfreduction sites (and SWA gfx950) to avoidninfpoisoning with-infsentinels. - Add regression tests covering the
fx.maxnumfcontract and guarding that score-reduction fastmath excludesninf.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
tests/unit/test_fastmath_context.py |
Adds contract + fastmath-flag regression tests for fx.maxnumf. |
tests/kernels/test_flash_attn_fwd.py |
Adds a guard asserting score-reduction fastmath includes nnan but excludes ninf, and that no bare fx.maxnumf remains in flash_attn_utils.py. |
python/flydsl/expr/arith.py |
Re-wraps maxnumf to preserve the stable return-type/shape contract and resolve ambient fastmath explicitly. |
kernels/attention/swa_gfx950.py |
Switches SWA masking max to use _MAX_FASTMATH (nnan-only) instead of inheriting ambient flags (which may include ninf). |
kernels/attention/flash_attn_utils.py |
Defines _MAX_FASTMATH and applies it to all score-reduction fx.maxnumf sites to prevent ninf interaction with -inf masks. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
Merge-order note: this PR's guard asserts no bare Either PR is fine on its own; whichever merges second needs that one call to carry |
The ambient is fast, which includes ninf, and a fully masked row carries -inf into this max -- the same invariant pa_decode_tile.py records and #1050 applies to the other reductions in this file. Explicit here is not the ambient being re-plumbed by hand; it is the ambient deliberately not being used.
…ductions Two follow-ups to #1035. fx.maxnumf is in the stable catalog and returns the DSL type of a, but the bare dsl_math_wrap_result it moved to does not: a keyword binding came back as a raw ArithValue, a logical (2, 2) came back flat, and a generic vector dtype came back concrete. Hand-wrap it again and resolve the ambient inside, which is exact parity plus the flag. Tests cover keyword scalars, keyword vectors and generic vector dtype; they fail on main. The 16 maxnumf sites in flash_attn_utils.py were inheriting the ambient fast, which carries ninf, while _score_pair_max is seeded with literal -inf and masked scores are -inf too -- an infinite operand under ninf is poison. Pass nnan explicitly instead, the same flag and the same reasoning pa_decode_tile.py already records. swa_gfx950.py masks with -inf as well and now uses it rather than the ambient it was reaching for. nnan is where the speed was: 1213.5 / 1207.2 TFLOP/s against main's 1210.3 / 1208.3 at S=61,380 / 180,180, two rounds, so #1035's recovery is unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
235ef04 to
ca9b848
Compare
Follow-ups to #1035, both from @jhinpan's post-merge review.
1.
fx.maxnumfresult contractfx.maxnumfis in the stable catalog and documented to return the DSL type ofa. The bare@dsl_math_wrap_resultit moved to does not do that:maxnumf(a=x, b=x),Float32Float32ArithValueVectorshape(2, 2)(2, 2)(4,)Vector(..., dtype=Float)FloatFloat32exemplar="a"fixes the first two but not the third, andpreserve_numeric_type=Truechanges generic-scalar behaviour, so this hand-wraps it again and resolves the ambient inside — exact parity plus the flag. Three regressions added for keyword scalar, keyword vector and generic vector dtype; they fail on main.2.
ninfon the score reductionsThe 16
maxnumfsites inflash_attn_utils.pyinherit the ambientfast, which carriesninf. But_score_pair_maxis seeded with literal-infand masked scores are-inf, and an infinite operand underninfis poison.pa_decode_tile.pyalready records the invariant:So they carry
nnanexplicitly now.swa_gfx950.pymasks with-inftoo and was reaching for the ambient through acurrent_fastmath()workaround whose comment no longer held; it uses the same flag.The speed was in
nnan. Two rounds, cache cold, B=2 H=32 D=128 bf16:fast)nnan)Within noise, so #1035's recovery is untouched.
Testing
test_fastmath_context.py— 25 passed, no GPU. Includes an IR guard that the reduction flag emitsfastmath<nnan>with noninf.test_flash_attn_fwd.py— 94 passed. Includes a check that the flag excludesninfand that no barefx.maxnumfis left in that module.test_swa_gfx950.py— 5 passed.Breaking Changes
None. The contract change restores the pre-#1035 behaviour.