]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/aarch64/driver-aarch64.c
Update copyright years.
[thirdparty/gcc.git] / gcc / config / aarch64 / driver-aarch64.c
CommitLineData
8b81ce60 1/* Native CPU detection for aarch64.
fbd26352 2 Copyright (C) 2015-2019 Free Software Foundation, Inc.
8b81ce60 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
785790dc 20#define IN_TARGET_CODE 1
21
8b81ce60 22#include "config.h"
4d963951 23#define INCLUDE_STRING
8b81ce60 24#include "system.h"
4d963951 25#include "coretypes.h"
26#include "tm.h"
8b81ce60 27
4d963951 28/* Defined in common/config/aarch64/aarch64-common.c. */
29std::string aarch64_get_extension_string_for_isa_flags (unsigned long,
30 unsigned long);
31
32struct aarch64_arch_extension
8b81ce60 33{
34 const char *ext;
a702492c 35 unsigned int flag;
8b81ce60 36 const char *feat_string;
37};
38
a702492c 39#define AARCH64_OPT_EXTENSION(EXT_NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, FEATURE_STRING) \
40 { EXT_NAME, FLAG_CANONICAL, FEATURE_STRING },
4d963951 41static struct aarch64_arch_extension aarch64_extensions[] =
8b81ce60 42{
43#include "aarch64-option-extensions.def"
44};
8b81ce60 45
46
47struct aarch64_core_data
48{
49 const char* name;
50 const char* arch;
14326a22 51 unsigned char implementer_id; /* Exactly 8 bits */
52 unsigned int part_no; /* 12 bits + 12 bits */
7a2c84f9 53 unsigned variant;
4d963951 54 const unsigned long flags;
8b81ce60 55};
56
14326a22 57#define AARCH64_BIG_LITTLE(BIG, LITTLE) \
58 (((BIG)&0xFFFu) << 12 | ((LITTLE) & 0xFFFu))
59#define INVALID_IMP ((unsigned char) -1)
60#define INVALID_CORE ((unsigned)-1)
7a2c84f9 61#define ALL_VARIANTS ((unsigned)-1)
14326a22 62
7a2c84f9 63#define AARCH64_CORE(CORE_NAME, CORE_IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART, VARIANT) \
64 { CORE_NAME, #ARCH, IMP, PART, VARIANT, FLAGS },
8b81ce60 65
4d963951 66static struct aarch64_core_data aarch64_cpu_data[] =
8b81ce60 67{
68#include "aarch64-cores.def"
7a2c84f9 69 { NULL, NULL, INVALID_IMP, INVALID_CORE, ALL_VARIANTS, 0 }
8b81ce60 70};
71
8b81ce60 72
9356ca16 73struct aarch64_arch_driver_info
8b81ce60 74{
75 const char* id;
76 const char* name;
4d963951 77 const unsigned long flags;
8b81ce60 78};
79
9356ca16 80#define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH_REV, FLAGS) \
4d963951 81 { #ARCH_IDENT, NAME, FLAGS },
8b81ce60 82
4d963951 83static struct aarch64_arch_driver_info aarch64_arches[] =
8b81ce60 84{
85#include "aarch64-arches.def"
4d963951 86 {NULL, NULL, 0}
8b81ce60 87};
88
8b81ce60 89
4d963951 90/* Return an aarch64_arch_driver_info for the architecture described
91 by ID, or NULL if ID describes something we don't know about. */
8b81ce60 92
4d963951 93static struct aarch64_arch_driver_info*
94get_arch_from_id (const char* id)
8b81ce60 95{
96 unsigned int i = 0;
97
98 for (i = 0; aarch64_arches[i].id != NULL; i++)
99 {
100 if (strcmp (id, aarch64_arches[i].id) == 0)
4d963951 101 return &aarch64_arches[i];
8b81ce60 102 }
103
104 return NULL;
105}
106
14326a22 107/* Check wether the CORE array is the same as the big.LITTLE BL_CORE.
108 For an example CORE={0xd08, 0xd03} and
109 BL_CORE=AARCH64_BIG_LITTLE (0xd08, 0xd03) will return true. */
8b81ce60 110
111static bool
14326a22 112valid_bL_core_p (unsigned int *core, unsigned int bL_core)
113{
114 return AARCH64_BIG_LITTLE (core[0], core[1]) == bL_core
115 || AARCH64_BIG_LITTLE (core[1], core[0]) == bL_core;
116}
117
118/* Returns the hex integer that is after ':' for the FIELD.
119 Returns -1 is returned if there was problem parsing the integer. */
120static unsigned
121parse_field (const char *field)
8b81ce60 122{
14326a22 123 const char *rest = strchr (field, ':');
124 char *after;
125 unsigned fint = strtol (rest + 1, &after, 16);
126 if (after == rest + 1)
127 return -1;
128 return fint;
8b81ce60 129}
130
14326a22 131/* Return true iff ARR contains CORE, in either of the two elements. */
8b81ce60 132
133static bool
14326a22 134contains_core_p (unsigned *arr, unsigned core)
8b81ce60 135{
14326a22 136 if (arr[0] != INVALID_CORE)
8b81ce60 137 {
14326a22 138 if (arr[0] == core)
139 return true;
8b81ce60 140
14326a22 141 if (arr[1] != INVALID_CORE)
142 return arr[1] == core;
8b81ce60 143 }
144
145 return false;
146}
147
148/* This will be called by the spec parser in gcc.c when it sees
149 a %:local_cpu_detect(args) construct. Currently it will be called
150 with either "arch", "cpu" or "tune" as argument depending on if
151 -march=native, -mcpu=native or -mtune=native is to be substituted.
152
153 It returns a string containing new command line parameters to be
154 put at the place of the above two options, depending on what CPU
155 this is executed. E.g. "-march=armv8-a" on a Cortex-A57 for
156 -march=native. If the routine can't detect a known processor,
157 the -march or -mtune option is discarded.
158
159 For -mtune and -mcpu arguments it attempts to detect the CPU or
160 a big.LITTLE system.
161 ARGC and ARGV are set depending on the actual arguments given
162 in the spec. */
163
164const char *
165host_detect_local_cpu (int argc, const char **argv)
166{
8b81ce60 167 const char *res = NULL;
4d963951 168 static const int num_exts = ARRAY_SIZE (aarch64_extensions);
8b81ce60 169 char buf[128];
170 FILE *f = NULL;
171 bool arch = false;
172 bool tune = false;
173 bool cpu = false;
174 unsigned int i = 0;
14326a22 175 unsigned char imp = INVALID_IMP;
176 unsigned int cores[2] = { INVALID_CORE, INVALID_CORE };
8b81ce60 177 unsigned int n_cores = 0;
7a2c84f9 178 unsigned int variants[2] = { ALL_VARIANTS, ALL_VARIANTS };
179 unsigned int n_variants = 0;
8b81ce60 180 bool processed_exts = false;
181 const char *ext_string = "";
4d963951 182 unsigned long extension_flags = 0;
183 unsigned long default_flags = 0;
8b81ce60 184
185 gcc_assert (argc);
186
187 if (!argv[0])
188 goto not_found;
189
190 /* Are we processing -march, mtune or mcpu? */
191 arch = strcmp (argv[0], "arch") == 0;
192 if (!arch)
193 tune = strcmp (argv[0], "tune") == 0;
194
195 if (!arch && !tune)
196 cpu = strcmp (argv[0], "cpu") == 0;
197
198 if (!arch && !tune && !cpu)
199 goto not_found;
200
201 f = fopen ("/proc/cpuinfo", "r");
202
203 if (f == NULL)
204 goto not_found;
205
206 /* Look through /proc/cpuinfo to determine the implementer
207 and then the part number that identifies a particular core. */
208 while (fgets (buf, sizeof (buf), f) != NULL)
209 {
210 if (strstr (buf, "implementer") != NULL)
211 {
14326a22 212 unsigned cimp = parse_field (buf);
213 if (cimp == INVALID_IMP)
214 goto not_found;
215
216 if (imp == INVALID_IMP)
217 imp = cimp;
218 /* FIXME: BIG.little implementers are always equal. */
219 else if (imp != cimp)
220 goto not_found;
8b81ce60 221 }
222
7a2c84f9 223 if (strstr (buf, "variant") != NULL)
224 {
225 unsigned cvariant = parse_field (buf);
226 if (!contains_core_p (variants, cvariant))
227 {
228 if (n_variants == 2)
229 goto not_found;
230
231 variants[n_variants++] = cvariant;
232 }
233 continue;
234 }
235
8b81ce60 236 if (strstr (buf, "part") != NULL)
237 {
14326a22 238 unsigned ccore = parse_field (buf);
18ce349d 239 if (!contains_core_p (cores, ccore))
240 {
241 if (n_cores == 2)
242 goto not_found;
243
244 cores[n_cores++] = ccore;
245 }
4d963951 246 continue;
247 }
8b81ce60 248 if (!tune && !processed_exts && strstr (buf, "Features") != NULL)
4d963951 249 {
250 for (i = 0; i < num_exts; i++)
251 {
252 char *p = NULL;
253 char *feat_string
254 = concat (aarch64_extensions[i].feat_string, NULL);
255 bool enabled = true;
256
257 /* This may be a multi-token feature string. We need
258 to match all parts, which could be in any order.
259 If this isn't a multi-token feature string, strtok is
260 just going to return a pointer to feat_string. */
261 p = strtok (feat_string, " ");
262 while (p != NULL)
263 {
264 if (strstr (buf, p) == NULL)
265 {
266 /* Failed to match this token. Turn off the
267 features we'd otherwise enable. */
268 enabled = false;
269 break;
270 }
271 p = strtok (NULL, " ");
272 }
273
274 if (enabled)
275 extension_flags |= aarch64_extensions[i].flag;
276 else
277 extension_flags &= ~(aarch64_extensions[i].flag);
278 }
279
280 processed_exts = true;
281 }
8b81ce60 282 }
283
284 fclose (f);
285 f = NULL;
286
287 /* Weird cpuinfo format that we don't know how to handle. */
7a2c84f9 288 if (n_cores == 0
289 || n_cores > 2
290 || (n_cores == 1 && n_variants != 1)
291 || imp == INVALID_IMP)
8b81ce60 292 goto not_found;
293
7a2c84f9 294 /* Simple case, one core type or just looking for the arch. */
295 if (n_cores == 1 || arch)
8b81ce60 296 {
18ce349d 297 /* Search for one of the cores in the list. */
298 for (i = 0; aarch64_cpu_data[i].name != NULL; i++)
299 if (aarch64_cpu_data[i].implementer_id == imp
7a2c84f9 300 && cores[0] == aarch64_cpu_data[i].part_no
301 && (aarch64_cpu_data[i].variant == ALL_VARIANTS
302 || variants[0] == aarch64_cpu_data[i].variant))
303 break;
304 if (aarch64_cpu_data[i].name == NULL)
305 goto not_found;
306
307 if (arch)
308 {
309 const char *arch_id = aarch64_cpu_data[i].arch;
310 aarch64_arch_driver_info* arch_info = get_arch_from_id (arch_id);
8b81ce60 311
7a2c84f9 312 /* We got some arch indentifier that's not in aarch64-arches.def? */
313 if (!arch_info)
314 goto not_found;
8b81ce60 315
7a2c84f9 316 res = concat ("-march=", arch_info->name, NULL);
317 default_flags = arch_info->flags;
318 }
319 else
320 {
321 default_flags = aarch64_cpu_data[i].flags;
322 res = concat ("-m",
323 cpu ? "cpu" : "tune", "=",
324 aarch64_cpu_data[i].name,
325 NULL);
326 }
8b81ce60 327 }
328 /* We have big.LITTLE. */
7a2c84f9 329 else
8b81ce60 330 {
4d963951 331 for (i = 0; aarch64_cpu_data[i].name != NULL; i++)
332 {
14326a22 333 if (aarch64_cpu_data[i].implementer_id == imp
334 && valid_bL_core_p (cores, aarch64_cpu_data[i].part_no))
4d963951 335 {
336 res = concat ("-m",
337 cpu ? "cpu" : "tune", "=",
338 aarch64_cpu_data[i].name,
339 NULL);
340 default_flags = aarch64_cpu_data[i].flags;
341 break;
342 }
343 }
8b81ce60 344 if (!res)
4d963951 345 goto not_found;
8b81ce60 346 }
8b81ce60 347
348 if (tune)
349 return res;
350
4d963951 351 ext_string
352 = aarch64_get_extension_string_for_isa_flags (extension_flags,
353 default_flags).c_str ();
354
8b81ce60 355 res = concat (res, ext_string, NULL);
356
357 return res;
358
359not_found:
360 {
361 /* If detection fails we ignore the option.
362 Clean up and return empty string. */
363
364 if (f)
365 fclose (f);
366
367 return "";
368 }
369}
370