picceler (Pixel Accelerator) is a compiled domain specific language for image processing. The language aims to simplify and fasten the development speed for image processing work (currently CPU-only).
Picceler doesn't aim to be a production language, rather it aims to provide a good example of what you can achieve with MLIR.
The process of building and installing can be quite long, please refer to the How to build guide for this information.
The picceler language is statically typed and immutable: every variable and function parameter
carries an explicit type annotation (int64, float64, string, image, kernel), and once a
name is declared it can't be reassigned. Keeping things simple.
Please refer to the Language document for more precise information on syntax and builtin operations.
An official VS Code extension is vendored as a submodule at
editors/vscode-picceler — see its
README for details.
Picceler uses MLIR to go from a parsed .pic source file, through a custom picceler dialect, down through several lowering passes, to LLVM IR and finally native machine code. LLVM's own middle-end
optimization pipeline runs on the way to machine code; -O0--O3 (default -O2) controls it, and
--native targets the host CPU instead of a portable generic baseline.
Refer to the Compiler Internals document for a full breakdown of the pass pipeline (phases, order, and rationale), and to the Dialect Reference for op/type-level detail on the MLIR dialects involved.
Picceler is measured against a hand written naive C++ loop and against OpenCV, on the same image:
| operation | picceler | naive C++ | OpenCV |
|---|---|---|---|
| invert | 9.5 ms | 7.0 ms | 4.8 ms |
| brightness(+30) | 9.4 ms | 7.9 ms | 5.2 ms |
| gaussian_blur(r=6) | 1106.1 ms | 1039.5 ms | 12.1 ms |
| sharpen(3x3) | 72.4 ms | 78.8 ms | 15.3 ms |
Picceler started out 4 to 6 times slower than naive C++ on elementwise
operations, and 1.2 to 1.4 times slower on convolutions. Enabling
optimizations that were free to add brought that down: CSE, dead value
elimination, and loop invariant code motion in the MLIR passes, plus a real
LLVM optimization pipeline (-O0 to -O3) and native CPU codegen
(--native). Elementwise operations now land within 1.2 to 1.4x of naive
C++, and sharpen is slightly faster than it.
Losing to OpenCV by a wide margin was always expected.
See bench/RESULTS.md for full numbers and bench/ for how to reproduce them.
I found out that building a compiler is hard, and comparing its output to production compilers and tech stacks is a harsh reality.
Compile with --profile to automatically instrument every image operation and get a
Perfetto-viewable trace of where a program actually spends its time — no language changes
required. See Profiling for usage, the .bin format, and how to convert a
trace for ui.perfetto.dev.
Generated API reference (Doxygen, rebuilt on every push to main): robertkq.github.io/picceler
See ROADMAP.md for what is intentionally out of scope for now.