Run Your First Code
Throughout this guide, we use one running example: WAXPBY, the vector update w = alpha * x + beta * y. It is plain C, with no pragmas, intrinsics, or GPU code.
#include <stdio.h>
#include <stdlib.h>
#define N (1 << 24)
int main(void) {
float* x = malloc(N * sizeof(float));
float* y = malloc(N * sizeof(float));
float* w = malloc(N * sizeof(float));
float alpha = 2.0f, beta = 3.0f;
for (int i = 0; i < N; i++) {
x[i] = (float)i;
y[i] = (float)(N - i);
}
// The kernel: w = alpha * x + beta * y
for (int i = 0; i < N; i++) {
w[i] = alpha * x[i] + beta * y[i];
}
printf("w[0] = %f, w[N-1] = %f\n", w[0], w[N - 1]);
free(x); free(y); free(w);
return 0;
}
Step 1: Compile it like with clang
docc accepts the same flags as clang, so you can use it on existing code right away:
docc -O3 waxpby.c -o waxpby
./waxpby
Without further options, docc behaves like a regular compiler and the program runs sequentially.
Step 2: Use all CPU cores
Select a target with -docc-tune. With openmp, docc detects that the loop iterations are independent and parallelizes the loop across all cores:
docc -O3 -docc-tune=openmp waxpby.c -o waxpby
./waxpby
Step 3: Offload to a GPU
The same source runs on a GPU when you change the target. docc generates the GPU kernel and the data transfers between host and device:
# NVIDIA
docc -O3 -docc-tune=cuda waxpby.c -o waxpby
# AMD
docc -O3 -docc-tune=rocm waxpby.c -o waxpby
During compilation, docc reports which GPU it compiles for, for example:
[DOCC] Compiling CUDA for sm_90 of NVIDIA H100
Tenstorrent Wormhole and Blackhole cards work the same way with -docc-tune=tenstorrent.
What happened
docc compiled your program with Clang, lifted the kernel loop into its intermediate representation (SDFG), parallelized it for the selected target, and linked the generated code back into your executable. Code that docc cannot optimize is compiled as usual, so the program always behaves the same as with clang.
Next step
Real applications are rarely a single file. In Using Libraries, we move the WAXPBY kernel into a shared library and see how docc avoids unnecessary GPU transfers across library calls.