Yes, it’s very similar to that, except the ic has no imagination, vision, or drive.
I wrote my first compiler about 35 years ago, and my first OS around the same time, well before LLMs were on the scene. I know exactly just how much work is involved with doing it well, which is why I’d never normally take on a project like this now I’m retired.
But we do not live in normal times. The language “I” have created (and it’s not as though I just said to Claude “hey, write me a compiler”) is (even if I say so myself) pretty cool. Here’s the full source of a Mandelbrot program:
#import "Stdio.xc"
#import "Par.xc"
#import "../src/include/bench_time.xc"
#define W 2048
#define SIZE (W * W)
i32 main(void)
{
// Eight runs: the first carries one-off costs (a GPU builds its kernel
// then), so the figure is the best run; the first is printed too. Auto
// decides after its fourth (two on each device), and uses the rest.
u32 total = 0;
i64 best = 0;
i64 first = 0;
for (u32 rep in 0..8)
{
total = 0;
i64 t0 = bench_now_us();
par mandel :reduce(+ total)
{
for (u32 i in 0..SIZE)
{
float cx = (float)(i % W) * (3.0f / 2048.0f) - 2.0f;
float cy = (float)(i / W) * (3.0f / 2048.0f) - 1.5f;
float x = 0.0f;
float y = 0.0f;
u32 k = 0;
while (k < 256 && x * x + y * y < 4.0f)
{
float xt = x * x - y * y + cx;
y = 2.0f * x * y + cy;
x = xt;
k = k + 1;
}
total = total + k;
}
}
i64 t1 = bench_now_us();
if (rep == 0)
first = t1 - t0;
if (rep == 0 || t1 - t0 < best)
best = t1 - t0;
}
Stdio.printf("%u %lld %lld\n", (total + 500000) / 1000000, best, first);
return 0;
}
Just one line in that source code is what turns it from a bog-standard C-like program into a GPU kernel, automatically tracked, scheduled, and all data hazards transparently managed.On my M4 max, that one line of code takes it from 481ms to 1.6ms. All ‘par’ does is say “this next block of code, call it “mandel”, is data-parallel, and for the ‘total’ variable all execution units should combine their output to that variable using +
No huge GPU boilerplate, no stream management for data transport from cpu to gpu and back, no memory barriers, no hassle. Just “hey, do this on the gpu”.
GPU blocks are bound at runtime using the best design for the hardware on the machine, obtained by measuring it if it hasn’t been measured before. If it has, the cache is read. The user can always override, which is why ‘par’ blocks can be named.
Next up is an overlapping scheduler, which keeps 3 work units in play {pending, being-processed, being-transferred-once-done} for a processing device (right now, just a local gpu), which is also the multi-gpu story, and even the networked-machines story.
Schrödinger's AI: can't come up with ideas on its own and we'll all be doomed once we come to rely on it, but we shouldn't credit you with what you use it for; it's all just AI slop. Neat work.
I think this is great work; these are strange times, i personally don't feel like i'm building stuff anymore, it is more like thinking it into existence