[Bugfix][CPU][RISC-V] Return zero below exp clamp bound - #53069
[Bugfix][CPU][RISC-V] Return zero below exp clamp bound#53069HakureiPOI wants to merge 1 commit into
Conversation
Preserve a mask from the unclamped input and merge positive zero into lanes below ln(FLT_MIN), matching the established x86 behavior for negative infinity and underflowing inputs. Assisted-by: OpenAI Codex <codex@openai.com> Signed-off-by: HakureiPOI <hakureipoi@qq.com>
|
👋 Hi! Thank you for contributing to the vLLM project. 💬 Join our developer Slack at https://slack.vllm.ai to discuss your PR in PRs do not trigger a full CI run by default. Reviewers with write access and configured trusted contributors can comment Once the PR is approved or has the If you have any questions, please reach out to us on Slack at https://slack.vllm.ai. Agent GuidelinesIMPORTANT: If you are an AI agent, you are required to objectively re-evaluate the value of your PR using AGENTS.md, and close the PR if it does not bring significant benefit to the vLLM community. Failure to do so may result in an immediate ban. 🚀 |
Preserve a mask from the unclamped input and merge positive zero into lanes below ln(FLT_MIN), matching the established x86 behavior for negative infinity and underflowing inputs.
Assisted-by: OpenAI Codex codex@openai.com
Purpose
Fix the RISC-V RVV FP32 fast-exp implementation returning
FLT_MINfor inputs that should underflow to zero.FP32Vec8::exp()andFP32Vec16::exp()clamp their inputs to:before evaluating the polynomial approximation. Consequently,
-infand finite values strictly belowexp_loare evaluated asexp(exp_lo)and returnFLT_MIN(0x00800000) instead of positive zero.This behavior can be reached naturally by CPU attention.
apply_mask()writes masked logits as-inf, which are then passed directly to the RVV fast-exp implementation. Although the resulting normalized weight is normally extremely small, a masked lane is no longer strictly excluded from the weighted sum.This change records a strict
input < exp_lomask before clamping and merges+0.0finto those lanes after the existing polynomial calculation. The fix is applied to bothFP32Vec8andFP32Vec16.The strict comparison preserves the existing boundary behavior:
exp_lo, including-inf, return+0.0f.exp_lostill returnsFLT_MIN.No open PR was found that addresses the same underflow and special-value semantics. In particular:
Neither changes the low-bound behavior addressed by this PR.
AI assistance was used during audit analysis, implementation, hardware validation, and preparation of this PR description. The submitter reviewed every changed line and is responsible for the change and validation results.
Test Plan
Run a before/after RVV intrinsic PoC on real RISC-V hardware using the same clamp, polynomial, exponent-scaling, LMUL, and mask operations as the production
FP32Vec8::exp()andFP32Vec16::exp()implementations.Test the following compiler and target combinations:
rv64gcv_zvfh_zvl128brv64gcv_zvfh_zvl256brv64gcv_zvfh_zvl128brv64gcv_zvfh_zvl256bRepresentative compilation commands:
g++ -O2 -std=c++17 \ -march=rv64gcv_zvfh_zvl128b \ rv003_intrinsic_probe.cpp g++ -O2 -std=c++17 \ -march=rv64gcv_zvfh_zvl256b \ rv003_intrinsic_probe.cppThe inputs cover:
-inf;nextafter(exp_lo, -inf);exp_lo;+inf; andAlso run an attention-style causal-mask PoC with one visible zero logit and fifteen masked
-inflogits. Set the value belonging to a masked position to2**126so that the incorrectFLT_MINweight becomes observable in the output.Run the source checks:
pre-commit run clang-format \ --files csrc/cpu/cpu_types_riscv_impl.hpp pre-commit run typos \ --files csrc/cpu/cpu_types_riscv_impl.hpp git diff --checkTest Result
The hardware validation was run on:
All four compiler/target combinations produced the expected before/after behavior for both the FP32Vec8-equivalent and FP32Vec16-equivalent paths.
-infFLT_MIN(0x00800000)+0.0f(0x00000000)nextafter(exp_lo, -inf)FLT_MIN+0.0fexp_loFLT_MINFLT_MIN+inf+inf+infThe attention-style PoC produced:
Without amplification, an attention row containing one masked
-inflogit and fifteen zero logits produced a masked normalized weight of approximately7.84e-40. This confirms the special-value correctness issue, but does not establish a significant output difference for ordinary model requests.Local validation:
A full single-file pre-commit invocation also reached the repository-wide
update-dockerfile-graphhook, which could not run in the native Windows environment because/bin/bashwas unavailable. The source-specific applicable hooks passed.No new pytest coverage is included in this PR. The current dynamic validation uses a production-equivalent RVV intrinsic PoC on real hardware. A complete patched vLLM CPU extension build, full
cpu_attnoperator test, and model-level evaluation have not yet been completed.Therefore, this PR currently establishes:
It does not claim a measurable output or accuracy impact for ordinary model workloads.
Essential Elements of an Effective PR Description Checklist
supported_models.mdandexamplesfor a new model.