1 /* Native CPU detection for aarch64.
2 Copyright (C) 2015-2019 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)
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
23 #define INCLUDE_STRING
25 #include "coretypes.h"
28 /* Defined in common/config/aarch64/aarch64-common.c. */
29 std::string
aarch64_get_extension_string_for_isa_flags (unsigned long,
32 struct aarch64_arch_extension
36 const char *feat_string
;
39 #define AARCH64_OPT_EXTENSION(EXT_NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, \
40 SYNTHETIC, FEATURE_STRING) \
41 { EXT_NAME, FLAG_CANONICAL, FEATURE_STRING },
42 static struct aarch64_arch_extension aarch64_extensions
[] =
44 #include "aarch64-option-extensions.def"
48 struct aarch64_core_data
52 unsigned char implementer_id
; /* Exactly 8 bits */
53 unsigned int part_no
; /* 12 bits + 12 bits */
58 #define AARCH64_BIG_LITTLE(BIG, LITTLE) \
59 (((BIG)&0xFFFu) << 12 | ((LITTLE) & 0xFFFu))
60 #define INVALID_IMP ((unsigned char) -1)
61 #define INVALID_CORE ((unsigned)-1)
62 #define ALL_VARIANTS ((unsigned)-1)
64 #define AARCH64_CORE(CORE_NAME, CORE_IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART, VARIANT) \
65 { CORE_NAME, #ARCH, IMP, PART, VARIANT, FLAGS },
67 static struct 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
81 #define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH_REV, FLAGS) \
82 { #ARCH_IDENT, NAME, FLAGS },
84 static struct aarch64_arch_driver_info aarch64_arches
[] =
86 #include "aarch64-arches.def"
91 /* Return an aarch64_arch_driver_info for the architecture described
92 by ID, or NULL if ID describes something we don't know about. */
94 static struct aarch64_arch_driver_info
*
95 get_arch_from_id (const char* id
)
99 for (i
= 0; aarch64_arches
[i
].id
!= NULL
; i
++)
101 if (strcmp (id
, aarch64_arches
[i
].id
) == 0)
102 return &aarch64_arches
[i
];
108 /* Check wether the CORE array is the same as the big.LITTLE BL_CORE.
109 For an example CORE={0xd08, 0xd03} and
110 BL_CORE=AARCH64_BIG_LITTLE (0xd08, 0xd03) will return true. */
113 valid_bL_core_p (unsigned int *core
, unsigned int bL_core
)
115 return AARCH64_BIG_LITTLE (core
[0], core
[1]) == bL_core
116 || AARCH64_BIG_LITTLE (core
[1], core
[0]) == bL_core
;
119 /* Returns the hex integer that is after ':' for the FIELD.
120 Returns -1 is returned if there was problem parsing the integer. */
122 parse_field (const char *field
)
124 const char *rest
= strchr (field
, ':');
126 unsigned fint
= strtol (rest
+ 1, &after
, 16);
127 if (after
== rest
+ 1)
132 /* Return true iff ARR contains CORE, in either of the two elements. */
135 contains_core_p (unsigned *arr
, unsigned core
)
137 if (arr
[0] != INVALID_CORE
)
142 if (arr
[1] != INVALID_CORE
)
143 return arr
[1] == core
;
149 /* This will be called by the spec parser in gcc.c when it sees
150 a %:local_cpu_detect(args) construct. Currently it will be called
151 with either "arch", "cpu" or "tune" as argument depending on if
152 -march=native, -mcpu=native or -mtune=native is to be substituted.
154 It returns a string containing new command line parameters to be
155 put at the place of the above two options, depending on what CPU
156 this is executed. E.g. "-march=armv8-a" on a Cortex-A57 for
157 -march=native. If the routine can't detect a known processor,
158 the -march or -mtune option is discarded.
160 For -mtune and -mcpu arguments it attempts to detect the CPU or
162 ARGC and ARGV are set depending on the actual arguments given
166 host_detect_local_cpu (int argc
, const char **argv
)
168 const char *res
= NULL
;
169 static const int num_exts
= ARRAY_SIZE (aarch64_extensions
);
176 unsigned char imp
= INVALID_IMP
;
177 unsigned int cores
[2] = { INVALID_CORE
, INVALID_CORE
};
178 unsigned int n_cores
= 0;
179 unsigned int variants
[2] = { ALL_VARIANTS
, ALL_VARIANTS
};
180 unsigned int n_variants
= 0;
181 bool processed_exts
= false;
182 uint64_t extension_flags
= 0;
183 uint64_t default_flags
= 0;
190 /* Are we processing -march, mtune or mcpu? */
191 arch
= strcmp (argv
[0], "arch") == 0;
193 tune
= strcmp (argv
[0], "tune") == 0;
196 cpu
= strcmp (argv
[0], "cpu") == 0;
198 if (!arch
&& !tune
&& !cpu
)
201 f
= fopen ("/proc/cpuinfo", "r");
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
)
210 if (strstr (buf
, "implementer") != NULL
)
212 unsigned cimp
= parse_field (buf
);
213 if (cimp
== INVALID_IMP
)
216 if (imp
== INVALID_IMP
)
218 /* FIXME: BIG.little implementers are always equal. */
219 else if (imp
!= cimp
)
223 if (strstr (buf
, "variant") != NULL
)
225 unsigned cvariant
= parse_field (buf
);
226 if (!contains_core_p (variants
, cvariant
))
231 variants
[n_variants
++] = cvariant
;
236 if (strstr (buf
, "part") != NULL
)
238 unsigned ccore
= parse_field (buf
);
239 if (!contains_core_p (cores
, ccore
))
244 cores
[n_cores
++] = ccore
;
248 if (!tune
&& !processed_exts
&& strstr (buf
, "Features") != NULL
)
250 for (i
= 0; i
< num_exts
; i
++)
252 const char *p
= aarch64_extensions
[i
].feat_string
;
254 /* If the feature contains no HWCAPS string then ignore it for the
261 /* This may be a multi-token feature string. We need
262 to match all parts, which could be in any order. */
263 size_t len
= strlen (buf
);
266 const char *end
= strchr (p
, ' ');
268 end
= strchr (p
, '\0');
269 if (memmem (buf
, len
, p
, end
- p
) == NULL
)
271 /* Failed to match this token. Turn off the
272 features we'd otherwise enable. */
283 extension_flags
|= aarch64_extensions
[i
].flag
;
285 extension_flags
&= ~(aarch64_extensions
[i
].flag
);
288 processed_exts
= true;
295 /* Weird cpuinfo format that we don't know how to handle. */
298 || (n_cores
== 1 && n_variants
!= 1)
299 || imp
== INVALID_IMP
)
302 /* Simple case, one core type or just looking for the arch. */
303 if (n_cores
== 1 || arch
)
305 /* Search for one of the cores in the list. */
306 for (i
= 0; aarch64_cpu_data
[i
].name
!= NULL
; i
++)
307 if (aarch64_cpu_data
[i
].implementer_id
== imp
308 && cores
[0] == aarch64_cpu_data
[i
].part_no
309 && (aarch64_cpu_data
[i
].variant
== ALL_VARIANTS
310 || variants
[0] == aarch64_cpu_data
[i
].variant
))
312 if (aarch64_cpu_data
[i
].name
== NULL
)
317 const char *arch_id
= aarch64_cpu_data
[i
].arch
;
318 aarch64_arch_driver_info
* arch_info
= get_arch_from_id (arch_id
);
320 /* We got some arch indentifier that's not in aarch64-arches.def? */
324 res
= concat ("-march=", arch_info
->name
, NULL
);
325 default_flags
= arch_info
->flags
;
329 default_flags
= aarch64_cpu_data
[i
].flags
;
331 cpu
? "cpu" : "tune", "=",
332 aarch64_cpu_data
[i
].name
,
336 /* We have big.LITTLE. */
339 for (i
= 0; aarch64_cpu_data
[i
].name
!= NULL
; i
++)
341 if (aarch64_cpu_data
[i
].implementer_id
== imp
342 && valid_bL_core_p (cores
, aarch64_cpu_data
[i
].part_no
))
345 cpu
? "cpu" : "tune", "=",
346 aarch64_cpu_data
[i
].name
,
348 default_flags
= aarch64_cpu_data
[i
].flags
;
360 std::string extension
361 = aarch64_get_extension_string_for_isa_flags (extension_flags
,
363 res
= concat (res
, extension
.c_str (), NULL
);
370 /* If detection fails we ignore the option.
371 Clean up and return NULL. */