Preloader

Show HN: Npunlock – Run custom C kernels for Intel NPUs

0

npunlock

Intel ships programmable SHAVE cores inside its NPUs, but the public stack
exposes only graph-level programming. npunlock reconstructs the missing path
from custom C code to a runnable NPU kernel.

How npunlock adds custom C kernels to an Intel NPU graph

The current implementation has been verified on Windows x64 with Meteor Lake /
NPU3720.

Latest breakthrough — 2026-09-23: One native graph can execute independent FP32-unary and FP16-binary custom branches; explicit ACT-group preflight handles the compiler’s branch reordering. Evidence and limits.

Quick example

This complete FP32 GELU example embeds the C kernel in Python, places it in an
NPU graph, and checks the result against NumPy. The bundled
npunlock/npu3720_kernel.h target header supplies the NPU3720 invocation and
tensor-address helpers. The tested MoviTools toolchain makes most conventional
libm functions available to kernels without including <math.h>; this
example calls tanhf directly. See the
mlibm.a symbol inventory for the observed candidates.

import numpy as np
import npunlock as npu

npu.configure(movi_dll_dir=r"C:pathtoMVC_DEPEND")

gelu_c: bytes = b"""
#define MLIBM_DEFINE_LINK_COMPAT 1
#include <npunlock/npu3720_kernel.h>

void controlled_act(unsigned layerParams) {
    act_abi_invocation invocation;
    ACT_ABI_LOAD_INVOCATION32_OR_RETURN(layerParams, invocation);
    const float *in = ACT_ABI_INPUT_PTR32(const float, invocation, 0u);
    float *out = ACT_ABI_OUTPUT_PTR32(float, invocation, 1u);
    const float SQRT_2_DIV_PI = 0.7978845608028654f;
    for (unsigned i = 0; i < invocation.element_count; ++i) {
        float x = in[i];
        float w = x + 0.044715f * x * x * x;
        w = tanhf(w * SQRT_2_DIV_PI);
        out[i] = 0.5f * x * (1.0f + w);
    }
}
"""

N = 2048
x = npu.input("x", shape=(1, N), dtype="f32")
y = npu.custom(
    x,
    source=gelu_c,
    carrier="Abs",
    _name="y",
)

program = npu.compile(npu.Graph(inputs=[x], outputs=[y], name="gelu_f32_example"))

input_value = np.linspace(-4, 4, N, dtype=np.float32).reshape(1, -1)
output = program.run({"x": input_value})["y"]
reference = 0.5 * input_value * (
    1.0
    + np.tanh(
        np.sqrt(2.0 / np.pi)
        * (input_value + 0.044715 * input_value**3)
    )
)
print(f"maximum absolute error: {np.max(np.abs(output - reference)):g}")

The same code is available as the runnable
FP32 GELU example. See also the
FP16 GELU and
multi-layer two-input examples,
plus a
mixed-precision graph with unary and binary custom branches.

Why npunlock?

Intel’s normal NPU software accepts graphs made from operations its compiler
supports; it does not expose a public workflow for supplying a C implementation
for an operation. The NPU’s ACT-SHAVE processors are programmable and run
software kernels. npunlock makes those processors usable for compatible
custom graph operations while retaining Intel’s compiler and driver for the
surrounding graph and hardware execution.

Requirements

  • Windows x64
  • Meteor Lake / Intel NPU3720
  • an installed Intel NPU driver for the device
  • Python 3.10 or newer
  • CMake 3.24 or newer and an installed MSVC toolchain for source installation
  • the extracted MoviTools MVC_DEPEND toolchain for custom C compilation

OpenVINO is not required as a runtime, Python package, or compiler frontend.
npunlock does emit OpenVINO-format IR for the installed Intel driver.

Install

npunlock is currently installed from a source checkout:

python -m pip install .

The build bundles npunlock.dll and npunlock_worker.exe inside the Python
package, so normal Python use does not require a separate native path.

Get MoviTools

Custom C compilation uses Intel/Movidius MoviTools, which npunlock does not
redistribute or download.

A MoviTools package verified to work was found in a legacy Lenovo driver pack. See Getting MoviTools for the official download,
hash, extraction command, and expected layout.

Extract the MVC_DEPEND payload from Lenovo’s older
Intel NPU driver package 31.0.100.1688, but remember, DO NOT install or downgrade to
that driver
. All we need is the bundled MoviTools.

Run an example

Point npunlock at the extracted MVC_DEPEND root and run GELU:

$env:NPUNLOCK_MOVITOOLS_DIR = 'C:pathtoMVC_DEPEND'
python examplesexample_gelu.py

The example runs on the NPU and reports its maximum error against a NumPy
reference.

What currently works

  • compile user-written C into ACT-SHAVE machine code
  • run custom kernels inside Intel NPU graphs
  • static dense FP16 unary and two-input custom kernels
  • a verified unary FP32 path
  • one graph containing independent FP32-unary and FP16-binary custom branches
  • nonlinear math such as GELU and tanhf
  • reusable NumPy-compatible host/NPU shared input and output buffers
  • Python, CLI, and native C APIs

Current limitations

Support is experimental and currently limited to Windows x64, Meteor Lake /
NPU3720, static shapes, compatible ACT carriers, and known tensor layouts.
Connected mixed-precision conversion groups are not yet patch-discoverable;
the verified mixed-precision example uses independent branches. Other NPU
generations have not been verified. See
Current limitations for the full compatibility boundary.

Help test Linux and newer NPUs

Have an NPU3720 Linux system or a newer Intel NPU? Contributions are welcome.
Two routes look especially promising but remain untested:

  • a patched NPU3720 graph produced on Windows may run on Linux because the NPU
    firmware executes the custom machine code; building SHAVE code on Linux would
    additionally require a way to load the Windows MoviTools DLLs;
  • newer NPUs may execute the existing 3720xx SHAVE image, or an older OEM
    driver package for that generation may provide matching MoviTools components.

Both need hardware validation, driver/firmware version records, and output
comparison against a host oracle. If you can test either path, feedback, failure
reports, and code contributions are welcome. See
Porting to Linux and newer NPUs for the hypotheses, caveats,
and a suggested test plan.

Documentation

Warning

A note on AI use: I did use AI while building this project–for scaffolding, repetitive implementation work, converting my reverse-engineered results into organized documentation, and fixing my English. The reverse engineering, experiments, debugging, and technical conclusions came from hands-on work. If that doesn’t bother you, there’s a pretty deep and surprisingly satisfying rabbit hole ahead.

License

npunlock is licensed under the Apache License 2.0. MoviTools and
the Intel/Movidius libraries are external proprietary dependencies and are not
covered or redistributed by this repository.


Source: Hacker News

Choose your Reaction!
Leave a Comment