Commit 2dab5d90 by Ian Lance Taylor

runtime: use a fence instruction before rdtsc

    
    This implements the same choices made in the gc runtime, except that
    for 32-bit x86 we only use the fence instruction if the processor
    supports SSE2.
    
    The code here is hacked up for speed; the gc runtime uses straight
    assembler.
    
    Reviewed-on: https://go-review.googlesource.com/97715

From-SVN: r258336
parent 6cde8c54
3287064c24cbf0c50776cdb87a720d29130b4363 2a07cd31927ac943104f55d2b696e53e7cd073b3
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -33,13 +33,47 @@ runtime_atoi(const byte *p, intgo len) ...@@ -33,13 +33,47 @@ runtime_atoi(const byte *p, intgo len)
return n; return n;
} }
#if defined(__i386__) || defined(__x86_64__) || defined (__s390__) || defined (__s390x__)
// When cputicks is just asm instructions, skip the split stack
// prologue for speed.
int64 runtime_cputicks(void) __attribute__((no_split_stack));
#endif
// Whether the processor supports SSE2.
#if defined (__i386__)
static _Bool hasSSE2;
// Force appropriate CPU level so that we can call the lfence/mfence
// builtins.
#pragma GCC push_options
#pragma GCC target("sse2")
#elif defined(__x86_64__)
#define hasSSE2 true
#endif
#if defined(__i386__) || defined(__x86_64__)
// Whether to use lfence, as opposed to mfence.
// Set based on cpuid.
static _Bool lfenceBeforeRdtsc;
#endif // defined(__i386__) || defined(__x86_64__)
int64 int64
runtime_cputicks(void) runtime_cputicks(void)
{ {
#if defined(__386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
uint32 low, high; if (hasSSE2) {
asm("rdtsc" : "=a" (low), "=d" (high)); if (lfenceBeforeRdtsc) {
return (int64)(((uint64)high << 32) | (uint64)low); __builtin_ia32_lfence();
} else {
__builtin_ia32_mfence();
}
}
return __builtin_ia32_rdtsc();
#elif defined (__s390__) || defined (__s390x__) #elif defined (__s390__) || defined (__s390x__)
uint64 clock = 0; uint64 clock = 0;
/* stckf may not write the return variable in case of a clock error, so make /* stckf may not write the return variable in case of a clock error, so make
...@@ -56,6 +90,10 @@ runtime_cputicks(void) ...@@ -56,6 +90,10 @@ runtime_cputicks(void)
#endif #endif
} }
#if defined(__i386__)
#pragma GCC pop_options
#endif
void void
runtime_signalstack(byte *p, uintptr n) runtime_signalstack(byte *p, uintptr n)
{ {
...@@ -146,8 +184,21 @@ runtime_cpuinit() ...@@ -146,8 +184,21 @@ runtime_cpuinit()
#if defined(__i386__) || defined(__x86_64__) #if defined(__i386__) || defined(__x86_64__)
unsigned int eax, ebx, ecx, edx; unsigned int eax, ebx, ecx, edx;
if (__get_cpuid(0, &eax, &ebx, &ecx, &edx)) {
if (eax != 0
&& ebx == 0x756E6547 // "Genu"
&& edx == 0x49656E69 // "ineI"
&& ecx == 0x6C65746E) { // "ntel"
lfenceBeforeRdtsc = true;
}
}
if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
setCpuidECX(ecx); setCpuidECX(ecx);
#if defined(__i386__)
if ((edx & bit_SSE2) != 0) {
hasSSE2 = true;
}
#endif
} }
#if defined(HAVE_AS_X86_AES) #if defined(HAVE_AS_X86_AES)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment