testsuite: Add dg-require-effective-target scheduling for some tests that set -fsched...
[official-gcc.git] / gcc / config / aarch64 / driver-aarch64.cc
blobb620351e572038d84da5d401a9c295fe19797b4e
1 /* Native CPU detection for aarch64.
2 Copyright (C) 2015-2024 Free Software Foundation, Inc.
4 This file is part of GCC.
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.
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.
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/>. */
20 #define IN_TARGET_CODE 1
22 #include "config.h"
23 #define INCLUDE_STRING
24 #define INCLUDE_SET
25 #include "system.h"
26 #include "coretypes.h"
27 #include "tm.h"
28 #include "aarch64-protos.h"
29 #include "aarch64-feature-deps.h"
31 struct aarch64_arch_extension
33 const char *ext;
34 aarch64_feature_flags flag;
35 const char *feat_string;
38 #define AARCH64_OPT_EXTENSION(EXT_NAME, IDENT, C, D, E, FEATURE_STRING) \
39 { EXT_NAME, AARCH64_FL_##IDENT, FEATURE_STRING },
40 static struct aarch64_arch_extension aarch64_extensions[] =
42 #include "aarch64-option-extensions.def"
46 struct aarch64_core_data
48 const char* name;
49 const char* arch;
50 unsigned char implementer_id; /* Exactly 8 bits */
51 unsigned int part_no; /* 12 bits + 12 bits */
52 unsigned variant;
53 aarch64_feature_flags flags;
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)
60 #define ALL_VARIANTS ((unsigned)-1)
61 /* Default architecture to use if -mcpu=native did not detect a known CPU. */
62 #define DEFAULT_ARCH "8A"
64 #define AARCH64_CORE(CORE_NAME, CORE_IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART, VARIANT) \
65 { CORE_NAME, #ARCH, IMP, PART, VARIANT, feature_deps::cpu_##CORE_IDENT },
67 static CONSTEXPR const aarch64_core_data aarch64_cpu_data[] =
69 #include "aarch64-cores.def"
70 { NULL, NULL, INVALID_IMP, INVALID_CORE, ALL_VARIANTS, 0 }
74 struct aarch64_arch_driver_info
76 const char* id;
77 const char* name;
78 aarch64_feature_flags flags;
81 /* Skip the leading "V" in the architecture name. */
82 #define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH_REV, FLAGS) \
83 { #ARCH_IDENT + 1, NAME, feature_deps::ARCH_IDENT ().enable },
85 static CONSTEXPR const aarch64_arch_driver_info aarch64_arches[] =
87 #include "aarch64-arches.def"
88 {NULL, NULL, 0}
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. */
95 static const aarch64_arch_driver_info *
96 get_arch_from_id (const char* id)
98 unsigned int i = 0;
100 for (i = 0; aarch64_arches[i].id != NULL; i++)
102 if (strcmp (id, aarch64_arches[i].id) == 0)
103 return &aarch64_arches[i];
106 return NULL;
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. */
113 static bool
114 valid_bL_core_p (unsigned int *core, unsigned int bL_core)
116 return AARCH64_BIG_LITTLE (core[0], core[1]) == bL_core
117 || AARCH64_BIG_LITTLE (core[1], core[0]) == bL_core;
120 /* Returns the hex integer that is after ':' for the FIELD.
121 Returns -1 is returned if there was problem parsing the integer. */
122 static unsigned
123 parse_field (const std::string &field)
125 const char *rest = strchr (field.c_str (), ':');
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;
132 char *after;
133 unsigned fint = strtol (rest + 1, &after, 16);
134 if (after == rest + 1)
135 return -1;
136 return fint;
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. */
143 static size_t
144 find_field (const std::string &field, const std::string &key)
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;
151 sep_pos = field.find (":", key_pos + 1);
152 if (sep_pos == std::string::npos)
153 return std::string::npos;
155 return sep_pos;
158 /* Splits and returns a string based on whitespace and return it as
159 part of a set. Empty strings are ignored. */
161 static void
162 split_words (const std::string &val, std::set<std::string> &result)
164 size_t cur, prev = 0;
165 std::string word;
166 while ((cur = val.find_first_of (" \n", prev)) != std::string::npos)
168 word = val.substr (prev, cur - prev);
169 /* Skip adding empty words. */
170 if (!word.empty ())
171 result.insert (word);
172 prev = cur + 1;
175 if (prev != cur)
176 result.insert (val.substr (prev));
179 /* Read an entire line from F until '\n' or EOF. */
181 static std::string
182 readline (FILE *f)
184 char *buf = NULL;
185 int size = 0;
186 int last = 0;
187 const int buf_size = 128;
189 if (feof (f))
190 return std::string ();
194 size += buf_size;
195 buf = (char*) xrealloc (buf, size);
196 gcc_assert (buf);
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 ();
204 /* If we're not at the end of the line then override the
205 \0 added by fgets. */
206 last = strnlen (buf, size);
208 while (!feof (f) && last > 0 && buf[last - 1] != '\n');
210 std::string result (buf);
211 free (buf);
212 return result;
215 /* Return true iff ARR contains CORE, in either of the two elements. */
217 static bool
218 contains_core_p (unsigned *arr, unsigned core)
220 if (arr[0] != INVALID_CORE)
222 if (arr[0] == core)
223 return true;
225 if (arr[1] != INVALID_CORE)
226 return arr[1] == core;
229 return false;
232 /* This will be called by the spec parser in gcc.cc when it sees
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.
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.
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. */
248 const char *
249 host_detect_local_cpu (int argc, const char **argv)
251 const char *res = NULL;
252 static const int num_exts = ARRAY_SIZE (aarch64_extensions);
253 FILE *f = NULL;
254 bool arch = false;
255 bool tune = false;
256 bool cpu = false;
257 unsigned int i = 0;
258 unsigned char imp = INVALID_IMP;
259 unsigned int cores[2] = { INVALID_CORE, INVALID_CORE };
260 unsigned int n_cores = 0;
261 unsigned int variants[2] = { ALL_VARIANTS, ALL_VARIANTS };
262 unsigned int n_variants = 0;
263 bool processed_exts = false;
264 aarch64_feature_flags extension_flags = 0;
265 aarch64_feature_flags unchecked_extension_flags = 0;
266 aarch64_feature_flags default_flags = 0;
267 std::string buf;
268 size_t sep_pos = -1;
269 char *fcpu_info;
271 gcc_assert (argc);
273 if (!argv[0])
274 goto not_found;
276 /* Are we processing -march, mtune or mcpu? */
277 arch = strcmp (argv[0], "arch") == 0;
278 if (!arch)
279 tune = strcmp (argv[0], "tune") == 0;
281 if (!arch && !tune)
282 cpu = strcmp (argv[0], "cpu") == 0;
284 if (!arch && !tune && !cpu)
285 goto not_found;
287 fcpu_info = getenv ("GCC_CPUINFO");
288 if (fcpu_info)
289 f = fopen (fcpu_info, "r");
290 else
291 f = fopen ("/proc/cpuinfo", "r");
293 if (f == NULL)
294 goto not_found;
296 /* Look through /proc/cpuinfo to determine the implementer
297 and then the part number that identifies a particular core. */
298 while (!(buf = readline (f)).empty ())
300 if (find_field (buf, "implementer") != std::string::npos)
302 unsigned cimp = parse_field (buf);
303 if (cimp == INVALID_IMP)
304 goto not_found;
306 if (imp == INVALID_IMP)
307 imp = cimp;
308 /* FIXME: BIG.little implementers are always equal. */
309 else if (imp != cimp)
310 goto not_found;
312 else if (find_field (buf, "variant") != std::string::npos)
314 unsigned cvariant = parse_field (buf);
315 if (!contains_core_p (variants, cvariant))
317 if (n_variants == 2)
318 goto not_found;
320 variants[n_variants++] = cvariant;
322 continue;
324 else if (find_field (buf, "part") != std::string::npos)
326 unsigned ccore = parse_field (buf);
327 if (!contains_core_p (cores, ccore))
329 if (n_cores == 2)
330 goto not_found;
332 cores[n_cores++] = ccore;
334 continue;
336 else if (!tune && !processed_exts
337 && (sep_pos = find_field (buf, "Features")) != std::string::npos)
339 /* First create the list of features in the buffer. */
340 std::set<std::string> features;
341 /* Drop everything till the :. */
342 buf = buf.substr (sep_pos + 1);
343 split_words (buf, features);
345 for (i = 0; i < num_exts; i++)
347 const std::string val (aarch64_extensions[i].feat_string);
349 /* If the feature contains no HWCAPS string then ignore it for the
350 auto detection. */
351 if (val.empty ())
353 unchecked_extension_flags |= aarch64_extensions[i].flag;
354 continue;
357 bool enabled = true;
359 /* This may be a multi-token feature string. We need
360 to match all parts, which could be in any order. */
361 std::set<std::string> tokens;
362 split_words (val, tokens);
363 std::set<std::string>::iterator it;
365 /* Iterate till the first feature isn't found or all of them
366 are found. */
367 for (it = tokens.begin (); enabled && it != tokens.end (); ++it)
368 enabled = enabled && features.count (*it);
370 if (enabled)
371 extension_flags |= aarch64_extensions[i].flag;
372 else
373 extension_flags &= ~(aarch64_extensions[i].flag);
376 processed_exts = true;
380 fclose (f);
381 f = NULL;
383 /* Weird cpuinfo format that we don't know how to handle. */
384 if (n_cores == 0
385 || n_cores > 2
386 || (n_cores == 1 && n_variants != 1)
387 || imp == INVALID_IMP
388 || !processed_exts)
389 goto not_found;
391 /* Simple case, one core type or just looking for the arch. */
392 if (n_cores == 1 || arch)
394 /* Search for one of the cores in the list. */
395 for (i = 0; aarch64_cpu_data[i].name != NULL; i++)
396 if (aarch64_cpu_data[i].implementer_id == imp
397 && cores[0] == aarch64_cpu_data[i].part_no
398 && (aarch64_cpu_data[i].variant == ALL_VARIANTS
399 || variants[0] == aarch64_cpu_data[i].variant))
400 break;
402 if (aarch64_cpu_data[i].name == NULL)
404 auto arch_info = get_arch_from_id (DEFAULT_ARCH);
406 gcc_assert (arch_info);
408 res = concat ("-march=", arch_info->name, NULL);
409 default_flags = arch_info->flags;
411 else if (arch)
413 const char *arch_id = aarch64_cpu_data[i].arch;
414 auto arch_info = get_arch_from_id (arch_id);
416 /* We got some arch indentifier that's not in aarch64-arches.def? */
417 if (!arch_info)
418 goto not_found;
420 res = concat ("-march=", arch_info->name, NULL);
421 default_flags = arch_info->flags;
423 else
425 default_flags = aarch64_cpu_data[i].flags;
426 res = concat ("-m",
427 cpu ? "cpu" : "tune", "=",
428 aarch64_cpu_data[i].name,
429 NULL);
432 /* We have big.LITTLE. */
433 else
435 for (i = 0; aarch64_cpu_data[i].name != NULL; i++)
437 if (aarch64_cpu_data[i].implementer_id == imp
438 && valid_bL_core_p (cores, aarch64_cpu_data[i].part_no))
440 res = concat ("-m",
441 cpu ? "cpu" : "tune", "=",
442 aarch64_cpu_data[i].name,
443 NULL);
444 default_flags = aarch64_cpu_data[i].flags;
445 break;
448 if (!res)
449 goto not_found;
452 if (tune)
453 return res;
455 /* Add any features that should be present, but can't be verified using
456 the /proc/cpuinfo "Features" list. */
457 extension_flags |= unchecked_extension_flags & default_flags;
460 std::string extension
461 = aarch64_get_extension_string_for_isa_flags (extension_flags,
462 default_flags);
463 res = concat (res, extension.c_str (), NULL);
466 return res;
468 not_found:
470 /* If detection fails we ignore the option.
471 Clean up and return NULL. */
473 if (f)
474 fclose (f);
476 return NULL;