TQUANT

Instruction Diagram

Introduction

Quantizes a high-precision tile (FP32/BF16/FP16) into a low-precision format, and generates the quantized data tile together with the auxiliary per-group exponent/maximum/scaling tile. The target format, scaling algorithm, and grouping axis are all compile-time template parameters.

Target Format FamilyFormatGrouping MethodScaling Algorithm
Microscaling (MX)MXFP8 (e4m3), MXFP4 (e2m1)Every 32 elements share one exponentOCP, NV
IntegerINT8 (symmetric/asymmetric)One scale per tile (+ optional offset)Affine

Quantization Flow

MX Format (3 Stages, Group Size G = 32)

For a tile x∈RM×Nx \in \mathbb{R}^{M \times N}, group along grp_axis (ND: axis-1/columns; DN: axis-0/rows):

StageOperationOutput
1. Intra-group maximum valuemg=max⁡i∈g∣xi∣m_g = \max_{i \in g} |x_i|max (scratch, FP)
2. Exponent + scalingsg=biasedExp(mg)−emax⁡s_g = \mathrm{biasedExp}(m_g) - e_{\max}; αg=2254−sg\alpha_g = 2^{254 - s_g}exp (E8M0, 1 byte per group), scaling (scratch, FP)
3. Scaling + type conversionqi=clip[−Vmax⁡,Vmax⁡](xi⋅αg)→q_i = \mathrm{clip}_{[-V_{\max},V_{\max}]}(x_i \cdot \alpha_g) \to target formatdst (FP8/packed FP4)
  • emax⁡e_{\max} = maximum exponent of the target format (8 for e4m3, 1 for e2m1).
  • Vmax⁡V_{\max} = MAX_NORM of the target format (448 for e4m3, 6 for e2m1).
  • Stages 1–2 use exact IEEE-754 bit operations (no FP log/floor); stage 3 uses hardware type conversion + stochastic rounding (SPR.CTRL[50]=1).
  • ND ("normal direction", grp_axis=1): every 32 consecutive columns form a group — the default/standard grouping method. DN (grp_axis=0): every 32 consecutive rows form a group — transposed axis-0 grouping; the exponent tile shape is M̂×N, with M̂ = M/32.

Integer INT8 (Affine, 5-Stage Type Conversion)

qi=round ⁣(xiscale)+offset,qi∈[−128,127]q_i = \mathrm{round}\!\left(\frac{x_i}{\mathrm{scale}}\right) + \mathrm{offset}, \qquad q_i \in [-128, 127]

No grouping structure; scale (and the asymmetric offset) is an FP32 scalar/vector per tile. To avoid double rounding, the type conversion chain on Atlas A2/A3 training products/Atlas A2/A3 inference products is FP32 → S32 → FP32 → FP16 → INT8 (5 stages, via the tmp tile); Ascend 950PR/Ascend 950DT uses native broadcast + type conversion (no tmp required). The input must be FP32.

C++ Built-in APIs

Declared in include/pto/common/pto_instr.hpp.

The public include header is <pto/pto-inst.hpp>, and the internal declaration is located in pto/common/pto_instr.hpp.

template <int grp_axis, auto mx_alg, typename TileDataOut, typename TileDataSrc,
          typename TileDataExp, typename TileDataMax, typename TileDataScaling, typename... WaitEvents>
PTO_INST RecordEvent TQUANT(TileDataOut &dst, TileDataSrc &src, TileDataExp *exp, TileDataMax *max,
                            TileDataScaling *scaling, WaitEvents &...events);
Template ParameterValueMeaning
grp_axis0 = DN (axis-0 grouping), 1 = ND (axis-1 grouping)Quantization grouping axis
mx_algMxQuantAlg::OcpMxFp8E4M3, NvMxFp8E4M3, OcpMxFp4E2M1, NvMxFp4E2M1Format + scaling algorithm

MX — ND Legacy (QuantType + QuantScaleAlg)

template <auto quant_type, typename ...Tiles, auto scale_alg = QuantScaleAlg::OCP, typename... WaitEvents>
PTO_INST RecordEvent TQUANT(TileDataOut &dst, TileDataSrc &src, TileDataExp *exp, TileDataMax *max,
                            TileDataScaling *scaling, WaitEvents &...events);

// With explicit ZZ exponent storage mode.
template <auto quant_type, auto store_mode, typename ...Tiles, typename... WaitEvents>
PTO_INST RecordEvent TQUANT(TileDataOut &dst, TileDataSrc &src, TileDataExp *exp, TileDataMax *max,
                            TileDataScaling *scaling, TileDataExp *exp_zz, WaitEvents &...events);
quant_typeFormatscale_alg
QuantType::MXFP8e4m3 + E8M0OCP / NV
QuantType::MXFP4_E2M1e2m1 + E8M0OCP / NV

Integer INT8

// Symmetric.
template <auto quant_type, typename TileDataOut, typename TileDataSrc, typename TileDataPara, typename... WaitEvents>
PTO_INST RecordEvent TQUANT(TileDataOut &dst, TileDataSrc &src, TileDataPara &scale,
                            TileDataPara *offset = nullptr, WaitEvents &...events);
// With scratch (A2/A3).
template <auto quant_type, typename ...Tiles, typename TileDataTmp, typename... WaitEvents>
PTO_INST RecordEvent TQUANT(TileDataOut &dst, TileDataSrc &src, TileDataPara &scale, TileDataTmp &tmp,
                            TileDataPara *offset = nullptr, WaitEvents &...events);
quant_typeoffsetdst dtypeMode
QuantType::INT8_SYMnullptrint8_tSymmetric (q=round(x/scale)q = \mathrm{round}(x/\mathrm{scale}))
QuantType::INT8_ASYMProvideduint8_tAsymmetric (q=round(x/scale)+offsetq = \mathrm{round}(x/\mathrm{scale}) + \mathrm{offset})

The overload with tmp (dst, src, scale, tmp, offset) is used for API alignment with Atlas A2/A3 training products/Atlas A2/A3 inference products. Ascend 950PR/Ascend 950DT does not use tmp; on Atlas A2/A3 training products/Atlas A2/A3 inference products, tmp must be an M×NM \times N FP32 (S32 type conversion intermediate result).

Tile Size and Data Types

For an input tile shape M×NM \times N (dtype T∈{FP32,BF16,FP16}T \in \{\mathrm{FP32}, \mathrm{BF16}, \mathrm{FP16}\}), the group size G=32G = 32:

MXFP8 (e4m3)

TiledtypeShape (ND)Shape (DN)Byte Count
srcTTM×NM \times NM×NM \times NM⋅N⋅sizeof(T)M \cdot N \cdot \mathrm{sizeof}(T)
dstint8_t (e4m3 alias)M×NM \times NM×NM \times NM⋅NM \cdot N
expuint8_t (E8M0)M×N/32M \times N/32M/32×NM/32 \times NM⋅N/32M \cdot N / 32
max (scratch)TTM×N/32M \times N/32M/32×NM/32 \times NM⋅N/32⋅sizeof(T)M \cdot N / 32 \cdot \mathrm{sizeof}(T)
scaling (scratch)TTM×N/32M \times N/32M/32×NM/32 \times NM⋅N/32⋅sizeof(T)M \cdot N / 32 \cdot \mathrm{sizeof}(T)

MXFP4 (e2m1)

Same as MXFP8, but:

TiledtypeByte Count
dstfloat4_e2m1x2_t (packs 2 e2m1 per byte)M⋅N/2M \cdot N / 2

Input restriction: MXFP4 accepts only FP16/BF16 (does not support FP32).

INT8

TiledtypeShapeByte Count
srcfloat32_tM×NM \times NM⋅N⋅4M \cdot N \cdot 4
dst (SYM)int8_tM×NM \times NM⋅NM \cdot N
dst (ASYM)uint8_tM×NM \times NM⋅NM \cdot N
scaleFP32 scalar/vectorPer tile-
offset (ASYM)FP32 scalar/vectorPer tile-
tmp (Atlas A2/A3 training products/Atlas A2/A3 inference products only)FP32M×NM \times NM⋅N⋅4M \cdot N \cdot 4

tmp tile (Atlas A2/A3 training products/Atlas A2/A3 inference products only): Must be the same size as src (M×NM \times N FP32 = 4MN4MN bytes), and stores the FP32→S32 type conversion intermediate result (Atlas A3 training products/Atlas A3 inference products have no in-place tcvt). Ascend 950PR/Ascend 950DT accept the same-named tmp parameter to keep the API consistent, but do not use it (Ascend 950PR/Ascend 950DT use native vlds BRC_B32 broadcast).

Constraints

ConstraintApplicable ScopeReason
M mod 16=0M \bmod 16 = 0ND MX (ZZ layout)16-row ZZ block
M mod 32=0M \bmod 32 = 0DN MXaxis-0 group divisibility
M mod 64=0M \bmod 64 = 0DN MX + ZZ conversionδ pairing (M^/2\hat M / 2 is an integer)
N mod 32=0N \bmod 32 = 0All MXgroup size G=32G = 32
N mod 64=0N \bmod 64 = 0ND MX + ZZ conversioneven number of exponent groups
M⋅N≤59461M \cdot N \le 59461MX (UB 256KB)buffer budget after reuse
BF16/FP16: validCols % 32 != 0 → zero-padded to StaticColsMX B16 pathgroup alignment

Output Layout and Layout Conversion

TQUANT outputs ND (row-major) by default. The Cube Unit consumes two fractal layouts, which are generated by separate TMOV instructions:

OutputNative (TQUANT)Cube LayoutConversion
FP8/FP4 dataNDNZ (ColMajor+RowMajor fractal)TMOV(dstNZ, dst) (2 parameters)
E8M0 exponent (ND grouping)NDZZ (zigzag, [16,2] block)TMOV(e8Zz, e8, tmp) (3 parameters)
E8M0 exponent (DN grouping)DNZZTMOV<0>(e8Zz, e8Dn, tmp) (3 parameters, grp_axis=0)

The FP8 mantissa of DN data shares the same physical address as ND (the (r,c) elements are identical), so the 2-parameter TMOV ND→NZ also applies to DN data. Only the exponent path differs (DN→ZZ via TMOV<0>). See TQUANT_DN.md for details.

Supported Input Dtypes

FormatAcceptable Input DtypesDescription
MXFP8 (A5 only)FP32, BF16, FP16FP32: in-place FP8 output (4:1). BF16/FP16: source zero-padded to StaticCols; upcast to FP32 before type conversion (no direct b16→e4m3).
MXFP4 (e2m1) (A5 only)FP16, BF16 only (FP32 not supported)Outputs float4_e2m1x2_t (packed).
INT8 (sym/asym)FP32 onlySYM→int8_t, ASYM→uint8_t. Atlas A2/A3 training products/Atlas A2/A3 inference products require tmp = src size.

Micro-scaling (MXFP8/MXFP4) is supported only on A5; A2/A3 supports only the INT8 path (FP32 input).

Mathematical Semantics

Unless otherwise specified, semantics are defined within the valid region, and destination-related behavior is marked as implementation-defined.

Assembly Syntax

AS Level 1 (SSA)

%dst = pto.tquant %src, %qp : (!pto.tile<...>, !pto.tile<...>) -> !pto.tile<...>

AS Level 2 (DPS)

pto.tquant ins(%src, %qp : !pto.tile_buf<...>, !pto.tile_buf<...>) outs(%dst : !pto.tile_buf<...>)

ASM Examples

Automatic Mode

# Automatic mode: the compiler/runtime manages resource placement and scheduling.
%dst = pto.tquant %src, %qp : (!pto.tile<...>, !pto.tile<...>) -> !pto.tile<...>

Manual Mode

# Manual mode: explicitly bind resources before issuing the instruction.
# pto.tassign %arg0, @tile(0x1000)
# pto.tassign %arg1, @tile(0x2000)
%dst = pto.tquant %src, %qp : (!pto.tile<...>, !pto.tile<...>) -> !pto.tile<...>

PTO Assembly Form

%dst = pto.tquant %src, %qp : (!pto.tile<...>, !pto.tile<...>) -> !pto.tile<...>
# AS Level 2 (DPS)
pto.tquant ins(%src, %qp : !pto.tile_buf<...>, !pto.tile_buf<...>) outs(%dst : !pto.tile_buf<...>)

Examples

// MXFP8, DN grouping (axis-0), OCP scaling
TQUANT<0, MxQuantAlg::OcpMxFp8E4M3>(fp8Tile, srcTile, &e8DnTile, &maxTile, &scalingTile);

// MXFP8, ND grouping (legacy)
TQUANT<QuantType::MXFP8>(fp8Tile, srcTile, &e8NdTile, &maxTile, &scalingTile);

// MXFP4 E2M1, DN, NV scaling
TQUANT<0, MxQuantAlg::NvMxFp4E2M1>(fp4Tile, srcTile, &e8DnTile, &maxTile, &scalingTile);

// INT8 symmetric
TQUANT<QuantType::INT8_SYM>(int8Tile, srcTile, scale);

// Complete MXFP8 DN pipeline: quantization + layout conversion for Cube
TQUANT<0, MxQuantAlg::OcpMxFp8E4M3>(fp8Tile, srcTile, &e8DnTile, &maxTile, &scalingTile);
TMOV(fp8NZTile, fp8Tile);                  // Data ND→NZ
TMOV<0>(e8ZzTile, e8DnTile, tmpTile);      // Exponent DN→ZZ

For details, see TQUANT_DN.md (DN→ZZ conversion) and tests/npu/a5/src/st/testcase/tquant_dn/ (complete ST examples).