version 1.1.1.1.2.1, 2018/11/26 01:50:41 |
version 1.1.1.1.2.2, 2019/01/26 21:58:34 |
|
|
/* Native CPU detection for aarch64. |
/* Native CPU detection for aarch64. |
Copyright (C) 2015-2016 Free Software Foundation, Inc. |
Copyright (C) 2015-2017 Free Software Foundation, Inc. |
|
|
This file is part of GCC. |
This file is part of GCC. |
|
|
Line 41 static struct aarch64_arch_extension aar |
|
Line 41 static struct aarch64_arch_extension aar |
|
{ |
{ |
#include "aarch64-option-extensions.def" |
#include "aarch64-option-extensions.def" |
}; |
}; |
#undef AARCH64_OPT_EXTENSION |
|
|
|
|
|
struct aarch64_core_data |
struct aarch64_core_data |
{ |
{ |
const char* name; |
const char* name; |
const char* arch; |
const char* arch; |
const char* implementer_id; |
unsigned char implementer_id; /* Exactly 8 bits */ |
const char* part_no; |
unsigned int part_no; /* 12 bits + 12 bits */ |
|
unsigned variant; |
const unsigned long flags; |
const unsigned long flags; |
}; |
}; |
|
|
#define AARCH64_CORE(CORE_NAME, CORE_IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART) \ |
#define AARCH64_BIG_LITTLE(BIG, LITTLE) \ |
{ CORE_NAME, #ARCH, IMP, PART, FLAGS }, |
(((BIG)&0xFFFu) << 12 | ((LITTLE) & 0xFFFu)) |
|
#define INVALID_IMP ((unsigned char) -1) |
|
#define INVALID_CORE ((unsigned)-1) |
|
#define ALL_VARIANTS ((unsigned)-1) |
|
|
|
#define AARCH64_CORE(CORE_NAME, CORE_IDENT, SCHED, ARCH, FLAGS, COSTS, IMP, PART, VARIANT) \ |
|
{ CORE_NAME, #ARCH, IMP, PART, VARIANT, FLAGS }, |
|
|
static struct aarch64_core_data aarch64_cpu_data[] = |
static struct aarch64_core_data aarch64_cpu_data[] = |
{ |
{ |
#include "aarch64-cores.def" |
#include "aarch64-cores.def" |
{ NULL, NULL, NULL, NULL, 0 } |
{ NULL, NULL, INVALID_IMP, INVALID_CORE, ALL_VARIANTS, 0 } |
}; |
}; |
|
|
#undef AARCH64_CORE |
|
|
|
struct aarch64_arch_driver_info |
struct aarch64_arch_driver_info |
{ |
{ |
Line 80 static struct aarch64_arch_driver_info a |
|
Line 85 static struct aarch64_arch_driver_info a |
|
{NULL, NULL, 0} |
{NULL, NULL, 0} |
}; |
}; |
|
|
#undef AARCH64_ARCH |
|
|
|
/* Return an aarch64_arch_driver_info for the architecture described |
/* Return an aarch64_arch_driver_info for the architecture described |
by ID, or NULL if ID describes something we don't know about. */ |
by ID, or NULL if ID describes something we don't know about. */ |
Line 99 get_arch_from_id (const char* id) |
|
Line 103 get_arch_from_id (const char* id) |
|
return NULL; |
return NULL; |
} |
} |
|
|
/* Check wether the string CORE contains the same CPU part numbers |
/* Check wether the CORE array is the same as the big.LITTLE BL_CORE. |
as BL_STRING. For example CORE="{0xd03, 0xd07}" and BL_STRING="0xd07.0xd03" |
For an example CORE={0xd08, 0xd03} and |
should return true. */ |
BL_CORE=AARCH64_BIG_LITTLE (0xd08, 0xd03) will return true. */ |
|
|
static bool |
static bool |
valid_bL_string_p (const char** core, const char* bL_string) |
valid_bL_core_p (unsigned int *core, unsigned int bL_core) |
{ |
{ |
return strstr (bL_string, core[0]) != NULL |
return AARCH64_BIG_LITTLE (core[0], core[1]) == bL_core |
&& strstr (bL_string, core[1]) != NULL; |
|| AARCH64_BIG_LITTLE (core[1], core[0]) == bL_core; |
|
} |
|
|
|
/* Returns the hex integer that is after ':' for the FIELD. |
|
Returns -1 is returned if there was problem parsing the integer. */ |
|
static unsigned |
|
parse_field (const char *field) |
|
{ |
|
const char *rest = strchr (field, ':'); |
|
char *after; |
|
unsigned fint = strtol (rest + 1, &after, 16); |
|
if (after == rest + 1) |
|
return -1; |
|
return fint; |
} |
} |
|
|
/* Return true iff ARR contains STR in one of its two elements. */ |
/* Return true iff ARR contains CORE, in either of the two elements. */ |
|
|
static bool |
static bool |
contains_string_p (const char** arr, const char* str) |
contains_core_p (unsigned *arr, unsigned core) |
{ |
{ |
bool res = false; |
if (arr[0] != INVALID_CORE) |
|
|
if (arr[0] != NULL) |
|
{ |
{ |
res = strstr (arr[0], str) != NULL; |
if (arr[0] == core) |
if (res) |
return true; |
return res; |
|
|
|
if (arr[1] != NULL) |
if (arr[1] != INVALID_CORE) |
return strstr (arr[1], str) != NULL; |
return arr[1] == core; |
} |
} |
|
|
return false; |
return false; |
|
|
const char * |
const char * |
host_detect_local_cpu (int argc, const char **argv) |
host_detect_local_cpu (int argc, const char **argv) |
{ |
{ |
const char *arch_id = NULL; |
|
const char *res = NULL; |
const char *res = NULL; |
static const int num_exts = ARRAY_SIZE (aarch64_extensions); |
static const int num_exts = ARRAY_SIZE (aarch64_extensions); |
char buf[128]; |
char buf[128]; |
Line 360 host_detect_local_cpu (int argc, const c |
|
Line 373 host_detect_local_cpu (int argc, const c |
|
bool tune = false; |
bool tune = false; |
bool cpu = false; |
bool cpu = false; |
unsigned int i = 0; |
unsigned int i = 0; |
unsigned int core_idx = 0; |
unsigned char imp = INVALID_IMP; |
const char* imps[2] = { NULL, NULL }; |
unsigned int cores[2] = { INVALID_CORE, INVALID_CORE }; |
const char* cores[2] = { NULL, NULL }; |
|
unsigned int n_cores = 0; |
unsigned int n_cores = 0; |
unsigned int n_imps = 0; |
unsigned int variants[2] = { ALL_VARIANTS, ALL_VARIANTS }; |
|
unsigned int n_variants = 0; |
bool processed_exts = false; |
bool processed_exts = false; |
const char *ext_string = ""; |
const char *ext_string = ""; |
unsigned long extension_flags = 0; |
unsigned long extension_flags = 0; |
Line 397 host_detect_local_cpu (int argc, const c |
|
Line 410 host_detect_local_cpu (int argc, const c |
|
{ |
{ |
if (strstr (buf, "implementer") != NULL) |
if (strstr (buf, "implementer") != NULL) |
{ |
{ |
for (i = 0; aarch64_cpu_data[i].name != NULL; i++) |
unsigned cimp = parse_field (buf); |
if (strstr (buf, aarch64_cpu_data[i].implementer_id) != NULL |
if (cimp == INVALID_IMP) |
&& !contains_string_p (imps, |
goto not_found; |
aarch64_cpu_data[i].implementer_id)) |
|
{ |
if (imp == INVALID_IMP) |
if (n_imps == 2) |
imp = cimp; |
goto not_found; |
/* FIXME: BIG.little implementers are always equal. */ |
|
else if (imp != cimp) |
|
goto not_found; |
|
} |
|
|
imps[n_imps++] = aarch64_cpu_data[i].implementer_id; |
if (strstr (buf, "variant") != NULL) |
|
{ |
|
unsigned cvariant = parse_field (buf); |
|
if (!contains_core_p (variants, cvariant)) |
|
{ |
|
if (n_variants == 2) |
|
goto not_found; |
|
|
break; |
variants[n_variants++] = cvariant; |
} |
} |
continue; |
continue; |
} |
} |
|
|
if (strstr (buf, "part") != NULL) |
if (strstr (buf, "part") != NULL) |
{ |
{ |
for (i = 0; aarch64_cpu_data[i].name != NULL; i++) |
unsigned ccore = parse_field (buf); |
if (strstr (buf, aarch64_cpu_data[i].part_no) != NULL |
if (!contains_core_p (cores, ccore)) |
&& !contains_string_p (cores, aarch64_cpu_data[i].part_no)) |
{ |
{ |
if (n_cores == 2) |
if (n_cores == 2) |
goto not_found; |
goto not_found; |
|
|
|
cores[n_cores++] = aarch64_cpu_data[i].part_no; |
cores[n_cores++] = ccore; |
core_idx = i; |
} |
arch_id = aarch64_cpu_data[i].arch; |
|
break; |
|
} |
|
continue; |
continue; |
} |
} |
if (!tune && !processed_exts && strstr (buf, "Features") != NULL) |
if (!tune && !processed_exts && strstr (buf, "Features") != NULL) |
Line 468 host_detect_local_cpu (int argc, const c |
|
Line 486 host_detect_local_cpu (int argc, const c |
|
f = NULL; |
f = NULL; |
|
|
/* Weird cpuinfo format that we don't know how to handle. */ |
/* Weird cpuinfo format that we don't know how to handle. */ |
if (n_cores == 0 || n_cores > 2 || n_imps != 1) |
if (n_cores == 0 |
goto not_found; |
|| n_cores > 2 |
|
|| (n_cores == 1 && n_variants != 1) |
if (arch && !arch_id) |
|| imp == INVALID_IMP) |
goto not_found; |
goto not_found; |
|
|
if (arch) |
/* Simple case, one core type or just looking for the arch. */ |
|
if (n_cores == 1 || arch) |
{ |
{ |
struct aarch64_arch_driver_info* arch_info = get_arch_from_id (arch_id); |
/* Search for one of the cores in the list. */ |
|
for (i = 0; aarch64_cpu_data[i].name != NULL; i++) |
|
if (aarch64_cpu_data[i].implementer_id == imp |
|
&& cores[0] == aarch64_cpu_data[i].part_no |
|
&& (aarch64_cpu_data[i].variant == ALL_VARIANTS |
|
|| variants[0] == aarch64_cpu_data[i].variant)) |
|
break; |
|
if (aarch64_cpu_data[i].name == NULL) |
|
goto not_found; |
|
|
/* We got some arch indentifier that's not in aarch64-arches.def? */ |
if (arch) |
if (!arch_info) |
{ |
goto not_found; |
const char *arch_id = aarch64_cpu_data[i].arch; |
|
aarch64_arch_driver_info* arch_info = get_arch_from_id (arch_id); |
|
|
res = concat ("-march=", arch_info->name, NULL); |
/* We got some arch indentifier that's not in aarch64-arches.def? */ |
default_flags = arch_info->flags; |
if (!arch_info) |
|
goto not_found; |
|
|
|
res = concat ("-march=", arch_info->name, NULL); |
|
default_flags = arch_info->flags; |
|
} |
|
else |
|
{ |
|
default_flags = aarch64_cpu_data[i].flags; |
|
res = concat ("-m", |
|
cpu ? "cpu" : "tune", "=", |
|
aarch64_cpu_data[i].name, |
|
NULL); |
|
} |
} |
} |
/* We have big.LITTLE. */ |
/* We have big.LITTLE. */ |
else if (n_cores == 2) |
else |
{ |
{ |
for (i = 0; aarch64_cpu_data[i].name != NULL; i++) |
for (i = 0; aarch64_cpu_data[i].name != NULL; i++) |
{ |
{ |
if (strchr (aarch64_cpu_data[i].part_no, '.') != NULL |
if (aarch64_cpu_data[i].implementer_id == imp |
&& strncmp (aarch64_cpu_data[i].implementer_id, |
&& valid_bL_core_p (cores, aarch64_cpu_data[i].part_no)) |
imps[0], |
|
strlen (imps[0]) - 1) == 0 |
|
&& valid_bL_string_p (cores, aarch64_cpu_data[i].part_no)) |
|
{ |
{ |
res = concat ("-m", |
res = concat ("-m", |
cpu ? "cpu" : "tune", "=", |
cpu ? "cpu" : "tune", "=", |
Line 507 host_detect_local_cpu (int argc, const c |
|
Line 545 host_detect_local_cpu (int argc, const c |
|
if (!res) |
if (!res) |
goto not_found; |
goto not_found; |
} |
} |
/* The simple, non-big.LITTLE case. */ |
|
else |
|
{ |
|
if (strncmp (aarch64_cpu_data[core_idx].implementer_id, imps[0], |
|
strlen (imps[0]) - 1) != 0) |
|
goto not_found; |
|
|
|
res = concat ("-m", cpu ? "cpu" : "tune", "=", |
|
aarch64_cpu_data[core_idx].name, NULL); |
|
default_flags = aarch64_cpu_data[core_idx].flags; |
|
} |
|
|
|
if (tune) |
if (tune) |
return res; |
return res; |