diff options
Diffstat (limited to 'gas/config/tc-riscv.c')
-rw-r--r-- | gas/config/tc-riscv.c | 197 |
1 files changed, 93 insertions, 104 deletions
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c index d011864..77c92cf 100644 --- a/gas/config/tc-riscv.c +++ b/gas/config/tc-riscv.c @@ -61,9 +61,10 @@ struct riscv_cl_insn static const char default_arch[] = DEFAULT_ARCH; -unsigned xlen = 0; /* width of an x-register */ +static unsigned xlen = 0; /* width of an x-register */ +static unsigned abi_xlen = 0; /* width of a pointer in the ABI */ -#define LOAD_ADDRESS_INSN (xlen == 64 ? "ld" : "lw") +#define LOAD_ADDRESS_INSN (abi_xlen == 64 ? "ld" : "lw") #define ADD32_INSN (xlen == 64 ? "addiw" : "addi") static unsigned elf_flags = 0; @@ -129,56 +130,49 @@ riscv_add_subset (const char *subset) riscv_subsets = s; } -/* Set which ISA and extensions are available. Formally, ISA strings must - begin with RV32 or RV64, but we allow the prefix to be omitted. +/* Set which ISA and extensions are available. */ - FIXME: Version numbers are not supported yet. */ static void -riscv_set_arch (const char *p) +riscv_set_arch (const char *s) { - const char *all_subsets = "IMAFDC"; + const char *all_subsets = "imafdc"; const char *extension = NULL; - int rvc = 0; - int i; + const char *p = s; - if (strncasecmp (p, "RV32", 4) == 0) + if (strncmp (p, "rv32", 4) == 0) { xlen = 32; p += 4; } - else if (strncasecmp (p, "RV64", 4) == 0) + else if (strncmp (p, "rv64", 4) == 0) { xlen = 64; p += 4; } - else if (strncasecmp (p, "RV", 2) == 0) - p += 2; + else + as_fatal ("-march=%s: ISA string must begin with rv32 or rv64", s); - switch (TOUPPER(*p)) + switch (*p) { - case 'I': + case 'i': break; - case 'G': + case 'g': p++; - /* Fall through. */ - - case '\0': - for (i = 0; all_subsets[i] != '\0'; i++) + for ( ; *all_subsets != 'c'; all_subsets++) { - const char subset[] = {all_subsets[i], '\0'}; + const char subset[] = {*all_subsets, '\0'}; riscv_add_subset (subset); } break; default: - as_fatal ("`I' must be the first ISA subset name specified (got %c)", - *p); + as_fatal ("-march=%s: first ISA subset must be `i' or `g'", s); } while (*p) { - if (TOUPPER(*p) == 'X') + if (*p == 'x') { char *subset = xstrdup (p), *q = subset; @@ -187,8 +181,8 @@ riscv_set_arch (const char *p) *q = '\0'; if (extension) - as_fatal ("only one eXtension is supported (found %s and %s)", - extension, subset); + as_fatal ("-march=%s: only one non-standard extension is supported" + " (found `%s' and `%s')", s, extension, subset); extension = subset; riscv_add_subset (subset); p += strlen (subset); @@ -200,24 +194,11 @@ riscv_set_arch (const char *p) { const char subset[] = {*p, 0}; riscv_add_subset (subset); - if (TOUPPER(*p) == 'C') - rvc = 1; all_subsets++; p++; } else - as_fatal ("unsupported ISA subset %c", *p); - } - - if (rvc) - { - /* Override -m[no-]rvc setting if C was explicitly listed. */ - riscv_set_rvc (TRUE); - } - else - { - /* Add RVC anyway. -m[no-]rvc toggles its availability. */ - riscv_add_subset ("C"); + as_fatal ("-march=%s: unsupported ISA subset `%c'", s, *p); } } @@ -604,8 +585,9 @@ void md_begin (void) { int i = 0; + unsigned long mach = xlen == 64 ? bfd_mach_riscv64 : bfd_mach_riscv32; - if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, 0)) + if (! bfd_set_arch_mach (stdoutput, bfd_arch_riscv, mach)) as_warn (_("Could not set architecture and machine")); op_hash = hash_new (); @@ -1717,72 +1699,46 @@ const char *md_shortopts = "O::g::G:"; enum options { - OPTION_M32 = OPTION_MD_BASE, - OPTION_M64, - OPTION_MARCH, + OPTION_MARCH = OPTION_MD_BASE, OPTION_PIC, OPTION_NO_PIC, - OPTION_MSOFT_FLOAT, - OPTION_MHARD_FLOAT, - OPTION_MRVC, - OPTION_MNO_RVC, + OPTION_MABI, OPTION_END_OF_ENUM }; struct option md_longopts[] = { - {"m32", no_argument, NULL, OPTION_M32}, - {"m64", no_argument, NULL, OPTION_M64}, {"march", required_argument, NULL, OPTION_MARCH}, {"fPIC", no_argument, NULL, OPTION_PIC}, {"fpic", no_argument, NULL, OPTION_PIC}, {"fno-pic", no_argument, NULL, OPTION_NO_PIC}, - {"mrvc", no_argument, NULL, OPTION_MRVC}, - {"mno-rvc", no_argument, NULL, OPTION_MNO_RVC}, - {"msoft-float", no_argument, NULL, OPTION_MSOFT_FLOAT}, - {"mhard-float", no_argument, NULL, OPTION_MHARD_FLOAT}, + {"mabi", required_argument, NULL, OPTION_MABI}, {NULL, no_argument, NULL, 0} }; size_t md_longopts_size = sizeof (md_longopts); -enum float_mode -{ - FLOAT_MODE_DEFAULT, - FLOAT_MODE_SOFT, - FLOAT_MODE_HARD +enum float_abi { + FLOAT_ABI_DEFAULT = -1, + FLOAT_ABI_SOFT, + FLOAT_ABI_SINGLE, + FLOAT_ABI_DOUBLE, + FLOAT_ABI_QUAD }; -static enum float_mode float_mode = FLOAT_MODE_DEFAULT; +static enum float_abi float_abi = FLOAT_ABI_DEFAULT; + +static void +riscv_set_abi (unsigned new_xlen, enum float_abi new_float_abi) +{ + abi_xlen = new_xlen; + float_abi = new_float_abi; +} int md_parse_option (int c, const char *arg) { switch (c) { - case OPTION_MRVC: - riscv_set_rvc (TRUE); - break; - - case OPTION_MNO_RVC: - riscv_set_rvc (FALSE); - break; - - case OPTION_MSOFT_FLOAT: - float_mode = FLOAT_MODE_SOFT; - break; - - case OPTION_MHARD_FLOAT: - float_mode = FLOAT_MODE_HARD; - break; - - case OPTION_M32: - xlen = 32; - break; - - case OPTION_M64: - xlen = 64; - break; - case OPTION_MARCH: riscv_set_arch (arg); break; @@ -1795,6 +1751,27 @@ md_parse_option (int c, const char *arg) riscv_opts.pic = TRUE; break; + case OPTION_MABI: + if (strcmp (arg, "ilp32") == 0) + riscv_set_abi (32, FLOAT_ABI_SOFT); + else if (strcmp (arg, "ilp32f") == 0) + riscv_set_abi (32, FLOAT_ABI_SINGLE); + else if (strcmp (arg, "ilp32d") == 0) + riscv_set_abi (32, FLOAT_ABI_DOUBLE); + else if (strcmp (arg, "ilp32q") == 0) + riscv_set_abi (32, FLOAT_ABI_QUAD); + else if (strcmp (arg, "lp64") == 0) + riscv_set_abi (64, FLOAT_ABI_SOFT); + else if (strcmp (arg, "lp64f") == 0) + riscv_set_abi (64, FLOAT_ABI_SINGLE); + else if (strcmp (arg, "lp64d") == 0) + riscv_set_abi (64, FLOAT_ABI_DOUBLE); + else if (strcmp (arg, "lp64q") == 0) + riscv_set_abi (64, FLOAT_ABI_QUAD); + else + return 0; + break; + default: return 0; } @@ -1805,9 +1782,6 @@ md_parse_option (int c, const char *arg) void riscv_after_parse_args (void) { - if (riscv_subsets == NULL) - riscv_set_arch ("RVIMAFD"); - if (xlen == 0) { if (strcmp (default_arch, "riscv32") == 0) @@ -1817,6 +1791,38 @@ riscv_after_parse_args (void) else as_bad ("unknown default architecture `%s'", default_arch); } + + if (riscv_subsets == NULL) + riscv_set_arch (xlen == 64 ? "rv64g" : "rv32g"); + + /* Add the RVC extension, regardless of -march, to support .option rvc. */ + if (riscv_subset_supports ("c")) + riscv_set_rvc (TRUE); + else + riscv_add_subset ("c"); + + /* Infer ABI from ISA if not specified on command line. */ + if (abi_xlen == 0) + abi_xlen = xlen; + else if (abi_xlen > xlen) + as_bad ("can't have %d-bit ABI on %d-bit ISA", abi_xlen, xlen); + else if (abi_xlen < xlen) + as_bad ("%d-bit ABI not yet supported on %d-bit ISA", abi_xlen, xlen); + + if (float_abi == FLOAT_ABI_DEFAULT) + { + struct riscv_subset *subset; + + /* Assume soft-float unless D extension is present. */ + float_abi = FLOAT_ABI_SOFT; + + for (subset = riscv_subsets; subset != NULL; subset = subset->next) + if (strcasecmp (subset->name, "D") == 0) + float_abi = FLOAT_ABI_DOUBLE; + } + + /* Insert float_abi into the EF_RISCV_FLOAT_ABI field of elf_flags. */ + elf_flags |= float_abi * (EF_RISCV_FLOAT_ABI & ~(EF_RISCV_FLOAT_ABI << 1)); } long @@ -2449,24 +2455,7 @@ tc_riscv_regname_to_dw2regnum (char *regname) void riscv_elf_final_processing (void) { - enum float_mode elf_float_mode = float_mode; - elf_elfheader (stdoutput)->e_flags |= elf_flags; - - if (elf_float_mode == FLOAT_MODE_DEFAULT) - { - struct riscv_subset *subset; - - /* Assume soft-float unless D extension is present. */ - elf_float_mode = FLOAT_MODE_SOFT; - - for (subset = riscv_subsets; subset != NULL; subset = subset->next) - if (strcasecmp (subset->name, "D") == 0) - elf_float_mode = FLOAT_MODE_HARD; - } - - if (elf_float_mode == FLOAT_MODE_SOFT) - elf_elfheader (stdoutput)->e_flags |= EF_RISCV_SOFT_FLOAT; } /* Parse the .sleb128 and .uleb128 pseudos. Only allow constant expressions, |