1.58-bit SIMD-Native Inference Engine Disclaimer: This project is distributed under the Elastic License 2.0. Please see the License section for more details.
TernixEngine is a bare-metal, dependency-free C++20 and CUDA inference execution engine optimized exclusively for 1.58-bit ternary Large Language Models (LLMs). By completely bypassing floating-point matrix multiplications (FP16/FP32), the engine utilizes AVX2 SIMD integer operations and CUDA shared-memory warp tiling to achieve hardware-level roofline saturation. The architecture resolves the de-quantization wall by utilizing in-register weight unpacking and branchless compute operations.
- The Bottleneck: De-Quantization Wall & Warp Divergence
- Architectural Methodology
- Conceptual Overview
- System Architecture
- Directory Structure
- Technology Stack
- DevOps & Testing
- Environment Setup & Execution
- Empirical Benchmarks & Evaluation
- Current Project Status
- Limitations & Future Work
- Troubleshooting
- License
- Project Referencing Guide
- Support & Maintenance
- Contribution Policy
Conventional inference engines evaluating sub-byte quantized Large Language Models (LLMs) suffer from severe memory and architectural bottlenecks:
- The De-Quantization Wall: Current implementations unpack 2-bit weights into INT8 or FP16 arrays before entering the General Matrix Multiply (GEMM) loop. This read-modify-compute pattern saturates L1 cache bandwidth, stalling the arithmetic logic unit (ALU).
- Sparse Branch Misprediction: Naive implementations attempting to optimize sparse ternary weights {-1, 0, 1} use scalar conditional logic (
if (weight == 0)). This destroys CPU branch predictor pipelines, causing instruction flushes that negate any theoretical compute savings. - CUDA Thread Divergence: Unaligned global memory fetches for packed sub-byte weights cause extreme warp divergence and non-coalesced memory transactions, crippling SM (Streaming Multiprocessor) occupancy.
Our approach synthesizes techniques from 5 foundational whitepapers on 1-bit transformers and hardware scaling (BitNet, T-MAC, QuIP#, MARLIN).
Derived from the BitNet scaling architecture, the core requirement is to avoid casting activations to floats. The C++ kernel executes:
- Bitwise Weight Extraction: Uses the
_mm256_srlv_epi32AVX2 intrinsic to shift and isolate packed 2-bit weights directly within the 256-bit register. - Branchless Compute: Uses a shift-and-arithmetic-right-shift (
_mm256_srai_epi32) to map binary weights {00, 01, 11} to sign controls {0, 1, -1}. The_mm256_sign_epi32instruction applies these to the activation vector. This completely eliminates branch misprediction. - Loop Tiling: We process the matrix loops in
M -> K -> Norder (tiled by 8 along N), ensuring that the accumulator vectors remain in the L0 registers across the entireKdimension.
Ternary weights are structured offline in a transposed K x (N/4) layout. This layout allows the AVX2 kernel to load 16-bit packed weights without strided DRAM access. A single contiguous read fetches 8 elements across the output channels, perfectly feeding the 8 lanes of the AVX2 vector space.
To mitigate the global memory latency bottleneck on the GPU, the CUDA kernel utilizes cp.async to bypass the L1 cache, streaming activations and weights directly into __shared__ memory.
- XOR Memory Swizzling: Prevents shared memory bank conflicts by mapping thread indices via
ty ^ tx. - Warp-Level Reduction: Avoids thread-per-element scaling. Instead, the warp collaborates to compute 32 values along the
Kdimension, followed by a logarithmic parallel reduction using__shfl_down_sync.
The core idea is to reduce standard high-precision weights down to simple integers (-1, 0, 1). This allows us to replace computationally expensive floating-point multiplication with basic integer addition and subtraction. By packing four of these 2-bit values into a single byte, we can use AVX2 vector instructions to process them concurrently without conditional branching.
graph TD
A[PyBind11 Interface] --> B[Model Loader & Memory Aligner]
B --> C{Execution Backend}
C -->|CPU| D[AVX2 In-Register Compute]
C -->|GPU| E[CUDA Warp Reduction]
D --> F[L0/L1 Cache]
E --> G[Shared Memory Tiles]
F --> H(Output INT32 Tensor)
G --> H
The system initializes via a Python wrapper or C++ CLI. The Model struct parses interleaved weights from disk, aligning them in 32-byte chunks using _mm_malloc for SIMD compatibility. The kernel execution branches to either the highly optimized CPU AVX2 loop or the asynchronous CUDA kernel based on runtime topology.
TernixEngine/
├── benchmarks/ # Google Benchmark integration and Python graphing scripts
│ ├── bench_end_to_end.cpp # Full pipeline inference benchmarks
│ ├── bench_simd_math.cpp # Microbenchmarks for scalar vs AVX2 ternary ops
│ ├── results.json # (Gitignored) Raw latency output from benchmarks
│ └── benchmark_results.png# Auto-generated visualization of CPU times
├── bindings/ # Interoperability layers
│ └── python/
│ └── pybind11_wrapper.cpp # Exposes C++ models to Python via Pybind11
├── include/
│ └── ternix/ # Public API Headers
│ ├── bitpack.h # 1.58-bit ternary quantization logic
│ ├── model.h # Model architectures and layers
│ ├── simd_math.h # Declarations for SIMD and baseline math
│ ├── tensor.h # Multi-dimensional tensor management
│ └── transformer.h # Transformer execution blocks
├── scripts/
│ └── plot_results.py # Automates matplotlib graphing and README injection
├── src/ # Core Implementation
│ ├── bitpack.cpp # Bitwise packing implementations
│ ├── cuda_kernels.cu # GPU acceleration (Warp-level reductions)
│ ├── main.cpp # CLI entrypoint
│ ├── model.cpp # Model abstractions
│ ├── mul_mat_ternary.cpp # Core SIMD (AVX2) ternary multiplication logic
│ ├── simd_math.cpp # Wrappers for math algorithms
│ ├── tensor.cpp # Tensor memory allocation
│ └── transformer.cpp # Layer processing and attention mechanisms
├── tests/ # GoogleTest unit testing suite
│ ├── test_bitpack.cpp # Validates packing/unpacking accuracy
│ └── test_simd_math.cpp # Validates SIMD math against scalar truth
├── CMakeLists.txt # Build matrix config (C++20, FetchContent, CUDA)
├── README.md # Project documentation
└── run_all.bat # Universal CI/CD execution pipeline script
- C++20: Strict compliance for advanced memory semantics.
- CUDA 12.x: For NVIDIA Ampere+ architectures.
- Intrinsics: Intel AVX2 (
<immintrin.h>). - Dependencies (Git Submodules): Google Benchmark, GoogleTest, Pybind11.
- Build System: CMake, Ninja.
Unit tests are implemented using GoogleTest, located in the tests/ directory. They specifically validate:
- Lossless 2-bit packing and unpacking mechanisms.
- Mathematical accuracy of AVX2 auxiliary layers (RMSNorm, SwiGLU) compared to floating-point standards.
Execute tests via
ctest --output-on-failurewithin the build directory.
Hardware:
- CPU: x86-64 Processor with AVX2 instruction set support (Intel Haswell / AMD Zen or newer).
- GPU (Optional): NVIDIA GPU with Compute Capability 7.5+ (Turing architecture or newer) for CUDA acceleration.
- RAM: Minimum 16GB (32GB+ recommended for large matrices).
Software:
- OS: Windows 10/11 (Linux support is theoretically possible via CMake, but
run_all.batis Windows-native). - C++ Compiler: MSVC (Visual Studio 2022/2026 Build Tools) - Must support C++20.
- CUDA Toolkit (Optional): v12.x or v13.x for GPU offloading (
nvccmust be in PATH). - Python: 3.8+ (for plotting and pybind11 integration).
- Build Tools: CMake (3.20+) and Ninja.
- Git: Required for CMake
FetchContentto download Google Benchmark, GoogleTest, and Pybind11.
We provide a unified batch script that handles dependencies, cache clearing, compiling, testing, benchmarking, and graphing seamlessly.
- Ensure you have opened the x64 Native Tools Command Prompt for VS (do not use standard PowerShell).
- Execute the pipeline:
run_all.bat
This script automates CMake generation, compilation, unit testing, microbenchmarking, and graph visualization. Please refer to .antigravity/tech.md for private host setup guidelines.
Benchmarks are tracked using the Google Benchmark framework, which outputs statistical traces directly to benchmarks/results.json. The scripts/plot_results.py script visualizes this data programmatically and dynamically injects the realtime hardware metrics directly into the table below!
Hardware Testbed: Intel(R) Core(TM) i7-14650HX CPU | NVIDIA GeForce RTX 5060 Laptop GPU | 512x512 FP16/INT2 Matrix Execution
Based on our empirical microbenchmarking on a 512x512 matrix execution:
| Implementation Strategy | Loop Constraints | Instruction Set | Throughput Speedup (Actual) | Time (ms) |
|---|---|---|---|---|
| Naive Scalar | Branching if (w == 0) |
Base C++ | 1.0x (Baseline) | 122.40 ms |
| Tiled SIMD Accumulation | Tiled M -> K -> N |
AVX2 (_mm256_srlv_epi32) |
~8.2x | 15.00 ms |
| Asynchronous CUDA Warp | 32x32 Shared Mem |
NVCC (__shfl_down_sync) |
Pending GPU Profile | N/A |
The data confirms that the structural alignment of the SIMD integer accumulations with proper weight interleaving yields over an order of magnitude improvement by eliminating the scalar control-flow hazard entirely.
The project is currently a mathematical kernel library with scaffolding. It is not yet a functional end-to-end inference engine.
- Core Math Kernel: The 1.58-bit ternary matrix multiplication kernel (
src/mul_mat_ternary.cpp) is implemented and verified. It uses AVX2 intrinsics (_mm256_srlv_epi32,_mm256_sign_epi32) for branchless, integer-only accumulation. - Microbenchmarking: Google Benchmark is integrated to measure latency, currently showing an ~8.2x speedup over the scalar branching baseline.
- Python Interoperability: PyBind11 is configured and successfully compiles
ternix_engine.pydfor python integrations. - Repository Structure: The CMake configuration, GTest suite, and initial documentation are set up.
- Weight Quantization (
quantize.py): This is completely empty (a structural stub). It does not load HuggingFace models, does not apply BitNet scaling, and does not pack into our 2-bit interleaved layout yet. - Model Architecture (
model.cpp): The model loader is a stub. It hardcodes dimensions (32000, 4096, 32) and allocates empty memory. It does not execute a full forward pass (Attention + FFN). - CUDA Kernels: The GPU warp-reduction kernels exist structurally but require deeper validation to ensure they match the theoretical throughput of the MARLIN paper.
Based on our analysis of the codebase and literature:
- Lookup Table (LUT) Integration: While QuIP# and T-MAC recommend E8-lattice codebooks for cache-resident LUT operations, our current iteration hardcodes the ternary arithmetic. Future work requires generating a 1KiB LUT to process groups of weights natively.
- AVX-512 VNNI: The current architecture uses AVX2 for maximum hardware compatibility. Implementing
_mm512_dpbusd_epi32(AVX-512) will theoretically double throughput on Sapphire Rapids and Zen 4 architectures. - End-to-End Latency Tracing: The
bench_end_to_end.cppfile is currently a structural stub. It must be expanded to track actual token-generation latency (Tokens/sec) rather than isolated matrix multiplications.
nvccis not recognized: If you installed the CUDA Toolkit but the terminal cannot findnvcc, you must add the CUDA binary path (e.g.,C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.3\bin) to your Windows systemPATHenvironment variable. Additionally, ensure you completely restart your terminal or IDE so it inherits the updated PATH.- Nsight VSE Installation Warnings: When installing newer CUDA toolkits (e.g., 13.x) with newer Visual Studio versions (e.g., VS 2026), the installer may warn that it could not install the "Nsight Visual Studio Edition" plugin for an older VS version like 2022. This is completely harmless. Nsight is just a debugging UI plugin; its absence does not affect the core
nvcccompiler or your ability to build and run CUDA code. run_all.ps1opens in Notepad: We strictly utilize.batfiles for the execution pipeline now because the MSVC x64 Native Tools terminal is built oncmd.exe. Do not use.ps1scripts for the pipeline.- CMake cannot find compiler or CUDA: Ensure you are running from the x64 Native Tools Command Prompt, not standard PowerShell. If it still fails, your
build/CMakeCache.txtmay be stale. Ourrun_all.batautomatically deletes this cache to prevent CMake staleness. - NVCC Fatal Error (Multiple Input Files): If
nvccfails with input file errors, ensure you are using CMake Generator Expressions ($<$<COMPILE_LANGUAGE:CXX>:/O2>) inCMakeLists.txtfor all optimization flags. Otherwise, CMake will pass C++ flags like/arch:AVX2directly tonvcc, which will parse them as corrupted input files. - C2719 Error (MSVC): Ensure all
__m256iarguments are passed by reference or pointer, as MSVC prohibits passing aligned types by value in older configurations. - CUDA PTX Errors: Verify that your NVIDIA Studio Driver matches the CUDA Toolkit version. Game Ready drivers may cause unexpected PTX instruction failures during
cp.async.
This project is distributed under the Elastic License 2.0.
What this means:
- [Yes] You can view, use, and modify this code for your own internal use
- [Yes] You can share this project with attribution
- [No] You cannot provide the software to third parties as a hosted or managed service
- [No] You cannot circumvent the licensing limitations
See LICENSE for the full legal text. This software is provided as-is without any warranties.
If you utilize TernixEngine in your academic research or production environment, please use the following citation format:
@software{ternix_engine_2026,
author = {TernixEngine Contributors},
title = {TernixEngine: Hyper-Optimized 1.58-bit Inference Engine},
year = {2026},
url = {https://github.com/PundarikakshNTripathi/TernixEngine}
}For bug reports, feature requests, or performance optimization discussions, please open an issue in the repository. Please provide your CMakeCache.txt and hardware specifications when reporting performance deviations.
We welcome contributions under the Elastic License 2.0. Please refer to CONTRIBUTING.md for guidelines on workflow, standards, and issue reporting. Please ensure all new kernels include corresponding unit tests in the tests/ directory and update the README.md if adding new CLI flags or features.
