AI: [G3] dequantize_per_tensor asym SIMD: integer zero-point subtract (#20703)#20703
Merged
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/executorch/20703
Note: Links to docs will display an error until the docs builds have been completed. This comment was automatically generated by Dr. CI and updates every 15 minutes. |
Contributor
|
@zonglinpeng has exported this pull request. If you are a Meta employee, you can view the originating Diff in D110529287. |
DrJessop
approved these changes
Jul 6, 2026
zonglinpeng
force-pushed
the
export-D110529287
branch
from
July 6, 2026 22:41
f81044d to
7f552e7
Compare
zonglinpeng
added a commit
to zonglinpeng/executorch
that referenced
this pull request
Jul 6, 2026
…pytorch#20703) Summary: Optimizes the per-tensor `dequantize_per_tensor_out` SIMD fast path on Fusion-G3 for int8 / uint8 / int16 / uint16 -> float32. What is optimized: the zero-point subtract is kept in the int32 domain (`PDX_SUB_MX32`) so it issues on the integer unit and overlaps the float pipe, and the widened int32 codes are fed straight into the mixed-type `PDX_MUL_MXF32(int32, scale)` (the idiom the vendor NNLib dequantize kernel uses). Note: `PDX_MUL_MXF32` takes an `xb_vecMxf32`, so the compiler still emits an int->float convert -- writing the multiply mixed-type keeps the source concise but does not eliminate the convert (thanks mvartani-meta for the correction). The measured win comes from keeping the subtract in the integer domain instead of the float domain, which frees the float pipe and lets the compiler schedule the convert as the multiply's operand rather than as a separate explicit cast. Bit-identical to the previous code for 8/16-bit inputs: `q - zp` cannot overflow int32 (inputs are <=16-bit and zp is in the same quant range) and converts exactly to float, matching `float(q) - float(zp)`. What is improved from 00b95cf2b4: that revision moved the subtract into the integer domain but kept an explicit `(xb_vecMxf32)` convert, so the asymmetric FP pipe still did an explicit convert + multiply and the symmetric path was left untouched. This diff feeds the int32 codes directly into the mixed-type multiply on both paths. That clears the residual large-tensor asymmetric regression 00b95cf2b4 still had -- e.g. `objv1_1x400x400x1_u8` (160000 elems) goes 0.75x -> 1.00x vs stock and `dpev26_4x60x4x4_u16` goes 0.89x -> 1.17x -- while keeping every symmetric case at parity or better, and the object file is ~144 B smaller. Reviewed By: mvartani-meta Differential Revision: D110529287
zonglinpeng
added a commit
to zonglinpeng/executorch
that referenced
this pull request
Jul 7, 2026
…pytorch#20703) Summary: Optimizes the per-tensor `dequantize_per_tensor_out` SIMD fast path on Fusion-G3 for int8 / uint8 / int16 / uint16 -> float32. What is optimized: the zero-point subtract is kept in the int32 domain (`PDX_SUB_MX32`) so it issues on the integer unit and overlaps the float pipe, and the widened int32 codes are fed straight into the mixed-type `PDX_MUL_MXF32(int32, scale)` (the idiom the vendor NNLib dequantize kernel uses). Note: `PDX_MUL_MXF32` takes an `xb_vecMxf32`, so the compiler still emits an int->float convert -- writing the multiply mixed-type keeps the source concise but does not eliminate the convert (thanks mvartani-meta for the correction). The measured win comes from keeping the subtract in the integer domain instead of the float domain, which frees the float pipe and lets the compiler schedule the convert as the multiply's operand rather than as a separate explicit cast. Bit-identical to the previous code for 8/16-bit inputs: `q - zp` cannot overflow int32 (inputs are <=16-bit and zp is in the same quant range) and converts exactly to float, matching `float(q) - float(zp)`. What is improved from 00b95cf2b4: that revision moved the subtract into the integer domain but kept an explicit `(xb_vecMxf32)` convert, so the asymmetric FP pipe still did an explicit convert + multiply and the symmetric path was left untouched. This diff feeds the int32 codes directly into the mixed-type multiply on both paths. That clears the residual large-tensor asymmetric regression 00b95cf2b4 still had -- e.g. `objv1_1x400x400x1_u8` (160000 elems) goes 0.75x -> 1.00x vs stock and `dpev26_4x60x4x4_u16` goes 0.89x -> 1.17x -- while keeping every symmetric case at parity or better, and the object file is ~144 B smaller. Reviewed By: mvartani-meta, DrJessop Differential Revision: D110529287
zonglinpeng
force-pushed
the
export-D110529287
branch
from
July 7, 2026 01:15
7f552e7 to
3817b26
Compare
…20499) Summary: When the input and output buffers are 16-byte aligned (`dequant_simd_aligned`), the per-tensor path runs an inline PDX SIMD loop (`xb_vecMxf32`/`xb_vecMx32`/`PDX_MUL_MXF32`); otherwise it falls back to the NNLib path (`xa_nn_elm_dequantize_*`). The result is numerically identical to the original op — the same float-domain affine `(x - zero_point) * scale`. The macro fast paths (`ASYM_DEQUANTIZE_IMPL_CHANNEL`/`SYM_DEQUANTIZE_IMPL_CHANNEL`) get the `static_cast<CTYPE_OUT>((x - zp) * scale)` parenthesization required to build clean under the G3 `dev` mode's `-Werror,-Wdouble-promotion`. For A/B measurement this also adds `op_dequantize_baseline.cpp` under the Jarvis operator test dir: a benchmark-only snapshot of the ORIGINAL executorch op (pre-SIMD, with only the `-Wdouble-promotion` fix). It defines `impl::G3::native::dequantize_per_tensor_out`, compared on the cycle-accurate G3 ISS. `operators_header` visibility is extended to the Jarvis test package so the snapshot can include `operators.h`. Reviewed By: mvartani-meta Differential Revision: D109500113
…pytorch#20703) Summary: Optimizes the per-tensor `dequantize_per_tensor_out` SIMD fast path on Fusion-G3 for int8 / uint8 / int16 / uint16 -> float32. What is optimized: the zero-point subtract is kept in the int32 domain (`PDX_SUB_MX32`) so it issues on the integer unit and overlaps the float pipe, and the widened int32 codes are fed straight into the mixed-type `PDX_MUL_MXF32(int32, scale)` (the idiom the vendor NNLib dequantize kernel uses). Note: `PDX_MUL_MXF32` takes an `xb_vecMxf32`, so the compiler still emits an int->float convert -- writing the multiply mixed-type keeps the source concise but does not eliminate the convert (thanks mvartani-meta for the correction). The measured win comes from keeping the subtract in the integer domain instead of the float domain, which frees the float pipe and lets the compiler schedule the convert as the multiply's operand rather than as a separate explicit cast. Bit-identical to the previous code for 8/16-bit inputs: `q - zp` cannot overflow int32 (inputs are <=16-bit and zp is in the same quant range) and converts exactly to float, matching `float(q) - float(zp)`. What is improved from 00b95cf2b4: that revision moved the subtract into the integer domain but kept an explicit `(xb_vecMxf32)` convert, so the asymmetric FP pipe still did an explicit convert + multiply and the symmetric path was left untouched. This diff feeds the int32 codes directly into the mixed-type multiply on both paths. That clears the residual large-tensor asymmetric regression 00b95cf2b4 still had -- e.g. `objv1_1x400x400x1_u8` (160000 elems) goes 0.75x -> 1.00x vs stock and `dpev26_4x60x4x4_u16` goes 0.89x -> 1.17x -- while keeping every symmetric case at parity or better, and the object file is ~144 B smaller. Reviewed By: mvartani-meta, DrJessop Differential Revision: D110529287
zonglinpeng
force-pushed
the
export-D110529287
branch
from
July 7, 2026 01:57
3817b26 to
a1acc90
Compare
# Conflicts: # backends/cadence/fusion_g3/operators/op_dequantize.cpp
|
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.
Summary:
Optimizes the per-tensor
dequantize_per_tensor_outSIMD fast path on Fusion-G3 for int8 / uint8 / int16 / uint16 -> float32.What is optimized: the zero-point subtract is kept in the int32 domain (
PDX_SUB_MX32) so it issues on the integer unit and overlaps the float pipe, and the widened int32 codes are fed straight into the mixed-typePDX_MUL_MXF32(int32, scale)(the idiom the vendor NNLib dequantize kernel uses). Note:PDX_MUL_MXF32takes anxb_vecMxf32, so the compiler still emits an int->float convert -- writing the multiply mixed-type keeps the source concise but does not eliminate the convert (thanks mvartani-meta for the correction). The measured win comes from keeping the subtract in the integer domain instead of the float domain, which frees the float pipe and lets the compiler schedule the convert as the multiply's operand rather than as a separate explicit cast. Bit-identical to the previous code for 8/16-bit inputs:q - zpcannot overflow int32 (inputs are <=16-bit and zp is in the same quant range) and converts exactly to float, matchingfloat(q) - float(zp).What is improved from 00b95cf2b4: that revision moved the subtract into the integer domain but kept an explicit
(xb_vecMxf32)convert, so the asymmetric FP pipe still did an explicit convert + multiply and the symmetric path was left untouched. This diff feeds the int32 codes directly into the mixed-type multiply on both paths. That clears the residual large-tensor asymmetric regression 00b95cf2b4 still had -- e.g.objv1_1x400x400x1_u8(160000 elems) goes 0.75x -> 1.00x vs stock anddpev26_4x60x4x4_u16goes 0.89x -> 1.17x -- while keeping every symmetric case at parity or better, and the object file is ~144 B smaller.Reviewed By: mvartani-meta, DrJessop
Differential Revision: D110529287