1 /* Subroutines for the gcc driver.
2    Copyright (C) 2006, 2007 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_SSSE3 (1 << 9)
43 #define bit_SSE4a (1 << 6)
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.  */
host_detect_local_cpu(int argc,const char ** argv)62 const 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;
72   unsigned char has_longmode = 0, has_cmpxchg8b = 0, has_sse4a = 0;
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);
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;
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;
276     case PROCESSOR_GENERIC32:
277     case PROCESSOR_GENERIC64:
278       cpu = "generic";
279       break;
280     default:
281       abort ();
282       break;
283     }
284 
285 done:
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.  */
host_detect_local_cpu(int argc,const char ** argv)291 const 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 */
315