#include "libiberty.h"
#include "elfxx-riscv.h"
#include "safe-ctype.h"
-#include "cpu-riscv.h"
#define MINUS_ONE ((bfd_vma)0 - 1)
{"e", "i", check_implicit_always},
{"i", "zicsr", check_implicit_for_i},
{"i", "zifencei", check_implicit_for_i},
+ {"g", "i", check_implicit_always},
+ {"g", "m", check_implicit_always},
+ {"g", "a", check_implicit_always},
+ {"g", "f", check_implicit_always},
+ {"g", "d", check_implicit_always},
{"g", "zicsr", check_implicit_always},
{"g", "zifencei", check_implicit_always},
{"q", "d", check_implicit_always},
{NULL, NULL, NULL}
};
-/* Lists of prefixed class extensions that binutils should know about.
- Whether or not a particular entry is in these lists will dictate if
- gas/ld will accept its presence in the architecture string.
+/* For default_enable field, decide if the extension should
+ be enbaled by default. */
- Please add the extensions to the lists in lower case. However, keep
- these subsets in alphabetical order in these tables is recommended,
- although there is no impact on the current implementation. */
+#define EXT_DEFAULT 0x1
-static const char * const riscv_std_z_ext_strtab[] =
+/* List all extensions that binutils should know about. */
+
+struct riscv_supported_ext
{
- "zba", "zbb", "zbc", "zicsr", "zifencei", "zihintpause", NULL
+ const char *name;
+ enum riscv_spec_class isa_spec_class;
+ int major_version;
+ int minor_version;
+ unsigned long default_enable;
};
-static const char * const riscv_std_s_ext_strtab[] =
+/* The standard extensions must be added in canonical order. */
+
+static struct riscv_supported_ext riscv_supported_std_ext[] =
{
- NULL
+ {"e", ISA_SPEC_CLASS_20191213, 1, 9, 0 },
+ {"e", ISA_SPEC_CLASS_20190608, 1, 9, 0 },
+ {"e", ISA_SPEC_CLASS_2P2, 1, 9, 0 },
+ {"i", ISA_SPEC_CLASS_20191213, 2, 1, 0 },
+ {"i", ISA_SPEC_CLASS_20190608, 2, 1, 0 },
+ {"i", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
+ /* The g is a special case which we don't want to output it,
+ but still need it when adding implicit extensions. */
+ {"g", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, EXT_DEFAULT },
+ {"m", ISA_SPEC_CLASS_20191213, 2, 0, 0 },
+ {"m", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
+ {"m", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
+ {"a", ISA_SPEC_CLASS_20191213, 2, 1, 0 },
+ {"a", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
+ {"a", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
+ {"f", ISA_SPEC_CLASS_20191213, 2, 2, 0 },
+ {"f", ISA_SPEC_CLASS_20190608, 2, 2, 0 },
+ {"f", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
+ {"d", ISA_SPEC_CLASS_20191213, 2, 2, 0 },
+ {"d", ISA_SPEC_CLASS_20190608, 2, 2, 0 },
+ {"d", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
+ {"q", ISA_SPEC_CLASS_20191213, 2, 2, 0 },
+ {"q", ISA_SPEC_CLASS_20190608, 2, 2, 0 },
+ {"q", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
+ {"l", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+ {"c", ISA_SPEC_CLASS_20191213, 2, 0, 0 },
+ {"c", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
+ {"c", ISA_SPEC_CLASS_2P2, 2, 0, 0 },
+ {"b", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+ {"j", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+ {"t", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+ {"p", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+ {"v", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+ {"n", ISA_SPEC_CLASS_NONE, RISCV_UNKNOWN_VERSION, RISCV_UNKNOWN_VERSION, 0 },
+ {NULL, 0, 0, 0, 0}
};
-static const char * const riscv_std_h_ext_strtab[] =
+static struct riscv_supported_ext riscv_supported_std_z_ext[] =
{
- NULL
+ {"zicsr", ISA_SPEC_CLASS_20191213, 2, 0, 0 },
+ {"zicsr", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
+ {"zifencei", ISA_SPEC_CLASS_20191213, 2, 0, 0 },
+ {"zifencei", ISA_SPEC_CLASS_20190608, 2, 0, 0 },
+ {"zihintpause", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zbb", ISA_SPEC_CLASS_DRAFT, 0, 93, 0 },
+ {"zba", ISA_SPEC_CLASS_DRAFT, 0, 93, 0 },
+ {"zbc", ISA_SPEC_CLASS_DRAFT, 0, 93, 0 },
+ {NULL, 0, 0, 0, 0}
+};
+
+static struct riscv_supported_ext riscv_supported_std_s_ext[] =
+{
+ {NULL, 0, 0, 0, 0}
+};
+
+static struct riscv_supported_ext riscv_supported_std_h_ext[] =
+{
+ {NULL, 0, 0, 0, 0}
};
-static const char * const riscv_std_zxm_ext_strtab[] =
+static struct riscv_supported_ext riscv_supported_std_zxm_ext[] =
{
+ {NULL, 0, 0, 0, 0}
+};
+
+const struct riscv_supported_ext *riscv_all_supported_ext[] =
+{
+ riscv_supported_std_ext,
+ riscv_supported_std_z_ext,
+ riscv_supported_std_s_ext,
+ riscv_supported_std_h_ext,
+ riscv_supported_std_zxm_ext,
NULL
};
static bool
riscv_known_prefixed_ext (const char *ext,
- const char *const *known_exts)
+ struct riscv_supported_ext *known_exts)
{
size_t i;
- for (i = 0; known_exts[i]; ++i)
- if (strcmp (ext, known_exts[i]) == 0)
+ for (i = 0; known_exts[i].name != NULL; ++i)
+ if (strcmp (ext, known_exts[i].name) == 0)
return true;
return false;
}
switch (class)
{
case RV_ISA_CLASS_Z:
- return riscv_known_prefixed_ext (ext, riscv_std_z_ext_strtab);
+ return riscv_known_prefixed_ext (ext, riscv_supported_std_z_ext);
case RV_ISA_CLASS_ZXM:
- return riscv_known_prefixed_ext (ext, riscv_std_zxm_ext_strtab);
+ return riscv_known_prefixed_ext (ext, riscv_supported_std_zxm_ext);
case RV_ISA_CLASS_S:
- return riscv_known_prefixed_ext (ext, riscv_std_s_ext_strtab);
+ return riscv_known_prefixed_ext (ext, riscv_supported_std_s_ext);
case RV_ISA_CLASS_H:
- return riscv_known_prefixed_ext (ext, riscv_std_h_ext_strtab);
+ return riscv_known_prefixed_ext (ext, riscv_supported_std_h_ext);
case RV_ISA_CLASS_X:
/* Only the single x is invalid. */
if (strcmp (ext, "x") != 0)
riscv_init_ext_order (void)
{
static bool inited = false;
- const char *std_base_exts = "eig";
- const char *std_remain_exts = riscv_supported_std_ext ();
- const char *ext;
- int order;
-
if (inited)
return;
/* The orders of all standard extensions are positive. */
- order = 1;
-
- /* Init the standard base extensions first. */
- for (ext = std_base_exts; *ext; ext++)
- riscv_ext_order[(*ext - 'a')] = order++;
+ int order = 1;
- /* Init the standard remaining extensions. */
- for (ext = std_remain_exts; *ext; ext++)
- riscv_ext_order[(*ext - 'a')] = order++;
+ int i = 0;
+ while (riscv_supported_std_ext[i].name != NULL)
+ {
+ const char *ext = riscv_supported_std_ext[i].name;
+ riscv_ext_order[(*ext - 'a')] = order++;
+ i++;
+ while (riscv_supported_std_ext[i].name
+ && strcmp (ext, riscv_supported_std_ext[i].name) == 0)
+ i++;
+ }
/* Some of the prefixed keyword are not single letter, so we set
their prefixed orders in the riscv_compare_subsets directly,
subset_list->tail = new;
}
+/* Get the default versions from the riscv_supported_*ext tables. */
+
+static void
+riscv_get_default_ext_version (enum riscv_spec_class default_isa_spec,
+ const char *name,
+ int *major_version,
+ int *minor_version)
+{
+ if (name == NULL || default_isa_spec == ISA_SPEC_CLASS_NONE)
+ return;
+
+ struct riscv_supported_ext *table = NULL;
+ enum riscv_prefix_ext_class class = riscv_get_prefix_class (name);
+ switch (class)
+ {
+ case RV_ISA_CLASS_ZXM: table = riscv_supported_std_zxm_ext; break;
+ case RV_ISA_CLASS_Z: table = riscv_supported_std_z_ext; break;
+ case RV_ISA_CLASS_S: table = riscv_supported_std_s_ext; break;
+ case RV_ISA_CLASS_H: table = riscv_supported_std_h_ext; break;
+ case RV_ISA_CLASS_X:
+ break;
+ default:
+ table = riscv_supported_std_ext;
+ }
+
+ int i = 0;
+ while (table != NULL && table[i].name != NULL)
+ {
+ if (strcmp (table[i].name, name) == 0
+ && (table[i].isa_spec_class == ISA_SPEC_CLASS_DRAFT
+ || table[i].isa_spec_class == default_isa_spec))
+ {
+ *major_version = table[i].major_version;
+ *minor_version = table[i].minor_version;
+ return;
+ }
+ i++;
+ }
+}
+
/* Find the default versions for the extension before adding them to
the subset list, if their versions are RISCV_UNKNOWN_VERSION.
Afterwards, report errors if we can not find their default versions. */
int major_version = major;
int minor_version = minor;
- if ((major_version == RISCV_UNKNOWN_VERSION
+ if (major_version == RISCV_UNKNOWN_VERSION
|| minor_version == RISCV_UNKNOWN_VERSION)
- && rps->get_default_version != NULL)
- rps->get_default_version (subset, &major_version, &minor_version);
+ riscv_get_default_ext_version (rps->isa_spec, subset,
+ &major_version, &minor_version);
/* We don't care the versions of the implicit extensions. */
if (!implicit
return p;
}
-/* Return string which contain all supported standard extensions in
- canonical order. */
-
-const char *
-riscv_supported_std_ext (void)
-{
- return "mafdqlcbjtpvn";
-}
-
/* Parsing function for standard extensions.
Return Value:
const char *arch,
const char *p)
{
- const char *all_std_exts = riscv_supported_std_ext ();
- const char *std_exts = all_std_exts;
- int major_version;
- int minor_version;
- char subset[2] = {0, 0};
-
/* First letter must start with i, e or g. */
- switch (*p)
+ if (*p != 'e' && *p != 'i' && *p != 'g')
{
- case 'i':
- p = riscv_parsing_subset_version (rps, arch, ++p,
- &major_version,
- &minor_version, true);
- riscv_parse_add_subset (rps, "i",
- major_version,
- minor_version, false);
- break;
-
- case 'e':
- p = riscv_parsing_subset_version (rps, arch, ++p,
- &major_version,
- &minor_version, true);
- riscv_parse_add_subset (rps, "e",
- major_version,
- minor_version, false);
- break;
-
- case 'g':
- p = riscv_parsing_subset_version (rps, arch, ++p,
- &major_version,
- &minor_version, true);
- /* Expand g to imafd. */
- riscv_parse_add_subset (rps, "i",
- RISCV_UNKNOWN_VERSION,
- RISCV_UNKNOWN_VERSION, false);
- for ( ; *std_exts != 'q'; std_exts++)
- {
- subset[0] = *std_exts;
- riscv_parse_add_subset (rps, subset,
- RISCV_UNKNOWN_VERSION,
- RISCV_UNKNOWN_VERSION, false);
- }
- /* Add g as an implicit extension. */
- riscv_parse_add_subset (rps, "g",
- RISCV_UNKNOWN_VERSION,
- RISCV_UNKNOWN_VERSION, true);
- break;
-
- default:
- rps->error_handler
- (_("%s: first ISA extension must be `e', `i' or `g'"),
- arch);
- return NULL;
+ rps->error_handler
+ (_("%s: first ISA extension must be `e', `i' or `g'"),
+ arch);
+ return NULL;
}
while (p != NULL && *p != '\0')
continue;
}
- /* Checking canonical order. */
- char std_ext = *p;
- while (*std_exts && std_ext != *std_exts)
- std_exts++;
+ bool implicit = false;
+ int major = RISCV_UNKNOWN_VERSION;
+ int minor = RISCV_UNKNOWN_VERSION;
+ char subset[2] = {0, 0};
+
+ subset[0] = *p;
- if (std_ext != *std_exts)
+ /* Check if the standard extension is supported. */
+ if (riscv_ext_order[(subset[0] - 'a')] == 0)
{
- if (riscv_ext_order[(std_ext - 'a')] == 0)
- rps->error_handler
- (_("%s: unknown standard ISA extension `%c'"),
- arch, std_ext);
- else
- rps->error_handler
- (_("%s: standard ISA extension `%c' is not "
- "in canonical order"), arch, std_ext);
+ rps->error_handler
+ (_("%s: unknown standard ISA extension `%c'"),
+ arch, subset[0]);
return NULL;
}
- std_exts++;
- subset[0] = std_ext;
- p = riscv_parsing_subset_version (rps, arch, ++p,
- &major_version,
- &minor_version, true);
- riscv_parse_add_subset (rps, subset,
- major_version,
- minor_version, false);
+ /* Checking canonical order. */
+ if (rps->subset_list->tail != NULL
+ && riscv_compare_subsets (rps->subset_list->tail->name, subset) > 0)
+ {
+ rps->error_handler
+ (_("%s: standard ISA extension `%c' is not "
+ "in canonical order"), arch, subset[0]);
+ return NULL;
+ }
+
+ p = riscv_parsing_subset_version (rps, arch, ++p, &major, &minor, true);
+ /* Added g as an implicit extension. */
+ if (subset[0] == 'g')
+ {
+ implicit = true;
+ major = RISCV_UNKNOWN_VERSION;
+ minor = RISCV_UNKNOWN_VERSION;
+ }
+ riscv_parse_add_subset (rps, subset, major, minor, implicit);
}
return p;
return no_conflict;
}
+/* Set the default subset list according to the default_enable field
+ of riscv_supported_*ext tables. */
+
+static void
+riscv_set_default_arch (riscv_parse_subset_t *rps)
+{
+ unsigned long enable = EXT_DEFAULT;
+ int i, j;
+ for (i = 0; riscv_all_supported_ext[i] != NULL; i++)
+ {
+ const struct riscv_supported_ext *table = riscv_all_supported_ext[i];
+ for (j = 0; table[j].name != NULL; j++)
+ {
+ bool implicit = false;
+ if (strcmp (table[j].name, "g") == 0)
+ implicit = true;
+ if (table[j].default_enable & enable)
+ riscv_parse_add_subset (rps, table[j].name,
+ RISCV_UNKNOWN_VERSION,
+ RISCV_UNKNOWN_VERSION, implicit);
+ }
+ }
+}
+
/* Function for parsing ISA string.
Return Value:
{
const char *p;
+ /* Init the riscv_ext_order array to compare the order of extensions
+ quickly. */
+ riscv_init_ext_order ();
+
+ if (arch == NULL)
+ {
+ riscv_set_default_arch (rps);
+ riscv_parse_add_implicit_subsets (rps);
+ return riscv_parse_check_conflicts (rps);
+ }
+
for (p = arch; *p != '\0'; p++)
{
if (ISUPPER (*p))
}
else
{
- /* ISA string shouldn't be NULL or empty here. However,
- it might be empty only when we failed to merge the ISA
- string in the riscv_merge_attributes. We have already
- issued the correct error message in another side, so do
- not issue this error when the ISA string is empty. */
+ /* ISA string shouldn't be NULL or empty here. For linker,
+ it might be empty when we failed to merge the ISA string
+ in the riscv_merge_attributes. For assembler, we might
+ give an empty string by .attribute arch, "" or -march=.
+ However, We have already issued the correct error message
+ in another side, so do not issue this error when the ISA
+ string is empty. */
if (strlen (arch))
rps->error_handler (
_("%s: ISA string must begin with rv32 or rv64"),
return false;
}
- /* Init the riscv_ext_order array to compare the order of extensions
- quickly. */
- riscv_init_ext_order ();
-
/* Parsing standard extension. */
p = riscv_parse_std_ext (rps, arch, p);
#include "dwarf2dbg.h"
#include "dw2gencfi.h"
-#include "bfd/cpu-riscv.h"
#include "bfd/elfxx-riscv.h"
#include "elf/riscv.h"
#include "opcode/riscv.h"
struct riscv_csr_extra *next;
};
-/* All standard/Z* extensions defined in all supported ISA spec. */
-struct riscv_ext_version
-{
- const char *name;
- enum riscv_spec_class isa_spec_class;
- int major_version;
- int minor_version;
-};
-
-static const struct riscv_ext_version ext_version_table[] =
-{
- {"e", ISA_SPEC_CLASS_20191213, 1, 9},
- {"e", ISA_SPEC_CLASS_20190608, 1, 9},
- {"e", ISA_SPEC_CLASS_2P2, 1, 9},
-
- {"i", ISA_SPEC_CLASS_20191213, 2, 1},
- {"i", ISA_SPEC_CLASS_20190608, 2, 1},
- {"i", ISA_SPEC_CLASS_2P2, 2, 0},
-
- {"m", ISA_SPEC_CLASS_20191213, 2, 0},
- {"m", ISA_SPEC_CLASS_20190608, 2, 0},
- {"m", ISA_SPEC_CLASS_2P2, 2, 0},
-
- {"a", ISA_SPEC_CLASS_20191213, 2, 1},
- {"a", ISA_SPEC_CLASS_20190608, 2, 0},
- {"a", ISA_SPEC_CLASS_2P2, 2, 0},
-
- {"f", ISA_SPEC_CLASS_20191213, 2, 2},
- {"f", ISA_SPEC_CLASS_20190608, 2, 2},
- {"f", ISA_SPEC_CLASS_2P2, 2, 0},
-
- {"d", ISA_SPEC_CLASS_20191213, 2, 2},
- {"d", ISA_SPEC_CLASS_20190608, 2, 2},
- {"d", ISA_SPEC_CLASS_2P2, 2, 0},
-
- {"q", ISA_SPEC_CLASS_20191213, 2, 2},
- {"q", ISA_SPEC_CLASS_20190608, 2, 2},
- {"q", ISA_SPEC_CLASS_2P2, 2, 0},
-
- {"c", ISA_SPEC_CLASS_20191213, 2, 0},
- {"c", ISA_SPEC_CLASS_20190608, 2, 0},
- {"c", ISA_SPEC_CLASS_2P2, 2, 0},
-
- {"zicsr", ISA_SPEC_CLASS_20191213, 2, 0},
- {"zicsr", ISA_SPEC_CLASS_20190608, 2, 0},
-
- {"zifencei", ISA_SPEC_CLASS_20191213, 2, 0},
- {"zifencei", ISA_SPEC_CLASS_20190608, 2, 0},
-
- {"zihintpause", ISA_SPEC_CLASS_DRAFT, 1, 0},
-
- {"zbb", ISA_SPEC_CLASS_DRAFT, 0, 93},
- {"zba", ISA_SPEC_CLASS_DRAFT, 0, 93},
- {"zbc", ISA_SPEC_CLASS_DRAFT, 0, 93},
-
- /* Terminate the list. */
- {NULL, 0, 0, 0}
-};
-
#ifndef DEFAULT_ARCH
#define DEFAULT_ARCH "riscv64"
#endif
}
}
-/* Handle of the extension with version hash table. */
-static htab_t ext_version_hash = NULL;
-
-static htab_t
-init_ext_version_hash (void)
-{
- const struct riscv_ext_version *table = ext_version_table;
- htab_t hash = str_htab_create ();
- int i = 0;
-
- while (table[i].name)
- {
- const char *name = table[i].name;
- if (str_hash_insert (hash, name, &table[i], 0) != NULL)
- as_fatal (_("internal: duplicate %s"), name);
-
- i++;
- while (table[i].name
- && strcmp (table[i].name, name) == 0)
- i++;
- }
-
- return hash;
-}
-
-static void
-riscv_get_default_ext_version (const char *name,
- int *major_version,
- int *minor_version)
-{
- struct riscv_ext_version *ext;
-
- if (name == NULL || default_isa_spec == ISA_SPEC_CLASS_NONE)
- return;
-
- ext = (struct riscv_ext_version *) str_hash_find (ext_version_hash, name);
- while (ext
- && ext->name
- && strcmp (ext->name, name) == 0)
- {
- if (ext->isa_spec_class == ISA_SPEC_CLASS_DRAFT
- || ext->isa_spec_class == default_isa_spec)
- {
- *major_version = ext->major_version;
- *minor_version = ext->minor_version;
- return;
- }
- ext++;
- }
-}
-
/* Set which ISA and extensions are available. */
static void
rps.subset_list = &riscv_subsets;
rps.error_handler = as_bad;
rps.xlen = &xlen;
- rps.get_default_version = riscv_get_default_ext_version;
+ rps.isa_spec = default_isa_spec;
rps.check_unknown_prefixed_ext = true;
- if (s == NULL)
- return;
+ if (s != NULL && strcmp (s, "") == 0)
+ {
+ as_bad (_("the architecture string of -march and elf architecture "
+ "attributes cannot be empty"));
+ return;
+ }
riscv_release_subset_list (&riscv_subsets);
riscv_parse_subset (&rps, s);
else
as_bad ("unknown default architecture `%s'", default_arch);
}
- if (default_arch_with_ext == NULL)
- default_arch_with_ext = xlen == 64 ? "rv64g" : "rv32g";
-
- /* Initialize the hash table for extensions with default version. */
- ext_version_hash = init_ext_version_hash ();
/* Set default specs. */
if (default_isa_spec == ISA_SPEC_CLASS_NONE)