GCC defines many macros to determine at compile-time whether a particular feature is supported by the microarchitecture specified using -march
. You can find the full list in the source code here. It's clear that GCC does not define such a macro for RDTSCP
(or even RDTSC
for that matter). The processors that support RDTSCP
are listed in: What is the gcc cpu-type that includes support for RDTSCP?.
So you can make your own (potentially incomplete) list microarchitectures that support RDTSCP
. Then write a build script that checks the argument passed to -march
and see if it is in the list. If it is, then define a macro such as __RDTSCP__
and use it in your code. I presume that even if your list is incomplete, this should not compromise the correctness of your code.
Unfortunately, the Intel datasheets do not seem to specify whether a particular processor supports RDTSCP
even though they discuss other features such as AVX2.
One potential problem here is that there is no guarantee that every single processor that implements a particular microarchitecture, such as Skylake, supports RDTSCP
. I'm not aware of such exceptions though.
Related: What is the gcc cpu-type that includes support for RDTSCP?.
To determine RDTSCP support at run-time, the following code can be used on compilers supporting GNU extensions (GCC, clang, ICC), on any x86 OS. cpuid.h
comes with the compiler, not the OS.
#include <cpuid.h>
int rdtscp_supported(void) {
unsigned a, b, c, d;
if (__get_cpuid(0x80000001, &a, &b, &c, &d) && (d & (1<<27)))
{
// RDTSCP is supported.
return 1;
}
else
{
// RDTSCP is not supported.
return 0;
}
}
__get_cpuid()
runs CPUID twice: once to check max level, once with the specified leaf value. It returns false if the requested level isn't even available, that's why it's part of a &&
expression. You probably don't want to use this every time before rdtscp, just as an initializer for a variable unless it's just a simple one-off program. See it on the Godbolt compiler explorer.
For MSVC, see How to detect rdtscp support in Visual C++? for code using its intrinsic.
For some CPU features that GCC does know about, you can use __builtin_cpu_supports
to check a feature bitmap that's initialized early in startup.
// unfortunately no equivalent for RDTSCP
int sse42_supported() {
return __builtin_cpu_supports("sse4.2");
}