tools/cpuflags.c
branchpyrit
changeset 68 2c154aad7f33
child 70 4b84e90325c5
equal deleted inserted replaced
67:249553e1d4fe 68:2c154aad7f33
       
     1 /*
       
     2  * cpuflags
       
     3  *
       
     4  * Simple tool which detects CPU capabilities
       
     5  * and outputs appropriate compiler flags.
       
     6  *
       
     7  * Usage:
       
     8  *  cpuflags [gcc version] [intelc version]
       
     9  *
       
    10  * Returns:
       
    11  *  [arch]
       
    12  *  [gcc flags]
       
    13  *  [intelc flags]
       
    14  *
       
    15  * The gcc/intelc version must be passed as floating point value,
       
    16  * e.g. 4.23
       
    17  *
       
    18  * Copyright (C) 2008  Radek Brich <radek@brich.org>
       
    19  *
       
    20  * Based on x86cpucaps
       
    21  * by Osamu Kayasono <jacobi@jcom.home.ne.jp>
       
    22  * http://members.jcom.home.ne.jp/jacobi/linux/softwares.html
       
    23  *
       
    24  * This program is free software; you can redistribute it and/or
       
    25  * modify it under the terms of the GNU General Public License
       
    26  * as published by the Free Software Foundation; either version 2
       
    27  * of the License, or (at your option) any later version.
       
    28  *
       
    29  * This program is distributed in the hope that it will be useful,
       
    30  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    31  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    32  * GNU General Public License for more details.
       
    33  *
       
    34  * You should have received a copy of the GNU General Public License
       
    35  * along with this program; if not, write to the Free Software
       
    36  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
       
    37  */
       
    38 
       
    39 #include <stdio.h>
       
    40 #include <stdlib.h>
       
    41 #include <string.h>
       
    42 
       
    43 #define LEN_VENDORNAME 13
       
    44 
       
    45 #define VENDOR_INTEL     1
       
    46 #define VENDOR_AMD       2
       
    47 #define VENDOR_CYRIX     3
       
    48 #define VENDOR_CENTAUR   4
       
    49 #define VENDOR_TRANSMETA 5
       
    50 #define VENDOR_OTHERS    0
       
    51 
       
    52 struct simdcaps
       
    53 {
       
    54    unsigned int has_mmx;
       
    55    unsigned int has_sse;
       
    56    unsigned int has_sse2;
       
    57    unsigned int has_sse3;
       
    58    unsigned int has_ssse3;
       
    59    unsigned int has_sse41;
       
    60    unsigned int has_sse42;
       
    61    unsigned int has_mmxext;
       
    62    unsigned int has_3dnowext;
       
    63    unsigned int has_3dnow;
       
    64 };
       
    65 
       
    66 /* CPU caps */
       
    67 #define FLAG_MMX      (1<<23)
       
    68 #define FLAG_SSE      (1<<25)
       
    69 #define FLAG_SSE2     (1<<26)
       
    70 
       
    71 /* CPU caps 2 */
       
    72 #define FLAG_SSE3     (1<<0)
       
    73 #define FLAG_SSSE3    (1<<9)
       
    74 #define FLAG_SSE41    (1<<19)
       
    75 #define FLAG_SSE42    (1<<20)
       
    76 
       
    77 /* AMD CPU caps */
       
    78 #define FLAG_MMXEXT   (1<<22)
       
    79 #define FLAG_3DNOWEXT (1<<30)
       
    80 #define FLAG_3DNOW    (1<<31)
       
    81 
       
    82 
       
    83 /* cpuid, from kernel source ( linux/include/asm-i386/processor.h ) */
       
    84 inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
       
    85 {
       
    86    __asm__("cpuid" : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) : "a" (op));
       
    87 }
       
    88 
       
    89 /*
       
    90  * check SIMD capabilities
       
    91  */
       
    92 int x86cpucaps_simd(struct simdcaps *simd)
       
    93 {
       
    94    int ex[4];
       
    95 
       
    96    memset(&(*simd),0,sizeof(struct simdcaps));
       
    97 
       
    98    /* check CPU has CPUID */
       
    99    cpuid(0,&ex[0],&ex[1],&ex[2],&ex[3]);
       
   100    if ( ex[0] < 1) return 1;
       
   101 
       
   102    cpuid(0x80000001,&ex[0],&ex[1],&ex[2],&ex[3]);
       
   103    if ( (ex[3] & FLAG_MMXEXT ) == FLAG_MMXEXT) simd->has_mmxext = 1;
       
   104    if ( (ex[3] & FLAG_3DNOW ) == FLAG_3DNOW) simd->has_3dnow = 1;
       
   105    if ( (ex[3] & FLAG_3DNOWEXT ) == FLAG_3DNOWEXT) simd->has_3dnowext = 1;
       
   106 
       
   107    cpuid(1,&ex[0],&ex[1],&ex[2],&ex[3]);
       
   108    if ( (ex[3] & FLAG_MMX  ) == FLAG_MMX ) simd->has_mmx = 1;
       
   109    if ( (ex[3] & FLAG_SSE  ) == FLAG_SSE ) simd->has_sse = 1;
       
   110    if ( (ex[3] & FLAG_SSE2 ) == FLAG_SSE2) simd->has_sse2 = 1;
       
   111    if ( (ex[2] & FLAG_SSE3  ) == FLAG_SSE3 ) simd->has_sse3 = 1;
       
   112    if ( (ex[2] & FLAG_SSSE3  ) == FLAG_SSSE3 ) simd->has_ssse3 = 1;
       
   113    if ( (ex[2] & FLAG_SSE41  ) == FLAG_SSE41 ) simd->has_sse41 = 1;
       
   114    if ( (ex[2] & FLAG_SSE42  ) == FLAG_SSE42 ) simd->has_sse42 = 1;
       
   115 
       
   116    /* SSE CPU supports mmxext too */
       
   117    if (simd->has_sse == 1) simd->has_mmxext = 1;
       
   118 
       
   119    return 0;
       
   120 }
       
   121 
       
   122 /*
       
   123  * check CPU Family-Model-Stepping
       
   124  */
       
   125 int x86cpucaps_cpumodel()
       
   126 {
       
   127    int ex[4];
       
   128    int f = 0;
       
   129 
       
   130    /* check CPU has CPUID */
       
   131    cpuid(0,&ex[0],&ex[1],&ex[2],&ex[3]);
       
   132    if ( ex[0] < 1) return f;
       
   133 
       
   134    cpuid(1,&ex[0],&ex[1],&ex[2],&ex[3]);
       
   135    f = ex[0] & 0x0fff;
       
   136 
       
   137    return f;
       
   138 }
       
   139 
       
   140 /*
       
   141  * check CPU Vendor
       
   142  */
       
   143 int x86cpucaps_vendor(char *vendorname)
       
   144 {
       
   145    int ex[4];
       
   146    int f = 0;
       
   147    char vendorstr[LEN_VENDORNAME];
       
   148 
       
   149    /* check CPU has CPUID */
       
   150    cpuid(0,&ex[0],&ex[1],&ex[2],&ex[3]);
       
   151    if ( ex[0] < 1) return f;
       
   152 
       
   153    /* read Vendor Strings */
       
   154    vendorstr[0] =  ex[1] & 0xff;
       
   155    vendorstr[1] =  (ex[1] >> 8) & 0xff;
       
   156    vendorstr[2] = (ex[1] >> 16) & 0xff;
       
   157    vendorstr[3] = (ex[1] >> 24) & 0xff;
       
   158    vendorstr[4] =  ex[3] & 0xff;
       
   159    vendorstr[5] = (ex[3] >> 8) & 0xff;
       
   160    vendorstr[6] = (ex[3] >> 16) & 0xff;
       
   161    vendorstr[7] = (ex[3] >> 24) & 0xff;
       
   162    vendorstr[8] =  ex[2] & 0xff;
       
   163    vendorstr[9] = (ex[2] >> 8) & 0xff;
       
   164    vendorstr[10]= (ex[2] >> 16) & 0xff;
       
   165    vendorstr[11]= (ex[2] >> 24) & 0xff;
       
   166    vendorstr[12]= '\0';
       
   167 
       
   168    if ( strcmp(vendorstr, "GenuineIntel") == 0 )
       
   169      f = VENDOR_INTEL;
       
   170    else if ( strcmp(vendorstr, "AuthenticAMD") == 0 )
       
   171      f = VENDOR_AMD;
       
   172    else if ( strcmp(vendorstr, "CyrixInstead") == 0 )
       
   173      f = VENDOR_CYRIX;
       
   174    else if ( strcmp(vendorstr, "CentaurHauls") == 0 )
       
   175      f = VENDOR_CENTAUR;
       
   176    else if ( strcmp(vendorstr, "GenuineTMx86") == 0 )
       
   177      f = VENDOR_TRANSMETA;
       
   178 
       
   179    strncpy(vendorname, vendorstr, LEN_VENDORNAME);
       
   180 
       
   181    return f;
       
   182 }
       
   183 
       
   184 
       
   185 int main(int argc, char **argv)
       
   186 {
       
   187    int family, model, stepping;
       
   188    char *arch, *gccarch, *gccsimd, *iccarch, *icctune, *iccsimd;
       
   189 
       
   190    int cpu_id = x86cpucaps_cpumodel();
       
   191    char vendorname[LEN_VENDORNAME];
       
   192    int vendor_id = x86cpucaps_vendor(vendorname);
       
   193    struct simdcaps simd;
       
   194 
       
   195    float gccver = 999.;
       
   196    float iccver = 999.;
       
   197 
       
   198    if (argc > 1)
       
   199      gccver = atof(argv[1]);
       
   200    if (argc > 2)
       
   201      iccver = atof(argv[2]);
       
   202 
       
   203    family   = (cpu_id & 0xf00) >> 8;
       
   204    model    = (cpu_id & 0x0f0) >> 4;
       
   205    stepping =  cpu_id & 0x00f;
       
   206 
       
   207    switch (vendor_id)
       
   208    {
       
   209 
       
   210    case VENDOR_INTEL:
       
   211      if (family == 4)
       
   212      {
       
   213        arch = "i486";
       
   214      }
       
   215      else if (family == 5)
       
   216      {
       
   217        if (model < 4) arch = "pentium";
       
   218        else arch = "pentium-mmx";
       
   219      }
       
   220      else if (family == 6)
       
   221      {
       
   222        if (model <= 1) arch = "pentiumpro";
       
   223        else if (model < 7) arch = "pentium2";
       
   224        else if (model == 7) arch = "pentium3";
       
   225        else if (model < 15) arch = "pentium-m";
       
   226        else if (model == 15)
       
   227        {
       
   228          if (stepping < 6) arch = "core";
       
   229          else arch = "core2";
       
   230        }
       
   231 
       
   232      }
       
   233      else if (family > 6)
       
   234      { /* family == 15 */
       
   235        arch = "pentium4";
       
   236      }
       
   237      else
       
   238      {
       
   239        arch = "i386";
       
   240      }
       
   241      break;
       
   242 
       
   243    case VENDOR_AMD:
       
   244      if (family == 4)
       
   245      {
       
   246        if (model <= 9) arch = "i486";
       
   247        else arch = "i586";
       
   248      }
       
   249      else if (family == 5)
       
   250      {
       
   251        if (model <= 3) arch = "i586";
       
   252        else if (model <= 7) arch = "k6";
       
   253        else if (model == 8) arch = "k6-2";
       
   254        else arch = "k6-3";
       
   255      }
       
   256      else if (family == 6)
       
   257      {
       
   258        if (model <= 3) arch = "athlon";
       
   259        else if (model == 4) arch = "athlon-tbird";
       
   260        else arch = "athlon-xp";
       
   261      }
       
   262      else if (family > 6)
       
   263      {
       
   264        arch = "k8";
       
   265      }
       
   266      else
       
   267      {
       
   268        arch = "unknown";
       
   269      }
       
   270      break;
       
   271 
       
   272    case VENDOR_CYRIX:
       
   273      if (family == 4) arch = "i586";
       
   274      else if (family == 5) arch = "i586";
       
   275      else if (family == 6) arch = "i686";
       
   276      else arch = "unknown";
       
   277      break;
       
   278 
       
   279    case VENDOR_CENTAUR:
       
   280      if (family == 5) arch = "i586";
       
   281      else arch = "unknown";
       
   282      break;
       
   283 
       
   284    case VENDOR_TRANSMETA:
       
   285      arch = "i686";
       
   286      break;
       
   287 
       
   288    default:
       
   289      arch = "unknown";
       
   290      break;
       
   291 
       
   292    }
       
   293 
       
   294    /* some targets not supported by older gcc */
       
   295    gccarch = arch;
       
   296    if (gccver < (float)4.3)
       
   297    {
       
   298      if (!strcmp(gccarch, "core2")) gccarch = "pentium3";
       
   299    }
       
   300    if (gccver < (float)3.4)
       
   301    {
       
   302      if (!strcmp(gccarch, "k8")) gccarch = "athlon-xp";
       
   303    }
       
   304    if (gccver < (float)3.1)
       
   305    {
       
   306      if (strstr(gccarch, "athlon-") != NULL)
       
   307        gccarch = "athlon";
       
   308      else if (strstr(gccarch, "k6-") != NULL)
       
   309        gccarch = "k6";
       
   310      else if (!strcmp(gccarch, "pentium-mmx"))
       
   311        gccarch = "pentium";
       
   312      else if (!strcmp(gccarch, "pentium2")
       
   313      || !strcmp(gccarch, "pentium3")
       
   314      || !strcmp(gccarch, "pentium4"))
       
   315        gccarch = "pentiumpro";
       
   316    }
       
   317 
       
   318    if (gccver < (float)3.0)
       
   319    {
       
   320      if (!strcmp(gccarch, "athlon"))
       
   321        gccarch = "pentiumpro";
       
   322      else if (!strcmp(gccarch, "k6"))
       
   323        gccarch = "pentium";
       
   324    }
       
   325 
       
   326    if (gccver < (float)2.9)
       
   327    {
       
   328      if (!strcmp(gccarch, "pentiumpro"))
       
   329        gccarch = "i686";
       
   330      else if (!strcmp(gccarch, "pentium"))
       
   331        gccarch = "i586";
       
   332    }
       
   333 
       
   334    /* SIMD options */
       
   335    x86cpucaps_simd(&simd);
       
   336    gccsimd = "";
       
   337    if (gccver >= 3.1) {
       
   338      if ( simd.has_3dnow || simd.has_3dnowext )
       
   339        gccsimd = "-m3dnow";
       
   340      else
       
   341      {
       
   342        if (gccver >= 4.3)
       
   343        {
       
   344          if (simd.has_sse41 || simd.has_sse42) gccsimd = "-msse4 -mfpmath=sse";
       
   345          else if (simd.has_ssse3) gccsimd = "-mssse3 -mfpmath=sse";
       
   346        }
       
   347        else if ( gccver >= 3.4 && simd.has_sse3 ) gccsimd = "-msse3 -mfpmath=sse";
       
   348        else if ( simd.has_sse2 ) gccsimd = "-msse2 -mfpmath=sse";
       
   349        else if ( simd.has_sse ) gccsimd = "-msse";
       
   350        else if ( simd.has_mmx ) gccsimd = "-mmmx";
       
   351      }
       
   352    }
       
   353 
       
   354    /* intelc options */
       
   355    iccarch = arch;
       
   356    icctune = arch;
       
   357    iccsimd = "";
       
   358    if (simd.has_sse41 || simd.has_sse42) iccsimd = "-xS";
       
   359    else if (simd.has_ssse3) iccsimd = "-xT";
       
   360    else if (simd.has_sse3) iccsimd = "-msse3 -xP";
       
   361    else if (simd.has_sse2) iccsimd = "-msse2";
       
   362 
       
   363    printf("%s\n", arch);
       
   364    if (gccver >= 4.2) gccarch = "native";
       
   365    printf("-march=%s -mtune=%s %s\n", gccarch, gccarch, gccsimd);
       
   366    printf("-march=%s -mtune=%s %s\n", iccarch, icctune, iccsimd);
       
   367    return 0;
       
   368 }