1 /* Subroutines for the gcc driver.
2    Copyright (C) 2011-2018 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 3, 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 COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19 
20 #define IN_TARGET_CODE 1
21 
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "configargs.h"
27 
28 struct vendor_cpu {
29   const char *part_no;
30   const char *arch_name;
31   const char *cpu_name;
32 };
33 
34 static struct vendor_cpu arm_cpu_table[] = {
35     {"0x926", "armv5te", "arm926ej-s"},
36     {"0xa26", "armv5te", "arm1026ej-s"},
37     {"0xb02", "armv6k", "mpcore"},
38     {"0xb36", "armv6j", "arm1136jf-s"},
39     {"0xb56", "armv6t2", "arm1156t2f-s"},
40     /* armv6kz is the correct spelling for ARMv6KZ but may not be supported in
41        the version of binutils used.  The incorrect spelling is supported in
42        legacy and current binutils so that is used instead.  */
43     {"0xb76", "armv6zk", "arm1176jzf-s"},
44     {"0xc05", "armv7-a", "cortex-a5"},
45     {"0xc07", "armv7ve", "cortex-a7"},
46     {"0xc08", "armv7-a", "cortex-a8"},
47     {"0xc09", "armv7-a", "cortex-a9"},
48     {"0xc0d", "armv7ve", "cortex-a12"},
49     {"0xc0e", "armv7ve", "cortex-a17"},
50     {"0xc0f", "armv7ve", "cortex-a15"},
51     {"0xd01", "armv8-a+crc", "cortex-a32"},
52     {"0xd04", "armv8-a+crc", "cortex-a35"},
53     {"0xd03", "armv8-a+crc", "cortex-a53"},
54     {"0xd07", "armv8-a+crc", "cortex-a57"},
55     {"0xd08", "armv8-a+crc", "cortex-a72"},
56     {"0xd09", "armv8-a+crc", "cortex-a73"},
57     {"0xd05", "armv8.2-a+fp16+dotprod", "cortex-a55"},
58     {"0xd0a", "armv8.2-a+fp16+dotprod", "cortex-a75"},
59     {"0xd40", "armv8.4-a+fp16", "neoverse-v1"},
60     {"0xd49", "armv8.4-a+fp16", "neoverse-n2"},
61     {"0xc14", "armv7-r", "cortex-r4"},
62     {"0xc15", "armv7-r", "cortex-r5"},
63     {"0xc17", "armv7-r", "cortex-r7"},
64     {"0xc18", "armv7-r", "cortex-r8"},
65     {"0xd13", "armv8-r+crc", "cortex-r52"},
66     {"0xc20", "armv6-m", "cortex-m0"},
67     {"0xc21", "armv6-m", "cortex-m1"},
68     {"0xc23", "armv7-m", "cortex-m3"},
69     {"0xc24", "armv7e-m", "cortex-m4"},
70     {NULL, NULL, NULL}
71 };
72 
73 static struct {
74   const char *vendor_no;
75   const struct vendor_cpu *vendor_parts;
76 } vendors[] = {
77     {"0x41", arm_cpu_table},
78     {NULL, NULL}
79 };
80 
81 /* This will be called by the spec parser in gcc.c when it sees
82    a %:local_cpu_detect(args) construct.  Currently it will be called
83    with either "arch", "cpu" or "tune" as argument depending on if
84    -march=native, -mcpu=native or -mtune=native is to be substituted.
85 
86    It returns a string containing new command line parameters to be
87    put at the place of the above two options, depending on what CPU
88    this is executed.  E.g. "-march=armv7-a" on a Cortex-A8 for
89    -march=native.  If the routine can't detect a known processor,
90    the -march or -mtune option is discarded.
91 
92    ARGC and ARGV are set depending on the actual arguments given
93    in the spec.  */
94 const char *
host_detect_local_cpu(int argc,const char ** argv)95 host_detect_local_cpu (int argc, const char **argv)
96 {
97   const char *val = NULL;
98   char buf[128];
99   FILE *f = NULL;
100   bool arch;
101   const struct vendor_cpu *cpu_table = NULL;
102   char *fcpu_info = NULL;
103 
104   if (argc < 1)
105     goto not_found;
106 
107   arch = strcmp (argv[0], "arch") == 0;
108   if (!arch && strcmp (argv[0], "cpu") != 0 && strcmp (argv[0], "tune"))
109     goto not_found;
110 
111   fcpu_info = getenv ("GCC_CPUINFO");
112   if (fcpu_info)
113     f = fopen (fcpu_info, "r");
114   else
115     f = fopen ("/proc/cpuinfo", "r");
116 
117   if (f == NULL)
118     goto not_found;
119 
120   while (fgets (buf, sizeof (buf), f) != NULL)
121     {
122       /* Ensure that CPU implementer is ARM (0x41).  */
123       if (strncmp (buf, "CPU implementer", sizeof ("CPU implementer") - 1) == 0)
124 	{
125 	  int i;
126 	  for (i = 0; vendors[i].vendor_no != NULL; i++)
127 	    if (strstr (buf, vendors[i].vendor_no) != NULL)
128 	      {
129 		cpu_table = vendors[i].vendor_parts;
130 		break;
131 	      }
132 	}
133 
134       /* Detect arch/cpu.  */
135       if (strncmp (buf, "CPU part", sizeof ("CPU part") - 1) == 0)
136 	{
137 	  int i;
138 
139 	  if (cpu_table == NULL)
140 	    goto not_found;
141 
142 	  for (i = 0; cpu_table[i].part_no != NULL; i++)
143 	    if (strstr (buf, cpu_table[i].part_no) != NULL)
144 	      {
145 		val = arch ? cpu_table[i].arch_name : cpu_table[i].cpu_name;
146 		break;
147 	      }
148 	  break;
149 	}
150     }
151 
152   if (val)
153     {
154       fclose (f);
155       return concat ("-m", argv[0], "=", val, NULL);
156      }
157 
158 not_found:
159   {
160     unsigned int i;
161     unsigned int opt;
162     const char *search[] = {NULL, "arch"};
163 
164     if (f)
165       fclose (f);
166 
167     search[0] = argv[0];
168     for (opt = 0; opt < ARRAY_SIZE (search); opt++)
169       for (i = 0; i < ARRAY_SIZE (configure_default_options); i++)
170 	if (strcmp (configure_default_options[i].name, search[opt]) == 0)
171 	  return concat ("-m", search[opt], "=",
172 			 configure_default_options[i].value, NULL);
173     return NULL;
174   }
175 }
176