2 * This file is part of the KDE libraries
3 * Copyright (C) 2003 Fredrik Höglund <fredrik@kde.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <config-workspace.h>
34 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
35 # define HAVE_GNU_INLINE_ASM
39 // Copied from kdecore/kglobal.h
40 #if __GNUC__ - 0 > 3 || (__GNUC__ - 0 == 3 && __GNUC_MINOR__ - 0 > 2)
41 # define KDE_NO_EXPORT __attribute__ ((visibility("hidden")))
43 # define KDE_NO_EXPORT
46 typedef void (*kde_sighandler_t
) (int);
52 // Sighandler for the SSE OS support check
53 static void sighandler( int )
55 std::longjmp( env
, 1 );
61 static sigjmp_buf jmpbuf
;
62 static sig_atomic_t canjump
= 0;
64 static void sigill_handler( int sig
)
67 signal( sig
, SIG_DFL
);
71 siglongjmp( jmpbuf
, 1 );
75 static int getCpuFeatures()
77 volatile int features
= 0;
79 #if defined( HAVE_GNU_INLINE_ASM )
80 #if defined( __i386__ )
81 bool haveCPUID
= false;
82 bool have3DNOW
= false;
85 // First check if the CPU supports the CPUID instruction
87 // Try to toggle the CPUID bit in the EFLAGS register
88 "pushf \n\t" // Push the EFLAGS register onto the stack
89 "popl %%ecx \n\t" // Pop the value into ECX
90 "movl %%ecx, %%edx \n\t" // Copy ECX to EDX
91 "xorl $0x00200000, %%ecx \n\t" // Toggle bit 21 (CPUID) in ECX
92 "pushl %%ecx \n\t" // Push the modified value onto the stack
93 "popf \n\t" // Pop it back into EFLAGS
95 // Check if the CPUID bit was successfully toggled
96 "pushf \n\t" // Push EFLAGS back onto the stack
97 "popl %%ecx \n\t" // Pop the value into ECX
98 "xorl %%eax, %%eax \n\t" // Zero out the EAX register
99 "cmpl %%ecx, %%edx \n\t" // Compare ECX with EDX
100 "je .Lno_cpuid_support%= \n\t" // Jump if they're identical
101 "movl $1, %%eax \n\t" // Set EAX to true
102 ".Lno_cpuid_support%=: \n\t"
103 : "=a"(haveCPUID
) : : "%ecx", "%edx" );
105 // If we don't have CPUID we won't have the other extensions either
109 // Execute CPUID with the feature request bit set
110 __asm__
__volatile__(
111 "pushl %%ebx \n\t" // Save EBX
112 "movl $1, %%eax \n\t" // Set EAX to 1 (features request)
113 "cpuid \n\t" // Call CPUID
114 "popl %%ebx \n\t" // Restore EBX
115 : "=d"(result
) : : "%eax", "%ecx" );
117 // Test bit 23 (MMX support)
118 if ( result
& 0x00800000 )
119 features
|= KCPUInfo::IntelMMX
;
121 __asm__
__volatile__(
123 "movl $0x80000000, %%eax \n\t"
125 "cmpl $0x80000000, %%eax \n\t"
126 "jbe .Lno_extended%= \n\t"
127 "movl $0x80000001, %%eax \n\t"
129 "test $0x80000000, %%edx \n\t"
130 "jz .Lno_extended%= \n\t"
131 "movl $1, %%eax \n\t" // // Set EAX to true
132 ".Lno_extended%=: \n\t"
133 "popl %%ebx \n\t" // Restore EBX
134 : "=a"(have3DNOW
) : );
137 features
|= KCPUInfo::AMD3DNOW
;
140 // Test bit 25 (SSE support)
141 if ( result
& 0x00200000 ) {
142 features
|= KCPUInfo::IntelSSE
;
144 // OS support test for SSE.
145 // Install our own sighandler for SIGILL.
146 kde_sighandler_t oldhandler
= std::signal( SIGILL
, sighandler
);
148 // Try executing an SSE insn to see if we get a SIGILL
150 features
^= KCPUInfo::IntelSSE
; // The OS support test failed
152 __asm__
__volatile__("xorps %xmm0, %xmm0");
154 // Restore the default sighandler
155 std::signal( SIGILL
, oldhandler
);
157 // Test bit 26 (SSE2 support)
158 if ( (result
& 0x00400000) && (features
& KCPUInfo::IntelSSE
) )
159 features
|= KCPUInfo::IntelSSE2
;
161 // Note: The OS requirements for SSE2 are the same as for SSE
162 // so we don't have to do any additional tests for that.
164 #endif // HAVE_X86_SSE
165 #elif defined __PPC__ && defined HAVE_PPC_ALTIVEC
166 signal( SIGILL
, sigill_handler
);
167 if ( sigsetjmp( jmpbuf
, 1 ) ) {
168 signal( SIGILL
, SIG_DFL
);
171 __asm__
__volatile__( "mtspr 256, %0\n\t"
172 "vand %%v0, %%v0, %%v0"
175 signal( SIGILL
, SIG_DFL
);
176 features
|= KCPUInfo::AltiVec
;
179 #endif //HAVE_GNU_INLINE_ASM
184 unsigned int KCPUInfo::s_features
= getCpuFeatures();