]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/aarch64/driver-aarch64.cc
Merge remote-tracking branch 'origin/master' into devel/c++-contracts
[thirdparty/gcc.git] / gcc / config / aarch64 / driver-aarch64.cc
CommitLineData
7e1bcce3 1/* Native CPU detection for aarch64.
7adcbafe 2 Copyright (C) 2015-2022 Free Software Foundation, Inc.
7e1bcce3
KT
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
8fcc61f8
RS
20#define IN_TARGET_CODE 1
21
7e1bcce3 22#include "config.h"
8433cb91 23#define INCLUDE_STRING
b399f3c6 24#define INCLUDE_SET
7e1bcce3 25#include "system.h"
8433cb91
JG
26#include "coretypes.h"
27#include "tm.h"
cb5ecbc4 28#include "aarch64-protos.h"
11a113d5 29#include "aarch64-feature-deps.h"
8433cb91
JG
30
31struct aarch64_arch_extension
7e1bcce3
KT
32{
33 const char *ext;
fed55a60 34 aarch64_feature_flags flag;
7e1bcce3
KT
35 const char *feat_string;
36};
37
11a113d5
RS
38#define AARCH64_OPT_EXTENSION(EXT_NAME, IDENT, C, D, E, FEATURE_STRING) \
39 { EXT_NAME, AARCH64_FL_##IDENT, FEATURE_STRING },
8433cb91 40static struct aarch64_arch_extension aarch64_extensions[] =
7e1bcce3
KT
41{
42#include "aarch64-option-extensions.def"
43};
7e1bcce3
KT
44
45
46struct aarch64_core_data
47{
48 const char* name;
49 const char* arch;
2e721daa
AP
50 unsigned char implementer_id; /* Exactly 8 bits */
51 unsigned int part_no; /* 12 bits + 12 bits */
e8fcc9fa 52 unsigned variant;
fed55a60 53 aarch64_feature_flags flags;
7e1bcce3
KT
54};
55
2e721daa
AP
56#define AARCH64_BIG_LITTLE(BIG, LITTLE) \
57 (((BIG)&0xFFFu) << 12 | ((LITTLE) & 0xFFFu))
58#define INVALID_IMP ((unsigned char) -1)
59#define INVALID_CORE ((unsigned)-1)
e8fcc9fa 60#define ALL_VARIANTS ((unsigned)-1)
e91a17fe
TC
61/* Default architecture to use if -mcpu=native did not detect a known CPU. */
62#define DEFAULT_ARCH "8A"
2e721daa 63
e8fcc9fa 64#define AARCH64_CORE(CORE_NAME, CORE_IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART, VARIANT) \
11a113d5 65 { CORE_NAME, #ARCH, IMP, PART, VARIANT, feature_deps::cpu_##CORE_IDENT },
7e1bcce3 66
f95d3d5d 67static CONSTEXPR const aarch64_core_data aarch64_cpu_data[] =
7e1bcce3
KT
68{
69#include "aarch64-cores.def"
e8fcc9fa 70 { NULL, NULL, INVALID_IMP, INVALID_CORE, ALL_VARIANTS, 0 }
7e1bcce3
KT
71};
72
7e1bcce3 73
393ae126 74struct aarch64_arch_driver_info
7e1bcce3
KT
75{
76 const char* id;
77 const char* name;
fed55a60 78 aarch64_feature_flags flags;
7e1bcce3
KT
79};
80
00c22ba6 81/* Skip the leading "V" in the architecture name. */
393ae126 82#define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH_REV, FLAGS) \
11a113d5 83 { #ARCH_IDENT + 1, NAME, feature_deps::ARCH_IDENT ().enable },
7e1bcce3 84
f95d3d5d 85static CONSTEXPR const aarch64_arch_driver_info aarch64_arches[] =
7e1bcce3
KT
86{
87#include "aarch64-arches.def"
8433cb91 88 {NULL, NULL, 0}
7e1bcce3
KT
89};
90
7e1bcce3 91
8433cb91
JG
92/* Return an aarch64_arch_driver_info for the architecture described
93 by ID, or NULL if ID describes something we don't know about. */
7e1bcce3 94
60dee638 95static const aarch64_arch_driver_info *
8433cb91 96get_arch_from_id (const char* id)
7e1bcce3
KT
97{
98 unsigned int i = 0;
99
100 for (i = 0; aarch64_arches[i].id != NULL; i++)
101 {
102 if (strcmp (id, aarch64_arches[i].id) == 0)
8433cb91 103 return &aarch64_arches[i];
7e1bcce3
KT
104 }
105
106 return NULL;
107}
108
2e721daa
AP
109/* Check wether the CORE array is the same as the big.LITTLE BL_CORE.
110 For an example CORE={0xd08, 0xd03} and
111 BL_CORE=AARCH64_BIG_LITTLE (0xd08, 0xd03) will return true. */
7e1bcce3
KT
112
113static bool
2e721daa
AP
114valid_bL_core_p (unsigned int *core, unsigned int bL_core)
115{
116 return AARCH64_BIG_LITTLE (core[0], core[1]) == bL_core
117 || AARCH64_BIG_LITTLE (core[1], core[0]) == bL_core;
118}
119
120/* Returns the hex integer that is after ':' for the FIELD.
121 Returns -1 is returned if there was problem parsing the integer. */
122static unsigned
b399f3c6 123parse_field (const std::string &field)
7e1bcce3 124{
b399f3c6
TC
125 const char *rest = strchr (field.c_str (), ':');
126
127 /* The line must be in the format of <name>:<value>, if it's not
128 then we have a weird format. */
129 if (rest == NULL)
130 return -1;
131
2e721daa
AP
132 char *after;
133 unsigned fint = strtol (rest + 1, &after, 16);
134 if (after == rest + 1)
135 return -1;
136 return fint;
7e1bcce3
KT
137}
138
b399f3c6
TC
139/* Returns the index of the ':' inside the FIELD which must be found
140 after the value of KEY. Returns string::npos if line does not contain
141 a field. */
142
143static size_t
144find_field (const std::string &field, const std::string &key)
145{
146 size_t key_pos, sep_pos;
147 key_pos = field.find (key);
148 if (key_pos == std::string::npos)
149 return std::string::npos;
150
151 sep_pos = field.find (":", key_pos + 1);
152 if (sep_pos == std::string::npos)
153 return std::string::npos;
154
155 return sep_pos;
156}
157
158/* Splits and returns a string based on whitespace and return it as
159 part of a set. Empty strings are ignored. */
160
161static void
162split_words (const std::string &val, std::set<std::string> &result)
163{
164 size_t cur, prev = 0;
165 std::string word;
166 while ((cur = val.find_first_of (" \n", prev)) != std::string::npos)
167 {
168 word = val.substr (prev, cur - prev);
169 /* Skip adding empty words. */
170 if (!word.empty ())
171 result.insert (word);
172 prev = cur + 1;
173 }
174
175 if (prev != cur)
176 result.insert (val.substr (prev));
177}
178
179/* Read an entire line from F until '\n' or EOF. */
180
181static std::string
182readline (FILE *f)
183{
184 char *buf = NULL;
185 int size = 0;
186 int last = 0;
187 const int buf_size = 128;
188
189 if (feof (f))
190 return std::string ();
191
192 do
193 {
194 size += buf_size;
195 buf = (char*) xrealloc (buf, size);
196 gcc_assert (buf);
34157340
TC
197 /* If fgets fails it returns NULL, but if it reaches EOF
198 with 0 characters read it also returns EOF. However
199 the condition on the loop would have broken out of the
200 loop in that case, and if we are in the first iteration
201 then the empty string is the correct thing to return. */
202 if (!fgets (buf + last, buf_size, f))
203 return std::string ();
b399f3c6
TC
204 /* If we're not at the end of the line then override the
205 \0 added by fgets. */
b1cfbccc 206 last = strnlen (buf, size);
b399f3c6 207 }
b1cfbccc 208 while (!feof (f) && last > 0 && buf[last - 1] != '\n');
b399f3c6
TC
209
210 std::string result (buf);
211 free (buf);
212 return result;
213}
214
2e721daa 215/* Return true iff ARR contains CORE, in either of the two elements. */
7e1bcce3
KT
216
217static bool
2e721daa 218contains_core_p (unsigned *arr, unsigned core)
7e1bcce3 219{
2e721daa 220 if (arr[0] != INVALID_CORE)
7e1bcce3 221 {
2e721daa
AP
222 if (arr[0] == core)
223 return true;
7e1bcce3 224
2e721daa
AP
225 if (arr[1] != INVALID_CORE)
226 return arr[1] == core;
7e1bcce3
KT
227 }
228
229 return false;
230}
231
e53b6e56 232/* This will be called by the spec parser in gcc.cc when it sees
7e1bcce3
KT
233 a %:local_cpu_detect(args) construct. Currently it will be called
234 with either "arch", "cpu" or "tune" as argument depending on if
235 -march=native, -mcpu=native or -mtune=native is to be substituted.
236
237 It returns a string containing new command line parameters to be
238 put at the place of the above two options, depending on what CPU
239 this is executed. E.g. "-march=armv8-a" on a Cortex-A57 for
240 -march=native. If the routine can't detect a known processor,
241 the -march or -mtune option is discarded.
242
243 For -mtune and -mcpu arguments it attempts to detect the CPU or
244 a big.LITTLE system.
245 ARGC and ARGV are set depending on the actual arguments given
246 in the spec. */
247
248const char *
249host_detect_local_cpu (int argc, const char **argv)
250{
7e1bcce3 251 const char *res = NULL;
8433cb91 252 static const int num_exts = ARRAY_SIZE (aarch64_extensions);
7e1bcce3
KT
253 FILE *f = NULL;
254 bool arch = false;
255 bool tune = false;
256 bool cpu = false;
257 unsigned int i = 0;
2e721daa
AP
258 unsigned char imp = INVALID_IMP;
259 unsigned int cores[2] = { INVALID_CORE, INVALID_CORE };
7e1bcce3 260 unsigned int n_cores = 0;
e8fcc9fa
AP
261 unsigned int variants[2] = { ALL_VARIANTS, ALL_VARIANTS };
262 unsigned int n_variants = 0;
7e1bcce3 263 bool processed_exts = false;
fed55a60
RS
264 aarch64_feature_flags extension_flags = 0;
265 aarch64_feature_flags default_flags = 0;
b399f3c6
TC
266 std::string buf;
267 size_t sep_pos = -1;
55f6addc 268 char *fcpu_info;
7e1bcce3
KT
269
270 gcc_assert (argc);
271
272 if (!argv[0])
273 goto not_found;
274
275 /* Are we processing -march, mtune or mcpu? */
276 arch = strcmp (argv[0], "arch") == 0;
277 if (!arch)
278 tune = strcmp (argv[0], "tune") == 0;
279
280 if (!arch && !tune)
281 cpu = strcmp (argv[0], "cpu") == 0;
282
283 if (!arch && !tune && !cpu)
284 goto not_found;
285
55f6addc
TC
286 fcpu_info = getenv ("GCC_CPUINFO");
287 if (fcpu_info)
288 f = fopen (fcpu_info, "r");
289 else
290 f = fopen ("/proc/cpuinfo", "r");
7e1bcce3
KT
291
292 if (f == NULL)
293 goto not_found;
294
295 /* Look through /proc/cpuinfo to determine the implementer
296 and then the part number that identifies a particular core. */
b399f3c6 297 while (!(buf = readline (f)).empty ())
7e1bcce3 298 {
b399f3c6 299 if (find_field (buf, "implementer") != std::string::npos)
7e1bcce3 300 {
2e721daa
AP
301 unsigned cimp = parse_field (buf);
302 if (cimp == INVALID_IMP)
303 goto not_found;
304
305 if (imp == INVALID_IMP)
306 imp = cimp;
307 /* FIXME: BIG.little implementers are always equal. */
308 else if (imp != cimp)
309 goto not_found;
7e1bcce3 310 }
b399f3c6 311 else if (find_field (buf, "variant") != std::string::npos)
e8fcc9fa
AP
312 {
313 unsigned cvariant = parse_field (buf);
314 if (!contains_core_p (variants, cvariant))
315 {
316 if (n_variants == 2)
317 goto not_found;
318
319 variants[n_variants++] = cvariant;
320 }
321 continue;
322 }
b399f3c6 323 else if (find_field (buf, "part") != std::string::npos)
7e1bcce3 324 {
2e721daa 325 unsigned ccore = parse_field (buf);
bd5849af
AP
326 if (!contains_core_p (cores, ccore))
327 {
328 if (n_cores == 2)
329 goto not_found;
330
331 cores[n_cores++] = ccore;
332 }
8433cb91
JG
333 continue;
334 }
b399f3c6
TC
335 else if (!tune && !processed_exts
336 && (sep_pos = find_field (buf, "Features")) != std::string::npos)
8433cb91 337 {
b399f3c6
TC
338 /* First create the list of features in the buffer. */
339 std::set<std::string> features;
340 /* Drop everything till the :. */
341 buf = buf.substr (sep_pos + 1);
342 split_words (buf, features);
343
8433cb91
JG
344 for (i = 0; i < num_exts; i++)
345 {
b399f3c6 346 const std::string val (aarch64_extensions[i].feat_string);
29c6debc
TC
347
348 /* If the feature contains no HWCAPS string then ignore it for the
349 auto detection. */
b399f3c6 350 if (val.empty ())
29c6debc
TC
351 continue;
352
8433cb91
JG
353 bool enabled = true;
354
355 /* This may be a multi-token feature string. We need
29c6debc 356 to match all parts, which could be in any order. */
b399f3c6
TC
357 std::set<std::string> tokens;
358 split_words (val, tokens);
359 std::set<std::string>::iterator it;
360
361 /* Iterate till the first feature isn't found or all of them
362 are found. */
363 for (it = tokens.begin (); enabled && it != tokens.end (); ++it)
364 enabled = enabled && features.count (*it);
8433cb91
JG
365
366 if (enabled)
367 extension_flags |= aarch64_extensions[i].flag;
368 else
369 extension_flags &= ~(aarch64_extensions[i].flag);
370 }
371
372 processed_exts = true;
373 }
7e1bcce3
KT
374 }
375
376 fclose (f);
377 f = NULL;
378
379 /* Weird cpuinfo format that we don't know how to handle. */
e8fcc9fa
AP
380 if (n_cores == 0
381 || n_cores > 2
382 || (n_cores == 1 && n_variants != 1)
383 || imp == INVALID_IMP)
7e1bcce3
KT
384 goto not_found;
385
e8fcc9fa
AP
386 /* Simple case, one core type or just looking for the arch. */
387 if (n_cores == 1 || arch)
7e1bcce3 388 {
bd5849af
AP
389 /* Search for one of the cores in the list. */
390 for (i = 0; aarch64_cpu_data[i].name != NULL; i++)
391 if (aarch64_cpu_data[i].implementer_id == imp
e8fcc9fa
AP
392 && cores[0] == aarch64_cpu_data[i].part_no
393 && (aarch64_cpu_data[i].variant == ALL_VARIANTS
394 || variants[0] == aarch64_cpu_data[i].variant))
395 break;
e91a17fe 396
e8fcc9fa 397 if (aarch64_cpu_data[i].name == NULL)
e91a17fe 398 {
60dee638 399 auto arch_info = get_arch_from_id (DEFAULT_ARCH);
e91a17fe
TC
400
401 gcc_assert (arch_info);
e8fcc9fa 402
e91a17fe
TC
403 res = concat ("-march=", arch_info->name, NULL);
404 default_flags = arch_info->flags;
405 }
406 else if (arch)
e8fcc9fa
AP
407 {
408 const char *arch_id = aarch64_cpu_data[i].arch;
60dee638 409 auto arch_info = get_arch_from_id (arch_id);
7e1bcce3 410
e8fcc9fa
AP
411 /* We got some arch indentifier that's not in aarch64-arches.def? */
412 if (!arch_info)
413 goto not_found;
7e1bcce3 414
e8fcc9fa
AP
415 res = concat ("-march=", arch_info->name, NULL);
416 default_flags = arch_info->flags;
417 }
418 else
419 {
420 default_flags = aarch64_cpu_data[i].flags;
421 res = concat ("-m",
422 cpu ? "cpu" : "tune", "=",
423 aarch64_cpu_data[i].name,
424 NULL);
425 }
7e1bcce3
KT
426 }
427 /* We have big.LITTLE. */
e8fcc9fa 428 else
7e1bcce3 429 {
8433cb91
JG
430 for (i = 0; aarch64_cpu_data[i].name != NULL; i++)
431 {
2e721daa
AP
432 if (aarch64_cpu_data[i].implementer_id == imp
433 && valid_bL_core_p (cores, aarch64_cpu_data[i].part_no))
8433cb91
JG
434 {
435 res = concat ("-m",
436 cpu ? "cpu" : "tune", "=",
437 aarch64_cpu_data[i].name,
438 NULL);
439 default_flags = aarch64_cpu_data[i].flags;
440 break;
441 }
442 }
7e1bcce3 443 if (!res)
8433cb91 444 goto not_found;
7e1bcce3 445 }
7e1bcce3
KT
446
447 if (tune)
448 return res;
449
6770fa53
DM
450 {
451 std::string extension
452 = aarch64_get_extension_string_for_isa_flags (extension_flags,
453 default_flags);
454 res = concat (res, extension.c_str (), NULL);
455 }
7e1bcce3
KT
456
457 return res;
458
459not_found:
460 {
461 /* If detection fails we ignore the option.
29c6debc 462 Clean up and return NULL. */
7e1bcce3
KT
463
464 if (f)
465 fclose (f);
466
29c6debc 467 return NULL;
7e1bcce3
KT
468 }
469}
470