terralang / terra

Terra is a low-level system programming language that is embedded in and meta-programmed by the Lua programming language.
terralang.org
Other
2.71k stars 197 forks source link

SPIRV Support #615

Open elliottslaughter opened 1 year ago

elliottslaughter commented 1 year ago

This is a tracking / note taking issue for ongoing work on support for SPIR-V.

An experimental SPIR-V target landed in LLVM 15. Rather unhelpfully documented at: https://llvm.org/docs/SPIRVUsage.html

Why use the target instead of the existing SPIR-V/LLVM translator? Because when you use the latter, there is no target that exists in LLVM to support it. You can hack around this, but it breaks all sorts of code paths that Terra normally assumes to work. @lizdulac heroically put effort into this in #469 but I've never been entirely comfortable merging it because it rips up a bunch of Terra's target code.

Clang supports the new target via a flag: https://releases.llvm.org/15.0.0/tools/clang/docs/ReleaseNotes.html#spir-v-support-in-clang

In order to get LLVM to actually build the SPIR-V backend (as of LLVM 15), you need to build with -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=SPIRV. Otherwise the Clang flag above doesn't work. (I found in my local build that I also needed -DLLVM_ENABLE_DUMP=ON, but this was not the case in the corresponding CI build, so I'm not sure if this is fundamental or not.)

Next step is to test the Clang support and check (after rebuilding LLVM) whether I can access the target from Terra. I'm optimistic, given my experience with the AMDGPU target, that this should mostly just work (at least on our end). Of course I have no idea what the quality of the backend itself is right now.

elliottslaughter commented 1 year ago

Wow, it actually works:

test_spirv.t:

local spirv_target = terralib.newtarget {
  Triple = 'spirv64v1.0',
}

terra f(x : double)
  return x + 1
end

terralib.saveobj("test_spirv.t.spv", "object", {f=f}, nil, spirv_target)

test_spirv.c:

double f(double x) {
  return x+ 1;
}
$ ./build/bin/terra test_spirv.t
$ .../llvm-15-src-spirv/install/bin/clang -fintegrated-objemitter -target spirv64v1.0 test_spirv.c -o test_spirv.c.spv -c -O2
$ diff test_spirv.t.spv test_spirv.c.spv

Output files are bitwise identical.

This is with unmodified Terra at ee17b60f8238c204c3da2a1ab44c7fbc8d0ea5c5. I guess the only thing I needed was the working LLVM target.

Next up:

elliottslaughter commented 1 year ago

I'm hitting a crash when I try to compile a (very slightly) more complicated OpenCL kernel with Clang 15.0.2: https://github.com/llvm/llvm-project/issues/58234

Unless they come up with a workaround, this may make LLVM 15 non-viable for our purposes.