1 : /* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is SSE.cpp
16 : *
17 : * The Initial Developer of the Original Code is the Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2009
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * L. David Baron <dbaron@dbaron.org>, Mozilla Corporation (original author)
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /* compile-time and runtime tests for whether to use SSE instructions */
39 :
40 : #include "SSE.h"
41 :
42 : namespace {
43 :
44 : // SSE.h has parallel #ifs which declare MOZILLA_SSE_HAVE_CPUID_DETECTION.
45 : // We can't declare these functions in the header file, however, because
46 : // <intrin.h> conflicts with <windows.h> on MSVC 2005, and some files want to
47 : // include both SSE.h and <windows.h>.
48 :
49 : #ifdef HAVE_CPUID_H
50 :
51 : // cpuid.h is available on gcc 4.3 and higher on i386 and x86_64
52 : #include <cpuid.h>
53 :
54 : enum CPUIDRegister { eax = 0, ebx = 1, ecx = 2, edx = 3 };
55 :
56 : static bool
57 11712 : has_cpuid_bit(unsigned int level, CPUIDRegister reg, unsigned int bit)
58 : {
59 : unsigned int regs[4];
60 11712 : return __get_cpuid(level, ®s[0], ®s[1], ®s[2], ®s[3]) &&
61 11712 : (regs[reg] & bit);
62 : }
63 :
64 : #elif defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(_M_IX86) || defined(_M_AMD64))
65 :
66 : // MSVC 2005 or newer on x86-32 or x86-64
67 : #include <intrin.h>
68 :
69 : enum CPUIDRegister { eax = 0, ebx = 1, ecx = 2, edx = 3 };
70 :
71 : static bool
72 : has_cpuid_bit(unsigned int level, CPUIDRegister reg, unsigned int bit)
73 : {
74 : // Check that the level in question is supported.
75 : int regs[4];
76 : __cpuid(regs, level & 0x80000000u);
77 : if (unsigned(regs[0]) < level)
78 : return false;
79 :
80 : __cpuid(regs, level);
81 : return !!(unsigned(regs[reg]) & bit);
82 : }
83 :
84 : #elif defined(__SUNPRO_CC) && (defined(__i386) || defined(__x86_64__))
85 :
86 : enum CPUIDRegister { eax = 0, ebx = 1, ecx = 2, edx = 3 };
87 :
88 : #ifdef __i386
89 : static void
90 : moz_cpuid(int CPUInfo[4], int InfoType)
91 : {
92 : asm (
93 : "xchg %esi, %ebx\n"
94 : "cpuid\n"
95 : "movl %eax, (%edi)\n"
96 : "movl %ebx, 4(%edi)\n"
97 : "movl %ecx, 8(%edi)\n"
98 : "movl %edx, 12(%edi)\n"
99 : "xchg %esi, %ebx\n"
100 : :
101 : : "a"(InfoType), // %eax
102 : "D"(CPUInfo) // %edi
103 : : "%ecx", "%edx", "%esi"
104 : );
105 : }
106 : #else
107 : static void
108 : moz_cpuid(int CPUInfo[4], int InfoType)
109 : {
110 : asm (
111 : "xchg %rsi, %rbx\n"
112 : "cpuid\n"
113 : "movl %eax, (%rdi)\n"
114 : "movl %ebx, 4(%rdi)\n"
115 : "movl %ecx, 8(%rdi)\n"
116 : "movl %edx, 12(%rdi)\n"
117 : "xchg %rsi, %rbx\n"
118 : :
119 : : "a"(InfoType), // %eax
120 : "D"(CPUInfo) // %rdi
121 : : "%ecx", "%edx", "%rsi"
122 : );
123 : }
124 : #endif
125 :
126 : static bool
127 : has_cpuid_bit(unsigned int level, CPUIDRegister reg, unsigned int bit)
128 : {
129 : // Check that the level in question is supported.
130 : volatile int regs[4];
131 : moz_cpuid((int *)regs, level & 0x80000000u);
132 : if (unsigned(regs[0]) < level)
133 : return false;
134 :
135 : moz_cpuid((int *)regs, level);
136 : return !!(unsigned(regs[reg]) & bit);
137 : }
138 :
139 : #endif // end CPUID declarations
140 :
141 : }
142 :
143 : namespace mozilla {
144 :
145 : namespace sse_private {
146 :
147 : #if defined(MOZILLA_SSE_HAVE_CPUID_DETECTION)
148 :
149 : #if !defined(MOZILLA_PRESUME_MMX)
150 1464 : bool mmx_enabled = has_cpuid_bit(1u, edx, (1u<<23));
151 : #endif
152 :
153 : #if !defined(MOZILLA_PRESUME_SSE)
154 1464 : bool sse_enabled = has_cpuid_bit(1u, edx, (1u<<25));
155 : #endif
156 :
157 : #if !defined(MOZILLA_PRESUME_SSE2)
158 1464 : bool sse2_enabled = has_cpuid_bit(1u, edx, (1u<<26));
159 : #endif
160 :
161 : #if !defined(MOZILLA_PRESUME_SSE3)
162 1464 : bool sse3_enabled = has_cpuid_bit(1u, ecx, (1u<<0));
163 : #endif
164 :
165 : #if !defined(MOZILLA_PRESUME_SSSE3)
166 1464 : bool ssse3_enabled = has_cpuid_bit(1u, ecx, (1u<<9));
167 : #endif
168 :
169 : #if !defined(MOZILLA_PRESUME_SSE4A)
170 1464 : bool sse4a_enabled = has_cpuid_bit(0x80000001u, ecx, (1u<<6));
171 : #endif
172 :
173 : #if !defined(MOZILLA_PRESUME_SSE4_1)
174 1464 : bool sse4_1_enabled = has_cpuid_bit(1u, ecx, (1u<<19));
175 : #endif
176 :
177 : #if !defined(MOZILLA_PRESUME_SSE4_2)
178 1464 : bool sse4_2_enabled = has_cpuid_bit(1u, ecx, (1u<<20));
179 : #endif
180 :
181 : #endif
182 :
183 : } // namespace sse_private
184 4392 : } // namespace mozilla
|