aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.2.1-5666.3/gcc/config/i386/driver-i386.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.2.1-5666.3/gcc/config/i386/driver-i386.c')
-rw-r--r--gcc-4.2.1-5666.3/gcc/config/i386/driver-i386.c300
1 files changed, 300 insertions, 0 deletions
diff --git a/gcc-4.2.1-5666.3/gcc/config/i386/driver-i386.c b/gcc-4.2.1-5666.3/gcc/config/i386/driver-i386.c
new file mode 100644
index 000000000..ffcee4e55
--- /dev/null
+++ b/gcc-4.2.1-5666.3/gcc/config/i386/driver-i386.c
@@ -0,0 +1,300 @@
+/* Subroutines for the gcc driver.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include <stdlib.h>
+
+const char *host_detect_local_cpu (int argc, const char **argv);
+
+#ifdef GCC_VERSION
+#define cpuid(num,a,b,c,d) \
+ asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1" \
+ : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
+ : "0" (num))
+
+#define bit_CMPXCHG8B (1 << 8)
+#define bit_CMOV (1 << 15)
+#define bit_MMX (1 << 23)
+#define bit_SSE (1 << 25)
+#define bit_SSE2 (1 << 26)
+
+#define bit_SSE3 (1 << 0)
+#define bit_CMPXCHG16B (1 << 13)
+
+#define bit_3DNOW (1 << 31)
+#define bit_3DNOWP (1 << 30)
+#define bit_LM (1 << 29)
+
+/* This will be called by the spec parser in gcc.c when it sees
+ a %:local_cpu_detect(args) construct. Currently it will be called
+ with either "arch" or "tune" as argument depending on if -march=native
+ or -mtune=native is to be substituted.
+
+ It returns a string containing new command line parameters to be
+ put at the place of the above two options, depending on what CPU
+ this is executed. E.g. "-march=k8" on an AMD64 machine
+ for -march=native.
+
+ ARGC and ARGV are set depending on the actual arguments given
+ in the spec. */
+const char *host_detect_local_cpu (int argc, const char **argv)
+{
+ const char *cpu = NULL;
+ enum processor_type processor = PROCESSOR_I386;
+ unsigned int eax, ebx, ecx, edx;
+ unsigned int max_level;
+ unsigned int vendor;
+ unsigned int ext_level;
+ unsigned char has_mmx = 0, has_3dnow = 0, has_3dnowp = 0, has_sse = 0;
+ unsigned char has_sse2 = 0, has_sse3 = 0, has_cmov = 0;
+ unsigned char has_longmode = 0, has_cmpxchg8b = 0;
+ unsigned char is_amd = 0;
+ unsigned int family = 0;
+ bool arch;
+
+ if (argc < 1)
+ return NULL;
+
+ arch = strcmp (argv[0], "arch") == 0;
+ if (!arch && strcmp (argv[0], "tune"))
+ return NULL;
+
+#ifndef __x86_64__
+ /* See if we can use cpuid. */
+ asm volatile ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;"
+ "pushl %0; popfl; pushfl; popl %0; popfl"
+ : "=&r" (eax), "=&r" (ebx)
+ : "i" (0x00200000));
+
+ if (((eax ^ ebx) & 0x00200000) == 0)
+ goto done;
+#endif
+
+ processor = PROCESSOR_PENTIUM;
+
+ /* Check the highest input value for eax. */
+ cpuid (0, eax, ebx, ecx, edx);
+ max_level = eax;
+ /* We only look at the first four characters. */
+ vendor = ebx;
+ if (max_level == 0)
+ goto done;
+
+ cpuid (1, eax, ebx, ecx, edx);
+ has_cmpxchg8b = !!(edx & bit_CMPXCHG8B);
+ has_cmov = !!(edx & bit_CMOV);
+ has_mmx = !!(edx & bit_MMX);
+ has_sse = !!(edx & bit_SSE);
+ has_sse2 = !!(edx & bit_SSE2);
+ has_sse3 = !!(ecx & bit_SSE3);
+ /* We don't care for extended family. */
+ family = (eax >> 8) & ~(1 << 4);
+
+ cpuid (0x80000000, eax, ebx, ecx, edx);
+ ext_level = eax;
+ if (ext_level >= 0x80000000)
+ {
+ cpuid (0x80000001, eax, ebx, ecx, edx);
+ has_3dnow = !!(edx & bit_3DNOW);
+ has_3dnowp = !!(edx & bit_3DNOWP);
+ has_longmode = !!(edx & bit_LM);
+ }
+
+ is_amd = vendor == *(unsigned int*)"Auth";
+
+ if (is_amd)
+ {
+ if (has_mmx)
+ processor = PROCESSOR_K6;
+ if (has_3dnowp)
+ processor = PROCESSOR_ATHLON;
+ if (has_sse2 || has_longmode)
+ processor = PROCESSOR_K8;
+ }
+ else
+ {
+ switch (family)
+ {
+ case 5:
+ /* Default is PROCESSOR_PENTIUM. */
+ break;
+ case 6:
+ processor = PROCESSOR_PENTIUMPRO;
+ break;
+ case 15:
+ processor = PROCESSOR_PENTIUM4;
+ break;
+ default:
+ /* We have no idea. Use something reasonable. */
+ if (arch)
+ {
+ if (has_sse3)
+ {
+ if (has_longmode)
+ cpu = "nocona";
+ else
+ cpu = "prescott";
+ }
+ else if (has_sse2)
+ cpu = "pentium4";
+ else if (has_cmov)
+ cpu = "pentiumpro";
+ else if (has_mmx)
+ cpu = "pentium-mmx";
+ else if (has_cmpxchg8b)
+ cpu = "pentium";
+ else
+ cpu = "i386";
+ }
+ else
+ cpu = "generic";
+ goto done;
+ break;
+ }
+ }
+
+ switch (processor)
+ {
+ case PROCESSOR_I386:
+ cpu = "i386";
+ break;
+ case PROCESSOR_I486:
+ cpu = "i486";
+ break;
+ case PROCESSOR_PENTIUM:
+ if (has_mmx)
+ cpu = "pentium-mmx";
+ else
+ cpu = "pentium";
+ break;
+ case PROCESSOR_PENTIUMPRO:
+ if (arch)
+ {
+ if (has_sse3)
+ {
+ if (has_longmode)
+ {
+ /* It is Core 2 Duo. */
+ cpu = "nocona";
+ }
+ else
+ {
+ /* It is Core Duo. */
+ cpu = "prescott";
+ }
+ }
+ else if (has_sse2)
+ {
+ /* It is Pentium M. */
+ cpu = "pentium4";
+ }
+ else if (has_sse)
+ {
+ /* It is Pentium III. */
+ cpu = "pentium3";
+ }
+ else if (has_mmx)
+ {
+ /* It is Pentium II. */
+ cpu = "pentium2";
+ }
+ else
+ {
+ /* Default to Pentium Pro. */
+ cpu = "pentiumpro";
+ }
+ }
+ else
+ {
+ /* For -mtune, we default to -mtune=generic. */
+ cpu = "generic";
+ }
+ break;
+ case PROCESSOR_K6:
+ if (has_3dnow)
+ cpu = "k6-3";
+ else
+ cpu = "k6";
+ break;
+ case PROCESSOR_ATHLON:
+ if (has_sse)
+ cpu = "athlon-4";
+ else
+ cpu = "athlon";
+ break;
+ case PROCESSOR_PENTIUM4:
+ if (has_sse3)
+ {
+ if (has_longmode)
+ cpu = "nocona";
+ else
+ cpu = "prescott";
+ }
+ else
+ cpu = "pentium4";
+ break;
+ case PROCESSOR_K8:
+ cpu = "k8";
+ break;
+ case PROCESSOR_NOCONA:
+ cpu = "nocona";
+ break;
+ case PROCESSOR_GENERIC32:
+ case PROCESSOR_GENERIC64:
+ cpu = "generic";
+ break;
+ default:
+ abort ();
+ break;
+ }
+
+done:
+ return concat ("-m", argv[0], "=", cpu, NULL);
+}
+#else
+/* If we aren't compiling with GCC we just provide a minimal
+ default value. */
+const char *host_detect_local_cpu (int argc, const char **argv)
+{
+ const char *cpu;
+ bool arch;
+
+ if (argc < 1)
+ return NULL;
+
+ arch = strcmp (argv[0], "arch") == 0;
+ if (!arch && strcmp (argv[0], "tune"))
+ return NULL;
+
+ if (arch)
+ {
+ /* FIXME: i386 is wrong for 64bit compiler. How can we tell if
+ we are generating 64bit or 32bit code? */
+ cpu = "i386";
+ }
+ else
+ cpu = "generic";
+
+ return concat ("-m", argv[0], "=", cpu, NULL);
+}
+#endif /* GCC_VERSION */