AMD GCN Radeon Support in GCC 9
gcc.gnu.org
gcc.gnu.org
So to answer your question, you wouldn't really use C/C++ to target GCN. I think this is more akin to how CUDA works by using a dialect on top of C.
With few CUDA specific extensions.
"CppCon 2017: Olivier Giroux "Designing (New) C++ Hardware”" https://www.youtube.com/watch?v=86seb-iZCnI
Why not target SPIR-V for Vulkan driver?
Also, you still have the usual nasty issues of the GPU having a separate memory space from the CPU. This is just a code generation backend; not some transparent GPU system model for C/C++.
You see, the (not so) dirty secret of GCN is that from a very real perspective, the best way to think about it is that it's a bunch of CPU cores with extremely wide masked SIMD units.
Almost all GPU programming languages obscure that fact, and their compilers do magic behind the scenes to make it appear as if you were programming individual threads without SIMD.
GCC is the odd one out, which is really quite fascinating.
(e.g. slide 22)
Docs say that the performance depends on the actual distribution of pointers, i.e. for best performance you should ensure that the pointers are consecutive (use SoA instead of AoS layouts, etc.), but I imagine that the drop in performance is somewhat gradual and graceful as your pointers become more scattered. I don't think the details are really documented though, and I wouldn't be surprised if those details changed between GCN generations.
The bigger implication of the SIMD design is that for any conditional all your "threads" should take the same route, otherwise you may end up computing both paths for every thread.
This is not quite doing it justice. GPU threads allow for branching (which thus includes things like early return). They do loose performance because inactive branches are sleeping (although I didn't test this with Volta and onward, which is supposedly brings some improvements), but that's way better than just breaking vectorization outright. This makes it much easier to port some naive (or just cache-optimized) piece of numerics code to GPU rather than trying to vectorize it on CPU.
You can look at the actual hardware ISA, it's all documented e.g. here: https://rocm-documentation.readthedocs.io/en/latest/GCN_ISA_..., and both the HCC compiler and Mesa's OpenGL and Vulkan implementations are open-source and based on LLVM, where the backend is even upstream, so you can take a look for yourself.
Essentially everything those compilers do would be possible on a CPU with masked SIMD instructions (e.g. AVX512). In fact, that's basically how ISPC works. The one exception is that GCN has much more powerful scatter/gather support than CPUs do (and graphics-focused stuff like texture sampling hardware). But as far as the execution model is concerned, it's really the same.
Volta / Turing does branching per-PC now, but it is opt-in optional. In any case, I expect Volta / Turing to prefer the old SIMD model of compute.
The only reason Volta / Turing supports per-PC branching is to handle some multi-thread communication issues. The execution units are still SIMD, so you take a heavy penalty going to the per-PC model.
PS: I haven't actually programmed Volta/Turing, its just my understanding from the white paper.
AMD GCN has hardware accelerated masking + stacks for this purpose. AMD's GPU is basically a combination of masking + fork/join commands, to split up wavefronts.
But its really just hardware accelerated masks. You sometimes need to store the masks + program counters in a stack to allow for divergent threads, and then pop the masks off and execute older commands... (Complex if / then / else branches where every thread takes a different set of branches).
https://www.reddit.com/r/ROCm/comments/adyu5k/amd_rocm_hcc_p...
https://www.reddit.com/r/gpgpu/comments/adyxpi/musings_on_ve...
There's a 3rd story here: GCC's style is OpenMP 4.5. The big news is that the following kind of code is now possible:
#pragma omp target map(a,b,c,d)
{
#pragma parallel for
for(int i=0; i<1000000; i++){
a[i] = b[i] * c + d ;
}
}
The above code will run on the GPU. GCC, CLang, and other languages are trying to support OpenMP 4.5's ability to offload code to GPUs.That's what this GCC9 news is about: AMD GPUs are gaining the ability to execute the above code, integrated into OpenMP Tasks and all that good stuff.
That said, getting GCC to do a better job implementing code for those is a big step in that direction.
By the way; I'm confused trying to make sense of the effects of this patchset. In Andrew Stubbs' original e-mail, he states that the patchset which is discussed in this e-mail thread is for the "non-OpenACC/OpenMP portions" of the port. Not only that, but only C and Fortran are supported, C++ is explicitly unsupported, and everything else is untested.
So then, that means definite effects of implementing this patchset will be that the front-end which is non-OpenACC/OpenMP for C and Fortran will be operational, plus whatever the effects are of the patches with unspecified details for different areas (backend, config, and testsuite) which he mentioned briefly.
Given these definite effects, what are the noteworthy or most important effects of them? How much does this "power on" GCN?
Given that C++ now has a defined memory model, it might very well be that it's now impossible to implement C++ in a standard conforming way on exotic architectures.
Also C has a defined memory model since C11
> https://davmac.wordpress.com/2018/01/28/understanding-the-c-...
and it is the same as the memory model from C++11:
> https://en.wikipedia.org/w/index.php?title=Memory_model_(pro...
"After it was established that threads could not be implemented safely as a library without placing certain restrictions on the implementation and, in particular, that the C and C++ standards (C99 and C++03) lacked necessary restrictions, the C++ threading subcommittee set to work on suitable memory model; in 2005, they submitted C working document n1131 to get the C Committee on board with their efforts. The final revision of the proposed memory model, C++ n2429, was accepted into the C++ draft standard at the October 2007 meeting in Kona. The memory model was then included in the next C++ and C standards, C++11 and C11.".
Otherwise assuming no fancy features are used they are identical in their programming model.
Before that, intro-warp divergence combined with badly placed synchronization operations could result in hard hangs.
I don't think this makes a different in terms of raw low level performance, but it might have an impact in terms of implementation algorithms that require synchronization?
omp_target_alloc, omp_target_memcpy, omp_target-associate_ptr provide some other utility functions that you'd expect for these use cases. omp_target_memcpy can copy from host-to-device, device-to-host, or even device-to-device.
That is to say, I'd much rather optimize GPU kernels for things like sequential access, register use and programmable caches than make it vectorize on the various versions of AVX, treat multi-core parallelization separately and then fit everything into the fastest CPU cache possible just because the CPU's memory bandwidth is so damn slow.