Skip to main content

Native DetessDequant boundary

Use simaai/kernels/ops/detessdequant.h for shared admission and simaai/kernels/ev74/detessdequant.h for device encoding. Link SimaKernels::detessdequant. These host targets require no MetaWare, ConfigManager, JSON or GStreamer.

Contract​

The DetessDequant contract applies to both backends: MlaTiled INT8 input becomes contiguous or byte-strided FP32 or BF16 output with the same explicit logical shape. Ranks one through six and empty tensors are supported; rank-zero scalars are not. Empty execution submits no numerical job.

D/H/W/C axis mappings remain explicit; C is required and unmapped logical axes are independent outer dimensions. Compact and padded-to-16 input channels are supported. Contiguous output means logical row-major order, not necessarily channels last. Explicit Strided output supports scalar-aligned, non-overlapping positive strides on non-unit axes, including pitches, steps and physical axis permutations. Singleton strides may be zero. FP16 output and UINT8/INT16/INT32 tensor inputs are outside this native contract. Legacy graph entries do not expand it.

Compiler channel-block input​

The shared contract also admits MlaCBlocked input with trailing H/W/C at ranks 3–6; see the physical addressing equation. The native codec carries an explicit blocked-layout flag. The device validates the trailing axes and padded-channel contract before dispatch. Existing firmware that does not understand this flag rejects the packet; deploy matching firmware and host artifacts together.

The worker gathers valid 16-channel fragments directly into bounded local panels, then uses the existing ordered dequantization core. No DDR intermediate or A65 tensor scan is required. Dense output task ownership and DMA retirement rules remain unchanged. Pixel-major-only bulk readers are not used for blocked payloads.

Parameters​

Supply Params{scale, zero_point}. scale is required, finite and strictly positive, including positive FP32 subnormals. zero_point defaults to zero and admits the full INT32 parameter domain. This does not add INT32 tensor support. Parameters follow Dequant semantics but have a distinct nominal C++ type so Runtime can distinguish the two requests. No caller-selected numerical route, rounding mode, per-axis scale or hardware-specific parameter is needed.

Numerical behavior​

For every logical signed INT8 value q, perform these ordered stages:

z = round_to_nearest_even_FP32(zero_point)
d = round_to_nearest_even_FP32(FP32(q) - z)
r = round_to_nearest_even_FP32(d * scale)
FP32 output = r
BF16 output = round_to_nearest_even_BF16(r)

The subtraction and multiplication are not contracted into FMA. Wide zero points must round to FP32 before subtraction; integer affine rewrites are not interchangeable for the entire admitted domain. Overflow may produce infinity; underflow may produce signed zero or subnormal output. These are valid results. Valid inputs and parameters do not produce NaN.

Normal-scale EV execution converts signed INT8 lanes to exact FP32 values, subtracts the rounded zero point and multiplies by scale. BF16 uses integer nearest-even narrowing of the resulting FP32 bits. It does not use FP16 arithmetic. For subnormal scales, preparation builds an exact 256-entry table using integer arithmetic. Each entry models the same separately rounded stages, including wide-zero-point rounding and signed underflow. This avoids dependence on device FP32 flush behavior without adding CPU work proportional to tensor size. The table is immutable, reused across submissions and copied to worker-local storage once per invocation. BF16 entries contain the final narrowed bits.

A65 checks the executing thread's FP environment before writes; EV selects its normal or exact-table implementation from the admitted scale. See the canonical A65 numerical contract for host FP-state requirements.

C++ call​

Use the A65 call for explicit specifications and checked execution with caller-supplied storage. Shared preparation is ops::detessdequant::check_inference(request). A65 derives a numerical plan with a65::detessdequant::prepare(metadata). Runtime accepts the same request and selects hardware outside the mathematical parameters.

check_inference → EV representability check → encode_relocatable
→ retained DMA-BUF bindings and address relocation
→ asynchronous submission → confirmed retirement and coherency

bind() supports integrations with resolved device regions. CPU pointers are not EV addresses. Runtime's synchronous convenience call submits the same job and waits; no second runner or configuration adapter is introduced.

Place the includes and namespace aliases at file scope; the remaining statements belong in a simaai::kernels::Status-returning caller function. It checks metadata and encodes a relocatable descriptor, not EV74 computation. Runtime must map actual buffers, bind addresses and retain inputs, outputs and any workspace until confirmed device completion.

#include <array>
#include <simaai/kernels/ev74/detessdequant.h>
#include <simaai/kernels/ops/detessdequant.h>

namespace k = simaai::kernels;
namespace op = k::ops::detessdequant;
namespace ev = k::ev74::detessdequant;
k::MlaTiled tiled;
tiled.axes = {-1, -1, 0, 1}; // Shape [W,C], with an explicit channel axis.
tiled.tile_shape = {1, 1, 2, 3};
const std::array inputs{k::TensorSpec{{2, 3}, k::DType::Int8, tiled}};
const std::array outputs{k::TensorSpec{{2, 3}, k::DType::BFloat16}};
const op::Request request{inputs, outputs, op::Params{1.0F}};
auto checked = op::check_inference(request);
if (const auto *error = std::get_if<k::Error>(&checked)) return *error;
const auto &plan = std::get<op::Plan>(checked);
auto encoded = ev::encode_relocatable(plan);
if (const auto *error = std::get_if<k::Error>(&encoded)) return *error;
// Encoding leaves device addresses unbound; no device work has run.
return {};

See the host contract tests (EV74/detessdequant/tests/correctness.cpp) and device fixture (EV74/detessdequant/tests/runtime_e2e.cpp) for binding and execution coverage.

Memory and lifecycle​

Preparation derives physical tiled input storage and the full addressed output span, including holes. Input alignment is 16 bytes; output alignment is two bytes for BF16 or four for FP32. Required ranges must not overlap. Padding and alignment gaps in the input are ignored, even if nonzero; the output contains only logical elements.

Runtime owns allocations, mappings, coherency, scheduling and recovery. It retains buffers and prepared descriptor storage until confirmed retirement. A timeout does not authorize releasing storage still accessible by DMA. Successful execution needs no full untiled intermediate, CPU tensor prescan, per-frame table generation or per-tile A65 submission.

Native boundary​

The version-1 descriptor has a 176-byte base, with input/output address slots at offsets 24 and 32, scale bits at 168 and zero point at 172. Normal-scale packets are 176 bytes; subnormal-scale BF16 and FP32 packets are 688 and 1,200 bytes. Six-capacity dimensions, mapping, tile shape and padding describe the input. Dense output strides are derived rather than redundantly supplied. Non-dense output sets STRIDED and appends six little-endian 64-bit byte strides after the 176-byte header. Its normal-scale packet is 224 bytes. The exact table follows the stride trailer, so subnormal BF16 and FP32 packets are 736 and 1,248 bytes. Explicit row-major strides, ignoring singleton strides, use the dense packet formats and numerical workers described above. Both target compilers assert control-layout offsets, sizes and alignment. EV-visible ranges must fit the checked 32-bit address aperture.

Platform firmware must explicitly register simaai_kernels_ev74_detessdequant_v1 and Runtime must verify its capability before numerical submission. Installing a host library does not install firmware or establish device qualification.

Strided output ownership​

For byte-strided output, the addressed scalar offset is

offset = sum(coordinate[axis] * strides_bytes[axis])
span = scalar_bytes + sum((shape[axis] - 1) * strides_bytes[axis])

Admission sorts non-unit axes by stride and proves each new axis starts beyond the complete previously addressed extent; it checks alignment, signed-64-bit representability, overflow and capacity. The device repeats those checks before dispatch and rejects nonzero unused stride slots. Bindings must cover the full span, not just elements * scalar_bytes. Output holes remain untouched.

A private strided worker reuses the bounded tiled gather and unchanged numerical conversion, then coalesces the largest contiguous logical suffix into output spans. Whole aligned 16-byte interiors use DMA; exact scalar-boundary bytes do not round into holes. Each write retires before another span or exact boundary can share its physical write granule. Arbitrary strided output uses one owner: logical non-overlap alone does not prove independent DMA granules. Input-slot prefetch still overlaps conversion; no full untiled DDR intermediate or A65 per-element processing is introduced. Dense workers retain their existing parallel ownership and slot pipeline.

The host/native suites include pitched, stepped, permuted and singleton views, panel transitions, both output dtypes, compiler-block input, guarded holes and immediate/deferred DMA. Old firmware rejects the new flag/length; deploy the matching package, transport capability table and firmware together. Compilation and host expression models are not real-device qualification.

Implementation notes​

DetessDequant gathers bounded INT8 panels into worker-owned output intervals,
selects normal FP32 arithmetic or exact subnormal-table lookup, and retires
aligned DMA or exact boundary stores.

Workers own disjoint dense output intervals, not input tiles. Different channel tiles may contribute neighboring elements to the same dense pixel. Ownership boundaries derive from the actual output bus address: interior writes are aligned whole-16-byte DMA ranges; unique global head/tail tasks use exact scalar-width stores. Neither guards nor neighboring views are written to round up a DMA transfer.

Each panel contains at most 4,096 elements. Two 4 KiB INT8 input slots alternate with two output slots and bounded 4 KiB raw-fragment scratch. There are no BF16 low/high input planes: a physical INT8 pixel contains one byte per stored channel. Source tile storage is aligned to 16 bytes and boundary tiles use their actual extents. Bulk reads use DMA; tiny fragments do not silently become a scalar DDR implementation.

The bounded geometry has sixteen full/boundary tile classes. Contiguous channel runs, split-channel pixel gathers, padded channels and permuted-axis rectangles reuse regular DMA spans. Unrepresentable DMA pitches split into exact row transfers rather than being narrowed. Local gathering follows logical output order, then conversion writes that panel directly. Coordinate state is reused across regular runs instead of interpreted anew for every scalar.

Rank-one channel tensors use one direct input DMA per panel when the tensor fits one tile or each full channel tile contains a multiple of sixteen elements. In that geometry, logical input bytes form a contiguous physical prefix, even with channel padding; final padding is not read as data. Other tile sizes retain the general reader. Conversion, output ownership and rounding are unchanged.

Six internal implementations cover the four output-dtype × normal/exact-table combinations and two metadata-selected execution families:

  • Normal-scale BF16 rank-one channel tensors use a compact direct-input worker when there is one channel tile or full tiles contain a multiple of sixteen elements. It uses the same arithmetic and exact head/tail output ownership, without the general tiled-reader scratch or control flow.
  • Normal-scale FP32 channel bands admit canonical channel-last axes, three or four C tiles of 16 or 32, unit D tiles, complete spatial tiles, W tiles divisible by sixteen, and 16-byte-aligned output. Each bounded band gathers its channel tiles into one dense output interval. Admission preserves the general reader’s available worker parallelism; unsupported geometry uses that reader.

Neither family changes the INT8-to-FP32 arithmetic order, BF16 narrowing, zero-point handling, or exact-table fallback. The native entry selects once. The next input panel is prefetched; input completion precedes consumption and output completion precedes slot reuse. All output transfers drain before numerical completion. Explicit local arrays are not the complete VCCM cost: target qualification must inspect generated stack frames, spills and nested calls as well.

Tests and qualification​

ev74_detessdequant_contract checks codec, malformed descriptors, mock dispatch and independent numerical/layout references. Optional Clang tests execute the actual OpenCL expressions with immediate and deferred DMA models. Those models check bounds and software wait ordering, not EV ISA or hardware concurrency. Standalone Dequant regression tests cover the shared exact-subnormal helper.

Runtime's detessdequant_executor_contract covers shared admission, A65 execution and asynchronous owner lifetime. detessdequant_cvu_e2e runs real correctness and latency by default, including process CPU time. Qualification requires both output types, all INT8 values, wide zero points, subnormal scales, rank/axis/tile tails, dirty padding, giant physical tiles, exact output guards and one through four workers. Source compilation is not a device pass.

Measure the complete composed firmware, including neighboring operations. Existing Quant median failures remain independent blockers; adding this entry must not reset their baselines. Percentile tails remain diagnostic under the median qualification policy.

Channel-inner physical output traversal​

The device entry validates the packet and buffer spans, then may reorder private traversal for a channel-contiguous physical output. Mapped source axes, outer strides and logical associations are permuted together. Bounded source runs may follow W, H or D using their exact tile pitch and current extent. INT8 conversion/table semantics and output holes are unchanged. Strided publication retains one owner. Channel-outer and CBlocked cases remain on their established routes until a cheaper bounded read/write strategy is proved.

H/C and D/C traversal can trade additional exact input-row commands for fewer scalar output writes. Host models report input/output DMA calls, payload bytes and output bytes left to typed stores; input-command count alone is not a latency criterion. Paired device qualification must decide the net benefit.

detessdequant_cvu_e2e --shared-family-only measures H/C and D/C output families with both output dtypes, channel tails, C-first logical order, holes and phases. The default fixture includes the same cases and checks every output scalar, untouched hole and guard using its independent INT8/tiled oracle.