1 /* Subroutines for the gcc driver.
2 Copyright (C) 2006 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to
18 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include <stdlib.h>
26
27 const char *host_detect_local_cpu (int argc, const char **argv);
28
29 #ifdef GCC_VERSION
30 #define cpuid(num,a,b,c,d) \
31 asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \
32 : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
33 : "0" (num))
34
35 #define bit_CMPXCHG8B (1 << 8)
36 #define bit_CMOV (1 << 15)
37 #define bit_MMX (1 << 23)
38 #define bit_SSE (1 << 25)
39 #define bit_SSE2 (1 << 26)
40
41 #define bit_SSE3 (1 << 0)
42 #define bit_CMPXCHG16B (1 << 13)
43
44 #define bit_3DNOW (1 << 31)
45 #define bit_3DNOWP (1 << 30)
46 #define bit_LM (1 << 29)
47
48 /* This will be called by the spec parser in gcc.c when it sees
49 a %:local_cpu_detect(args) construct. Currently it will be called
50 with either "arch" or "tune" as argument depending on if -march=native
51 or -mtune=native is to be substituted.
52
53 It returns a string containing new command line parameters to be
54 put at the place of the above two options, depending on what CPU
55 this is executed. E.g. "-march=k8" on an AMD64 machine
56 for -march=native.
57
58 ARGC and ARGV are set depending on the actual arguments given
59 in the spec. */
host_detect_local_cpu(int argc,const char ** argv)60 const char *host_detect_local_cpu (int argc, const char **argv)
61 {
62 const char *cpu = NULL;
63 enum processor_type processor = PROCESSOR_I386;
64 unsigned int eax, ebx, ecx, edx;
65 unsigned int max_level;
66 unsigned int vendor;
67 unsigned int ext_level;
68 unsigned char has_mmx = 0, has_3dnow = 0, has_3dnowp = 0, has_sse = 0;
69 unsigned char has_sse2 = 0, has_sse3 = 0, has_cmov = 0;
70 unsigned char has_longmode = 0, has_cmpxchg8b = 0;
71 unsigned char is_amd = 0;
72 unsigned int family = 0;
73 bool arch;
74
75 if (argc < 1)
76 return NULL;
77
78 arch = strcmp (argv[0], "arch") == 0;
79 if (!arch && strcmp (argv[0], "tune"))
80 return NULL;
81
82 #ifndef __x86_64__
83 /* See if we can use cpuid. */
84 asm volatile ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;"
85 "pushl %0; popfl; pushfl; popl %0; popfl"
86 : "=&r" (eax), "=&r" (ebx)
87 : "i" (0x00200000));
88
89 if (((eax ^ ebx) & 0x00200000) == 0)
90 goto done;
91 #endif
92
93 processor = PROCESSOR_PENTIUM;
94
95 /* Check the highest input value for eax. */
96 cpuid (0, eax, ebx, ecx, edx);
97 max_level = eax;
98 /* We only look at the first four characters. */
99 vendor = ebx;
100 if (max_level == 0)
101 goto done;
102
103 cpuid (1, eax, ebx, ecx, edx);
104 has_cmpxchg8b = !!(edx & bit_CMPXCHG8B);
105 has_cmov = !!(edx & bit_CMOV);
106 has_mmx = !!(edx & bit_MMX);
107 has_sse = !!(edx & bit_SSE);
108 has_sse2 = !!(edx & bit_SSE2);
109 has_sse3 = !!(ecx & bit_SSE3);
110 /* We don't care for extended family. */
111 family = (eax >> 8) & ~(1 << 4);
112
113 cpuid (0x80000000, eax, ebx, ecx, edx);
114 ext_level = eax;
115 if (ext_level >= 0x80000000)
116 {
117 cpuid (0x80000001, eax, ebx, ecx, edx);
118 has_3dnow = !!(edx & bit_3DNOW);
119 has_3dnowp = !!(edx & bit_3DNOWP);
120 has_longmode = !!(edx & bit_LM);
121 }
122
123 is_amd = vendor == *(unsigned int*)"Auth";
124
125 if (is_amd)
126 {
127 if (has_mmx)
128 processor = PROCESSOR_K6;
129 if (has_3dnowp)
130 processor = PROCESSOR_ATHLON;
131 if (has_sse2 || has_longmode)
132 processor = PROCESSOR_K8;
133 }
134 else
135 {
136 switch (family)
137 {
138 case 5:
139 /* Default is PROCESSOR_PENTIUM. */
140 break;
141 case 6:
142 processor = PROCESSOR_PENTIUMPRO;
143 break;
144 case 15:
145 processor = PROCESSOR_PENTIUM4;
146 break;
147 default:
148 /* We have no idea. Use something reasonable. */
149 if (arch)
150 {
151 if (has_sse3)
152 {
153 if (has_longmode)
154 cpu = "nocona";
155 else
156 cpu = "prescott";
157 }
158 else if (has_sse2)
159 cpu = "pentium4";
160 else if (has_cmov)
161 cpu = "pentiumpro";
162 else if (has_mmx)
163 cpu = "pentium-mmx";
164 else if (has_cmpxchg8b)
165 cpu = "pentium";
166 else
167 cpu = "i386";
168 }
169 else
170 cpu = "generic";
171 goto done;
172 break;
173 }
174 }
175
176 switch (processor)
177 {
178 case PROCESSOR_I386:
179 cpu = "i386";
180 break;
181 case PROCESSOR_I486:
182 cpu = "i486";
183 break;
184 case PROCESSOR_PENTIUM:
185 if (has_mmx)
186 cpu = "pentium-mmx";
187 else
188 cpu = "pentium";
189 break;
190 case PROCESSOR_PENTIUMPRO:
191 if (arch)
192 {
193 if (has_sse3)
194 {
195 if (has_longmode)
196 {
197 /* It is Core 2 Duo. */
198 cpu = "nocona";
199 }
200 else
201 {
202 /* It is Core Duo. */
203 cpu = "prescott";
204 }
205 }
206 else if (has_sse2)
207 {
208 /* It is Pentium M. */
209 cpu = "pentium4";
210 }
211 else if (has_sse)
212 {
213 /* It is Pentium III. */
214 cpu = "pentium3";
215 }
216 else if (has_mmx)
217 {
218 /* It is Pentium II. */
219 cpu = "pentium2";
220 }
221 else
222 {
223 /* Default to Pentium Pro. */
224 cpu = "pentiumpro";
225 }
226 }
227 else
228 {
229 /* For -mtune, we default to -mtune=generic. */
230 cpu = "generic";
231 }
232 break;
233 case PROCESSOR_K6:
234 if (has_3dnow)
235 cpu = "k6-3";
236 else
237 cpu = "k6";
238 break;
239 case PROCESSOR_ATHLON:
240 if (has_sse)
241 cpu = "athlon-4";
242 else
243 cpu = "athlon";
244 break;
245 case PROCESSOR_PENTIUM4:
246 if (has_sse3)
247 {
248 if (has_longmode)
249 cpu = "nocona";
250 else
251 cpu = "prescott";
252 }
253 else
254 cpu = "pentium4";
255 break;
256 case PROCESSOR_K8:
257 cpu = "k8";
258 break;
259 case PROCESSOR_NOCONA:
260 cpu = "nocona";
261 break;
262 case PROCESSOR_GENERIC32:
263 case PROCESSOR_GENERIC64:
264 cpu = "generic";
265 break;
266 default:
267 abort ();
268 break;
269 }
270
271 done:
272 return concat ("-m", argv[0], "=", cpu, NULL);
273 }
274 #else
275 /* If we aren't compiling with GCC we just provide a minimal
276 default value. */
host_detect_local_cpu(int argc,const char ** argv)277 const char *host_detect_local_cpu (int argc, const char **argv)
278 {
279 const char *cpu;
280 bool arch;
281
282 if (argc < 1)
283 return NULL;
284
285 arch = strcmp (argv[0], "arch") == 0;
286 if (!arch && strcmp (argv[0], "tune"))
287 return NULL;
288
289 if (arch)
290 {
291 /* FIXME: i386 is wrong for 64bit compiler. How can we tell if
292 we are generating 64bit or 32bit code? */
293 cpu = "i386";
294 }
295 else
296 cpu = "generic";
297
298 return concat ("-m", argv[0], "=", cpu, NULL);
299 }
300 #endif /* GCC_VERSION */
301