Skip to content

Specialize std::numeric_limits for dace::half and dace::bfloat16 - #2485

Open
ThrudPrimrose wants to merge 1 commit into
mainfrom
numeric-limits-fp16-bf16
Open

Specialize std::numeric_limits for dace::half and dace::bfloat16#2485
ThrudPrimrose wants to merge 1 commit into
mainfrom
numeric-limits-fp16-bf16

Conversation

@ThrudPrimrose

Copy link
Copy Markdown
Collaborator

The primary std::numeric_limits template answers max() == lowest() == infinity() == T() for any unspecialized class type, i.e. zero for dace::half and dace::bfloat16. Code that seeds a min/max reduction or scan identity from std::numeric_limits<T> therefore still compiles and silently produces zeros -- dace/libraries/torch/dispatchers/cpp_torch_extension.py emits exactly std::numeric_limits<{dtype.ctype}>::infinity() for that purpose. We hit this as a min-scan over fp16 returning all zeros.

This adds <limits> plus the std::numeric_limits specializations for the two 16-bit low-precision structs, with static_asserts pinning max() and denorm_min() to the IEEE binary16 / bfloat16 bit patterns so a typo in a literal cannot pass as a plausible-looking value. The block is excluded under __CUDACC__/__HIPCC__, where dace::half/dace::bfloat16 are the vendor native types instead. The fp8 structs in the same header are left alone here to keep the diff minimal.

tests/codegen/lowp_numeric_limits_test.py compiles and runs a probe against dace/runtime/include; every check compares against a value the primary template cannot produce, so the probe exits 1 on main and 0 with this change. The new header code is warning-free under g++ and clang++ at -Wall -Wextra -Wpedantic -Werror.

🤖 Generated with Claude Code

The primary std::numeric_limits template answers max() == lowest() ==
infinity() == T() -- zero -- for unspecialized class types, so code that
seeds a min/max reduction identity from it silently produces zeros
instead of failing to compile. Add the binary16 and bfloat16
specializations to the CPU low-precision structs, with static_asserts
pinning the max() and denorm_min() bit patterns.
@ThrudPrimrose
ThrudPrimrose marked this pull request as ready for review August 10, 2026 09:32

@tbennun tbennun left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I like it but needs (1) to look at the nit; (2) end-to-end regression test that caused this PR to exist.

Comment on lines +349 to +352
DACE_LP_LIMITS(half, 11, 3, 5, -13, -4, 16, 4, true, 6.5504e+4f, 6.103515625e-05f, 9.765625e-04f,
5.9604644775390625e-08f);
DACE_LP_LIMITS(bfloat16, 8, 2, 4, -125, -37, 128, 38, false, 3.38953139e+38f, 1.17549435e-38f, 7.8125e-03f,
9.18354962e-41f);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

why add the f suffix when these are cast to the data type anyway?

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.

2 participants