]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/i386/driver-i386.c
re PR c/28706 (Compile failure with --combine and explicitly aligned structures)
[thirdparty/gcc.git] / gcc / config / i386 / driver-i386.c
CommitLineData
fa959ce4
MM
1/* Subroutines for the gcc driver.
2 Copyright (C) 2006 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 <stdlib.h>
24
fa959ce4
MM
25#ifdef GCC_VERSION
26#define cpuid(num,a,b,c,d) \
27 asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \
28 : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
29 : "0" (num))
30
31#define bit_CMPXCHG8B (1 << 8)
32#define bit_CMOV (1 << 15)
33#define bit_MMX (1 << 23)
34#define bit_SSE (1 << 25)
35#define bit_SSE2 (1 << 26)
36
37#define bit_SSE3 (1 << 0)
38#define bit_CMPXCHG16B (1 << 13)
39
40#define bit_3DNOW (1 << 31)
41#define bit_3DNOWP (1 << 30)
42#define bit_LM (1 << 29)
43
44/* This will be called by the spec parser in gcc.c when it sees
45 a %:local_cpu_detect(args) construct. Currently it will be called
46 with either "arch" or "tune" as argument depending on if -march=native
47 or -mtune=native is to be substituted.
48
49 It returns a string containing new command line parameters to be
50 put at the place of the above two options, depending on what CPU
51 this is executed. E.g. "-march=k8" on an AMD64 machine
52 for -march=native.
53
54 ARGC and ARGV are set depending on the actual arguments given
55 in the spec. */
56const char *host_detect_local_cpu (int argc, const char **argv)
57{
58 const char *cpu = "i386";
59 unsigned int eax, ebx, ecx, edx;
60 unsigned int max_level;
61 unsigned int vendor;
62 unsigned int ext_level;
63 unsigned char has_mmx = 0, has_3dnow = 0, has_3dnowp = 0, has_sse = 0;
64 unsigned char has_sse2 = 0, has_sse3 = 0, has_cmov = 0;
65 unsigned char has_longmode = 0;
66 unsigned char is_amd = 0;
67 unsigned int family = 0;
68 if (argc < 1
69 || (strcmp (argv[0], "arch")
70 && strcmp (argv[0], "tune")))
71 return NULL;
72
73#ifndef __x86_64__
74 /* See if we can use cpuid. */
75 asm volatile ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;"
76 "pushl %0; popfl; pushfl; popl %0; popfl"
77 : "=&r" (eax), "=&r" (ebx)
78 : "i" (0x00200000));
79
80 if (((eax ^ ebx) & 0x00200000) == 0)
81 goto done;
82#endif
83
84 cpu = "i586";
85
86 /* Check the highest input value for eax. */
87 cpuid (0, eax, ebx, ecx, edx);
88 max_level = eax;
89 /* We only look at the first four characters. */
90 vendor = ebx;
91 if (max_level == 0)
92 goto done;
93
94 cpuid (1, eax, ebx, ecx, edx);
95 has_cmov = !!(edx & bit_CMOV);
96 has_mmx = !!(edx & bit_MMX);
97 has_sse = !!(edx & bit_SSE);
98 has_sse2 = !!(edx & bit_SSE2);
99 has_sse3 = !!(ecx & bit_SSE3);
100 /* We don't care for extended family. */
101 family = (eax >> 8) & ~(1 << 4);
102
103 cpuid (0x80000000, eax, ebx, ecx, edx);
104 ext_level = eax;
105 if (ext_level >= 0x80000000)
106 {
107 cpuid (0x80000001, eax, ebx, ecx, edx);
108 has_3dnow = !!(edx & bit_3DNOW);
109 has_3dnowp = !!(edx & bit_3DNOWP);
110 has_longmode = !!(edx & bit_LM);
111 }
112
113 is_amd = vendor == *(unsigned int*)"Auth";
114
115 if (is_amd)
116 {
117 if (has_mmx)
118 cpu = "k6";
119 if (has_3dnow)
120 cpu = "k6-3";
121 if (has_3dnowp)
122 cpu = "athlon";
123 if (has_sse)
124 cpu = "athlon-4";
125 if (has_sse2 || has_longmode)
126 cpu = "k8";
127 }
128 else
129 {
130 if (family == 5)
131 {
132 if (has_mmx)
133 cpu = "pentium-mmx";
134 }
135 else if (has_mmx)
136 cpu = "pentium2";
137 if (has_sse)
138 cpu = "pentium3";
139 if (has_sse2)
140 {
141 if (family == 6)
142 /* It's a pentiumpro with sse2 --> pentium-m */
143 cpu = "pentium-m";
144 else
145 /* Would have to look at extended family, but it's at least
146 an pentium4 core. */
147 cpu = "pentium4";
148 }
149 if (has_sse3)
150 {
151 if (has_longmode)
152 cpu = "nocona";
153 else
154 cpu = "prescott";
155 }
156 }
157
158done:
159 return concat ("-m", argv[0], "=", cpu, NULL);
160}
161#else
162/* If we aren't compiling with GCC we just provide a minimal
163 default value. */
164const char *host_detect_local_cpu (int argc, const char **argv)
165{
166 return concat ("-m", argv[0], "=i386", NULL);
167}
682cd442 168#endif /* GCC_VERSION */