Skip to content

AI: [G3] dequantize_per_tensor asym SIMD: integer zero-point subtract (#20703)#20703

Merged
zonglinpeng merged 4 commits into
pytorch:mainfrom
zonglinpeng:export-D110529287
Jul 20, 2026
Merged

AI: [G3] dequantize_per_tensor asym SIMD: integer zero-point subtract (#20703)#20703
zonglinpeng merged 4 commits into
pytorch:mainfrom
zonglinpeng:export-D110529287

Conversation

@zonglinpeng

@zonglinpeng zonglinpeng commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

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

@pytorch-bot

pytorch-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown

🔗 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.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 2, 2026
@meta-codesync

meta-codesync Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

@zonglinpeng has exported this pull request. If you are a Meta employee, you can view the originating Diff in D110529287.

@zonglinpeng zonglinpeng added the release notes: cadence Changes to the Cadence backend delegate label Jul 6, 2026
@meta-codesync meta-codesync Bot changed the title AI: [G3] dequantize_per_tensor asym SIMD: integer zero-point subtract AI: [G3] dequantize_per_tensor asym SIMD: integer zero-point subtract (#20703) Jul 6, 2026
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
…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
# Conflicts:
#	backends/cadence/fusion_g3/operators/op_dequantize.cpp
@linux-foundation-easycla

linux-foundation-easycla Bot commented Jul 20, 2026

Copy link
Copy Markdown

CLA Missing ID

  • ✅ login: zonglinpeng / name: JP (dc93720)
  • ✅ login: zonglinpeng / name: Zonglin Peng (9223ce5, a1acc90)
  • ❌ The email address for the commit (1d4b9ab) is not linked to the GitHub account, preventing the EasyCLA check. Consult this Help Article and GitHub Help to resolve. (To view the commit's email address, add .patch at the end of this PR page's URL.) For further assistance with EasyCLA, please visit our EasyCLA portal and chat with our support bot.

@zonglinpeng
zonglinpeng merged commit 2c90c5e into pytorch:main Jul 20, 2026
171 of 174 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. meta-exported release notes: cadence Changes to the Cadence backend delegate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants