DCompute Metal Backend
Asadbek
aosindarov at gmail.com
Sun Aug 16 21:02:00 UTC 2026
Hello everyone,
I wanted to share an update on my progress in adding a Metal GPU
backend to DCompute.
Over the past few weeks, I’ve been researching how languages with
mature Metal GPU backends: such as Julia, Mojo, and AdaptiveCpp,
handle their compilation pipelines. I decided to adopt an
approach inspired by the Julia compiler's architecture.
For context, the fundamental challenge with targeting Apple Metal
GPU is that Apple relies on a custom, older fork of LLVM. While
upstream LLVM supports backward compatibility for *reading* older
bitcode formats, the LLVM bitcode writer cannot *emit* older
bitcode versions.
To bypass this limitation, Julia’s maintainers copied an older
LLVM IR bitcode writer and built an independent utility to
"downgrade" modern LLVM bitcode into the Apple-compatible format
(Apple IR / AIR). You can see their utility
[here](https://github.com/JuliaLLVM/llvm-downgrade).
Their high-level device code compilation pipeline looks like this:
```text
[ Julia Source Code ]
│
▼ (Frontend)
[ LLVM IR ]
│
▼
[ LLVM IR + Apple-specific Metadata ]
│
▼ (Custom LLVM Downgrader)
[ Metal-Compatible LLVM Bitcode (AIR) ]
```
While Julia doesn't strictly separate host and device code at the
user level, their lower-level infrastructure still performs two
distinct compilations, ultimately passing the downgraded device
binary to the GPU via host buffers
Inspired by Julia's
[LLVMDowngrader_jll.jl](https://github.com/JuliaBinaryWrappers/LLVMDowngrader_jll.jl), I have created a D alternative: [llvm_downgrader](https://github.com/asindarov/llvm_downgrader).
With that being said, we only need the LDC compiler to generate
device code with the necessary Apple-specific metadata attached
(implementation
[here](https://github.com/asindarov/ldc/blob/metal-backend/gen/dcompute/targetMetal.cpp) in my fork). Once LDC emits this IR, DCompute leverages the new LLVM downgrader to translate it into Apple IR. Finally, we use Apple's `xcrun metallib` linker to package it into a `.metallib` binary ready for execution.
Our final compilation pass for DCompute and LDC looks like this:
```text
[ D Device Code ]
│
▼ (LDC Compiler)
[ LLVM IR + Apple-specific Metadata ]
│
▼ (llvm_downgrader)
[ Apple-compatible LLVM Bitcode (AIR) ]
│
▼ (xcrun metallib)
[ .metallib Binary ]
```
Link to the linker integration
[here](https://github.com/asindarov/dcompute/blob/584160a531640fadfb6653b1d4f5c504daf5a9c3/source/dcompute/driver/metal/program.d#L40-L66).
This is now fully functional, and basic kernels are successfully
executing on Metal GPUs.
Here are the relevant PRs for those interested:
LDC: [#5118](https://github.com/ldc-developers/ldc/pull/5118)
Dcompute: [#99](https://github.com/libmir/dcompute/pull/99)
Thanks again to everyone who has provided feedback so far on the
PRs! I will keep you updated as I continue to expand the
functionality.
More information about the Digitalmars-d
mailing list