Fixed gcc inline assembly issue with PIC and older gcc compilers
authorErik Lindahl <erik@kth.se>
Thu, 21 Jun 2012 09:38:12 +0000 (11:38 +0200)
committerErik Lindahl <erik@kth.se>
Thu, 21 Jun 2012 18:51:10 +0000 (20:51 +0200)
Some gcc versions had problems with the recently introduced inline
assembly for cpuid (clobbering of ebx register), and since we used
a slightly different inline assembly instruction test in cmake we
did not detect it properly. This patch both makes the inline asm
itself much more portable, and we also test with exactly the same
instruction in cmake so we don't set the flag for supporting inline
asm unless we know this instruction works.

Change-Id: Ib479e2706024abb5e3f66d0249291ce55f1257b1

cmake/TestInlineASM_gcc_x86.c
cmake/gmxDetectAcceleration.cmake
cmake/gmxTestInlineASM.cmake
src/gmxlib/gmx_detectcpu.c

index 824489fafaf46bbaa801c4d77d33b95176e2f64c..152cddfafd63ca46fde188ab9c92ae356b715313 100644 (file)
@@ -1,9 +1,23 @@
 int
 main()
 {
-  float f;
-  int i; 
+  unsigned int _eax,_ebx,_ecx,_edx;
+  unsigned int level = 0;
+
   /* Test gcc inline asm for x86 */
-  asm("fld %1\nfistpl %0\n" : "=m" (*&i) : "f" (f));
+#if defined (__x86_64__) || defined (_M_X64)
+    __asm__("push %%rbx       \n\t"
+            "cpuid            \n\t"
+            "movl %%ebx, %1   \n\t"
+            "pop %%rbx        \n\t"
+            : "=a"(_eax), "=r"(_ebx), "=c"(_ecx), "=d"(_edx) : "0"(level));
+#else
+    __asm__("push %%ebx       \n\t"
+            "cpuid            \n\t"
+            "movl %%ebx, %1   \n\t"
+            "pop %%ebx        \n\t"
+            : "=a"(_eax), "=r"(_ebx), "=c"(_ecx), "=d"(_edx) : "0"(level));
+#endif
+
   return 0;
 }    
index 7f707bf06e4f0509a6023708b19a2f535b345e12..dbe18b242877da413a98e5d0121cce012dd5fc89 100644 (file)
@@ -29,7 +29,16 @@ macro(gmx_detect_acceleration GMX_SUGGESTED_ACCELERATION)
             ${CMAKE_BINARY_DIR}
             ${CMAKE_SOURCE_DIR}/src/gmxlib/gmx_detectcpu.c
             COMPILE_DEFINITIONS "@GCC_INLINE_ASM_DEFINE@ -I${CMAKE_SOURCE_DIR}/include -DGMX_DETECTCPU_STANDALONE"
-            RUN_OUTPUT_VARIABLE OUTPUT_TMP ARGS "-acceleration")
+            RUN_OUTPUT_VARIABLE OUTPUT_TMP
+            COMPILE_OUTPUT_VARIABLE GMX_DETECTCPU_COMPILE_OUTPUT 
+            ARGS "-acceleration")
+
+    if(NOT GMX_DETECTCPU_COMPILED)
+        message(WARNING "Cannot compile CPU detection code, which means no optimization.")
+        message(STATUS "Compile output: ${GMX_DETECTCPU_COMPILE_OUTPUT}")
+        set(OUTPUT_TMP "None")
+    endif(NOT GMX_DETECTCPU_COMPILED)
+
     string(STRIP "@OUTPUT_TMP@" OUTPUT_ACC)
 
     message(STATUS "Detecting best acceleration for this CPU - @OUTPUT_ACC@")
index 5934901484b23f07a308cfeb006c9c4e4d81b955..bb5669df17387543826f5a8c5903150b2f26c981 100644 (file)
@@ -12,7 +12,8 @@ MACRO(GMX_TEST_INLINE_ASM_GCC_X86 VARIABLE)
         MESSAGE(STATUS "Checking for GCC x86 inline asm")
 
         TRY_COMPILE(${VARIABLE} "${CMAKE_BINARY_DIR}"    
-                    "${CMAKE_SOURCE_DIR}/cmake/TestInlineASM_gcc_x86.c")
+                    "${CMAKE_SOURCE_DIR}/cmake/TestInlineASM_gcc_x86.c"
+                    OUTPUT_VARIABLE INLINE_ASM_COMPILE_OUTPUT)
 
         if(${VARIABLE})
             MESSAGE(STATUS "Checking for GCC x86 inline asm - supported")
@@ -22,7 +23,6 @@ MACRO(GMX_TEST_INLINE_ASM_GCC_X86 VARIABLE)
             set(${VARIABLE} 0 CACHE INTERNAL "Result of test for GCC x86 inline asm" FORCE)
        endif(${VARIABLE})
 
-
     ENDIF(NOT DEFINED ${VARIABLE})
 ENDMACRO(GMX_TEST_INLINE_ASM_GCC_X86 VARIABLE)
 
index e0c998e4bc00524ae3985276dbd3f3998629f86b..d58d34bd29037580680fad7ecbb2bda97f983a1e 100644 (file)
@@ -117,10 +117,11 @@ execute_cpuid_x86(unsigned int level,
                   unsigned int * edx)
 {
     unsigned int _eax,_ebx,_ecx,_edx;
-    int CPUInfo[4];
     int rc;
 
 #ifdef _MSC_VER
+    int CPUInfo[4];
+
     /* MSVC */
     __cpuid(CPUInfo,level);
 
@@ -136,8 +137,20 @@ execute_cpuid_x86(unsigned int level,
      * but there might be more options added in the future.
      */
     /* tested on 32 & 64 GCC, and Intel icc. */
-    __asm__("cpuid" : "=a"(_eax), "=b"(_ebx), "=c"(_ecx), "=d"(_edx) : "0"(level));
-
+#if defined (__x86_64__) || defined (_M_X64)
+    __asm__("push  %%rbx      \n\t"
+            "cpuid            \n\t"
+            "movl %%ebx, %1   \n\t"
+            "pop  %%rbx       \n\t"
+            : "=a"(_eax), "=r"(_ebx), "=c"(_ecx), "=d"(_edx) : "0"(level));
+#else
+    __asm__("push %%ebx       \n\t"
+            "cpuid            \n\t"
+            "movl %%ebx, %1   \n\t"
+            "pop %%ebx        \n\t"
+            : "=a"(_eax), "=r"(_ebx), "=c"(_ecx), "=d"(_edx) : "0"(level));
+#endif
+    
     rc = 0;
 #endif
     /* If you end up having a compiler that really doesn't understand this and
@@ -251,8 +264,6 @@ detectcpu_amd(gmx_detectcpu_t *              data)
 {
     int                       max_stdfn,max_extfn;
     unsigned int              eax,ebx,ecx,edx;
-    char                      str[GMX_DETECTCPU_STRLEN];
-    char *                    p;
 
     detectcpu_common_x86(data);
 
@@ -281,8 +292,6 @@ detectcpu_intel(gmx_detectcpu_t *              data)
 {
     int                       max_stdfn;
     unsigned int              eax,ebx,ecx,edx;
-    char                      str[GMX_DETECTCPU_STRLEN];
-    char *                    p;
 
     detectcpu_common_x86(data);
 
@@ -310,7 +319,6 @@ detectcpu_vendor(void)
     gmx_detectcpu_vendorid_t   i,vendor;
     /* Register data used on x86 */
     unsigned int               eax,ebx,ecx,edx;
-    unsigned int *             p;
     char                       vendorstring[13];
 
     /* Set default first */
@@ -539,7 +547,6 @@ main(int argc, char **argv)
 {
     gmx_detectcpu_t               data;
     gmx_detectcpu_acceleration_t  acc;
-    char                          str[1024];
     int                           i,cnt;
 
     if(argc<2)