sdl2-compat: implemented SDL_HasRDTSC

From 813d840e4208981da41d63006fe09e491aa35daf Mon Sep 17 00:00:00 2001
From: Ozkan Sezer <[EMAIL REDACTED]>
Date: Sat, 1 Apr 2023 14:10:10 +0300
Subject: [PATCH] implemented SDL_HasRDTSC

---
 src/sdl2_compat.c | 116 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 114 insertions(+), 2 deletions(-)

diff --git a/src/sdl2_compat.c b/src/sdl2_compat.c
index b7e9657..0e22227 100644
--- a/src/sdl2_compat.c
+++ b/src/sdl2_compat.c
@@ -4374,6 +4374,104 @@ SDL_Vulkan_GetInstanceExtensions(SDL_Window *window, unsigned int *pCount, const
 
 
 /* SDL3 doesn't have 3dNow or RDTSC. */
+static int
+CPU_haveCPUID(void)
+{
+    int has_CPUID = 0;
+
+/* *INDENT-OFF* */
+#ifndef SDL_CPUINFO_DISABLED
+#if (defined(__GNUC__) || defined(__llvm__)) && defined(__i386__)
+    __asm__ (
+"        pushfl                      # Get original EFLAGS             \n"
+"        popl    %%eax                                                 \n"
+"        movl    %%eax,%%ecx                                           \n"
+"        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
+"        pushl   %%eax               # Save new EFLAGS value on stack  \n"
+"        popfl                       # Replace current EFLAGS value    \n"
+"        pushfl                      # Get new EFLAGS                  \n"
+"        popl    %%eax               # Store new EFLAGS in EAX         \n"
+"        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
+"        jz      1f                  # Processor=80486                 \n"
+"        movl    $1,%0               # We have CPUID support           \n"
+"1:                                                                    \n"
+    : "=m" (has_CPUID)
+    :
+    : "%eax", "%ecx"
+    );
+#elif (defined(__GNUC__) || defined(__llvm__)) && defined(__x86_64__)
+/* Technically, if this is being compiled under __x86_64__ then it has 
+   CPUid by definition.  But it's nice to be able to prove it.  :)      */
+    __asm__ (
+"        pushfq                      # Get original EFLAGS             \n"
+"        popq    %%rax                                                 \n"
+"        movq    %%rax,%%rcx                                           \n"
+"        xorl    $0x200000,%%eax     # Flip ID bit in EFLAGS           \n"
+"        pushq   %%rax               # Save new EFLAGS value on stack  \n"
+"        popfq                       # Replace current EFLAGS value    \n"
+"        pushfq                      # Get new EFLAGS                  \n"
+"        popq    %%rax               # Store new EFLAGS in EAX         \n"
+"        xorl    %%ecx,%%eax         # Can not toggle ID bit,          \n"
+"        jz      1f                  # Processor=80486                 \n"
+"        movl    $1,%0               # We have CPUID support           \n"
+"1:                                                                    \n"
+    : "=m" (has_CPUID)
+    :
+    : "%rax", "%rcx"
+    );
+#elif (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__)
+    __asm {
+        pushfd                      ; Get original EFLAGS
+        pop     eax
+        mov     ecx, eax
+        xor     eax, 200000h        ; Flip ID bit in EFLAGS
+        push    eax                 ; Save new EFLAGS value on stack
+        popfd                       ; Replace current EFLAGS value
+        pushfd                      ; Get new EFLAGS
+        pop     eax                 ; Store new EFLAGS in EAX
+        xor     eax, ecx            ; Can not toggle ID bit,
+        jz      done                ; Processor=80486
+        mov     has_CPUID,1         ; We have CPUID support
+done:
+    }
+#elif defined(_MSC_VER) && defined(_M_X64)
+    has_CPUID = 1;
+#elif defined(__sun) && defined(__i386)
+    __asm (
+"       pushfl                 \n"
+"       popl    %eax           \n"
+"       movl    %eax,%ecx      \n"
+"       xorl    $0x200000,%eax \n"
+"       pushl   %eax           \n"
+"       popfl                  \n"
+"       pushfl                 \n"
+"       popl    %eax           \n"
+"       xorl    %ecx,%eax      \n"
+"       jz      1f             \n"
+"       movl    $1,-8(%ebp)    \n"
+"1:                            \n"
+    );
+#elif defined(__sun) && defined(__amd64)
+    __asm (
+"       pushfq                 \n"
+"       popq    %rax           \n"
+"       movq    %rax,%rcx      \n"
+"       xorl    $0x200000,%eax \n"
+"       pushq   %rax           \n"
+"       popfq                  \n"
+"       pushfq                 \n"
+"       popq    %rax           \n"
+"       xorl    %ecx,%eax      \n"
+"       jz      1f             \n"
+"       movl    $1,-8(%rbp)    \n"
+"1:                            \n"
+    );
+#endif
+#endif
+/* *INDENT-ON* */
+    return has_CPUID;
+}
+
 #if (defined(__GNUC__) || defined(__llvm__)) && defined(__i386__)
 #define cpuid(func, a, b, c, d) \
     __asm__ __volatile__ ( \
@@ -4439,8 +4537,22 @@ SDL_Has3DNow(void)
 DECLSPEC SDL_bool SDLCALL
 SDL_HasRDTSC(void)
 {
-    /* FIXME */
-    return SDL_FALSE;
+    static SDL_bool checked = SDL_FALSE;
+    static SDL_bool has_RDTSC = SDL_FALSE;
+    if (!checked) {
+        checked = SDL_TRUE;
+        if (CPU_haveCPUID()) {
+            int a, b, c, d;
+            cpuid(0, a, b, c, d);
+            if (a /* CPUIDMaxFunction */ >= 1) {
+                cpuid(1, a, b, c, d);
+                if (d & 0x00000010) {
+                    has_RDTSC = SDL_TRUE;
+                }
+            }
+        }
+    }
+    return has_RDTSC;
 }