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