/* RISC-V-specific support for ELF.
- Copyright (C) 2011-2021 Free Software Foundation, Inc.
+ Copyright (C) 2011-2023 Free Software Foundation, Inc.
Contributed by Andrew Waterman (andrew@sifive.com).
Based on TILE-Gx and MIPS targets.
relocations for the debug info. */
static bfd_reloc_status_type riscv_elf_add_sub_reloc
(bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
+static bfd_reloc_status_type riscv_elf_ignore_reloc
+ (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **);
/* The relocation table used for SHT_RELA sections. */
/* No relocation. */
HOWTO (R_RISCV_NONE, /* type */
0, /* rightshift */
- 3, /* size */
+ 0, /* size */
0, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 32 bit relocation. */
HOWTO (R_RISCV_32, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 64 bit relocation. */
HOWTO (R_RISCV_64, /* type */
0, /* rightshift */
- 4, /* size */
+ 8, /* size */
64, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* Relocation against a local symbol in a shared object. */
HOWTO (R_RISCV_RELATIVE, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
HOWTO (R_RISCV_JUMP_SLOT, /* type */
0, /* rightshift */
- 4, /* size */
+ 8, /* size */
64, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* Dynamic TLS relocations. */
HOWTO (R_RISCV_TLS_DTPMOD32, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
HOWTO (R_RISCV_TLS_DTPMOD64, /* type */
0, /* rightshift */
- 4, /* size */
+ 8, /* size */
64, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
HOWTO (R_RISCV_TLS_DTPREL32, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
HOWTO (R_RISCV_TLS_DTPREL64, /* type */
0, /* rightshift */
- 4, /* size */
+ 8, /* size */
64, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
HOWTO (R_RISCV_TLS_TPREL32, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
HOWTO (R_RISCV_TLS_TPREL64, /* type */
0, /* rightshift */
- 4, /* size */
+ 8, /* size */
64, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 12-bit PC-relative branch offset. */
HOWTO (R_RISCV_BRANCH, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
/* 20-bit PC-relative jump offset. */
HOWTO (R_RISCV_JAL, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
/* 32-bit PC-relative function call (AUIPC/JALR). */
HOWTO (R_RISCV_CALL, /* type */
0, /* rightshift */
- 4, /* size */
+ 8, /* size */
64, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
/* Like R_RISCV_CALL, but not locally binding. */
HOWTO (R_RISCV_CALL_PLT, /* type */
0, /* rightshift */
- 4, /* size */
+ 8, /* size */
64, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
/* High 20 bits of 32-bit PC-relative GOT access. */
HOWTO (R_RISCV_GOT_HI20, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
/* High 20 bits of 32-bit PC-relative TLS IE GOT access. */
HOWTO (R_RISCV_TLS_GOT_HI20, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
/* High 20 bits of 32-bit PC-relative TLS GD GOT reference. */
HOWTO (R_RISCV_TLS_GD_HI20, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
/* High 20 bits of 32-bit PC-relative reference. */
HOWTO (R_RISCV_PCREL_HI20, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
/* Low 12 bits of a 32-bit PC-relative load or add. */
HOWTO (R_RISCV_PCREL_LO12_I, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* Low 12 bits of a 32-bit PC-relative store. */
HOWTO (R_RISCV_PCREL_LO12_S, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* High 20 bits of 32-bit absolute address. */
HOWTO (R_RISCV_HI20, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* High 12 bits of 32-bit load or add. */
HOWTO (R_RISCV_LO12_I, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* High 12 bits of 32-bit store. */
HOWTO (R_RISCV_LO12_S, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* High 20 bits of TLS LE thread pointer offset. */
HOWTO (R_RISCV_TPREL_HI20, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* Low 12 bits of TLS LE thread pointer offset for loads and adds. */
HOWTO (R_RISCV_TPREL_LO12_I, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* Low 12 bits of TLS LE thread pointer offset for stores. */
HOWTO (R_RISCV_TPREL_LO12_S, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* TLS LE thread pointer usage. May be relaxed. */
HOWTO (R_RISCV_TPREL_ADD, /* type */
0, /* rightshift */
- 3, /* size */
+ 0, /* size */
0, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 8-bit in-place addition, for local label subtraction. */
HOWTO (R_RISCV_ADD8, /* type */
0, /* rightshift */
- 0, /* size */
+ 1, /* size */
8, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 16-bit in-place addition, for local label subtraction. */
HOWTO (R_RISCV_ADD16, /* type */
0, /* rightshift */
- 1, /* size */
+ 2, /* size */
16, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 32-bit in-place addition, for local label subtraction. */
HOWTO (R_RISCV_ADD32, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 64-bit in-place addition, for local label subtraction. */
HOWTO (R_RISCV_ADD64, /* type */
0, /* rightshift */
- 4, /* size */
+ 8, /* size */
64, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 8-bit in-place addition, for local label subtraction. */
HOWTO (R_RISCV_SUB8, /* type */
0, /* rightshift */
- 0, /* size */
+ 1, /* size */
8, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 16-bit in-place addition, for local label subtraction. */
HOWTO (R_RISCV_SUB16, /* type */
0, /* rightshift */
- 1, /* size */
+ 2, /* size */
16, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 32-bit in-place addition, for local label subtraction. */
HOWTO (R_RISCV_SUB32, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 64-bit in-place addition, for local label subtraction. */
HOWTO (R_RISCV_SUB64, /* type */
0, /* rightshift */
- 4, /* size */
+ 8, /* size */
64, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
MINUS_ONE, /* dst_mask */
false), /* pcrel_offset */
- /* GNU extension to record C++ vtable hierarchy */
- HOWTO (R_RISCV_GNU_VTINHERIT, /* type */
- 0, /* rightshift */
- 4, /* size */
- 0, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- NULL, /* special_function */
- "R_RISCV_GNU_VTINHERIT", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- false), /* pcrel_offset */
-
- /* GNU extension to record C++ vtable member usage */
- HOWTO (R_RISCV_GNU_VTENTRY, /* type */
- 0, /* rightshift */
- 4, /* size */
- 0, /* bitsize */
- false, /* pc_relative */
- 0, /* bitpos */
- complain_overflow_dont, /* complain_on_overflow */
- _bfd_elf_rel_vtable_reloc_fn, /* special_function */
- "R_RISCV_GNU_VTENTRY", /* name */
- false, /* partial_inplace */
- 0, /* src_mask */
- 0, /* dst_mask */
- false), /* pcrel_offset */
+ /* 41 and 42 are reserved. */
+ EMPTY_HOWTO (0),
+ EMPTY_HOWTO (0),
/* Indicates an alignment statement. The addend field encodes how many
bytes of NOPs follow the statement. The desired alignment is the
addend rounded up to the next power of two. */
HOWTO (R_RISCV_ALIGN, /* type */
0, /* rightshift */
- 3, /* size */
+ 0, /* size */
0, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 8-bit PC-relative branch offset. */
HOWTO (R_RISCV_RVC_BRANCH, /* type */
0, /* rightshift */
- 1, /* size */
+ 2, /* size */
16, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
/* 11-bit PC-relative jump offset. */
HOWTO (R_RISCV_RVC_JUMP, /* type */
0, /* rightshift */
- 1, /* size */
+ 2, /* size */
16, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
/* High 6 bits of 18-bit absolute address. */
HOWTO (R_RISCV_RVC_LUI, /* type */
0, /* rightshift */
- 1, /* size */
+ 2, /* size */
16, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* GP-relative load. */
HOWTO (R_RISCV_GPREL_I, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* GP-relative store. */
HOWTO (R_RISCV_GPREL_S, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* TP-relative TLS LE load. */
HOWTO (R_RISCV_TPREL_I, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* TP-relative TLS LE store. */
HOWTO (R_RISCV_TPREL_S, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* The paired relocation may be relaxed. */
HOWTO (R_RISCV_RELAX, /* type */
0, /* rightshift */
- 3, /* size */
+ 0, /* size */
0, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 6-bit in-place addition, for local label subtraction. */
HOWTO (R_RISCV_SUB6, /* type */
0, /* rightshift */
- 0, /* size */
+ 1, /* size */
8, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 6-bit in-place setting, for local label subtraction. */
HOWTO (R_RISCV_SET6, /* type */
0, /* rightshift */
- 0, /* size */
+ 1, /* size */
8, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 8-bit in-place setting, for local label subtraction. */
HOWTO (R_RISCV_SET8, /* type */
0, /* rightshift */
- 0, /* size */
+ 1, /* size */
8, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 16-bit in-place setting, for local label subtraction. */
HOWTO (R_RISCV_SET16, /* type */
0, /* rightshift */
- 1, /* size */
+ 2, /* size */
16, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 32-bit in-place setting, for local label subtraction. */
HOWTO (R_RISCV_SET32, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
/* 32-bit PC relative. */
HOWTO (R_RISCV_32_PCREL, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
true, /* pc_relative */
0, /* bitpos */
/* Relocation against a local ifunc symbol in a shared object. */
HOWTO (R_RISCV_IRELATIVE, /* type */
0, /* rightshift */
- 2, /* size */
+ 4, /* size */
32, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
0, /* src_mask */
0xffffffff, /* dst_mask */
false), /* pcrel_offset */
+
+ /* Reserved for R_RISCV_PLT32. */
+ EMPTY_HOWTO (59),
+
+ /* N-bit in-place setting, for unsigned-leb128 local label subtraction. */
+ HOWTO (R_RISCV_SET_ULEB128, /* type */
+ 0, /* rightshift */
+ 0, /* size */
+ 0, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ riscv_elf_ignore_reloc, /* special_function */
+ "R_RISCV_SET_ULEB128", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* N-bit in-place addition, for unsigned-leb128 local label subtraction. */
+ HOWTO (R_RISCV_SUB_ULEB128, /* type */
+ 0, /* rightshift */
+ 0, /* size */
+ 0, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ riscv_elf_ignore_reloc, /* special_function */
+ "R_RISCV_SUB_ULEB128", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ false), /* pcrel_offset */
};
/* A mapping from BFD reloc types to RISC-V ELF reloc types. */
{ BFD_RELOC_RISCV_SET16, R_RISCV_SET16 },
{ BFD_RELOC_RISCV_SET32, R_RISCV_SET32 },
{ BFD_RELOC_RISCV_32_PCREL, R_RISCV_32_PCREL },
+ { BFD_RELOC_RISCV_SET_ULEB128, R_RISCV_SET_ULEB128 },
+ { BFD_RELOC_RISCV_SUB_ULEB128, R_RISCV_SUB_ULEB128 },
};
/* Given a BFD reloc type, return a howto structure. */
relocation = old_value + relocation;
break;
case R_RISCV_SUB6:
+ relocation = (old_value & ~howto->dst_mask)
+ | (((old_value & howto->dst_mask) - relocation)
+ & howto->dst_mask);
+ break;
case R_RISCV_SUB8:
case R_RISCV_SUB16:
case R_RISCV_SUB32:
return bfd_reloc_ok;
}
+/* Special handler for relocations which don't have to be relocated.
+ This function just simply return bfd_reloc_ok. */
+
+static bfd_reloc_status_type
+riscv_elf_ignore_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *reloc_entry,
+ asymbol *symbol ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED,
+ asection *input_section,
+ bfd *output_bfd,
+ char **error_message ATTRIBUTE_UNUSED)
+{
+ if (output_bfd != NULL)
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+}
+
/* Always add the IMPLICIT for the SUBSET. */
static bool
{"g", "d", check_implicit_always},
{"g", "zicsr", check_implicit_always},
{"g", "zifencei", check_implicit_always},
+ {"m", "zmmul", check_implicit_always},
+ {"h", "zicsr", check_implicit_always},
{"q", "d", check_implicit_always},
+ {"v", "d", check_implicit_always},
+ {"v", "zve64d", check_implicit_always},
+ {"v", "zvl128b", check_implicit_always},
+ {"zve64d", "d", check_implicit_always},
+ {"zve64d", "zve64f", check_implicit_always},
+ {"zve64f", "zve32f", check_implicit_always},
+ {"zve64f", "zve64x", check_implicit_always},
+ {"zve64f", "zvl64b", check_implicit_always},
+ {"zve32f", "f", check_implicit_always},
+ {"zve32f", "zvl32b", check_implicit_always},
+ {"zve32f", "zve32x", check_implicit_always},
+ {"zve64x", "zve32x", check_implicit_always},
+ {"zve64x", "zvl64b", check_implicit_always},
+ {"zve32x", "zvl32b", check_implicit_always},
+ {"zvl65536b", "zvl32768b", check_implicit_always},
+ {"zvl32768b", "zvl16384b", check_implicit_always},
+ {"zvl16384b", "zvl8192b", check_implicit_always},
+ {"zvl8192b", "zvl4096b", check_implicit_always},
+ {"zvl4096b", "zvl2048b", check_implicit_always},
+ {"zvl2048b", "zvl1024b", check_implicit_always},
+ {"zvl1024b", "zvl512b", check_implicit_always},
+ {"zvl512b", "zvl256b", check_implicit_always},
+ {"zvl256b", "zvl128b", check_implicit_always},
+ {"zvl128b", "zvl64b", check_implicit_always},
+ {"zvl64b", "zvl32b", check_implicit_always},
+ {"zfa", "f", check_implicit_always},
{"d", "f", check_implicit_always},
+ {"zfh", "zfhmin", check_implicit_always},
+ {"zfhmin", "f", check_implicit_always},
{"f", "zicsr", check_implicit_always},
+ {"zqinx", "zdinx", check_implicit_always},
+ {"zdinx", "zfinx", check_implicit_always},
+ {"zhinx", "zhinxmin", check_implicit_always},
+ {"zhinxmin", "zfinx", check_implicit_always},
+ {"zfinx", "zicsr", check_implicit_always},
{"zk", "zkn", check_implicit_always},
{"zk", "zkr", check_implicit_always},
{"zk", "zkt", check_implicit_always},
{"zks", "zbkx", check_implicit_always},
{"zks", "zksed", check_implicit_always},
{"zks", "zksh", check_implicit_always},
+ {"zvkn", "zvkned", check_implicit_always},
+ {"zvkn", "zvknha", check_implicit_always},
+ {"zvkn", "zvknhb", check_implicit_always},
+ {"zvkn", "zvbb", check_implicit_always},
+ {"zvkn", "zvkt", check_implicit_always},
+ {"zvkng", "zvkn", check_implicit_always},
+ {"zvkng", "zvkg", check_implicit_always},
+ {"zvknc", "zvkn", check_implicit_always},
+ {"zvknc", "zvbc", check_implicit_always},
+ {"zvks", "zvksed", check_implicit_always},
+ {"zvks", "zvksh", check_implicit_always},
+ {"zvks", "zvbb", check_implicit_always},
+ {"zvks", "zvkt", check_implicit_always},
+ {"zvksg", "zvks", check_implicit_always},
+ {"zvksg", "zvkg", check_implicit_always},
+ {"zvksc", "zvks", check_implicit_always},
+ {"zvksc", "zvbc", check_implicit_always},
+ {"smaia", "ssaia", check_implicit_always},
+ {"smstateen", "ssstateen", check_implicit_always},
+ {"smepmp", "zicsr", check_implicit_always},
+ {"ssaia", "zicsr", check_implicit_always},
+ {"sscofpmf", "zicsr", check_implicit_always},
+ {"ssstateen", "zicsr", check_implicit_always},
+ {"sstc", "zicsr", check_implicit_always},
{NULL, NULL, NULL}
};
{"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 },
- {"k", 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 },
+ {"v", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"h", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{NULL, 0, 0, 0, 0}
};
static struct riscv_supported_ext riscv_supported_std_z_ext[] =
{
+ {"zicbom", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zicbop", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zicboz", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zicond", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"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 },
+ {"zihintpause", ISA_SPEC_CLASS_DRAFT, 2, 0, 0 },
+ {"zmmul", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zawrs", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zfa", ISA_SPEC_CLASS_DRAFT, 0, 1, 0 },
+ {"zfh", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zfhmin", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zfinx", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zdinx", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zqinx", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zhinx", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zhinxmin", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zbb", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zba", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zbc", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zksed", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zksh", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zkt", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zve32x", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zve32f", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zve32d", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zve64x", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zve64f", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zve64d", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvbb", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvbc", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvkg", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvkn", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvkng", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvknc", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvkned", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvknha", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvknhb", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvksed", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvksh", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvks", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvksg", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvksc", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvkt", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvl32b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvl64b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvl128b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvl256b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvl512b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvl1024b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvl2048b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvl4096b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvl8192b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvl16384b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvl32768b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"zvl65536b", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"ztso", ISA_SPEC_CLASS_DRAFT, 0, 1, 0 },
{NULL, 0, 0, 0, 0}
};
static struct riscv_supported_ext riscv_supported_std_s_ext[] =
{
+ {"smaia", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"smepmp", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"smstateen", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"ssaia", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"sscofpmf", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"ssstateen", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"sstc", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"svinval", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"svnapot", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"svpbmt", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{NULL, 0, 0, 0, 0}
};
-static struct riscv_supported_ext riscv_supported_std_h_ext[] =
+static struct riscv_supported_ext riscv_supported_std_zxm_ext[] =
{
{NULL, 0, 0, 0, 0}
};
-static struct riscv_supported_ext riscv_supported_std_zxm_ext[] =
+static struct riscv_supported_ext riscv_supported_vendor_x_ext[] =
{
+ {"xtheadba", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"xtheadbb", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"xtheadbs", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"xtheadcmo", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"xtheadcondmov", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"xtheadfmemidx", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"xtheadfmv", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"xtheadint", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"xtheadmac", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"xtheadmemidx", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"xtheadmempair", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ {"xtheadsync", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
+ /* XVentanaCondOps: https://github.com/ventanamicro/ventana-custom-extensions/releases/download/v1.0.0/ventana-custom-extensions-v1.0.0.pdf */
+ {"xventanacondops", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{NULL, 0, 0, 0, 0}
};
riscv_supported_std_ext,
riscv_supported_std_z_ext,
riscv_supported_std_s_ext,
- riscv_supported_std_h_ext,
riscv_supported_std_zxm_ext,
+ riscv_supported_vendor_x_ext,
NULL
};
{
RV_ISA_CLASS_Z = 1,
RV_ISA_CLASS_S,
- RV_ISA_CLASS_H,
RV_ISA_CLASS_ZXM,
RV_ISA_CLASS_X,
- RV_ISA_CLASS_UNKNOWN
+ RV_ISA_CLASS_SINGLE
};
/* Record the strings of the prefixed extensions, and their corresponding
{RV_ISA_CLASS_ZXM, "zxm"},
{RV_ISA_CLASS_Z, "z"},
{RV_ISA_CLASS_S, "s"},
- {RV_ISA_CLASS_H, "h"},
{RV_ISA_CLASS_X, "x"},
- {RV_ISA_CLASS_UNKNOWN, NULL}
+ {RV_ISA_CLASS_SINGLE, NULL}
};
/* Get the prefixed name class for the extensions, the class also
riscv_get_prefix_class (const char *arch)
{
int i = 0;
- while (parse_config[i].class != RV_ISA_CLASS_UNKNOWN)
+ while (parse_config[i].class != RV_ISA_CLASS_SINGLE)
{
if (strncmp (arch, parse_config[i].prefix,
strlen (parse_config[i].prefix)) == 0)
return parse_config[i].class;
i++;
}
- return RV_ISA_CLASS_UNKNOWN;
+ return RV_ISA_CLASS_SINGLE;
}
/* Check KNOWN_EXTS to see if the EXT is supported. */
return riscv_known_prefixed_ext (ext, riscv_supported_std_zxm_ext);
case RV_ISA_CLASS_S:
return riscv_known_prefixed_ext (ext, riscv_supported_std_s_ext);
- case RV_ISA_CLASS_H:
- return riscv_known_prefixed_ext (ext, riscv_supported_std_h_ext);
case RV_ISA_CLASS_X:
/* Only the single x is unrecognized. */
if (strcmp (ext, "x") != 0)
return false;
}
+/* Canonical order for single letter extensions. */
+static const char riscv_ext_canonical_order[] = "eigmafdqlcbkjtpvnh";
+
/* Array is used to compare the orders of standard extensions quickly. */
static int riscv_ext_order[26] = {0};
/* The orders of all standard extensions are positive. */
int order = 1;
- 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++;
- }
+ for (const char *ext = &riscv_ext_canonical_order[0]; *ext; ++ext)
+ riscv_ext_order[(*ext - 'a')] = order++;
/* Some of the prefixed keyword are not single letter, so we set
their prefixed orders in the riscv_compare_subsets directly,
enum riscv_prefix_ext_class class1 = riscv_get_prefix_class (subset1);
enum riscv_prefix_ext_class class2 = riscv_get_prefix_class (subset2);
- if (class1 != RV_ISA_CLASS_UNKNOWN)
+ if (class1 != RV_ISA_CLASS_SINGLE)
order1 = - (int) class1;
- if (class2 != RV_ISA_CLASS_UNKNOWN)
+ if (class2 != RV_ISA_CLASS_SINGLE)
order2 = - (int) class2;
if (order1 == order2)
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;
+ case RV_ISA_CLASS_X: table = riscv_supported_vendor_x_ext; break;
default:
table = riscv_supported_std_ext;
}
rps->error_handler
(_("x ISA extension `%s' must be set with the versions"),
subset);
- else
+ /* Allow old ISA spec can recognize zicsr and zifencei. */
+ else if (strcmp (subset, "zicsr") != 0
+ && strcmp (subset, "zifencei") != 0)
rps->error_handler
(_("cannot find default versions of the ISA extension `%s'"),
subset);
}
subset_list->tail = NULL;
+
+ if (subset_list->arch_str != NULL)
+ {
+ free ((void*) subset_list->arch_str);
+ subset_list->arch_str = NULL;
+ }
}
/* Parsing extension version.
return p;
}
-/* Parsing function for standard extensions.
+/* Parsing function for both standard and prefixed extensions.
Return Value:
Points to the end of extensions.
`p`: Curent parsing position. */
static const char *
-riscv_parse_std_ext (riscv_parse_subset_t *rps,
- const char *arch,
- const char *p)
+riscv_parse_extensions (riscv_parse_subset_t *rps,
+ const char *arch,
+ const char *p)
{
/* First letter must start with i, e or g. */
if (*p != 'e' && *p != 'i' && *p != 'g')
return NULL;
}
- while (p != NULL && *p != '\0')
- {
- /* Stop when we parsed the known prefix class. */
- enum riscv_prefix_ext_class class = riscv_get_prefix_class (p);
- if (class != RV_ISA_CLASS_UNKNOWN)
- break;
-
- if (*p == '_')
- {
- p++;
- continue;
- }
-
- bool implicit = false;
- int major = RISCV_UNKNOWN_VERSION;
- int minor = RISCV_UNKNOWN_VERSION;
- char subset[2] = {0, 0};
-
- subset[0] = *p;
-
- /* Check if the standard extension is supported. */
- if (riscv_ext_order[(subset[0] - 'a')] == 0)
- {
- rps->error_handler
- (_("%s: unknown standard ISA extension `%c'"),
- arch, subset[0]);
- return NULL;
- }
-
- /* 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 (++p, &major, &minor);
- /* 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;
-}
-
-/* Parsing function for prefixed extensions.
-
- Return Value:
- Points to the end of extension.
-
- Arguments:
- `rps`: Hooks and status for parsing extensions.
- `arch`: Full ISA string.
- `p`: Curent parsing position. */
-
-static const char *
-riscv_parse_prefixed_ext (riscv_parse_subset_t *rps,
- const char *arch,
- const char *p)
-{
- int major_version;
- int minor_version;
- const char *last_name;
- enum riscv_prefix_ext_class class;
-
- while (*p)
+ while (*p != '\0')
{
if (*p == '_')
{
continue;
}
- class = riscv_get_prefix_class (p);
- if (class == RV_ISA_CLASS_UNKNOWN)
- {
- rps->error_handler
- (_("%s: unknown prefix class for the ISA extension `%s'"),
- arch, p);
- return NULL;
- }
-
char *subset = xstrdup (p);
- char *q = subset;
+ char *q = subset; /* Start of version. */
const char *end_of_version;
+ bool implicit = false;
- /* Extract the whole prefixed extension by '_'. */
- while (*++q != '\0' && *q != '_')
- ;
- /* Look forward to the first letter which is not <major>p<minor>. */
- bool find_any_version = false;
- bool find_minor_version = false;
- while (1)
+ enum riscv_prefix_ext_class class = riscv_get_prefix_class (p);
+ if (class == RV_ISA_CLASS_SINGLE)
{
- q--;
- if (ISDIGIT (*q))
- find_any_version = true;
- else if (find_any_version
- && !find_minor_version
- && *q == 'p'
- && ISDIGIT (*(q - 1)))
- find_minor_version = true;
- else
- break;
+ if (riscv_ext_order[(*subset - 'a')] == 0)
+ {
+ rps->error_handler
+ (_("%s: unknown standard ISA extension or prefix class `%c'"),
+ arch, *subset);
+ free (subset);
+ return NULL;
+ }
+ q++;
}
- q++;
-
- /* Check if the end of extension is 'p' or not. If yes, then
- the second letter from the end cannot be number. */
- if (*(q - 1) == 'p' && ISDIGIT (*(q - 2)))
+ else
{
- *q = '\0';
- rps->error_handler
- (_("%s: invalid prefixed ISA extension `%s' ends with <number>p"),
- arch, subset);
- free (subset);
- return NULL;
+ /* Extract the whole prefixed extension by '_'. */
+ while (*++q != '\0' && *q != '_')
+ ;
+ /* Look forward to the first letter which is not <major>p<minor>. */
+ bool find_any_version = false;
+ bool find_minor_version = false;
+ while (1)
+ {
+ q--;
+ if (ISDIGIT (*q))
+ find_any_version = true;
+ else if (find_any_version
+ && !find_minor_version
+ && *q == 'p'
+ && ISDIGIT (*(q - 1)))
+ find_minor_version = true;
+ else
+ break;
+ }
+ q++;
+
+ /* Check if the end of extension is 'p' or not. If yes, then
+ the second letter from the end cannot be number. */
+ if (*(q - 1) == 'p' && ISDIGIT (*(q - 2)))
+ {
+ *q = '\0';
+ rps->error_handler
+ (_("%s: invalid prefixed ISA extension `%s' ends with <number>p"),
+ arch, subset);
+ free (subset);
+ return NULL;
+ }
}
+ int major_version = RISCV_UNKNOWN_VERSION;
+ int minor_version = RISCV_UNKNOWN_VERSION;
end_of_version =
riscv_parsing_subset_version (q, &major_version, &minor_version);
*q = '\0';
return NULL;
}
- /* Check that the extension name is well-formed. */
- if (rps->check_unknown_prefixed_ext
+ /* Check if the prefixed extension name is well-formed. */
+ if (class != RV_ISA_CLASS_SINGLE
+ && rps->check_unknown_prefixed_ext
&& !riscv_recognized_prefixed_ext (subset))
{
rps->error_handler
return NULL;
}
- /* Check that the extension isn't duplicate. */
- last_name = rps->subset_list->tail->name;
- if (!strcasecmp (last_name, subset))
- {
- rps->error_handler
- (_("%s: duplicate prefixed ISA extension `%s'"),
- arch, subset);
- free (subset);
- return NULL;
- }
-
- /* Check that the extension is in expected order. */
- if (riscv_compare_subsets (last_name, subset) > 0)
+ /* Added g as an implicit extension. */
+ if (class == RV_ISA_CLASS_SINGLE
+ && strcmp (subset, "g") == 0)
{
- rps->error_handler
- (_("%s: prefixed ISA extension `%s' is not in expected "
- "order. It must come before `%s'"),
- arch, subset, last_name);
- free (subset);
- return NULL;
+ implicit = true;
+ major_version = RISCV_UNKNOWN_VERSION;
+ minor_version = RISCV_UNKNOWN_VERSION;
}
-
riscv_parse_add_subset (rps, subset,
major_version,
- minor_version, false);
+ minor_version, implicit);
p += end_of_version - subset;
free (subset);
- if (*p != '\0' && *p != '_')
+ if (class != RV_ISA_CLASS_SINGLE
+ && *p != '\0' && *p != '_')
{
rps->error_handler
(_("%s: prefixed ISA extension must separate with _"),
riscv_parse_add_implicit_subsets (riscv_parse_subset_t *rps)
{
struct riscv_implicit_subset *t = riscv_implicit_subsets;
- for (; t->subset_name; t++)
+ bool finished = false;
+ while (!finished)
{
- riscv_subset_t *subset = NULL;
- if (riscv_lookup_subset (rps->subset_list, t->subset_name, &subset)
- && t->check_func (t->implicit_name, subset))
- riscv_parse_add_subset (rps, t->implicit_name,
- RISCV_UNKNOWN_VERSION,
- RISCV_UNKNOWN_VERSION, true);
+ finished = true;
+ for (; t->subset_name; t++)
+ {
+ riscv_subset_t *subset = NULL;
+ riscv_subset_t *implicit_subset = NULL;
+ if (riscv_lookup_subset (rps->subset_list, t->subset_name, &subset)
+ && !riscv_lookup_subset (rps->subset_list, t->implicit_name,
+ &implicit_subset)
+ && t->check_func (t->implicit_name, subset))
+ {
+ riscv_parse_add_subset (rps, t->implicit_name,
+ RISCV_UNKNOWN_VERSION,
+ RISCV_UNKNOWN_VERSION, true);
+
+ /* Restart the loop and pick up any new implications. */
+ finished = false;
+ t = riscv_implicit_subsets;
+ break;
+ }
+ }
}
}
no_conflict = false;
}
if (riscv_lookup_subset (rps->subset_list, "q", &subset)
+ && (subset->major_version < 2 || (subset->major_version == 2
+ && subset->minor_version < 2))
&& xlen < 64)
{
- rps->error_handler
- (_("rv%d does not support the `q' extension"), xlen);
+ rps->error_handler (_("rv%d does not support the `q' extension"), xlen);
no_conflict = false;
}
- if (riscv_lookup_subset (rps->subset_list, "e", &subset)
+ if (riscv_lookup_subset (rps->subset_list, "zfinx", &subset)
&& riscv_lookup_subset (rps->subset_list, "f", &subset))
{
rps->error_handler
- (_("rv32e does not support the `f' extension"));
+ (_("`zfinx' is conflict with the `f/d/q/zfh/zfhmin' extension"));
+ no_conflict = false;
+ }
+
+ bool support_zve = false;
+ bool support_zvl = false;
+ riscv_subset_t *s = rps->subset_list->head;
+ for (; s != NULL; s = s->next)
+ {
+ if (!support_zve
+ && strncmp (s->name, "zve", 3) == 0)
+ support_zve = true;
+ if (!support_zvl
+ && strncmp (s->name, "zvl", 3) == 0)
+ support_zvl = true;
+ if (support_zve && support_zvl)
+ break;
+ }
+ if (support_zvl && !support_zve)
+ {
+ rps->error_handler
+ (_("zvl*b extensions need to enable either `v' or `zve' extension"));
no_conflict = false;
}
+
return no_conflict;
}
return false;
}
- /* Parsing standard extension. */
- p = riscv_parse_std_ext (rps, arch, p);
-
- if (p == NULL)
+ /* Parse single standard and prefixed extensions. */
+ if (riscv_parse_extensions (rps, arch, p) == NULL)
return false;
- /* Parse the different classes of extensions in the specified order. */
- while (*p != '\0')
- {
- p = riscv_parse_prefixed_ext (rps, arch, p);
-
- if (p == NULL)
- return false;
- }
-
/* Finally add implicit extensions according to the current
extensions. */
riscv_parse_add_implicit_subsets (rps);
return attr_str;
}
+/* Copy the subset in the subset list. */
+
+static struct riscv_subset_t *
+riscv_copy_subset (riscv_subset_list_t *subset_list,
+ riscv_subset_t *subset)
+{
+ if (subset == NULL)
+ return NULL;
+
+ riscv_subset_t *new = xmalloc (sizeof *new);
+ new->name = xstrdup (subset->name);
+ new->major_version = subset->major_version;
+ new->minor_version = subset->minor_version;
+ new->next = riscv_copy_subset (subset_list, subset->next);
+
+ if (subset->next == NULL)
+ subset_list->tail = new;
+
+ return new;
+}
+
+/* Copy the subset list. */
+
+riscv_subset_list_t *
+riscv_copy_subset_list (riscv_subset_list_t *subset_list)
+{
+ riscv_subset_list_t *new = xmalloc (sizeof *new);
+ new->head = riscv_copy_subset (new, subset_list->head);
+ new->arch_str = strdup (subset_list->arch_str);
+ return new;
+}
+
/* Remove the SUBSET from the subset list. */
static void
}
/* Add/Remove an extension to/from the subset list. This is used for
- the .option rvc or norvc. */
+ the .option rvc or norvc, and .option arch directives. */
bool
riscv_update_subset (riscv_parse_subset_t *rps,
- const char *subset,
- bool removed)
+ const char *str)
{
- if (strlen (subset) == 0
- || (strlen (subset) == 1
- && riscv_ext_order[(*subset - 'a')] == 0)
- || (strlen (subset) > 1
- && rps->check_unknown_prefixed_ext
- && !riscv_recognized_prefixed_ext (subset)))
- {
- rps->error_handler
- (_("riscv_update_subset: unknown ISA extension `%s'"), subset);
- return false;
- }
+ const char *p = str;
- if (removed)
+ do
{
- if (strcmp (subset, "i") == 0)
+ int major_version = RISCV_UNKNOWN_VERSION;
+ int minor_version = RISCV_UNKNOWN_VERSION;
+
+ bool removed = false;
+ switch (*p)
+ {
+ case '+': removed = false; break;
+ case '-': removed = true; break;
+ default:
+ riscv_release_subset_list (rps->subset_list);
+ return riscv_parse_subset (rps, p);
+ }
+ ++p;
+
+ char *subset = xstrdup (p);
+ char *q = subset;
+ const char *end_of_version;
+ /* Extract the whole prefixed extension by ','. */
+ while (*q != '\0' && *q != ',')
+ q++;
+
+ /* Look forward to the first letter which is not <major>p<minor>. */
+ bool find_any_version = false;
+ bool find_minor_version = false;
+ size_t len = q - subset;
+ size_t i;
+ for (i = len; i > 0; i--)
+ {
+ q--;
+ if (ISDIGIT (*q))
+ find_any_version = true;
+ else if (find_any_version
+ && !find_minor_version
+ && *q == 'p'
+ && ISDIGIT (*(q - 1)))
+ find_minor_version = true;
+ else
+ break;
+ }
+ if (len > 0)
+ q++;
+
+ /* Check if the end of extension is 'p' or not. If yes, then
+ the second letter from the end cannot be number. */
+ if (len > 1 && *(q - 1) == 'p' && ISDIGIT (*(q - 2)))
+ {
+ *q = '\0';
+ rps->error_handler
+ (_("invalid ISA extension ends with <number>p "
+ "in .option arch `%s'"), str);
+ free (subset);
+ return false;
+ }
+
+ end_of_version =
+ riscv_parsing_subset_version (q, &major_version, &minor_version);
+ *q = '\0';
+ if (end_of_version == NULL)
+ {
+ free (subset);
+ return false;
+ }
+
+ if (strlen (subset) == 0
+ || (strlen (subset) == 1
+ && riscv_ext_order[(*subset - 'a')] == 0)
+ || (strlen (subset) > 1
+ && rps->check_unknown_prefixed_ext
+ && !riscv_recognized_prefixed_ext (subset)))
{
rps->error_handler
- (_("riscv_update_subset: cannot remove extension i from "
- "the subset list"));
+ (_("unknown ISA extension `%s' in .option arch `%s'"),
+ subset, str);
+ free (subset);
+ return false;
+ }
+
+ if (strcmp (subset, "i") == 0
+ || strcmp (subset, "e") == 0
+ || strcmp (subset, "g") == 0)
+ {
+ rps->error_handler
+ (_("cannot + or - base extension `%s' in .option "
+ "arch `%s'"), subset, str);
+ free (subset);
return false;
}
- riscv_remove_subset (rps->subset_list, subset);
+
+ if (removed)
+ riscv_remove_subset (rps->subset_list, subset);
+ else
+ riscv_parse_add_subset (rps, subset, major_version, minor_version, true);
+ p += end_of_version - subset;
+ free (subset);
}
- else
- riscv_parse_add_subset (rps, subset,
- RISCV_UNKNOWN_VERSION,
- RISCV_UNKNOWN_VERSION, true);
+ while (*p++ == ',');
riscv_parse_add_implicit_subsets (rps);
return riscv_parse_check_conflicts (rps);
{
case INSN_CLASS_I:
return riscv_subset_supports (rps, "i");
+ case INSN_CLASS_ZICBOM:
+ return riscv_subset_supports (rps, "zicbom");
+ case INSN_CLASS_ZICBOP:
+ return riscv_subset_supports (rps, "zicbop");
+ case INSN_CLASS_ZICBOZ:
+ return riscv_subset_supports (rps, "zicboz");
+ case INSN_CLASS_ZICOND:
+ return riscv_subset_supports (rps, "zicond");
case INSN_CLASS_ZICSR:
return riscv_subset_supports (rps, "zicsr");
case INSN_CLASS_ZIFENCEI:
return riscv_subset_supports (rps, "zihintpause");
case INSN_CLASS_M:
return riscv_subset_supports (rps, "m");
+ case INSN_CLASS_ZMMUL:
+ return riscv_subset_supports (rps, "zmmul");
case INSN_CLASS_A:
return riscv_subset_supports (rps, "a");
+ case INSN_CLASS_ZAWRS:
+ return riscv_subset_supports (rps, "zawrs");
case INSN_CLASS_F:
return riscv_subset_supports (rps, "f");
case INSN_CLASS_D:
case INSN_CLASS_D_AND_C:
return (riscv_subset_supports (rps, "d")
&& riscv_subset_supports (rps, "c"));
+ case INSN_CLASS_F_INX:
+ return (riscv_subset_supports (rps, "f")
+ || riscv_subset_supports (rps, "zfinx"));
+ case INSN_CLASS_D_INX:
+ return (riscv_subset_supports (rps, "d")
+ || riscv_subset_supports (rps, "zdinx"));
+ case INSN_CLASS_Q_INX:
+ return (riscv_subset_supports (rps, "q")
+ || riscv_subset_supports (rps, "zqinx"));
+ case INSN_CLASS_ZFH_INX:
+ return (riscv_subset_supports (rps, "zfh")
+ || riscv_subset_supports (rps, "zhinx"));
+ case INSN_CLASS_ZFHMIN:
+ return riscv_subset_supports (rps, "zfhmin");
+ case INSN_CLASS_ZFHMIN_INX:
+ return (riscv_subset_supports (rps, "zfhmin")
+ || riscv_subset_supports (rps, "zhinxmin"));
+ case INSN_CLASS_ZFHMIN_AND_D_INX:
+ return ((riscv_subset_supports (rps, "zfhmin")
+ && riscv_subset_supports (rps, "d"))
+ || (riscv_subset_supports (rps, "zhinxmin")
+ && riscv_subset_supports (rps, "zdinx")));
+ case INSN_CLASS_ZFHMIN_AND_Q_INX:
+ return ((riscv_subset_supports (rps, "zfhmin")
+ && riscv_subset_supports (rps, "q"))
+ || (riscv_subset_supports (rps, "zhinxmin")
+ && riscv_subset_supports (rps, "zqinx")));
+ case INSN_CLASS_ZFA:
+ return riscv_subset_supports (rps, "zfa");
+ case INSN_CLASS_D_AND_ZFA:
+ return riscv_subset_supports (rps, "d")
+ && riscv_subset_supports (rps, "zfa");
+ case INSN_CLASS_Q_AND_ZFA:
+ return riscv_subset_supports (rps, "q")
+ && riscv_subset_supports (rps, "zfa");
+ case INSN_CLASS_ZFH_AND_ZFA:
+ return riscv_subset_supports (rps, "zfh")
+ && riscv_subset_supports (rps, "zfa");
case INSN_CLASS_ZBA:
return riscv_subset_supports (rps, "zba");
case INSN_CLASS_ZBB:
return riscv_subset_supports (rps, "zksed");
case INSN_CLASS_ZKSH:
return riscv_subset_supports (rps, "zksh");
+ case INSN_CLASS_V:
+ return (riscv_subset_supports (rps, "v")
+ || riscv_subset_supports (rps, "zve64x")
+ || riscv_subset_supports (rps, "zve32x"));
+ case INSN_CLASS_ZVEF:
+ return (riscv_subset_supports (rps, "v")
+ || riscv_subset_supports (rps, "zve64d")
+ || riscv_subset_supports (rps, "zve64f")
+ || riscv_subset_supports (rps, "zve32f"));
+ case INSN_CLASS_ZVBB:
+ return riscv_subset_supports (rps, "zvbb");
+ case INSN_CLASS_ZVBC:
+ return riscv_subset_supports (rps, "zvbc");
+ case INSN_CLASS_ZVKG:
+ return riscv_subset_supports (rps, "zvkg");
+ case INSN_CLASS_ZVKNED:
+ return riscv_subset_supports (rps, "zvkned");
+ case INSN_CLASS_ZVKNHA:
+ return riscv_subset_supports (rps, "zvknha");
+ case INSN_CLASS_ZVKNHB:
+ return riscv_subset_supports (rps, "zvknhb");
+ case INSN_CLASS_ZVKNHA_OR_ZVKNHB:
+ return (riscv_subset_supports (rps, "zvknha")
+ || riscv_subset_supports (rps, "zvknhb"));
+ case INSN_CLASS_ZVKSED:
+ return riscv_subset_supports (rps, "zvksed");
+ case INSN_CLASS_ZVKSH:
+ return riscv_subset_supports (rps, "zvksh");
+ case INSN_CLASS_SVINVAL:
+ return riscv_subset_supports (rps, "svinval");
+ case INSN_CLASS_H:
+ return riscv_subset_supports (rps, "h");
+ case INSN_CLASS_XTHEADBA:
+ return riscv_subset_supports (rps, "xtheadba");
+ case INSN_CLASS_XTHEADBB:
+ return riscv_subset_supports (rps, "xtheadbb");
+ case INSN_CLASS_XTHEADBS:
+ return riscv_subset_supports (rps, "xtheadbs");
+ case INSN_CLASS_XTHEADCMO:
+ return riscv_subset_supports (rps, "xtheadcmo");
+ case INSN_CLASS_XTHEADCONDMOV:
+ return riscv_subset_supports (rps, "xtheadcondmov");
+ case INSN_CLASS_XTHEADFMEMIDX:
+ return riscv_subset_supports (rps, "xtheadfmemidx");
+ case INSN_CLASS_XTHEADFMV:
+ return riscv_subset_supports (rps, "xtheadfmv");
+ case INSN_CLASS_XTHEADINT:
+ return riscv_subset_supports (rps, "xtheadint");
+ case INSN_CLASS_XTHEADMAC:
+ return riscv_subset_supports (rps, "xtheadmac");
+ case INSN_CLASS_XTHEADMEMIDX:
+ return riscv_subset_supports (rps, "xtheadmemidx");
+ case INSN_CLASS_XTHEADMEMPAIR:
+ return riscv_subset_supports (rps, "xtheadmempair");
+ case INSN_CLASS_XTHEADSYNC:
+ return riscv_subset_supports (rps, "xtheadsync");
+ case INSN_CLASS_XVENTANACONDOPS:
+ return riscv_subset_supports (rps, "xventanacondops");
default:
rps->error_handler
(_("internal: unreachable INSN_CLASS_*"));
return false;
}
}
+
+/* Each instuction is belonged to an instruction class INSN_CLASS_*.
+ Call riscv_subset_supports_ext to determine the missing extension. */
+
+const char *
+riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
+ enum riscv_insn_class insn_class)
+{
+ switch (insn_class)
+ {
+ case INSN_CLASS_I:
+ return "i";
+ case INSN_CLASS_ZICBOM:
+ return "zicbom";
+ case INSN_CLASS_ZICBOP:
+ return "zicbop";
+ case INSN_CLASS_ZICBOZ:
+ return "zicboz";
+ case INSN_CLASS_ZICOND:
+ return "zicond";
+ case INSN_CLASS_ZICSR:
+ return "zicsr";
+ case INSN_CLASS_ZIFENCEI:
+ return "zifencei";
+ case INSN_CLASS_ZIHINTPAUSE:
+ return "zihintpause";
+ case INSN_CLASS_M:
+ return "m";
+ case INSN_CLASS_ZMMUL:
+ return _ ("m' or `zmmul");
+ case INSN_CLASS_A:
+ return "a";
+ case INSN_CLASS_ZAWRS:
+ return "zawrs";
+ case INSN_CLASS_F:
+ return "f";
+ case INSN_CLASS_D:
+ return "d";
+ case INSN_CLASS_Q:
+ return "q";
+ case INSN_CLASS_C:
+ return "c";
+ case INSN_CLASS_F_AND_C:
+ if (!riscv_subset_supports (rps, "f")
+ && !riscv_subset_supports (rps, "c"))
+ return _("f' and `c");
+ else if (!riscv_subset_supports (rps, "f"))
+ return "f";
+ else
+ return "c";
+ case INSN_CLASS_D_AND_C:
+ if (!riscv_subset_supports (rps, "d")
+ && !riscv_subset_supports (rps, "c"))
+ return _("d' and `c");
+ else if (!riscv_subset_supports (rps, "d"))
+ return "d";
+ else
+ return "c";
+ case INSN_CLASS_F_INX:
+ return _("f' or `zfinx");
+ case INSN_CLASS_D_INX:
+ return _("d' or `zdinx");
+ case INSN_CLASS_Q_INX:
+ return _("q' or `zqinx");
+ case INSN_CLASS_ZFH_INX:
+ return _("zfh' or `zhinx");
+ case INSN_CLASS_ZFHMIN:
+ return "zfhmin";
+ case INSN_CLASS_ZFHMIN_INX:
+ return _("zfhmin' or `zhinxmin");
+ case INSN_CLASS_ZFHMIN_AND_D_INX:
+ if (riscv_subset_supports (rps, "zfhmin"))
+ return "d";
+ else if (riscv_subset_supports (rps, "d"))
+ return "zfhmin";
+ else if (riscv_subset_supports (rps, "zhinxmin"))
+ return "zdinx";
+ else if (riscv_subset_supports (rps, "zdinx"))
+ return "zhinxmin";
+ else
+ return _("zfhmin' and `d', or `zhinxmin' and `zdinx");
+ case INSN_CLASS_ZFHMIN_AND_Q_INX:
+ if (riscv_subset_supports (rps, "zfhmin"))
+ return "q";
+ else if (riscv_subset_supports (rps, "q"))
+ return "zfhmin";
+ else if (riscv_subset_supports (rps, "zhinxmin"))
+ return "zqinx";
+ else if (riscv_subset_supports (rps, "zqinx"))
+ return "zhinxmin";
+ else
+ return _("zfhmin' and `q', or `zhinxmin' and `zqinx");
+ case INSN_CLASS_ZFA:
+ return "zfa";
+ case INSN_CLASS_D_AND_ZFA:
+ if (!riscv_subset_supports (rps, "d")
+ && !riscv_subset_supports (rps, "zfa"))
+ return _("d' and `zfa");
+ else if (!riscv_subset_supports (rps, "d"))
+ return "d";
+ else
+ return "zfa";
+ case INSN_CLASS_Q_AND_ZFA:
+ if (!riscv_subset_supports (rps, "q")
+ && !riscv_subset_supports (rps, "zfa"))
+ return _("q' and `zfa");
+ else if (!riscv_subset_supports (rps, "q"))
+ return "q";
+ else
+ return "zfa";
+ case INSN_CLASS_ZFH_AND_ZFA:
+ if (!riscv_subset_supports (rps, "zfh")
+ && !riscv_subset_supports (rps, "zfa"))
+ return _("zfh' and `zfa");
+ else if (!riscv_subset_supports (rps, "zfh"))
+ return "zfh";
+ else
+ return "zfa";
+ case INSN_CLASS_ZBA:
+ return "zba";
+ case INSN_CLASS_ZBB:
+ return "zbb";
+ case INSN_CLASS_ZBC:
+ return "zbc";
+ case INSN_CLASS_ZBS:
+ return "zbs";
+ case INSN_CLASS_ZBKB:
+ return "zbkb";
+ case INSN_CLASS_ZBKC:
+ return "zbkc";
+ case INSN_CLASS_ZBKX:
+ return "zbkx";
+ case INSN_CLASS_ZBB_OR_ZBKB:
+ return _("zbb' or `zbkb");
+ case INSN_CLASS_ZBC_OR_ZBKC:
+ return _("zbc' or `zbkc");
+ case INSN_CLASS_ZKND:
+ return "zknd";
+ case INSN_CLASS_ZKNE:
+ return "zkne";
+ case INSN_CLASS_ZKNH:
+ return "zknh";
+ case INSN_CLASS_ZKND_OR_ZKNE:
+ return _("zknd' or `zkne");
+ case INSN_CLASS_ZKSED:
+ return "zksed";
+ case INSN_CLASS_ZKSH:
+ return "zksh";
+ case INSN_CLASS_V:
+ return _("v' or `zve64x' or `zve32x");
+ case INSN_CLASS_ZVEF:
+ return _("v' or `zve64d' or `zve64f' or `zve32f");
+ case INSN_CLASS_ZVBB:
+ return _("zvbb");
+ case INSN_CLASS_ZVBC:
+ return _("zvbc");
+ case INSN_CLASS_ZVKG:
+ return _("zvkg");
+ case INSN_CLASS_ZVKNED:
+ return _("zvkned");
+ case INSN_CLASS_ZVKNHA:
+ return _("zvknha");
+ case INSN_CLASS_ZVKNHB:
+ return _("zvknhb");
+ case INSN_CLASS_ZVKSED:
+ return _("zvksed");
+ case INSN_CLASS_ZVKSH:
+ return _("zvksh");
+ case INSN_CLASS_SVINVAL:
+ return "svinval";
+ case INSN_CLASS_H:
+ return _("h");
+ case INSN_CLASS_XTHEADBA:
+ return "xtheadba";
+ case INSN_CLASS_XTHEADBB:
+ return "xtheadbb";
+ case INSN_CLASS_XTHEADBS:
+ return "xtheadbs";
+ case INSN_CLASS_XTHEADCMO:
+ return "xtheadcmo";
+ case INSN_CLASS_XTHEADCONDMOV:
+ return "xtheadcondmov";
+ case INSN_CLASS_XTHEADFMEMIDX:
+ return "xtheadfmemidx";
+ case INSN_CLASS_XTHEADFMV:
+ return "xtheadfmv";
+ case INSN_CLASS_XTHEADINT:
+ return "xtheadint";
+ case INSN_CLASS_XTHEADMAC:
+ return "xtheadmac";
+ case INSN_CLASS_XTHEADMEMIDX:
+ return "xtheadmemidx";
+ case INSN_CLASS_XTHEADMEMPAIR:
+ return "xtheadmempair";
+ case INSN_CLASS_XTHEADSYNC:
+ return "xtheadsync";
+ default:
+ rps->error_handler
+ (_("internal: unreachable INSN_CLASS_*"));
+ return NULL;
+ }
+}