1 /* Native CPU detection for aarch64.
2 Copyright (C) 2015-2016 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/>. */
21 #define INCLUDE_STRING
23 #include "coretypes.h"
26 /* Defined in common/config/aarch64/aarch64-common.c. */
27 std::string
aarch64_get_extension_string_for_isa_flags (unsigned long,
30 struct aarch64_arch_extension
34 const char *feat_string
;
37 #define AARCH64_OPT_EXTENSION(EXT_NAME, FLAG_CANONICAL, FLAGS_ON, FLAGS_OFF, FEATURE_STRING) \
38 { EXT_NAME, FLAG_CANONICAL, FEATURE_STRING },
39 static struct aarch64_arch_extension aarch64_extensions
[] =
41 #include "aarch64-option-extensions.def"
45 struct aarch64_core_data
49 const char* implementer_id
;
51 const unsigned long flags
;
54 #define AARCH64_CORE(CORE_NAME, CORE_IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART) \
55 { CORE_NAME, #ARCH, IMP, PART, FLAGS },
57 static struct aarch64_core_data aarch64_cpu_data
[] =
59 #include "aarch64-cores.def"
60 { NULL
, NULL
, NULL
, NULL
, 0 }
64 struct aarch64_arch_driver_info
68 const unsigned long flags
;
71 #define AARCH64_ARCH(NAME, CORE, ARCH_IDENT, ARCH_REV, FLAGS) \
72 { #ARCH_IDENT, NAME, FLAGS },
74 static struct aarch64_arch_driver_info aarch64_arches
[] =
76 #include "aarch64-arches.def"
81 /* Return an aarch64_arch_driver_info for the architecture described
82 by ID, or NULL if ID describes something we don't know about. */
84 static struct aarch64_arch_driver_info
*
85 get_arch_from_id (const char* id
)
89 for (i
= 0; aarch64_arches
[i
].id
!= NULL
; i
++)
91 if (strcmp (id
, aarch64_arches
[i
].id
) == 0)
92 return &aarch64_arches
[i
];
98 /* Check wether the string CORE contains the same CPU part numbers
99 as BL_STRING. For example CORE="{0xd03, 0xd07}" and BL_STRING="0xd07.0xd03"
100 should return true. */
103 valid_bL_string_p (const char** core
, const char* bL_string
)
105 return strstr (bL_string
, core
[0]) != NULL
106 && strstr (bL_string
, core
[1]) != NULL
;
109 /* Return true iff ARR contains STR in one of its two elements. */
112 contains_string_p (const char** arr
, const char* str
)
118 res
= strstr (arr
[0], str
) != NULL
;
123 return strstr (arr
[1], str
) != NULL
;
129 /* This will be called by the spec parser in gcc.c when it sees
130 a %:local_cpu_detect(args) construct. Currently it will be called
131 with either "arch", "cpu" or "tune" as argument depending on if
132 -march=native, -mcpu=native or -mtune=native is to be substituted.
134 It returns a string containing new command line parameters to be
135 put at the place of the above two options, depending on what CPU
136 this is executed. E.g. "-march=armv8-a" on a Cortex-A57 for
137 -march=native. If the routine can't detect a known processor,
138 the -march or -mtune option is discarded.
140 For -mtune and -mcpu arguments it attempts to detect the CPU or
142 ARGC and ARGV are set depending on the actual arguments given
146 host_detect_local_cpu (int argc
, const char **argv
)
148 const char *arch_id
= NULL
;
149 const char *res
= NULL
;
150 static const int num_exts
= ARRAY_SIZE (aarch64_extensions
);
157 unsigned int core_idx
= 0;
158 const char* imps
[2] = { NULL
, NULL
};
159 const char* cores
[2] = { NULL
, NULL
};
160 unsigned int n_cores
= 0;
161 unsigned int n_imps
= 0;
162 bool processed_exts
= false;
163 const char *ext_string
= "";
164 unsigned long extension_flags
= 0;
165 unsigned long default_flags
= 0;
172 /* Are we processing -march, mtune or mcpu? */
173 arch
= strcmp (argv
[0], "arch") == 0;
175 tune
= strcmp (argv
[0], "tune") == 0;
178 cpu
= strcmp (argv
[0], "cpu") == 0;
180 if (!arch
&& !tune
&& !cpu
)
183 f
= fopen ("/proc/cpuinfo", "r");
188 /* Look through /proc/cpuinfo to determine the implementer
189 and then the part number that identifies a particular core. */
190 while (fgets (buf
, sizeof (buf
), f
) != NULL
)
192 if (strstr (buf
, "implementer") != NULL
)
194 for (i
= 0; aarch64_cpu_data
[i
].name
!= NULL
; i
++)
195 if (strstr (buf
, aarch64_cpu_data
[i
].implementer_id
) != NULL
196 && !contains_string_p (imps
,
197 aarch64_cpu_data
[i
].implementer_id
))
202 imps
[n_imps
++] = aarch64_cpu_data
[i
].implementer_id
;
209 if (strstr (buf
, "part") != NULL
)
211 for (i
= 0; aarch64_cpu_data
[i
].name
!= NULL
; i
++)
212 if (strstr (buf
, aarch64_cpu_data
[i
].part_no
) != NULL
213 && !contains_string_p (cores
, aarch64_cpu_data
[i
].part_no
))
218 cores
[n_cores
++] = aarch64_cpu_data
[i
].part_no
;
220 arch_id
= aarch64_cpu_data
[i
].arch
;
225 if (!tune
&& !processed_exts
&& strstr (buf
, "Features") != NULL
)
227 for (i
= 0; i
< num_exts
; i
++)
231 = concat (aarch64_extensions
[i
].feat_string
, NULL
);
234 /* This may be a multi-token feature string. We need
235 to match all parts, which could be in any order.
236 If this isn't a multi-token feature string, strtok is
237 just going to return a pointer to feat_string. */
238 p
= strtok (feat_string
, " ");
241 if (strstr (buf
, p
) == NULL
)
243 /* Failed to match this token. Turn off the
244 features we'd otherwise enable. */
248 p
= strtok (NULL
, " ");
252 extension_flags
|= aarch64_extensions
[i
].flag
;
254 extension_flags
&= ~(aarch64_extensions
[i
].flag
);
257 processed_exts
= true;
264 /* Weird cpuinfo format that we don't know how to handle. */
265 if (n_cores
== 0 || n_cores
> 2 || n_imps
!= 1)
268 if (arch
&& !arch_id
)
273 struct aarch64_arch_driver_info
* arch_info
= get_arch_from_id (arch_id
);
275 /* We got some arch indentifier that's not in aarch64-arches.def? */
279 res
= concat ("-march=", arch_info
->name
, NULL
);
280 default_flags
= arch_info
->flags
;
282 /* We have big.LITTLE. */
283 else if (n_cores
== 2)
285 for (i
= 0; aarch64_cpu_data
[i
].name
!= NULL
; i
++)
287 if (strchr (aarch64_cpu_data
[i
].part_no
, '.') != NULL
288 && strncmp (aarch64_cpu_data
[i
].implementer_id
,
290 strlen (imps
[0]) - 1) == 0
291 && valid_bL_string_p (cores
, aarch64_cpu_data
[i
].part_no
))
294 cpu
? "cpu" : "tune", "=",
295 aarch64_cpu_data
[i
].name
,
297 default_flags
= aarch64_cpu_data
[i
].flags
;
304 /* The simple, non-big.LITTLE case. */
307 if (strncmp (aarch64_cpu_data
[core_idx
].implementer_id
, imps
[0],
308 strlen (imps
[0]) - 1) != 0)
311 res
= concat ("-m", cpu
? "cpu" : "tune", "=",
312 aarch64_cpu_data
[core_idx
].name
, NULL
);
313 default_flags
= aarch64_cpu_data
[core_idx
].flags
;
320 = aarch64_get_extension_string_for_isa_flags (extension_flags
,
321 default_flags
).c_str ();
323 res
= concat (res
, ext_string
, NULL
);
329 /* If detection fails we ignore the option.
330 Clean up and return empty string. */