xref: /openbsd-src/gnu/gcc/gcc/config/i386/driver-i386.c (revision 404b540a9034ac75a6199ad1a32d1bbc7a0d4210)
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