3
votes

So, here is what I am trying to accomplish. In my C++ project that has to be compiled with Microsoft Visual Studio 2015 or above, I need to have some code have different versions depending on the newest SIMD instrunction set available in the CPU of the user, among: SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, AVX2 and AVX512.

Since what I am look for at this point is compile-time CPU dispatching, my first guess was that it could be easily accomplished using compiler macros. However, to my astonishment, it has been quite hard to find information on how to achieve such CPU dispatching with macros in VS2015.

For instance, the former question "Detect the availability of SSE/SSE2 instruction set in Visual Studio" has information on how to detect SSE and SSE2 for x86 code, but not for x64 code. Although, they make a reference to this Microsoft's document: http://msdn.microsoft.com/en-us/library/b0084kay.aspx

There, we only have information on how to detect whether SSE, SSE2, AVX and AVX2 are enabled in the compiler - not exactly whether they are supported by CPU. Also, there is nothing at all about the other instrunction sets, like SSE3, SSSE3, SSE4.1, SSE4.2 and AVX512.

So, my question becomes: how can I detect whether the user's CPU supports those instrunction sets via macro, just like other compilers do, but with Microsoft Visual Studio 2015?

1
Unless you're only going to run on the same machine you compile on, the set of supported CPU features is not a compile-time constant, and thus can't be a macro. But if you are, just do whatever the MSVC-equivalent of gcc's -march=native is, and look at the usual target-feature macros like #ifdef __AVX__Peter Cordes
@PeterCordes But that is exactly the problem. There are no macros besides __AVX__ and __AVX2__. The whole point of my question is precisely to investigate how people have achieved that because Vistual Studio seems to lack such macros.AndrewSteer
@PeterCordes As weird as it may be, that seems to be the case. The list of macros for MSVC only include macros for AVX and AVX2. And as linked in the question, an indirect macro for SSE2. That's the origin of my question: it's very hard to find information on this. About your question, I need both. For this part, I need compile time dispatching. But for other parts, I need runtime-dispatching - in which case I am using__cpuid as per Intel's manual and it works well for most part.AndrewSteer
For them to enabled, of couse CPU supports them. The problem here is saying "the CPU", like there was only one. If you're running the compiler on an old computer, building a binary that only needs to run on a new computer, you would enable AVX. The resulting binary won't run on the computer that built it, but it can create it just fine. In build-system and compiler terminology, we talk about "target" vs. "host". So enabling AVX is a target option, and macros can detect what's baseline for your target (i.e. enabled for use by the compiler).Peter Cordes
"Microsoft's macros for VS detect whether AVX or AVX2 are enabled in the options. For them to enabled, of couse CPU supports them. " No, that's a mistake. You can compile AVX code on a non-AVX CPU. "Compiling AVX code" just means that the compiler emits byte strings which encode AVX operations. Compiling doesn't involve executing the emitted byte strings.MSalters

1 Answers

1
votes

The problem you're facing is that Visual Studio historically is intended for software vendors. The idea that you compile your own software simply isn't in Microsoft's DNA.

The practical result is that Microsoft hardly cares about the processor of the build machine. That's unlikely to be the processor used to run the software.

On the upside, this also means that Microsoft doesn't suffer from the perennial Linux problem that the build system libraries are assumed to be present on the target machine. Building on Windows 10 for Windows 7 just works.

The compiler also doesn't allow you to enable up to SSE4.1, for example. You can only use /arch:avx or nothing. Also, that option only defines __AVX__, not the usual macros like __SSSE3__ that gcc/clang/icc define to indicate target support for previous instruction sets implied by AVX.