ggml-cpu: restore the src1 guard on the F16 Hadamard matmul path - #147
Open
bri-prism wants to merge 1 commit into
Open
ggml-cpu: restore the src1 guard on the F16 Hadamard matmul path#147bri-prism wants to merge 1 commit into
bri-prism wants to merge 1 commit into
Conversation
Two things about the F16 src1 support in forward_mul_mat. The conversion block it lives in runs whenever src1->type != vec_dot_type, and the F16 branch writes plain floats into wdata. That is only valid when the wdata rows are floats. With a quantized src0 the vec_dot_type is Q8_0/Q8_1/Q8_K, whose rows are about one byte per element (34 bytes per 32 for Q8_0), so writing four bytes per element would run roughly 3.8x off the end of the buffer. Nothing reaches that today: supports_op only admits an F16 src1 when src0 and dst are F32, so the scheduler never routes the bad combination to the CPU backend. But the assertion here used to be src1->type == GGML_TYPE_F32, which would have caught it, and widening it to admit F16 unconditionally left the invariant undefended for any caller that reaches forward_mul_mat without consulting supports_op. Assert what the code actually handles instead. Second, the branch hand-rolled a scalar F16 to F32 loop. ggml_cpu_fp16_to_fp32 is declared in ggml-cpu.h and defined further down this same file with F16C and AVX512F paths, so call it. Behaviour-preserving; no speedup measured or claimed, since this path only runs for Hadamard-hinted F32 matmuls. test-backend-ops on CPU: MUL_MAT 1249/1249, MUL_MAT_HADAMARD 18/18 including the four f16 src1 cases and the f16 FWHT case. Note the suite would not have caught the widened assert: no case drives a quantized src0 with an F16 src1, because supports_op refuses it and the harness skips it as unsupported.
There was a problem hiding this comment.
🟢 Approval recommended
The functional changes are sound; only a non-blocking comment-format issue remains.
Pull request overview
Restores safety checks and uses the existing optimized F16 conversion routine in CPU Hadamard matmul.
Changes:
- Restricts F16
src1conversion to F32 workspace rows. - Replaces scalar conversion with
ggml_cpu_fp16_to_fp32.
File summaries
| File | Description |
|---|---|
ggml/src/ggml-cpu/ggml-cpu.c |
Adds the guard, converter call, and required header. |
Review details
- Files reviewed: 1/1 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+1338
to
+1340
| // an F16 src1 is converted straight to float below, so it is only valid when the | ||
| // wdata rows are floats. A quantized vec_dot_type would size them at about one | ||
| // byte per element and the conversion would run off the end of the buffer. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two follow-ups to the F16
src1support on the Hadamard-hinted matmul path inggml_compute_forward_mul_mat. One restores an assertion, one replaces a hand-rolled loop withthe vectorised routine that already exists for it.
Why
The assertion. The conversion block the F16 branch lives in is entered whenever
src1->type != vec_dot_type, and that branch writes plain floats intowdata. That is onlyvalid when the
wdatarows are floats. With a quantizedsrc0thevec_dot_typeisQ8_0/Q8_1/Q8_K, whose rows are about one byte per element (34 bytes per 32 for Q8_0), so writing
four bytes per element would run roughly 3.8x past the end of the buffer.
Nothing reaches that today.
supports_opadmits an F16src1only whensrc0anddstareboth F32, so the scheduler never routes the bad combination to the CPU backend. The point is
narrower: the assertion here used to be
src1->type == GGML_TYPE_F32and would have caught it,and widening it to admit F16 unconditionally left the invariant undefended for any caller that
reaches
forward_mul_matwithout going throughsupports_op. This asserts what the codeactually handles.
The loop.
ggml_cpu_fp16_to_fp32is declared inggml-cpu.hand defined further down thissame file with F16C and AVX512F paths, so the branch can call it instead of converting element by
element. That needs the header included, since the definition sits below the call site.
Testing
test-backend-opson CPU:MUL_MAT1249/1249MUL_MAT_HADAMARD18/18, including the fourtype_b=f16cases and thetype_x=f16FWHT caseWorth stating plainly: the suite passes identically before and after, which is the expected
result. The converter swap is behaviour-preserving, and the assertion defends a path no test
drives, because
supports_oprefuses a quantizedsrc0with an F16src1and the harness skipsit as unsupported. So these tests show nothing is broken; they would not have caught the widened
assertion in the first place. Testing that invariant properly needs a direct call into
forward_mul_matoutside the scheduler, which is a larger change than this.No performance claim. The F16 branch only runs for Hadamard-hinted F32 matmuls, so it is off the
hot path for ordinary decode, and I did not measure it.
Notes
clang-formatis not applied. Adding an include makes it alphabetize and reflow the whole includeblock, which this file's order does not follow, so the formatting change would be larger and less
reviewable than the fix. The new include is grouped with the other
ggml-cpuheaders.The same two issues exist in the corresponding upstream PR, ggml-org#27779, which is
still open. If that lands as-is, upstream inherits both.