0

I'd like to create a simple function for CPU features detection.
I need it for Run Time dispatching of code paths by the CPU features.

I'd like something really simple like:

hasSSE3(), hasSSE4(), hasAVX(), hasAVX2(), etc..

It has to be portable, namely supports Windows, macOS and Linux.
Work both on AMD and Intel CPU's.

For instance, how would one implement hasAVX()?

Remark
All I care about is x86 (And only 64 Bit CPU's).

Thank You.

Royi
  • 4,640
  • 6
  • 46
  • 64
  • GNU C (at least gcc, probably also clang and ICC) has `__builtin_cpu_supports("sse4"):` and so on https://stackoverflow.com/questions/17758409/intrinsics-for-cpuid-like-informations. Do you need it to be portable across different *compilers* like MSVC, as well as target platforms? – Peter Cordes Feb 18 '18 at 14:48
  • If you rephrase your question to just ask how to portably implement `hasSSE4()` and so on, without explicitly asking for a header, it would be on topic. The answer can be a library recommendation, but the question can't be explicitly phrased as a request for one. – Peter Cordes Feb 18 '18 at 14:52
  • 1
    @PeterCordes, I would like to be also compiler portable (MSVC, ICC, GCC) yet for starter I'd be happy with ICC. – Royi Feb 18 '18 at 15:34
  • @Carcigenicate, Edited question accordingly. – Royi Feb 18 '18 at 15:48
  • Then use `__builtin_cpu_supports`, assuming ICC does support that GNU extension. – Peter Cordes Feb 18 '18 at 15:49
  • 1
    @PeterCordes, ICC does not support that. With ICC use e.g. `_may_i_use_cpu_feature (_FEATURE_AVX))` https://software.intel.com/en-us/node/523363 – Z boson Feb 20 '18 at 10:22

2 Answers2

3

Unfortunately, this isn't really a simple task if you want it to be portable. Compilers usually have something to help you out, but the functions are all different.

MSVC has a __cpuid intrinsic on x86/x86_64, but of course it's not supported on ARM. TBH I'm not sure how to get CPU capabilities on MSVC targeting ARM (or any non-x86 arch).

Compilers other than MSVC generally masquerade as GCC, so most of them will support the __builtin_cpu_init/__bulitin_cpu_supports intrinsics.

For other compilers you may have to use inline assembly to generate a CPUID instruction and handle the results yourself. That gets you through x86/x86_64.

Things for other architectures are a bit more complicated. For ARM, the instruction to get CPU information isn't generally accessible to unprivileged code. For glibc, you can use getauxval with AT_HWCAP and/or AT_HWCAP2. For non-glibc Linux, you may have to parse /proc/self/auxv and/or /proc/cpuinfo.

One pretty robust solution is Google's new cpu_features library.

If you can sacrifice some portability, there is a cpu module in portable-snippets (which I wrote) which could help. It's not nearly as robust as cpu_features, but it's a lot easier to integrate into your project. It should work pretty much everywhere on x86/x86_64 CPUs, but ARM support is limited to glibc, and other architectures aren't yet supported.

nemequ
  • 16,623
  • 1
  • 43
  • 62
  • Hi, I don't care about ARM. Only x86 and only 64 Bit CPU's. – Royi Feb 18 '18 at 18:22
  • Your offer of Google is great. But I don't understand how to itegrate it into a project as 'h' and 'c' files. What's the needed structure? – Royi Feb 18 '18 at 18:26
  • Look at CMakeLists.txt to see how the project is built. How to integrate it with your build system depends on your build system and how you want to use it. – nemequ Feb 18 '18 at 18:31
  • I have the most simple C. All I wanted is to add one line of `#include ""` to an `h` file and have the functions. I'm not into building large system. Really small code to manipulate some array with some math. As you can guess, I'm not that experienced with `CMAKE` or other. I just click on build on the IDE. – Royi Feb 18 '18 at 19:03
  • Then cpu_features is probably too complicated for you. In order to support larger and more complicated codebases a build system is pretty much a requirement. Since there is no standard way to access the information you're interested in, the more portable the solution the larger and more complicated it will be. There is probably a way to integrate cpu_features into your IDE's build system, but that's a different question and the answer depends on your IDE. – nemequ Feb 18 '18 at 19:58
  • As far as I know only GCC supports `__bulitin_cpu_supports` currently. With ICC use e.g. `_may_i_use_cpu_feature (_FEATURE_AVX))`. I don't know of an option for Clang. – Z boson Feb 20 '18 at 12:00
  • Clang supports `__builtin_cpu_supports`. I'm pretty sure modern ICC does, too, but I can't check it right now. – nemequ Feb 20 '18 at 18:59
  • ICC supports `__builtin_cpu_supports`, too. – nemequ Feb 21 '18 at 01:01
1

It seems that Agner Fog's library - Vector Class Library (VCL) can do exactly that.
One should just include the vectorclass.h in his project and call instrset_detect().

Royi
  • 4,640
  • 6
  • 46
  • 64
  • 1
    Note that VCL's license is GPL, not LGPL. You can only use it in open-source projects compatible with the GPL. (Or projects where you never distribute the executable to anyone who doesn't also get source, e.g. as part of the back-end of an online service.) – Peter Cordes Feb 19 '18 at 03:36
  • 1
    Also, C++-only (unusable from C). – nemequ Feb 20 '18 at 03:36
  • See also https://stackoverflow.com/questions/38319245/what-is-the-minimum-version-of-os-x-for-use-with-avx-avx2/38345423#38345423 – Z boson Feb 20 '18 at 12:07
  • Update, VCL is now Apache licensed. – Peter Cordes Mar 24 '21 at 13:30