[PATCH 3/3] RISC-V: Add support for XAndesPerf extension
Ethan Y. C. Liang
ycl669@andestech.com
Wed Nov 26 08:47:55 GMT 2025
The XAndesPerf extension provides performance enhancement instructions
for Andes RISC-V processors, including branch instructions, load
effective address instructions, GP-relative instructions, and string
processing instructions.
Spec: https://github.com/andestech/andes-v5-isa/releases/download/ast-v5_4_0-release/AndeStar_V5_ISA_Spec_UM165-v1.5.08-20250317.pdf
Contributors:
Ethan Y. C. Liang <ycl669@andestech.com>
Yu-Qi Liu <yuqiliu@andestech.com>
bfd/ChangeLog
* bfd-in2.h: Add XAndesPerf relocation types.
* libbfd.h: Likewise.
* reloc.c: Likewise.
* elfnn-riscv.c: Add support for XAndesPerf relocations and GP
relaxation. (riscv_has_subset is adapted from
riscv_use_table_jump in Jiawei's patch [1].)
* elfxx-riscv.c: Add XAndesPerf extension, instruction class,
relocation howto entries, and relocation mapping entries.
* elfxx-riscv.h: Add enum for relaxation passes.
gas/ChangeLog
* config/tc-riscv.c: Add support for XAndesPerf instruction
assembly and branch relaxation.
* doc/c-riscv.texi: Document XAndesPerf extension.
* testsuite/gas/riscv/march-help.l: Add xandesperf to available
-march extensions.
* testsuite/gas/riscv/x-andes-perf.d: New test.
* testsuite/gas/riscv/x-andes-perf.s: Likewise.
include/ChangeLog
* elf/riscv.h: Add vendor enum, vendor id, and vendor string for
Andes relocation.
* opcode/riscv-opc.h: Add opcode macros for XAndesPerf
instructions.
* opcode/riscv.h: Add immediate macros for XAndesPerf
instructions.
ld/ChangeLog
* emultempl/riscvelf.em: Change link_info.relax_pass from 2 to 4.
* testsuite/ld-riscv-elf/ld-riscv-elf.exp: Add XAndesPerf tests to
runtest list.
* testsuite/ld-riscv-elf/x-andes-perf-relax.d: New test.
* testsuite/ld-riscv-elf/x-andes-perf-relax.ld: Likewise.
* testsuite/ld-riscv-elf/x-andes-perf-relax.s: Likewise.
* testsuite/ld-riscv-elf/x-andes-perf-reloc.d: New test.
* testsuite/ld-riscv-elf/x-andes-perf-reloc.s: Likewise.
opcodes/ChangeLog
* riscv-dis.c Add support for XAndesPerf instruction disassembly.
* riscv-opc.c: Add XAndesPerf instruction entries.
[1] https://sourceware.org/pipermail/binutils/2024-January/131573.html
---
bfd/bfd-in2.h | 11 +
bfd/elfnn-riscv.c | 693 +++++++++++++++++-
bfd/elfxx-riscv.c | 183 +++++
bfd/elfxx-riscv.h | 8 +
bfd/libbfd.h | 9 +
bfd/reloc.c | 21 +
gas/config/tc-riscv.c | 307 +++++++-
gas/doc/c-riscv.texi | 5 +
gas/testsuite/gas/riscv/march-help.l | 1 +
gas/testsuite/gas/riscv/x-andes-perf.d | 107 +++
gas/testsuite/gas/riscv/x-andes-perf.s | 50 ++
include/elf/riscv.h | 18 +
include/opcode/riscv-opc.h | 89 +++
include/opcode/riscv.h | 78 ++
ld/emultempl/riscvelf.em | 2 +-
ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp | 3 +
.../ld-riscv-elf/x-andes-perf-relax.d | 14 +
.../ld-riscv-elf/x-andes-perf-relax.ld | 11 +
.../ld-riscv-elf/x-andes-perf-relax.s | 23 +
.../ld-riscv-elf/x-andes-perf-reloc.d | 26 +
.../ld-riscv-elf/x-andes-perf-reloc.s | 20 +
opcodes/riscv-dis.c | 89 +++
opcodes/riscv-opc.c | 31 +
23 files changed, 1787 insertions(+), 12 deletions(-)
create mode 100644 gas/testsuite/gas/riscv/x-andes-perf.d
create mode 100644 gas/testsuite/gas/riscv/x-andes-perf.s
create mode 100644 ld/testsuite/ld-riscv-elf/x-andes-perf-relax.d
create mode 100644 ld/testsuite/ld-riscv-elf/x-andes-perf-relax.ld
create mode 100644 ld/testsuite/ld-riscv-elf/x-andes-perf-relax.s
create mode 100644 ld/testsuite/ld-riscv-elf/x-andes-perf-reloc.d
create mode 100644 ld/testsuite/ld-riscv-elf/x-andes-perf-reloc.s
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 06e78a30a2b..07eecec43b2 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5451,6 +5451,17 @@ enum bfd_reloc_code_real
BFD_RELOC_RISCV_SUB_ULEB128,
BFD_RELOC_RISCV_VENDOR,
+ /* RISC-V vendor (Andes) relocations. */
+ BFD_RELOC_RISCV_NDS_BRANCH_10,
+ BFD_RELOC_RISCV_NDS_GPREL_18S0_I,
+ BFD_RELOC_RISCV_NDS_GPREL_17S1_I,
+ BFD_RELOC_RISCV_NDS_GPREL_17S2_I,
+ BFD_RELOC_RISCV_NDS_GPREL_17S3_I,
+ BFD_RELOC_RISCV_NDS_GPREL_18S0_S,
+ BFD_RELOC_RISCV_NDS_GPREL_17S1_S,
+ BFD_RELOC_RISCV_NDS_GPREL_17S2_S,
+ BFD_RELOC_RISCV_NDS_GPREL_17S3_S,
+
/* Renesas RL78 Relocations. */
BFD_RELOC_RL78_NEG8,
BFD_RELOC_RL78_NEG16,
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index f9e2f3a7597..2750578f11e 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -2014,6 +2014,64 @@ perform_relocation (const reloc_howto_type *howto,
bfd_reloc_status_type status = bfd_reloc_ok;
switch (vendor_id)
{
+ case RISCV_VENDOR_ID_NDS:
+ switch (ELFNN_R_TYPE (rel->r_info))
+ {
+ case R_RISCV_NDS_BRANCH_10:
+ if (!VALID_NDS_BRANCH_IMM10 (value))
+ return bfd_reloc_overflow;
+ value = ENCODE_NDS_BRANCH_IMM10 (value);
+ break;
+
+ case R_RISCV_NDS_GPREL_18S0_I:
+ if (!VALID_NDS_LBGP_IMM (value))
+ return bfd_reloc_overflow;
+ value = ENCODE_NDS_LBGP_IMM (value);
+ break;
+
+ case R_RISCV_NDS_GPREL_17S1_I:
+ if (!VALID_NDS_LHGP_IMM (value))
+ return bfd_reloc_overflow;
+ value = ENCODE_NDS_LHGP_IMM (value);
+ break;
+
+ case R_RISCV_NDS_GPREL_17S2_I:
+ if (!VALID_NDS_LWGP_IMM (value))
+ return bfd_reloc_overflow;
+ value = ENCODE_NDS_LWGP_IMM (value);
+ break;
+
+ case R_RISCV_NDS_GPREL_17S3_I:
+ if (!VALID_NDS_LDGP_IMM (value))
+ return bfd_reloc_overflow;
+ value = ENCODE_NDS_LDGP_IMM (value);
+ break;
+
+ case R_RISCV_NDS_GPREL_18S0_S:
+ if (!VALID_NDS_SBGP_IMM (value))
+ return bfd_reloc_overflow;
+ value = ENCODE_NDS_SBGP_IMM (value);
+ break;
+
+ case R_RISCV_NDS_GPREL_17S1_S:
+ if (!VALID_NDS_SHGP_IMM (value))
+ return bfd_reloc_overflow;
+ value = ENCODE_NDS_SHGP_IMM (value);
+ break;
+
+ case R_RISCV_NDS_GPREL_17S2_S:
+ if (!VALID_NDS_SWGP_IMM (value))
+ return bfd_reloc_overflow;
+ value = ENCODE_NDS_SWGP_IMM (value);
+ break;
+
+ case R_RISCV_NDS_GPREL_17S3_S:
+ if (!VALID_NDS_SDGP_IMM (value))
+ return bfd_reloc_overflow;
+ value = ENCODE_NDS_SDGP_IMM (value);
+ break;
+ }
+ break;
default:
return bfd_reloc_notsupported;
}
@@ -2837,6 +2895,29 @@ riscv_elf_relocate_section (bfd *output_bfd,
type was R_RISCV_VENDOR. */
switch (vendor_id)
{
+ case RISCV_VENDOR_ID_NDS:
+ switch (r_type)
+ {
+ case R_RISCV_NDS_GPREL_18S0_I:
+ case R_RISCV_NDS_GPREL_17S1_I:
+ case R_RISCV_NDS_GPREL_17S2_I:
+ case R_RISCV_NDS_GPREL_17S3_I:
+ case R_RISCV_NDS_GPREL_18S0_S:
+ case R_RISCV_NDS_GPREL_17S1_S:
+ case R_RISCV_NDS_GPREL_17S2_S:
+ case R_RISCV_NDS_GPREL_17S3_S:
+ {
+ bfd_vma gp = riscv_global_pointer_value (info);
+ rel->r_addend -= gp;
+ break;
+ }
+ case R_RISCV_NDS_BRANCH_10:
+ break;
+ default:
+ /* Unreachable: vendor_id was was validated earlier. */
+ BFD_ASSERT (false);
+ }
+ goto do_relocation;
default:
break;
}
@@ -4069,6 +4150,38 @@ riscv_i_or_e_p (bfd *ibfd,
return true;
}
+/* Return true if the output BFD contains this subset. */
+
+static bool
+riscv_has_subset (struct bfd_link_info *info, const char *subset)
+{
+ unsigned xlen = ARCH_SIZE;
+ riscv_subset_list_t subsets;
+ bool ret;
+
+ if (info->disable_target_specific_optimizations >= 1)
+ return false;
+
+ if (!bfd_link_executable (info))
+ return false;
+
+ bfd *obfd = info->output_bfd;
+ obj_attribute *out_attr = elf_known_obj_attributes_proc (obfd);
+
+ memset (&subsets, 0, sizeof (riscv_subset_list_t));
+
+ riscv_parse_subset_t riscv_rps_ld_out =
+ {&subsets, _bfd_error_handler, &xlen, NULL, false};
+
+ if (!riscv_parse_subset (&riscv_rps_ld_out, out_attr[Tag_RISCV_arch].s))
+ return false;
+
+ ret = riscv_subset_supports (&riscv_rps_ld_out, subset);
+ riscv_release_subset_list (&subsets);
+
+ return ret;
+}
+
/* Merge standard extensions.
Return Value:
@@ -4570,6 +4683,7 @@ struct riscv_pcgp_hi_reloc
asection *sym_sec;
bool undefined_weak;
riscv_pcgp_hi_reloc *next;
+ Elf_Internal_Rela *rel;
};
typedef struct riscv_pcgp_lo_reloc riscv_pcgp_lo_reloc;
@@ -5442,11 +5556,483 @@ bfd_elfNN_riscv_set_data_segment_info (struct bfd_link_info *info,
htab->data_segment_phase = data_segment_phase;
}
+/* Traverse all output sections and return the max alignment.
+ Only the output sections which are in the [gp-512K, gp+512K)
+ range need to be considered. */
+static bfd_vma
+_bfd_riscv_nds_get_max_alignment (asection *sec, bfd_vma gp)
+{
+ unsigned int max_alignment_power = 0;
+ asection *o;
+ bfd_signed_vma offset_min = -(1 << 19);
+ bfd_signed_vma offset_max = (1 << 19) - 1;
+
+ for (o = sec->output_section->owner->sections; o != NULL; o = o->next)
+ {
+ bool valid = true;
+ bfd_signed_vma sec_begin_offset = sec_addr (o) - gp;
+ bfd_signed_vma sec_end_offset = sec_addr (o) + o->size - gp;
+ if (!((sec_begin_offset >= offset_min
+ && sec_begin_offset <= offset_max)
+ || (sec_end_offset >= offset_min
+ && sec_end_offset <= offset_max)))
+ valid = false;
+
+ if (valid && o->alignment_power > max_alignment_power)
+ max_alignment_power = o->alignment_power;
+ }
+
+ return (bfd_vma) 1 << max_alignment_power;
+}
+
+/* Check alignment of symbol and addend. */
+static int
+riscv_nds_min_p2align (Elf_Internal_Rela *rel, asection *sec, bfd_vma symval)
+{
+ int limit = 3 < sec->alignment_power ? 3 : sec->alignment_power;
+ bfd_vma sym_offset = symval - sec->output_section->vma - sec->output_offset;
+ int i;
+ for (i = 0; i < limit; ++i)
+ {
+ unsigned int m = 1u << i;
+ if ((rel && (rel->r_addend & m)) || sym_offset & m)
+ break;
+ }
+
+ return i;
+}
+
+/* Check instruction type and distance of symbol. */
+static int
+riscv_nds_relax_gp_insn (bfd *abfd, asection *sec, asection *sym_sec,
+ Elf_Internal_Rela *rel, bfd_vma symval, unsigned sym,
+ bfd_vma addend, bfd_vma gp, bfd_vma reserve_size)
+{
+ bfd_byte *contents = elf_section_data (sec)->this_hdr.contents;
+ uint32_t insn = bfd_get_32 (abfd, contents + rel->r_offset);
+ bfd_signed_vma bias = symval - gp;
+ bias += (bias > 0) ? reserve_size : -reserve_size;
+ int gp_alignment = ffs (gp) - 1;
+
+ int worst_p2align = riscv_nds_min_p2align (rel, sym_sec, symval);
+
+ if ((insn & MASK_ADDI) == MATCH_ADDI && VALID_NDS_LBGP_IMM (bias))
+ {
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_NDS_GPREL_18S0_I);
+ insn = (insn & (OP_MASK_RD << OP_SH_RD)) | MATCH_NDS_ADDIGP;
+ }
+ else if ((insn & MASK_LB) == MATCH_LB && VALID_NDS_LBGP_IMM (bias))
+ {
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_NDS_GPREL_18S0_I);
+ insn = (insn & (OP_MASK_RD << OP_SH_RD)) | MATCH_NDS_LBGP;
+ }
+ else if ((insn & MASK_LBU) == MATCH_LBU && VALID_NDS_LBGP_IMM (bias))
+ {
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_NDS_GPREL_18S0_I);
+ insn = (insn & (OP_MASK_RD << OP_SH_RD)) | MATCH_NDS_LBUGP;
+ }
+ else if ((insn & MASK_LH) == MATCH_LH && VALID_NDS_LBGP_IMM (bias)
+ && worst_p2align > 0 && gp_alignment > 0)
+ {
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_NDS_GPREL_17S1_I);
+ insn = (insn & (OP_MASK_RD << OP_SH_RD)) | MATCH_NDS_LHGP;
+ }
+ else if ((insn & MASK_LHU) == MATCH_LHU && VALID_NDS_LBGP_IMM (bias)
+ && worst_p2align > 0 && gp_alignment > 0)
+ {
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_NDS_GPREL_17S1_I);
+ insn = (insn & (OP_MASK_RD << OP_SH_RD)) | MATCH_NDS_LHUGP;
+ }
+ else if ((insn & MASK_LW) == MATCH_LW && bias >= -(1 << 18)
+ && bias < (1 << 18) && worst_p2align > 1 && gp_alignment > 1)
+ {
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_NDS_GPREL_17S2_I);
+ insn = (insn & (OP_MASK_RD << OP_SH_RD)) | MATCH_NDS_LWGP;
+ }
+ else if ((insn & MASK_LWU) == MATCH_LWU && bias >= -(1 << 18)
+ && bias < (1 << 18) && worst_p2align > 1 && gp_alignment > 1)
+ {
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_NDS_GPREL_17S2_I);
+ insn = (insn & (OP_MASK_RD << OP_SH_RD)) | MATCH_NDS_LWUGP;
+ }
+ else if ((insn & MASK_LD) == MATCH_LD && bias >= -(1 << 19)
+ && bias < (1 << 19) && worst_p2align > 2 && gp_alignment > 2
+ && ARCH_SIZE == 64)
+ {
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_NDS_GPREL_17S3_I);
+ insn = (insn & (OP_MASK_RD << OP_SH_RD)) | MATCH_NDS_LDGP;
+ }
+ else if ((insn & MASK_SB) == MATCH_SB && VALID_NDS_SBGP_IMM (bias))
+ {
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_NDS_GPREL_18S0_S);
+ insn = (insn & (OP_MASK_RS2 << OP_SH_RS2)) | MATCH_NDS_SBGP;
+ }
+ else if ((insn & MASK_SH) == MATCH_SH && VALID_NDS_SBGP_IMM (bias)
+ && worst_p2align > 0 && gp_alignment > 0)
+ {
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_NDS_GPREL_17S1_S);
+ insn = (insn & (OP_MASK_RS2 << OP_SH_RS2)) | MATCH_NDS_SHGP;
+ }
+ else if ((insn & MASK_SW) == MATCH_SW && bias >= -(1 << 18)
+ && bias < (1 << 18) && worst_p2align > 1 && gp_alignment > 1)
+ {
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_NDS_GPREL_17S2_S);
+ insn = (insn & (OP_MASK_RS2 << OP_SH_RS2)) | MATCH_NDS_SWGP;
+ }
+ else if ((insn & MASK_SD) == MATCH_SD && bias >= -(1 << 19)
+ && bias < (1 << 19) && worst_p2align > 2 && gp_alignment > 2
+ && ARCH_SIZE == 64)
+ {
+ rel->r_info = ELFNN_R_INFO (sym, R_RISCV_NDS_GPREL_17S3_S);
+ insn = (insn & (OP_MASK_RS2 << OP_SH_RS2)) | MATCH_NDS_SDGP;
+ }
+ else
+ {
+ return false;
+ }
+ rel->r_addend = addend;
+
+ bfd_put_32 (abfd, insn, contents + rel->r_offset);
+
+ return true;
+}
+
+/* Structure used for recording symbol info for GP relaxation in
+ _bfd_riscv_nds_relax_lui. */
+typedef struct relax_gp_sym_info
+{
+ Elf_Internal_Sym *lsym;
+ struct elf_link_hash_entry *h;
+ asection *sec;
+ struct relax_gp_sym_info *next;
+} relax_gp_sym_info_t;
+static relax_gp_sym_info_t *relax_gp_sym_info_head = NULL;
+
+/* Record symbol if record is 1.
+ Find symbol if record is 0. */
+static relax_gp_sym_info_t *
+riscv_nds_record_and_find_relax_gp_syms (asection *sec,
+ Elf_Internal_Sym *lsym,
+ struct elf_link_hash_entry *h,
+ int record)
+{
+ struct relax_gp_sym_info *ptr, *pre_ptr;
+ ptr = relax_gp_sym_info_head;
+ pre_ptr = ptr;
+
+ /* Check whether the symbol is recorded. */
+ while (ptr)
+ {
+ if ((h && h == ptr->h && sec == ptr->sec)
+ || (lsym && lsym == ptr->lsym && sec == ptr->sec))
+ return ptr;
+ pre_ptr = ptr;
+ ptr = ptr->next;
+ }
+
+ if (!ptr && record)
+ {
+ ptr = bfd_malloc (sizeof (struct relax_gp_sym_info));
+ if (!ptr)
+ return NULL;
+ ptr->sec = sec;
+ ptr->lsym = lsym;
+ ptr->h = h;
+ ptr->next = NULL;
+
+ if (!relax_gp_sym_info_head)
+ relax_gp_sym_info_head = ptr;
+ else
+ pre_ptr->next = ptr;
+
+ return ptr;
+ }
+
+ return NULL;
+}
+
+/* PASS_XANDESPERF_GP1: Modify low part insns
+ PASS_XANDESPERF_GP2: Remove redundant high part insns. */
+static bool
+_bfd_riscv_nds_relax_lui (bfd *abfd,
+ asection *sec,
+ asection *sym_sec,
+ struct bfd_link_info *link_info,
+ Elf_Internal_Rela *rel,
+ bfd_vma symval,
+ bfd_vma max_alignment,
+ bfd_vma reserve_size,
+ bool *again ATTRIBUTE_UNUSED,
+ riscv_pcgp_relocs *pcgp_relocs ATTRIBUTE_UNUSED,
+ bool undefined_weak)
+{
+ bfd_vma gp = riscv_global_pointer_value (link_info);
+ bfd_vma data_segment_alignment = link_info->relro
+ ? ELF_MAXPAGESIZE + ELF_COMMONPAGESIZE
+ : ELF_MAXPAGESIZE;
+ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (abfd);
+ Elf_Internal_Sym *isym = NULL;
+ struct elf_link_hash_entry *hsym = NULL;
+
+ BFD_ASSERT (rel->r_offset + 4 <= sec->size);
+
+ /* Skip some unsupported cases. */
+ if (undefined_weak || !gp || sym_sec->output_section == bfd_abs_section_ptr
+ || elf_section_flags (sym_sec) & SHF_EXECINSTR)
+ return true;
+
+ /* If gp and the symbol are in the same output section, which is not the
+ abs section, then consider only that output section's alignment. */
+ struct bfd_link_hash_entry *h =
+ bfd_link_hash_lookup (link_info->hash, RISCV_GP_SYMBOL, false, false,
+ true);
+ if (h->u.def.section->output_section == sym_sec->output_section
+ && sym_sec->output_section != bfd_abs_section_ptr)
+ max_alignment = (bfd_vma) 1 << sym_sec->output_section->alignment_power;
+ else
+ {
+ /* Consider output section alignments which are in [gp-512K, gp+512K). */
+ max_alignment = _bfd_riscv_nds_get_max_alignment (sec, gp);
+ }
+
+ if (symval < sec_addr (sym_sec)
+ || symval > (sec_addr (sym_sec) + sym_sec->size))
+ max_alignment = data_segment_alignment > max_alignment
+ ? data_segment_alignment : max_alignment;
+
+ /* Record the symbols referenced by non-relaxed low part instructions during
+ PASS_XANDESPERF_GP1, and do not delete the high part instructions that
+ reference these symbols during PASS_XANDESPERF_GP2. */
+ if (symtab_hdr->sh_info != 0
+ && !symtab_hdr->contents
+ && !(symtab_hdr->contents =
+ (unsigned char *) bfd_elf_get_elf_syms (abfd, symtab_hdr,
+ symtab_hdr->sh_info,
+ 0, NULL, NULL, NULL)))
+ return false;
+
+ if (ELFNN_R_SYM (rel->r_info) < symtab_hdr->sh_info)
+ /* A local symbol. */
+ isym = ((Elf_Internal_Sym *) symtab_hdr->contents
+ + ELFNN_R_SYM (rel->r_info));
+ else
+ {
+ /* A global symbol. */
+ unsigned long indx;
+ indx = ELFNN_R_SYM (rel->r_info) - symtab_hdr->sh_info;
+ hsym = elf_sym_hashes (abfd)[indx];
+
+ while (hsym->root.type == bfd_link_hash_indirect
+ || hsym->root.type == bfd_link_hash_warning)
+ hsym = (struct elf_link_hash_entry *) hsym->root.u.i.link;
+ }
+
+ reserve_size += max_alignment;
+ switch (ELFNN_R_TYPE (rel->r_info))
+ {
+ case R_RISCV_LO12_I:
+ case R_RISCV_LO12_S:
+ {
+ /* Record high part that shouldn't be deleted. */
+ if (!riscv_nds_relax_gp_insn (abfd, sec, sym_sec, rel,
+ symval, ELFNN_R_SYM (rel->r_info),
+ rel->r_addend, gp, reserve_size)
+ && !riscv_nds_record_and_find_relax_gp_syms (sym_sec, isym,
+ hsym, 1))
+ return false;
+ }
+ break;
+
+ case R_RISCV_HI20:
+ if (!riscv_nds_record_and_find_relax_gp_syms (sym_sec, isym, hsym, 0))
+ {
+ /* Delete unnecessary LUI and reuse the reloc. */
+ return riscv_relax_delete_bytes (abfd, sec, rel->r_offset, 4,
+ link_info, pcgp_relocs, rel);
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ return true;
+}
+
+static bool
+riscv_nds_record_pcgp_hi_reloc_ext (riscv_pcgp_relocs *p, bfd_vma hi_sec_off,
+ bfd_vma hi_addend, bfd_vma hi_addr,
+ unsigned hi_sym, asection *sym_sec,
+ bool undefined_weak,
+ Elf_Internal_Rela *rel)
+{
+ bool rz = riscv_record_pcgp_hi_reloc (p, hi_sec_off, hi_addend, hi_addr,
+ hi_sym, sym_sec, undefined_weak);
+ if (rz)
+ p->hi->rel = rel;
+ return rz;
+}
+
+/* PASS_XANDESPERF_GP1: Modify low part insns. the high part
+ will be removed before riscv_free_pcgp_relocs executes. */
+static bool
+_bfd_riscv_nds_relax_pc (bfd *abfd,
+ asection *sec,
+ asection *sym_sec,
+ struct bfd_link_info *link_info,
+ Elf_Internal_Rela *rel,
+ bfd_vma symval,
+ bfd_vma max_alignment,
+ bfd_vma reserve_size,
+ bool *again ATTRIBUTE_UNUSED,
+ riscv_pcgp_relocs *pcgp_relocs,
+ bool undefined_weak)
+{
+ bfd_vma gp = riscv_global_pointer_value (link_info);
+ bfd_vma data_segment_alignment = link_info->relro
+ ? ELF_MAXPAGESIZE + ELF_COMMONPAGESIZE
+ : ELF_MAXPAGESIZE;
+
+ BFD_ASSERT (rel->r_offset + 4 <= sec->size);
+
+ /* Chain the _LO relocs to their cooresponding _HI reloc to compute the
+ actual target address. */
+ riscv_pcgp_hi_reloc hi_reloc;
+ memset (&hi_reloc, 0, sizeof (hi_reloc));
+ bfd_vma hi_sec_off;
+ switch (ELFNN_R_TYPE (rel->r_info))
+ {
+ case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_PCREL_LO12_S:
+ {
+ /* If the %lo has an addend, it isn't for the label pointing at the
+ hi part instruction, but rather for the symbol pointed at by the
+ hi part instruction. So we must subtract it here for the lookup.
+ It is still used below in the final symbol address. */
+ hi_sec_off = symval - sec_addr (sym_sec) - rel->r_addend;
+ riscv_pcgp_hi_reloc *hi = riscv_find_pcgp_hi_reloc (pcgp_relocs,
+ hi_sec_off);
+ if (hi == NULL)
+ {
+ riscv_record_pcgp_lo_reloc (pcgp_relocs, hi_sec_off);
+ return true;
+ }
+
+ hi_reloc = *hi;
+ symval = hi_reloc.hi_addr;
+ sym_sec = hi_reloc.sym_sec;
+
+ /* We can not know whether the undefined weak symbol is referenced
+ according to the information of R_RISCV_PCREL_LO12_I/S. Therefore,
+ we have to record the 'undefined_weak' flag when handling the
+ corresponding R_RISCV_HI20 reloc in riscv_record_pcgp_hi_reloc. */
+ undefined_weak = hi_reloc.undefined_weak;
+ }
+ break;
+
+ case R_RISCV_PCREL_HI20:
+ riscv_nds_record_pcgp_hi_reloc_ext (pcgp_relocs,
+ rel->r_offset,
+ rel->r_addend,
+ symval,
+ ELFNN_R_SYM (rel->r_info),
+ sym_sec, undefined_weak, rel);
+ return true;
+ break;
+
+ default:
+ abort ();
+ }
+
+ if (undefined_weak || !gp || sym_sec->output_section == bfd_abs_section_ptr
+ || elf_section_flags (sym_sec) & SHF_EXECINSTR)
+ {
+ riscv_record_pcgp_lo_reloc (pcgp_relocs, hi_sec_off);
+ return true; /* bypass to original handling */
+ }
+
+ /* If gp and the symbol are in the same output section, which is not the
+ abs section, then consider only that output section's alignment. */
+ struct bfd_link_hash_entry *h =
+ bfd_link_hash_lookup (link_info->hash, RISCV_GP_SYMBOL, false, false,
+ true);
+ if (h->u.def.section->output_section == sym_sec->output_section
+ && sym_sec->output_section != bfd_abs_section_ptr)
+ max_alignment = (bfd_vma) 1 << sym_sec->output_section->alignment_power;
+ else
+ {
+ /* Consider output section alignments which are in [gp-512K, gp+512K). */
+ max_alignment = _bfd_riscv_nds_get_max_alignment (sec, gp);
+ }
+
+ if (symval < sec_addr (sym_sec)
+ || symval > (sec_addr (sym_sec) + sym_sec->size))
+ max_alignment = data_segment_alignment > max_alignment
+ ? data_segment_alignment : max_alignment;
+
+ reserve_size += max_alignment;
+ switch (ELFNN_R_TYPE (rel->r_info))
+ {
+ case R_RISCV_PCREL_LO12_I:
+ case R_RISCV_PCREL_LO12_S:
+ {
+ if (!riscv_nds_relax_gp_insn (abfd, sec, sym_sec, rel, symval,
+ hi_reloc.hi_sym, hi_reloc.hi_addend,
+ gp, reserve_size))
+ riscv_record_pcgp_lo_reloc (pcgp_relocs, hi_sec_off);
+ }
+ break;
+
+ default:
+ abort ();
+ }
+
+ return true;
+}
+
+/* Delete the unnecessary AUIPC and reloc. */
+static void
+riscv_nds_relax_pc_final (riscv_pcgp_relocs *p)
+{
+ riscv_pcgp_hi_reloc *c;
+
+ for (c = p->hi; c != NULL; c = c->next)
+ {
+ if (!riscv_find_pcgp_lo_reloc (p, c->hi_sec_off))
+ {
+ c->rel->r_info = ELFNN_R_INFO (0, R_RISCV_DELETE);
+ c->rel->r_addend = 4;
+ }
+ }
+}
+
/* Relax a section.
- Pass 0: Shortens code sequences for LUI/CALL/TPREL/PCREL relocs and
- deletes the obsolete bytes.
- Pass 1: Which cannot be disabled, handles code alignment directives. */
+ Pass PASS_XANDESPERF_GP1
+ Stage 1 of Andes GP relaxation. In this stage, the low part of
+ a LUI pair is checked to determine whether it can be shortened
+ using Andes GP instructions. Because different Andes GP
+ instructions have different alignment limits, the high part of
+ the LUI instruction cannot be deleted before all low parts
+ have been checked. The high part of the LUI will therefore
+ remain until Stage 2.
+ On the other hand, the high part of a PC-relative (pcrel)
+ instruction is recorded to verify the low part of the same
+ pcrel instruction in this stage. The relaxation results are
+ stored in pcgp_relocs, which are later used to determine which
+ high parts should be deleted before _bfd_riscv_relax_section
+ returns.
+ Pass PASS_XANDESPERF_GP2
+ Stage 2 of Andes GP relaxation. In this stage, the high parts
+ of LUI are processed using the results from Stage 1 to determine
+ which high parts should be deleted. Additionally, relocations
+ generated by PASS_XANDESPERF_GP1 did not include R_RISCV_VENDOR.
+ R_RISCV_VENDOR relocations are added in this stage.
+ Pass PASS_SHORTEN
+ Shortens code sequences for LUI/CALL/TPREL/PCREL relocs and
+ deletes the obsolete bytes.
+ Pass PASS_ALIGN
+ Which cannot be disabled, handles code alignment directives. */
static bool
_bfd_riscv_relax_section (bfd *abfd, asection *sec,
@@ -5471,12 +6057,18 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
|| (sec->flags & SEC_RELOC) == 0
|| (sec->flags & SEC_HAS_CONTENTS) == 0
|| (info->disable_target_specific_optimizations
- && info->relax_pass == 0)
+ && info->relax_pass < PASS_ALIGN)
/* The exp_seg_relro_adjust is enum phase_enum (0x4),
and defined in ld/ldexp.h. */
|| *(htab->data_segment_phase) == 4)
return true;
+ if ((info->relax_pass == PASS_XANDESPERF_GP1
+ || info->relax_pass == PASS_XANDESPERF_GP2)
+ && (!riscv_has_subset (info, "xandesperf")
+ || !htab->params->relax_gp))
+ return true;
+
/* Record the first relax section, so that we can reset the
max_alignment_for_gp for the repeated relax passes. */
if (first_section == NULL)
@@ -5515,7 +6107,7 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
relax_func = NULL;
riscv_relax_delete_bytes = NULL;
- if (info->relax_pass == 0)
+ if (info->relax_pass == PASS_SHORTEN)
{
if (type == R_RISCV_CALL
|| type == R_RISCV_CALL_PLT)
@@ -5547,11 +6139,88 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
/* Skip over the R_RISCV_RELAX. */
i++;
}
- else if (info->relax_pass == 1 && type == R_RISCV_ALIGN)
+ else if (info->relax_pass == PASS_ALIGN && type == R_RISCV_ALIGN)
{
relax_func = _bfd_riscv_relax_align;
riscv_relax_delete_bytes = _riscv_relax_delete_immediate;
}
+ else if (info->relax_pass == PASS_XANDESPERF_GP1)
+ {
+ if (type == R_RISCV_LO12_I
+ || type == R_RISCV_LO12_S)
+ relax_func = _bfd_riscv_nds_relax_lui;
+ else if (!bfd_link_pic (info)
+ && (type == R_RISCV_PCREL_HI20
+ || type == R_RISCV_PCREL_LO12_I
+ || type == R_RISCV_PCREL_LO12_S))
+ relax_func = _bfd_riscv_nds_relax_pc;
+ else
+ continue;
+
+ /* Only relax this reloc if it is paired with R_RISCV_RELAX. */
+ if (i == sec->reloc_count - 1
+ || ELFNN_R_TYPE ((rel + 1)->r_info) != R_RISCV_RELAX
+ || rel->r_offset != (rel + 1)->r_offset)
+ continue;
+
+ /* Skip over the R_RISCV_RELAX. */
+ i++;
+ }
+ else if (info->relax_pass == PASS_XANDESPERF_GP2)
+ {
+ /* Add R_RISCV_VENDOR relocations using the space of original
+ R_RISCV_RELAX. */
+ if (type >= R_RISCV_NDS_GPREL_18S0_I
+ && type <= R_RISCV_NDS_GPREL_17S3_S
+ && i != sec->reloc_count - 1
+ && ELFNN_R_TYPE ((rel + 1)->r_info) == R_RISCV_RELAX
+ && rel->r_offset == (rel + 1)->r_offset)
+ {
+ memcpy (rel + 1, rel, sizeof (Elf_Internal_Rela));
+
+ if (!symtab_hdr->contents)
+ goto fail;
+
+ unsigned int symidx = 0;
+ const char *name = NULL;
+ bool find = false;
+ for (; symidx < symtab_hdr->sh_info; symidx++)
+ {
+ Elf_Internal_Sym *isym =
+ (Elf_Internal_Sym *) symtab_hdr->contents + symidx;
+ name = bfd_elf_sym_name (abfd, symtab_hdr, isym, NULL);
+ if (!strcmp (name, RISCV_VENDOR_STR_NDS))
+ {
+ find = true;
+ break;
+ }
+ }
+ if (find)
+ {
+ rel->r_info = ELFNN_R_INFO (symidx, R_RISCV_VENDOR);
+ rel->r_addend = 0;
+ }
+ else
+ BFD_ASSERT (0);
+ i++;
+ continue;
+ }
+
+ if (type == R_RISCV_HI20)
+ relax_func = _bfd_riscv_nds_relax_lui;
+ else
+ continue;
+ riscv_relax_delete_bytes = _riscv_relax_delete_piecewise;
+
+ /* Only relax this reloc if it is paired with R_RISCV_RELAX. */
+ if (i == sec->reloc_count - 1
+ || ELFNN_R_TYPE ((rel + 1)->r_info) != R_RISCV_RELAX
+ || rel->r_offset != (rel + 1)->r_offset)
+ continue;
+
+ /* Skip over the R_RISCV_RELAX. */
+ i++;
+ }
else
continue;
@@ -5714,6 +6383,9 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
&pcgp_relocs, undefined_weak))
goto fail;
}
+ /* Delete the unnecessary AUIPC and reloc. */
+ if (info->relax_pass == PASS_XANDESPERF_GP1)
+ riscv_nds_relax_pc_final (&pcgp_relocs);
/* Resolve R_RISCV_DELETE relocations. */
if (!riscv_relax_resolve_delete_relocs (abfd, sec, info, relocs))
@@ -5726,6 +6398,15 @@ _bfd_riscv_relax_section (bfd *abfd, asection *sec,
free (relocs);
riscv_free_pcgp_relocs (&pcgp_relocs, abfd, sec);
+ /* Free structures. */
+ if (info->relax_pass == PASS_XANDESPERF_GP2 + 1)
+ while (relax_gp_sym_info_head != NULL)
+ {
+ struct relax_gp_sym_info *temp = relax_gp_sym_info_head;
+ relax_gp_sym_info_head = relax_gp_sym_info_head->next;
+ free (temp);
+ }
+
return ret;
}
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 1a391c51f2b..731ce443570 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -1009,10 +1009,165 @@ static const reloc_howto_type howto_table_internal[] =
false), /* pcrel_offset */
};
+static reloc_howto_type howto_table_nds[] =
+{
+ EMPTY_HOWTO (192), EMPTY_HOWTO (193), EMPTY_HOWTO (194), EMPTY_HOWTO (195),
+ EMPTY_HOWTO (196), EMPTY_HOWTO (197), EMPTY_HOWTO (198), EMPTY_HOWTO (199),
+ EMPTY_HOWTO (200), EMPTY_HOWTO (201), EMPTY_HOWTO (202), EMPTY_HOWTO (203),
+ EMPTY_HOWTO (204), EMPTY_HOWTO (205), EMPTY_HOWTO (206), EMPTY_HOWTO (207),
+ EMPTY_HOWTO (208), EMPTY_HOWTO (209), EMPTY_HOWTO (210), EMPTY_HOWTO (211),
+ EMPTY_HOWTO (212), EMPTY_HOWTO (213), EMPTY_HOWTO (214), EMPTY_HOWTO (215),
+ EMPTY_HOWTO (216), EMPTY_HOWTO (217), EMPTY_HOWTO (218), EMPTY_HOWTO (219),
+ EMPTY_HOWTO (220), EMPTY_HOWTO (221), EMPTY_HOWTO (222), EMPTY_HOWTO (223),
+ EMPTY_HOWTO (224), EMPTY_HOWTO (225), EMPTY_HOWTO (226), EMPTY_HOWTO (227),
+ EMPTY_HOWTO (228), EMPTY_HOWTO (229), EMPTY_HOWTO (230), EMPTY_HOWTO (231),
+ EMPTY_HOWTO (232), EMPTY_HOWTO (233), EMPTY_HOWTO (234), EMPTY_HOWTO (235),
+ EMPTY_HOWTO (236), EMPTY_HOWTO (237), EMPTY_HOWTO (238), EMPTY_HOWTO (239),
+ EMPTY_HOWTO (240),
+
+ /* 10-bit PC-relative branch offset. */
+ HOWTO (R_RISCV_NDS_BRANCH_10, /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 32, /* bitsize */
+ true, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_NDS_BRANCH_10", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_NDS_BRANCH_IMM10 (-1U), /* dst_mask */
+ true), /* pcrel_offset */
+
+ EMPTY_HOWTO (242), EMPTY_HOWTO (243), EMPTY_HOWTO (244), EMPTY_HOWTO (245),
+
+ /* 18-bit GP-relative load offset. */
+ HOWTO (R_RISCV_NDS_GPREL_18S0_I, /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_NDS_GPREL_18S0_I", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_NDS_LBGP_IMM (-1U), /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* 17-bit and right shift 1-bit GP-relative load offset. */
+ HOWTO (R_RISCV_NDS_GPREL_17S1_I, /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_NDS_GPREL_17S1_I", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_NDS_LHGP_IMM (-1U), /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* 16-bit and right shift 2-bit GP-relative load offset. */
+ HOWTO (R_RISCV_NDS_GPREL_17S2_I, /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_NDS_GPREL_17S2_I", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_NDS_LWGP_IMM (-1U), /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* 15-bit and right shift 3-bit GP-relative load offset. */
+ HOWTO (R_RISCV_NDS_GPREL_17S3_I, /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_NDS_GPREL_17S3_I", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_NDS_LDGP_IMM (-1U), /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* 18-bit GP-relative store offset. */
+ HOWTO (R_RISCV_NDS_GPREL_18S0_S, /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_NDS_GPREL_18S0_S", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_NDS_SBGP_IMM (-1U), /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* 17-bit and right shift 1-bit GP-relative store offset. */
+ HOWTO (R_RISCV_NDS_GPREL_17S1_S, /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_NDS_GPREL_17S1_S", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_NDS_SHGP_IMM (-1U), /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* 16-bit and right shift 2-bit GP-relative store offset. */
+ HOWTO (R_RISCV_NDS_GPREL_17S2_S, /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_NDS_GPREL_17S2_S", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_NDS_SWGP_IMM (-1U), /* dst_mask */
+ false), /* pcrel_offset */
+
+ /* 15-bit and right shift 3-bit GP-relative store offset. */
+ HOWTO (R_RISCV_NDS_GPREL_17S3_S, /* type */
+ 0, /* rightshift */
+ 2, /* size */
+ 32, /* bitsize */
+ false, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_NDS_GPREL_17S3_S", /* name */
+ false, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_NDS_SDGP_IMM (-1U), /* dst_mask */
+ false) /* pcrel_offset */
+};
+
static const reloc_howto_type *const howto_table_vendors[] =
{
/* Register vendor howto tables here. The order must match the order of
strings in the vendor string table. */
+ howto_table_nds,
NULL
};
@@ -1020,6 +1175,7 @@ static const size_t howto_table_vendor_sizes[] =
{
/* Register vendor howto table sizes here. The order must match the order of
strings in the vendor string table. */
+ ARRAY_SIZE (howto_table_nds),
0
};
@@ -1086,10 +1242,24 @@ static const struct elf_reloc_map riscv_reloc_map[] =
{ BFD_RELOC_RISCV_VENDOR, R_RISCV_VENDOR },
};
+static const struct elf_reloc_map riscv_nds_reloc_map[] =
+{
+ { BFD_RELOC_RISCV_NDS_BRANCH_10, R_RISCV_NDS_BRANCH_10 },
+ { BFD_RELOC_RISCV_NDS_GPREL_18S0_I, R_RISCV_NDS_GPREL_18S0_I },
+ { BFD_RELOC_RISCV_NDS_GPREL_17S1_I, R_RISCV_NDS_GPREL_17S1_I },
+ { BFD_RELOC_RISCV_NDS_GPREL_17S2_I, R_RISCV_NDS_GPREL_17S2_I },
+ { BFD_RELOC_RISCV_NDS_GPREL_17S3_I, R_RISCV_NDS_GPREL_17S3_I },
+ { BFD_RELOC_RISCV_NDS_GPREL_18S0_S, R_RISCV_NDS_GPREL_18S0_S },
+ { BFD_RELOC_RISCV_NDS_GPREL_17S1_S, R_RISCV_NDS_GPREL_17S1_S },
+ { BFD_RELOC_RISCV_NDS_GPREL_17S2_S, R_RISCV_NDS_GPREL_17S2_S },
+ { BFD_RELOC_RISCV_NDS_GPREL_17S3_S, R_RISCV_NDS_GPREL_17S3_S },
+};
+
static const struct elf_reloc_map *const riscv_vendor_reloc_maps[] =
{
/* Register vendor relocation maps here. The order must match the order of
strings in the vendor string table. */
+ riscv_nds_reloc_map,
NULL
};
@@ -1097,13 +1267,20 @@ static const size_t riscv_vendor_reloc_map_sizes[] =
{
/* Register vendor relocation map sizes here. The order must match the order
of strings in the vendor string table. */
+ ARRAY_SIZE (riscv_nds_reloc_map),
0
};
+static const char *const riscv_nds_ext_with_reloc_table[] =
+{
+ "xandesperf"
+};
+
static const char *const *const riscv_vendor_ext_with_reloc_tables[] =
{
/* Register vendor extension-with-relocation tables here. The order must
match the order of strings in the vendor string table. */
+ riscv_nds_ext_with_reloc_table,
NULL
};
@@ -1111,6 +1288,7 @@ static const size_t riscv_vendor_ext_with_reloc_table_sizes[] =
{
/* Register vendor extension-with-relocation table sizes here. The order must
match the order of strings in the vendor string table. */
+ ARRAY_SIZE (riscv_nds_ext_with_reloc_table),
0
};
@@ -1783,6 +1961,7 @@ static const struct riscv_supported_ext riscv_supported_std_zxm_ext[] =
static const struct riscv_supported_ext riscv_supported_vendor_x_ext[] =
{
+ {"xandesperf", ISA_SPEC_CLASS_DRAFT, 5, 0, 0 },
{"xcvalu", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"xcvbi", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"xcvbitmanip", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
@@ -3190,6 +3369,8 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps,
return riscv_subset_supports (rps, "svinval");
case INSN_CLASS_H:
return riscv_subset_supports (rps, "h");
+ case INSN_CLASS_XANDESPERF:
+ return riscv_subset_supports (rps, "xandesperf");
case INSN_CLASS_XCVALU:
return riscv_subset_supports (rps, "xcvalu");
case INSN_CLASS_XCVBI:
@@ -3492,6 +3673,8 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
return "svinval";
case INSN_CLASS_H:
return _("h");
+ case INSN_CLASS_XANDESPERF:
+ return "xandesperf";
case INSN_CLASS_XCVALU:
return "xcvalu";
case INSN_CLASS_XCVBI:
diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
index 41631ad4465..f6080c99d5c 100644
--- a/bfd/elfxx-riscv.h
+++ b/bfd/elfxx-riscv.h
@@ -35,6 +35,14 @@ typedef enum
enum elf_riscv_vendor_id;
+enum relax_pass
+{
+ PASS_XANDESPERF_GP1, /* Stage 1 of XAndesPerf Relaxation */
+ PASS_XANDESPERF_GP2, /* Stage 2 of XAndesPerf Relaxation */
+ PASS_SHORTEN, /* Shortens code sequences. */
+ PASS_ALIGN /* Handles code alignment. */
+};
+
struct riscv_elf_params
{
/* Whether to relax code sequences to GP-relative addressing. */
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 9da65b4ec9d..b1ed38e738d 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2465,6 +2465,15 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
"BFD_RELOC_RISCV_SET_ULEB128",
"BFD_RELOC_RISCV_SUB_ULEB128",
"BFD_RELOC_RISCV_VENDOR",
+ "BFD_RELOC_RISCV_NDS_BRANCH_10",
+ "BFD_RELOC_RISCV_NDS_GPREL_18S0_I",
+ "BFD_RELOC_RISCV_NDS_GPREL_17S1_I",
+ "BFD_RELOC_RISCV_NDS_GPREL_17S2_I",
+ "BFD_RELOC_RISCV_NDS_GPREL_17S3_I",
+ "BFD_RELOC_RISCV_NDS_GPREL_18S0_S",
+ "BFD_RELOC_RISCV_NDS_GPREL_17S1_S",
+ "BFD_RELOC_RISCV_NDS_GPREL_17S2_S",
+ "BFD_RELOC_RISCV_NDS_GPREL_17S3_S",
"BFD_RELOC_RL78_NEG8",
"BFD_RELOC_RL78_NEG16",
"BFD_RELOC_RL78_NEG24",
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 0ef5e550403..3b9514b6644 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -5041,6 +5041,27 @@ ENUMX
ENUMDOC
RISC-V relocations.
+ENUM
+ BFD_RELOC_RISCV_NDS_BRANCH_10
+ENUMX
+ BFD_RELOC_RISCV_NDS_GPREL_18S0_I
+ENUMX
+ BFD_RELOC_RISCV_NDS_GPREL_17S1_I
+ENUMX
+ BFD_RELOC_RISCV_NDS_GPREL_17S2_I
+ENUMX
+ BFD_RELOC_RISCV_NDS_GPREL_17S3_I
+ENUMX
+ BFD_RELOC_RISCV_NDS_GPREL_18S0_S
+ENUMX
+ BFD_RELOC_RISCV_NDS_GPREL_17S1_S
+ENUMX
+ BFD_RELOC_RISCV_NDS_GPREL_17S2_S
+ENUMX
+ BFD_RELOC_RISCV_NDS_GPREL_17S3_S
+ENUMDOC
+ RISC-V vendor (Andes) relocations.
+
ENUM
BFD_RELOC_RL78_NEG8
ENUMX
diff --git a/gas/config/tc-riscv.c b/gas/config/tc-riscv.c
index 35deb8dcdae..d200e138b13 100644
--- a/gas/config/tc-riscv.c
+++ b/gas/config/tc-riscv.c
@@ -489,12 +489,14 @@ enum relax_branch_reloc
{
RELOC_INVALID = 0,
RELOC_BRANCH,
- RELOC_JAL
+ RELOC_JAL,
+ RELOC_NDS_BRANCH_10
};
-#define ENUM_RELAX_BRANCH_RELOC(reloc) \
- ((reloc) == BFD_RELOC_12_PCREL ? RELOC_BRANCH \
- : (reloc) == BFD_RELOC_RISCV_JMP ? RELOC_JAL \
+#define ENUM_RELAX_BRANCH_RELOC(reloc) \
+ ((reloc) == BFD_RELOC_12_PCREL ? RELOC_BRANCH \
+ : (reloc) == BFD_RELOC_RISCV_JMP ? RELOC_JAL \
+ : (reloc) == BFD_RELOC_RISCV_NDS_BRANCH_10 ? RELOC_NDS_BRANCH_10 \
: RELOC_INVALID)
/* Is the given value a sign-extended 32-bit value? */
@@ -864,6 +866,11 @@ relaxed_branch_length (fragS *fragp, asection *sec, int update)
length = 2;
break;
/* Add new branch/jump cases here. */
+ case RELOC_NDS_BRANCH_10:
+ if ((bfd_vma)(val + RISCV_NDS_BRANCH_10_REACH / 2)
+ < RISCV_NDS_BRANCH_10_REACH)
+ length = 4;
+ break;
default:
abort ();
}
@@ -1705,6 +1712,66 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
case 'X': /* Vendor-specific operands. */
switch (*++oparg)
{
+ case 'a': /* Vendor-specific (Andes) operands. */
+ switch (*++oparg)
+ {
+ case 'g':
+ used_bits |= ENCODE_NDS_BRANCH_IMM10 (-1U);
+ break;
+ case 'h':
+ used_bits |= ENCODE_NDS_BFO_IMM6H (-1U);
+ break;
+ case 'i':
+ used_bits |= ENCODE_NDS_BRANCH_IMM7 (-1U);
+ break;
+ case 'k':
+ used_bits |= ENCODE_NDS_BRANCH_IMM6 (-1U);
+ break;
+ case 'l':
+ used_bits |= ENCODE_NDS_BFO_IMM6L (-1U);
+ break;
+ case 'G':
+ switch (*++oparg)
+ {
+ case 'b':
+ used_bits |= ENCODE_NDS_LBGP_IMM (-1U);
+ break;
+ case 'h':
+ used_bits |= ENCODE_NDS_LHGP_IMM (-1U);
+ break;
+ case 'w':
+ used_bits |= ENCODE_NDS_LWGP_IMM (-1U);
+ break;
+ case 'd':
+ used_bits |= ENCODE_NDS_LDGP_IMM (-1U);
+ break;
+ default:
+ goto unknown_validate_operand;
+ }
+ break;
+ case 'H':
+ switch (*++oparg)
+ {
+ case 'b':
+ used_bits |= ENCODE_NDS_SBGP_IMM (-1U);
+ break;
+ case 'h':
+ used_bits |= ENCODE_NDS_SHGP_IMM (-1U);
+ break;
+ case 'w':
+ used_bits |= ENCODE_NDS_SWGP_IMM (-1U);
+ break;
+ case 'd':
+ used_bits |= ENCODE_NDS_SDGP_IMM (-1U);
+ break;
+ default:
+ goto unknown_validate_operand;
+ }
+ break;
+ default:
+ goto unknown_validate_operand;
+ }
+ break;
case 't': /* Vendor-specific (T-head) operands. */
{
size_t n;
@@ -2028,7 +2095,8 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr,
gas_assert (address_expr);
if (reloc_type == BFD_RELOC_12_PCREL
- || reloc_type == BFD_RELOC_RISCV_JMP)
+ || reloc_type == BFD_RELOC_RISCV_JMP
+ || reloc_type == BFD_RELOC_RISCV_NDS_BRANCH_10)
{
int best_case = insn_length (ip);
unsigned worst_case = relaxed_branch_length (NULL, NULL, 0);
@@ -4045,6 +4113,192 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
case 'X': /* Vendor-specific operands. */
switch (*++oparg)
{
+ case 'a': /* Vendor-specific (Andes) operands. */
+ switch (*++oparg)
+ {
+ case 'g':
+ my_getExpression (imm_expr, asarg, force_reloc);
+ *imm_reloc = BFD_RELOC_RISCV_NDS_BRANCH_10;
+ asarg = expr_parse_end;
+ continue;
+ case 'h':
+ my_getExpression (imm_expr, asarg, force_reloc);
+ if (imm_expr->X_op != O_constant
+ || imm_expr->X_add_number >= xlen
+ || imm_expr->X_add_number < 0)
+ break;
+ ip->insn_opcode
+ |= ENCODE_NDS_BFO_IMM6H (imm_expr->X_add_number);
+ imm_expr->X_op = O_absent;
+ asarg = expr_parse_end;
+ continue;
+ case 'i':
+ my_getExpression (imm_expr, asarg, force_reloc);
+ if (imm_expr->X_op != O_constant
+ || imm_expr->X_add_number
+ >= (signed)RISCV_NDS_IMM7_REACH
+ || imm_expr->X_add_number < 0)
+ break;
+ ip->insn_opcode
+ |= ENCODE_NDS_BRANCH_IMM7 (imm_expr->X_add_number);
+ imm_expr->X_op = O_absent;
+ asarg = expr_parse_end;
+ continue;
+ case 'k':
+ my_getExpression (imm_expr, asarg, force_reloc);
+ if (imm_expr->X_op != O_constant
+ || imm_expr->X_add_number >= xlen
+ || imm_expr->X_add_number < 0)
+ break;
+ ip->insn_opcode
+ |= ENCODE_NDS_BRANCH_IMM6 (imm_expr->X_add_number);
+ imm_expr->X_op = O_absent;
+ asarg = expr_parse_end;
+ continue;
+ case 'l':
+ my_getExpression (imm_expr, asarg, force_reloc);
+ if (imm_expr->X_op != O_constant
+ || imm_expr->X_add_number >= xlen
+ || imm_expr->X_add_number < 0)
+ break;
+ ip->insn_opcode
+ |= ENCODE_NDS_BFO_IMM6L (imm_expr->X_add_number);
+ imm_expr->X_op = O_absent;
+ asarg = expr_parse_end;
+ continue;
+ case 'G':
+ case 'H':
+ {
+ bool store = false;
+ if (*oparg == 'H')
+ store = true;
+ my_getExpression (imm_expr, asarg, force_reloc);
+ switch (*++oparg)
+ {
+ case 'b':
+ if (imm_expr->X_op == O_constant
+ && imm_expr->X_add_number
+ < (signed)RISCV_NDS_IMM18_REACH / 2
+ && imm_expr->X_add_number
+ >= -(signed)RISCV_NDS_IMM18_REACH / 2)
+ {
+ if (store)
+ ip->insn_opcode |= ENCODE_NDS_SBGP_IMM (
+ imm_expr->X_add_number);
+ else
+ ip->insn_opcode |= ENCODE_NDS_LBGP_IMM (
+ imm_expr->X_add_number);
+ asarg = expr_parse_end;
+ continue;
+ }
+ else if (imm_expr->X_op == O_symbol)
+ {
+ if (store)
+ *imm_reloc
+ = BFD_RELOC_RISCV_NDS_GPREL_18S0_S;
+ else
+ *imm_reloc
+ = BFD_RELOC_RISCV_NDS_GPREL_18S0_I;
+ asarg = expr_parse_end;
+ continue;
+ }
+ break;
+ case 'h':
+ if (imm_expr->X_op == O_constant
+ && imm_expr->X_add_number
+ < (signed)RISCV_NDS_IMM18_REACH / 2
+ && imm_expr->X_add_number
+ >= -(signed)RISCV_NDS_IMM18_REACH / 2
+ && (imm_expr->X_add_number & 0x1) == 0)
+ {
+ if (store)
+ ip->insn_opcode |= ENCODE_NDS_SHGP_IMM (
+ imm_expr->X_add_number);
+ else
+ ip->insn_opcode |= ENCODE_NDS_LHGP_IMM (
+ imm_expr->X_add_number);
+ asarg = expr_parse_end;
+ continue;
+ }
+ else if (imm_expr->X_op == O_symbol)
+ {
+ if (store)
+ *imm_reloc
+ = BFD_RELOC_RISCV_NDS_GPREL_17S1_S;
+ else
+ *imm_reloc
+ = BFD_RELOC_RISCV_NDS_GPREL_17S1_I;
+ asarg = expr_parse_end;
+ continue;
+ }
+ break;
+ case 'w':
+ if (imm_expr->X_op == O_constant
+ && imm_expr->X_add_number
+ < (signed)RISCV_NDS_IMM19_REACH / 2
+ && imm_expr->X_add_number
+ >= -(signed)RISCV_NDS_IMM19_REACH / 2
+ && (imm_expr->X_add_number & 0x3) == 0)
+ {
+ if (store)
+ ip->insn_opcode |= ENCODE_NDS_SWGP_IMM (
+ imm_expr->X_add_number);
+ else
+ ip->insn_opcode |= ENCODE_NDS_LWGP_IMM (
+ imm_expr->X_add_number);
+ asarg = expr_parse_end;
+ continue;
+ }
+ else if (imm_expr->X_op == O_symbol)
+ {
+ if (store)
+ *imm_reloc
+ = BFD_RELOC_RISCV_NDS_GPREL_17S2_S;
+ else
+ *imm_reloc
+ = BFD_RELOC_RISCV_NDS_GPREL_17S2_I;
+ asarg = expr_parse_end;
+ continue;
+ }
+ break;
+ case 'd':
+ if (imm_expr->X_op == O_constant
+ && imm_expr->X_add_number
+ < (signed)RISCV_NDS_IMM20_REACH / 2
+ && imm_expr->X_add_number
+ >= -(signed)RISCV_NDS_IMM20_REACH / 2
+ && (imm_expr->X_add_number & 0x7) == 0)
+ {
+ if (store)
+ ip->insn_opcode |= ENCODE_NDS_SDGP_IMM (
+ imm_expr->X_add_number);
+ else
+ ip->insn_opcode |= ENCODE_NDS_LDGP_IMM (
+ imm_expr->X_add_number);
+ asarg = expr_parse_end;
+ continue;
+ }
+ else if (imm_expr->X_op == O_symbol)
+ {
+ if (store)
+ *imm_reloc
+ = BFD_RELOC_RISCV_NDS_GPREL_17S3_S;
+ else
+ *imm_reloc
+ = BFD_RELOC_RISCV_NDS_GPREL_17S3_I;
+ asarg = expr_parse_end;
+ continue;
+ }
+ break;
+ default:
+ goto unknown_riscv_ip_operand;
+ }
+ break;
+ }
+ default:
+ goto unknown_riscv_ip_operand;
+ }
+ break;
case 't': /* Vendor-specific (T-head) operands. */
{
size_t n;
@@ -5084,6 +5338,34 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg)
case BFD_RELOC_RISCV_VENDOR:
break;
+ case BFD_RELOC_RISCV_NDS_BRANCH_10:
+ if (fixP->fx_addsy)
+ {
+ /* Fill in a tentative value to improve objdump readability. */
+ bfd_vma target = S_GET_VALUE (fixP->fx_addsy) + *valP;
+ bfd_vma delta = target - md_pcrel_from (fixP);
+ bfd_putl32 (bfd_getl32 (buf) | ENCODE_NDS_BRANCH_IMM10 (delta), buf);
+ if (!riscv_opts.relax && S_IS_LOCAL (fixP->fx_addsy))
+ {
+ if (!VALID_NDS_BRANCH_IMM10 (delta))
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("invalid NDS_BRANCH_10 offset (%+lld)"),
+ (long long)delta);
+ fixP->fx_done = 1;
+ }
+ }
+ break;
+
+ case BFD_RELOC_RISCV_NDS_GPREL_18S0_I:
+ case BFD_RELOC_RISCV_NDS_GPREL_17S1_I:
+ case BFD_RELOC_RISCV_NDS_GPREL_17S2_I:
+ case BFD_RELOC_RISCV_NDS_GPREL_17S3_I:
+ case BFD_RELOC_RISCV_NDS_GPREL_18S0_S:
+ case BFD_RELOC_RISCV_NDS_GPREL_17S1_S:
+ case BFD_RELOC_RISCV_NDS_GPREL_17S2_S:
+ case BFD_RELOC_RISCV_NDS_GPREL_17S3_S:
+ break;
+
default:
/* We ignore generic BFD relocations we don't know about. */
if (bfd_reloc_type_lookup (stdoutput, fixP->fx_r_type) != NULL)
@@ -5575,6 +5857,18 @@ md_convert_frag_branch (fragS *fragp)
insn ^= MATCH_BEQ ^ MATCH_BNE;
insn |= ENCODE_BTYPE_IMM (8);
}
+ else if (((insn & MASK_NDS_BEQC) == MATCH_NDS_BEQC)
+ || ((insn & MASK_NDS_BNEC) == MATCH_NDS_BNEC))
+ {
+ insn ^= MATCH_NDS_BEQC ^ MATCH_NDS_BNEC;
+ insn |= ENCODE_NDS_BRANCH_IMM10 (8);
+ }
+ else if (((insn & MASK_NDS_BBC) == MATCH_NDS_BBC)
+ || ((insn & MASK_NDS_BBS) == MATCH_NDS_BBS))
+ {
+ insn ^= MATCH_NDS_BBC ^ MATCH_NDS_BBS;
+ insn |= ENCODE_NDS_BRANCH_IMM10 (8);
+ }
/* Add new branch cases here. */
else
abort ();
@@ -5599,6 +5893,9 @@ md_convert_frag_branch (fragS *fragp)
reloc = BFD_RELOC_RISCV_JMP;
break;
/* Add new branch/jump cases here. */
+ case RELOC_NDS_BRANCH_10:
+ reloc = BFD_RELOC_RISCV_NDS_BRANCH_10;
+ break;
default:
abort ();
}
diff --git a/gas/doc/c-riscv.texi b/gas/doc/c-riscv.texi
index ea4be32a8ff..9e16a8e8848 100644
--- a/gas/doc/c-riscv.texi
+++ b/gas/doc/c-riscv.texi
@@ -767,6 +767,11 @@ extensions supported and provides the location of their
publicly-released documentation:
@table @r
+@item XAndesPerf
+The XAndesPerf extension provides performance enhancement instructions, including branch instructions, load effective address instructions, GP-relative instructions, and string processing instructions.
+
+It is documented in @url{https://github.com/andestech/andes-v5-isa/releases/download/ast-v5_4_0-release/AndeStar_V5_ISA_Spec_UM165-v1.5.08-20250317.pdf}.
+
@item XCvAlu
The XCvAlu extension provides instructions for general ALU operations.
diff --git a/gas/testsuite/gas/riscv/march-help.l b/gas/testsuite/gas/riscv/march-help.l
index 0ce2f896735..f62aac96242 100644
--- a/gas/testsuite/gas/riscv/march-help.l
+++ b/gas/testsuite/gas/riscv/march-help.l
@@ -154,6 +154,7 @@ All available -march extensions for RISC-V:
smmpm 1.0
sspm 1.0
supm 1.0
+ xandesperf 5.0
xcvalu 1.0
xcvbi 1.0
xcvbitmanip 1.0
diff --git a/gas/testsuite/gas/riscv/x-andes-perf.d b/gas/testsuite/gas/riscv/x-andes-perf.d
new file mode 100644
index 00000000000..2fe0c3ac905
--- /dev/null
+++ b/gas/testsuite/gas/riscv/x-andes-perf.d
@@ -0,0 +1,107 @@
+#as: -march=rv64i_xandesperf
+#source: x-andes-perf.s
+#objdump: -dr
+
+.*:[ ]+file format .*
+
+
+Disassembly of section .text:
+
+0+000 <target>:
+[ ]+[0-9a-f]+:[ ]+0005705b[ ]+nds\.bbc[ ]+a0,0,0 <target>
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_BRANCH_10[ ]target
+[ ]+[0-9a-f]+:[ ]+4005745b[ ]+nds\.bbs[ ]+a0,0,c.*
+[ ]+[0-9a-f]+:[ ]+ff9ff06f[ ]+j[ ]+0.*
+[ ]+[0-9a-f]+:[ ]+R_RISCV_JAL[ ]far
+[ ]+[0-9a-f]+:[ ]+4005745b[ ]+nds\.bbs[ ]+a0,0,14.*
+[ ]+[0-9a-f]+:[ ]+0000006f[ ]+j[ ]+10.*
+[ ]+[0-9a-f]+:[ ]+R_RISCV_JAL[ ]\*ABS\*\+0x1000
+[ ]+[0-9a-f]+:[ ]+fe05765b[ ]+nds\.bbs[ ]+a0,0,0 <target>
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_BRANCH_10[ ]target
+[ ]+[0-9a-f]+:[ ]+0005745b[ ]+nds\.bbc[ ]+a0,0,20.*
+[ ]+[0-9a-f]+:[ ]+fe5ff06f[ ]+j[ ]+0.*
+[ ]+[0-9a-f]+:[ ]+R_RISCV_JAL[ ]far
+[ ]+[0-9a-f]+:[ ]+0005745b[ ]+nds\.bbc[ ]+a0,0,28.*
+[ ]+[0-9a-f]+:[ ]+0000006f[ ]+j[ ]+24.*
+[ ]+[0-9a-f]+:[ ]+R_RISCV_JAL[ ]\*ABS\*\+0x1000
+[ ]+[0-9a-f]+:[ ]+bc055c5b[ ]+nds\.beqc[ ]+a0,0,0 <target>
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_BRANCH_10[ ]target
+[ ]+[0-9a-f]+:[ ]+0005645b[ ]+nds\.bnec[ ]+a0,0,34.*
+[ ]+[0-9a-f]+:[ ]+fd1ff06f[ ]+j[ ]+0.*
+[ ]+[0-9a-f]+:[ ]+R_RISCV_JAL[ ]far
+[ ]+[0-9a-f]+:[ ]+0005645b[ ]+nds\.bnec[ ]+a0,0,3c.*
+[ ]+[0-9a-f]+:[ ]+0000006f[ ]+j[ ]+38.*
+[ ]+[0-9a-f]+:[ ]+R_RISCV_JAL[ ]\*ABS\*\+0x1000
+[ ]+[0-9a-f]+:[ ]+bc05625b[ ]+nds\.bnec[ ]+a0,0,0 <target>
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_BRANCH_10[ ]target
+[ ]+[0-9a-f]+:[ ]+0005545b[ ]+nds\.beqc[ ]+a0,0,48.*
+[ ]+[0-9a-f]+:[ ]+fbdff06f[ ]+j[ ]+0.*
+[ ]+[0-9a-f]+:[ ]+R_RISCV_JAL[ ]far
+[ ]+[0-9a-f]+:[ ]+0005545b[ ]+nds\.beqc[ ]+a0,0,50.*
+[ ]+[0-9a-f]+:[ ]+0000006f[ ]+j[ ]+4c.*
+[ ]+[0-9a-f]+:[ ]+R_RISCV_JAL[ ]\*ABS\*\+0x1000
+[ ]+[0-9a-f]+:[ ]+0005b55b[ ]+nds\.bfos[ ]+a0,a1,0,0
+[ ]+[0-9a-f]+:[ ]+0005a55b[ ]+nds\.bfoz[ ]+a0,a1,0,0
+[ ]+[0-9a-f]+:[ ]+0ac5855b[ ]+nds\.lea\.h[ ]+a0,a1,a2
+[ ]+[0-9a-f]+:[ ]+0cc5855b[ ]+nds\.lea\.w[ ]+a0,a1,a2
+[ ]+[0-9a-f]+:[ ]+0ec5855b[ ]+nds\.lea\.d[ ]+a0,a1,a2
+[ ]+[0-9a-f]+:[ ]+10c5855b[ ]+nds\.lea\.b\.ze[ ]+a0,a1,a2
+[ ]+[0-9a-f]+:[ ]+12c5855b[ ]+nds\.lea\.h\.ze[ ]+a0,a1,a2
+[ ]+[0-9a-f]+:[ ]+14c5855b[ ]+nds\.lea\.w\.ze[ ]+a0,a1,a2
+[ ]+[0-9a-f]+:[ ]+16c5855b[ ]+nds\.lea\.d\.ze[ ]+a0,a1,a2
+[ ]+[0-9a-f]+:[ ]+0000150b[ ]+nds\.addigp[ ]+a0,0
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_GPREL_18S0_I[ ]target
+[ ]+[0-9a-f]+:[ ]+0002150b[ ]+nds\.addigp[ ]+a0,4096
+[ ]+[0-9a-f]+:[ ]+0000050b[ ]+nds\.lbgp[ ]+a0,0
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_GPREL_18S0_I[ ]target
+[ ]+[0-9a-f]+:[ ]+0002050b[ ]+nds\.lbgp[ ]+a0,4096
+[ ]+[0-9a-f]+:[ ]+0000250b[ ]+nds\.lbugp[ ]+a0,0
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_GPREL_18S0_I[ ]target
+[ ]+[0-9a-f]+:[ ]+0002250b[ ]+nds\.lbugp[ ]+a0,4096
+[ ]+[0-9a-f]+:[ ]+0000152b[ ]+nds\.lhgp[ ]+a0,0
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_GPREL_17S1_I[ ]target
+[ ]+[0-9a-f]+:[ ]+0002152b[ ]+nds\.lhgp[ ]+a0,4096
+[ ]+[0-9a-f]+:[ ]+0000552b[ ]+nds\.lhugp[ ]+a0,0
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_GPREL_17S1_I[ ]target
+[ ]+[0-9a-f]+:[ ]+0002552b[ ]+nds\.lhugp[ ]+a0,4096
+[ ]+[0-9a-f]+:[ ]+0000252b[ ]+nds\.lwgp[ ]+a0,0
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_GPREL_17S2_I[ ]target
+[ ]+[0-9a-f]+:[ ]+0002252b[ ]+nds\.lwgp[ ]+a0,4096
+[ ]+[0-9a-f]+:[ ]+0000652b[ ]+nds\.lwugp[ ]+a0,0
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_GPREL_17S2_I[ ]target
+[ ]+[0-9a-f]+:[ ]+0002652b[ ]+nds\.lwugp[ ]+a0,4096
+[ ]+[0-9a-f]+:[ ]+0000352b[ ]+nds\.ldgp[ ]+a0,0
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_GPREL_17S3_I[ ]target
+[ ]+[0-9a-f]+:[ ]+0002352b[ ]+nds\.ldgp[ ]+a0,4096
+[ ]+[0-9a-f]+:[ ]+00a0300b[ ]+nds\.sbgp[ ]+a0,0
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_GPREL_18S0_S[ ]target
+[ ]+[0-9a-f]+:[ ]+00a2300b[ ]+nds\.sbgp[ ]+a0,4096
+[ ]+[0-9a-f]+:[ ]+00a0002b[ ]+nds\.shgp[ ]+a0,0
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_GPREL_17S1_S[ ]target
+[ ]+[0-9a-f]+:[ ]+00a2002b[ ]+nds\.shgp[ ]+a0,4096
+[ ]+[0-9a-f]+:[ ]+00a0402b[ ]+nds\.swgp[ ]+a0,0
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_GPREL_17S2_S[ ]target
+[ ]+[0-9a-f]+:[ ]+00a2402b[ ]+nds\.swgp[ ]+a0,4096
+[ ]+[0-9a-f]+:[ ]+00a0702b[ ]+nds\.sdgp[ ]+a0,0
+[ ]+[0-9a-f]+:[ ]+R_RISCV_VENDOR[ ]ANDES
+[ ]+[0-9a-f]+:[ ]+R_RISCV_NDS_GPREL_17S3_S[ ]target
+[ ]+[0-9a-f]+:[ ]+00a2702b[ ]+nds\.sdgp[ ]+a0,4096
+[ ]+[0-9a-f]+:[ ]+20c5855b[ ]+nds\.ffb[ ]+a0,a1,a2
+[ ]+[0-9a-f]+:[ ]+22c5855b[ ]+nds\.ffzmism[ ]+a0,a1,a2
+[ ]+[0-9a-f]+:[ ]+24c5855b[ ]+nds\.ffmism[ ]+a0,a1,a2
+[ ]+[0-9a-f]+:[ ]+26c5855b[ ]+nds\.flmism[ ]+a0,a1,a2
diff --git a/gas/testsuite/gas/riscv/x-andes-perf.s b/gas/testsuite/gas/riscv/x-andes-perf.s
new file mode 100644
index 00000000000..9da87b41ce7
--- /dev/null
+++ b/gas/testsuite/gas/riscv/x-andes-perf.s
@@ -0,0 +1,50 @@
+target:
+ nds.bbc a0, 0, target
+ nds.bbc a0, 0, far
+ nds.bbc a0, 0, 0x1000
+ nds.bbs a0, 0, target
+ nds.bbs a0, 0, far
+ nds.bbs a0, 0, 0x1000
+ nds.beqc a0, 0, target
+ nds.beqc a0, 0, far
+ nds.beqc a0, 0, 0x1000
+ nds.bnec a0, 0, target
+ nds.bnec a0, 0, far
+ nds.bnec a0, 0, 0x1000
+ nds.bfos a0, a1, 0, 0
+ nds.bfoz a0, a1, 0, 0
+ nds.lea.h a0, a1, a2
+ nds.lea.w a0, a1, a2
+ nds.lea.d a0, a1, a2
+ nds.lea.b.ze a0, a1, a2
+ nds.lea.h.ze a0, a1, a2
+ nds.lea.w.ze a0, a1, a2
+ nds.lea.d.ze a0, a1, a2
+ nds.addigp a0, target
+ nds.addigp a0, 0x1000
+ nds.lbgp a0, target
+ nds.lbgp a0, 0x1000
+ nds.lbugp a0, target
+ nds.lbugp a0, 0x1000
+ nds.lhgp a0, target
+ nds.lhgp a0, 0x1000
+ nds.lhugp a0, target
+ nds.lhugp a0, 0x1000
+ nds.lwgp a0, target
+ nds.lwgp a0, 0x1000
+ nds.lwugp a0, target
+ nds.lwugp a0, 0x1000
+ nds.ldgp a0, target
+ nds.ldgp a0, 0x1000
+ nds.sbgp a0, target
+ nds.sbgp a0, 0x1000
+ nds.shgp a0, target
+ nds.shgp a0, 0x1000
+ nds.swgp a0, target
+ nds.swgp a0, 0x1000
+ nds.sdgp a0, target
+ nds.sdgp a0, 0x1000
+ nds.ffb a0, a1, a2
+ nds.ffzmism a0, a1, a2
+ nds.ffmism a0, a1, a2
+ nds.flmism a0, a1, a2
diff --git a/include/elf/riscv.h b/include/elf/riscv.h
index 8ce9fc98c43..7af96da42c0 100644
--- a/include/elf/riscv.h
+++ b/include/elf/riscv.h
@@ -99,6 +99,19 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
RELOC_NUMBER (R_RISCV_VENDOR, 191)
END_RELOC_NUMBERS ()
+/* Vendor (Andes) relocation types. */
+START_RELOC_NUMBERS (elf_riscv_nds_reloc_type)
+ RELOC_NUMBER (R_RISCV_NDS_BRANCH_10, 241)
+ RELOC_NUMBER (R_RISCV_NDS_GPREL_18S0_I, 246)
+ RELOC_NUMBER (R_RISCV_NDS_GPREL_17S1_I, 247)
+ RELOC_NUMBER (R_RISCV_NDS_GPREL_17S2_I, 248)
+ RELOC_NUMBER (R_RISCV_NDS_GPREL_17S3_I, 249)
+ RELOC_NUMBER (R_RISCV_NDS_GPREL_18S0_S, 250)
+ RELOC_NUMBER (R_RISCV_NDS_GPREL_17S1_S, 251)
+ RELOC_NUMBER (R_RISCV_NDS_GPREL_17S2_S, 252)
+ RELOC_NUMBER (R_RISCV_NDS_GPREL_17S3_S, 253)
+END_RELOC_NUMBERS ()
+
/* Internal relocations used exclusively by the relaxation pass. */
#define R_RISCV_DELETE (R_RISCV_internal_first)
#define R_RISCV_RVC_LUI (R_RISCV_internal_first + 1)
@@ -112,13 +125,17 @@ enum elf_riscv_vendor_id
RISCV_VENDOR_ID_NONE = -1,
/* Register vendor id here. The order must match the order of strings in the
vendor string table. */
+ RISCV_VENDOR_ID_NDS,
RISCV_VENDOR_ID_COUNT
};
+#define RISCV_VENDOR_STR_NDS "ANDES "
+
#define RISCV_VENDOR_STR_TABLE_INITIALIZER \
{ \
/* Register vendor strings (defined as macros) here. Remember to \
append a space to each string to avoid symbol conflicts. */ \
+ RISCV_VENDOR_STR_NDS, \
NULL \
}
@@ -132,6 +149,7 @@ static const char *(*elf_riscv_vendor_reloc_type_funcs[]) (unsigned long) =
/* Register vendor-defined functions (given a relocation number, return a
relocation name string) here. The order must match the order of strings
in the vendor string table. */
+ elf_riscv_nds_reloc_type,
NULL
};
diff --git a/include/opcode/riscv-opc.h b/include/opcode/riscv-opc.h
index 1c649628390..85f579a5213 100644
--- a/include/opcode/riscv-opc.h
+++ b/include/opcode/riscv-opc.h
@@ -2520,6 +2520,65 @@
#define MASK_VFWMACCBF16_VF 0xfc00707f
#define MATCH_VFWMACCBF16_VV 0xec001057
#define MASK_VFWMACCBF16_VV 0xfc00707f
+/* Vendor-specific (Andes) XAndesPerf instructions. */
+#define MATCH_NDS_BBC 0x705b
+#define MASK_NDS_BBC 0x4000707f
+#define MATCH_NDS_BBS 0x4000705b
+#define MASK_NDS_BBS 0x4000707f
+#define MATCH_NDS_BEQC 0x505b
+#define MASK_NDS_BEQC 0x707f
+#define MATCH_NDS_BNEC 0x605b
+#define MASK_NDS_BNEC 0x707f
+#define MATCH_NDS_BFOS 0x305b
+#define MASK_NDS_BFOS 0x707f
+#define MATCH_NDS_BFOZ 0x205b
+#define MASK_NDS_BFOZ 0x707f
+#define MATCH_NDS_LEA_H 0xa00005b
+#define MASK_NDS_LEA_H 0xfe00707f
+#define MATCH_NDS_LEA_W 0xc00005b
+#define MASK_NDS_LEA_W 0xfe00707f
+#define MATCH_NDS_LEA_D 0xe00005b
+#define MASK_NDS_LEA_D 0xfe00707f
+#define MATCH_NDS_LEA_B_ZE 0x1000005b
+#define MASK_NDS_LEA_B_ZE 0xfe00707f
+#define MATCH_NDS_LEA_H_ZE 0x1200005b
+#define MASK_NDS_LEA_H_ZE 0xfe00707f
+#define MATCH_NDS_LEA_W_ZE 0x1400005b
+#define MASK_NDS_LEA_W_ZE 0xfe00707f
+#define MATCH_NDS_LEA_D_ZE 0x1600005b
+#define MASK_NDS_LEA_D_ZE 0xfe00707f
+#define MATCH_NDS_ADDIGP 0x100b
+#define MASK_NDS_ADDIGP 0x307f
+#define MATCH_NDS_LBGP 0xb
+#define MASK_NDS_LBGP 0x307f
+#define MATCH_NDS_LBUGP 0x200b
+#define MASK_NDS_LBUGP 0x307f
+#define MATCH_NDS_LHGP 0x102b
+#define MASK_NDS_LHGP 0x707f
+#define MATCH_NDS_LHUGP 0x502b
+#define MASK_NDS_LHUGP 0x707f
+#define MATCH_NDS_LWGP 0x202b
+#define MASK_NDS_LWGP 0x707f
+#define MATCH_NDS_LWUGP 0x602b
+#define MASK_NDS_LWUGP 0x707f
+#define MATCH_NDS_LDGP 0x302b
+#define MASK_NDS_LDGP 0x707f
+#define MATCH_NDS_SBGP 0x300b
+#define MASK_NDS_SBGP 0x307f
+#define MATCH_NDS_SHGP 0x2b
+#define MASK_NDS_SHGP 0x707f
+#define MATCH_NDS_SWGP 0x402b
+#define MASK_NDS_SWGP 0x707f
+#define MATCH_NDS_SDGP 0x702b
+#define MASK_NDS_SDGP 0x707f
+#define MATCH_NDS_FFB 0x2000005b
+#define MASK_NDS_FFB 0xfe00707f
+#define MATCH_NDS_FFZMISM 0x2200005b
+#define MASK_NDS_FFZMISM 0xfe00707f
+#define MATCH_NDS_FFMISM 0x2400005b
+#define MASK_NDS_FFMISM 0xfe00707f
+#define MATCH_NDS_FLMISM 0x2600005b
+#define MASK_NDS_FLMISM 0xfe00707f
/* Vendor-specific (CORE-V) Xcvmac instructions. */
#define MATCH_CV_MAC 0x9000302b
#define MASK_CV_MAC 0xfe00707f
@@ -4836,6 +4895,36 @@ DECLARE_INSN(cm_jalt, MATCH_CM_JALT, MASK_CM_JALT)
DECLARE_INSN(sctrclr, MATCH_SCTRCLR, MASK_SCTRCLR)
/* Smrnmi instruction */
DECLARE_INSN(mnret, MATCH_MNRET, MASK_MNRET)
+/* Vendor-specific (Andes) XAndesPerf instructions. */
+DECLARE_INSN(nds_bbc, MATCH_NDS_BBC, MASK_NDS_BBC)
+DECLARE_INSN(nds_bbs, MATCH_NDS_BBS, MASK_NDS_BBS)
+DECLARE_INSN(nds_beqc, MATCH_NDS_BEQC, MASK_NDS_BEQC)
+DECLARE_INSN(nds_bnec, MATCH_NDS_BNEC, MASK_NDS_BNEC)
+DECLARE_INSN(nds_bfos, MATCH_NDS_BFOS, MASK_NDS_BFOS)
+DECLARE_INSN(nds_bfoz, MATCH_NDS_BFOZ, MASK_NDS_BFOZ)
+DECLARE_INSN(nds_lea_h, MATCH_NDS_LEA_H, MASK_NDS_LEA_H)
+DECLARE_INSN(nds_lea_w, MATCH_NDS_LEA_W, MASK_NDS_LEA_W)
+DECLARE_INSN(nds_lea_d, MATCH_NDS_LEA_D, MASK_NDS_LEA_D)
+DECLARE_INSN(nds_lea_b_ze, MATCH_NDS_LEA_B_ZE, MASK_NDS_LEA_B_ZE)
+DECLARE_INSN(nds_lea_h_ze, MATCH_NDS_LEA_H_ZE, MASK_NDS_LEA_H_ZE)
+DECLARE_INSN(nds_lea_w_ze, MATCH_NDS_LEA_W_ZE, MASK_NDS_LEA_W_ZE)
+DECLARE_INSN(nds_lea_d_ze, MATCH_NDS_LEA_D_ZE, MASK_NDS_LEA_D_ZE)
+DECLARE_INSN(nds_addigp, MATCH_NDS_ADDIGP, MASK_NDS_ADDIGP)
+DECLARE_INSN(nds_lbgp, MATCH_NDS_LBGP, MASK_NDS_LBGP)
+DECLARE_INSN(nds_lbugp, MATCH_NDS_LBUGP, MASK_NDS_LBUGP)
+DECLARE_INSN(nds_lhgp, MATCH_NDS_LHGP, MASK_NDS_LHGP)
+DECLARE_INSN(nds_lhugp, MATCH_NDS_LHUGP, MASK_NDS_LHUGP)
+DECLARE_INSN(nds_lwgp, MATCH_NDS_LWGP, MASK_NDS_LWGP)
+DECLARE_INSN(nds_lwugp, MATCH_NDS_LWUGP, MASK_NDS_LWUGP)
+DECLARE_INSN(nds_ldgp, MATCH_NDS_LDGP, MASK_NDS_LDGP)
+DECLARE_INSN(nds_sbgp, MATCH_NDS_SBGP, MASK_NDS_SBGP)
+DECLARE_INSN(nds_shgp, MATCH_NDS_SHGP, MASK_NDS_SHGP)
+DECLARE_INSN(nds_swgp, MATCH_NDS_SWGP, MASK_NDS_SWGP)
+DECLARE_INSN(nds_sdgp, MATCH_NDS_SDGP, MASK_NDS_SDGP)
+DECLARE_INSN(nds_ffb, MATCH_NDS_FFB, MASK_NDS_FFB)
+DECLARE_INSN(nds_ffzmism, MATCH_NDS_FFZMISM, MASK_NDS_FFZMISM)
+DECLARE_INSN(nds_ffmism, MATCH_NDS_FFMISM, MASK_NDS_FFMISM)
+DECLARE_INSN(nds_flmism, MATCH_NDS_FLMISM, MASK_NDS_FLMISM)
/* Vendor-specific (T-Head) XTheadBa instructions. */
DECLARE_INSN(th_addsl, MATCH_TH_ADDSL, MASK_TH_ADDSL)
/* Vendor-specific (T-Head) XTheadBb instructions. */
diff --git a/include/opcode/riscv.h b/include/opcode/riscv.h
index 858fcce6871..62b4643e3d7 100644
--- a/include/opcode/riscv.h
+++ b/include/opcode/riscv.h
@@ -117,6 +117,33 @@ static inline unsigned int riscv_insn_length (insn_t insn)
(RV_X(x, 2, 2) << 4)
#define EXTRACT_ZCMT_INDEX(x) \
(RV_X(x, 2, 8))
+/* Vendor-specific (Andes) extract macros. */
+#define EXTRACT_NDS_BRANCH_IMM6(x) \
+ (RV_X(x, 20, 5) | (RV_X(x, 7, 1) << 5))
+#define EXTRACT_NDS_BRANCH_IMM7(x) \
+ (RV_X(x, 20, 5) | (RV_X(x, 7, 1) << 5) | (RV_X(x, 30, 1) << 6))
+#define EXTRACT_NDS_BRANCH_IMM10(x) \
+ ((RV_X(x, 8, 4) << 1) | (RV_X(x, 25, 5) << 5) | (RV_IMM_SIGN(x) << 10))
+#define EXTRACT_NDS_BFO_IMM6H(x) \
+ (RV_X(x, 26, 6))
+#define EXTRACT_NDS_BFO_IMM6L(x) \
+ (RV_X(x, 20, 6))
+#define EXTRACT_NDS_LBGP_IMM(x) \
+ (RV_X(x, 14, 1) | (RV_X(x, 21, 10) << 1) | (RV_X(x, 20, 1) << 11) | (RV_X(x, 17, 3) << 12) | (RV_X(x, 15, 2) << 15) | (RV_IMM_SIGN(x) << 17))
+#define EXTRACT_NDS_LHGP_IMM(x) \
+ ((RV_X(x, 21, 10) << 1) | (RV_X(x, 20, 1) << 11) | (RV_X(x, 17, 3) << 12) | (RV_X(x, 15, 2) << 15) | (RV_IMM_SIGN(x) << 17))
+#define EXTRACT_NDS_LWGP_IMM(x) \
+ ((RV_X(x, 22, 9) << 2) | (RV_X(x, 20, 1) << 11) | (RV_X(x, 17, 3) << 12) | (RV_X(x, 15, 2) << 15) | (RV_X(x, 21, 1) << 17) | (RV_IMM_SIGN(x) << 18))
+#define EXTRACT_NDS_LDGP_IMM(x) \
+ ((RV_X(x, 23, 8) << 3) | (RV_X(x, 20, 1) << 11) | (RV_X(x, 17, 3) << 12) | (RV_X(x, 15, 2) << 15) | (RV_X(x, 21, 2) << 17) | (RV_IMM_SIGN(x) << 19))
+#define EXTRACT_NDS_SBGP_IMM(x) \
+ ((RV_X(x, 14, 1)) | (RV_X(x, 8, 4) << 1) | (RV_X(x, 25, 6) << 5) | (RV_X(x, 7, 1) << 11) | (RV_X(x, 17, 3) << 12) | (RV_X(x, 15, 2) << 15) | (RV_IMM_SIGN(x) << 17))
+#define EXTRACT_NDS_SHGP_IMM(x) \
+ ((RV_X(x, 8, 4) << 1) | (RV_X(x, 25, 6) << 5) | (RV_X(x, 7, 1) << 11) | (RV_X(x, 17, 3) << 12) | (RV_X(x, 15, 2) << 15) | (RV_IMM_SIGN(x) << 17))
+#define EXTRACT_NDS_SWGP_IMM(x) \
+ ((RV_X(x, 9, 3) << 2) | (RV_X(x, 25, 6) << 5) | (RV_X(x, 7, 1) << 11) | (RV_X(x, 17, 3) << 12) | (RV_X(x, 15, 2) << 15) | (RV_X(x, 8, 1) << 17) | (RV_IMM_SIGN(x) << 18))
+#define EXTRACT_NDS_SDGP_IMM(x) \
+ ((RV_X(x, 10, 2) << 3) | (RV_X(x, 25, 6) << 5) | (RV_X(x, 7, 1) << 11) | (RV_X(x, 17, 3) << 12) | (RV_X(x, 15, 2) << 15) | (RV_X(x, 8, 2) << 17) | (RV_IMM_SIGN(x) << 19))
/* Vendor-specific (CORE-V) extract macros. */
#define EXTRACT_CV_IS2_UIMM5(x) \
(RV_X(x, 20, 5))
@@ -196,6 +223,33 @@ static inline unsigned int riscv_insn_length (insn_t insn)
(RV_X(x, 4, 2) << 2)
#define ENCODE_ZCMT_INDEX(x) \
(RV_X(x, 0, 8) << 2)
+/* Vendor-specific (Andes) encode macros. */
+#define ENCODE_NDS_BRANCH_IMM6(x) \
+ ((RV_X(x, 0, 5) << 20) | (RV_X(x, 5, 1) << 7))
+#define ENCODE_NDS_BRANCH_IMM7(x) \
+ ((RV_X(x, 0, 5) << 20) | (RV_X(x, 5, 1) << 7) | (RV_X(x, 6, 1) << 30))
+#define ENCODE_NDS_BRANCH_IMM10(x) \
+ ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 5) << 25) | (RV_X(x, 10, 1) << 31))
+#define ENCODE_NDS_BFO_IMM6H(x) \
+ (RV_X(x, 0, 6) << 26)
+#define ENCODE_NDS_BFO_IMM6L(x) \
+ (RV_X(x, 0, 6) << 20)
+#define ENCODE_NDS_LBGP_IMM(x) \
+ ((RV_X(x, 0, 1) << 14) | (RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | (RV_X(x, 12, 3) << 17) | (RV_X(x, 15, 2) << 15) | (RV_X(x, 17, 1) << 31))
+#define ENCODE_NDS_LHGP_IMM(x) \
+ ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | (RV_X(x, 12, 3) << 17) | (RV_X(x, 15, 2) << 15) | (RV_X(x, 17, 1) << 31))
+#define ENCODE_NDS_LWGP_IMM(x) \
+ ((RV_X(x, 2, 9) << 22) | (RV_X(x, 11, 1) << 20) | (RV_X(x, 12, 3) << 17) | (RV_X(x, 15, 2) << 15) | (RV_X(x, 17, 1) << 21) | (RV_X(x, 18, 1) << 31))
+#define ENCODE_NDS_LDGP_IMM(x) \
+ ((RV_X(x, 3, 8) << 23) | (RV_X(x, 11, 1) << 20) | (RV_X(x, 12, 3) << 17) | (RV_X(x, 15, 2) << 15) | (RV_X(x, 17, 2) << 21) | (RV_X(x, 19, 1) << 31))
+#define ENCODE_NDS_SBGP_IMM(x) \
+ ((RV_X(x, 0, 1) << 14) | (RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 3) << 17) | (RV_X(x, 15, 2) << 15) | (RV_X(x, 17, 1) << 31))
+#define ENCODE_NDS_SHGP_IMM(x) \
+ ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 3) << 17) | (RV_X(x, 15, 2) << 15) | (RV_X(x, 17, 1) << 31))
+#define ENCODE_NDS_SWGP_IMM(x) \
+ ((RV_X(x, 2, 3) << 9) | (RV_X(x, 5, 6) << 25) | (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 3) << 17) | (RV_X(x, 15, 2) << 15) | (RV_X(x, 17, 1) << 8) | (RV_X(x, 18, 1) << 31))
+#define ENCODE_NDS_SDGP_IMM(x) \
+ ((RV_X(x, 3, 2) << 10) | (RV_X(x, 5, 6) << 25) | (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 3) << 17) | (RV_X(x, 15, 2) << 15) | (RV_X(x, 17, 2) << 8) | (RV_X(x, 19, 1) << 31))
/* Vendor-specific (CORE-V) encode macros. */
#define ENCODE_CV_IS2_UIMM5(x) \
(RV_X(x, 0, 5) << 20)
@@ -246,6 +300,16 @@ static inline unsigned int riscv_insn_length (insn_t insn)
#define VALID_ZCB_BYTE_UIMM(x) (EXTRACT_ZCB_BYTE_UIMM(ENCODE_ZCB_BYTE_UIMM(x)) == (x))
#define VALID_ZCB_HALFWORD_UIMM(x) (EXTRACT_ZCB_HALFWORD_UIMM(ENCODE_ZCB_HALFWORD_UIMM(x)) == (x))
#define VALID_ZCMP_SPIMM(x) (EXTRACT_ZCMP_SPIMM(ENCODE_ZCMP_SPIMM(x)) == (x))
+/* Vendor-specific (Andes) valid macros. */
+#define VALID_NDS_BRANCH_IMM10(x) (EXTRACT_NDS_BRANCH_IMM10(ENCODE_NDS_BRANCH_IMM10(x)) == (x))
+#define VALID_NDS_LBGP_IMM(x) (EXTRACT_NDS_LBGP_IMM(ENCODE_NDS_LBGP_IMM(x)) == (x))
+#define VALID_NDS_LHGP_IMM(x) (EXTRACT_NDS_LHGP_IMM(ENCODE_NDS_LHGP_IMM(x)) == (x))
+#define VALID_NDS_LWGP_IMM(x) (EXTRACT_NDS_LWGP_IMM(ENCODE_NDS_LWGP_IMM(x)) == (x))
+#define VALID_NDS_LDGP_IMM(x) (EXTRACT_NDS_LDGP_IMM(ENCODE_NDS_LDGP_IMM(x)) == (x))
+#define VALID_NDS_SBGP_IMM(x) (EXTRACT_NDS_SBGP_IMM(ENCODE_NDS_SBGP_IMM(x)) == (x))
+#define VALID_NDS_SHGP_IMM(x) (EXTRACT_NDS_SHGP_IMM(ENCODE_NDS_SHGP_IMM(x)) == (x))
+#define VALID_NDS_SWGP_IMM(x) (EXTRACT_NDS_SWGP_IMM(ENCODE_NDS_SWGP_IMM(x)) == (x))
+#define VALID_NDS_SDGP_IMM(x) (EXTRACT_NDS_SDGP_IMM(ENCODE_NDS_SDGP_IMM(x)) == (x))
#define RISCV_RTYPE(insn, rd, rs1, rs2) \
((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2))
@@ -284,6 +348,19 @@ static inline unsigned int riscv_insn_length (insn_t insn)
#define RISCV_BRANCH_ALIGN (1 << RISCV_BRANCH_ALIGN_BITS)
#define RISCV_BRANCH_REACH (RISCV_IMM_REACH * RISCV_BRANCH_ALIGN)
+/* Vendor-specific (Andes) immediate fields. */
+#define RISCV_NDS_IMM7_BITS 7
+#define RISCV_NDS_IMM7_REACH (1LL << RISCV_NDS_IMM7_BITS)
+#define RISCV_NDS_IMM10_BITS 10
+#define RISCV_NDS_IMM10_REACH (1LL << RISCV_NDS_IMM10_BITS)
+#define RISCV_NDS_BRANCH_10_REACH (RISCV_NDS_IMM10_REACH * RISCV_BRANCH_ALIGN)
+#define RISCV_NDS_IMM18_BITS 18
+#define RISCV_NDS_IMM18_REACH (1LL << RISCV_NDS_IMM18_BITS)
+#define RISCV_NDS_IMM19_BITS 19
+#define RISCV_NDS_IMM19_REACH (1LL << RISCV_NDS_IMM19_BITS)
+#define RISCV_NDS_IMM20_BITS 20
+#define RISCV_NDS_IMM20_REACH (1LL << RISCV_NDS_IMM20_BITS)
+
/* RV fields. */
#define OP_MASK_OP 0x7f
@@ -574,6 +651,7 @@ enum riscv_insn_class
INSN_CLASS_ZACAS,
INSN_CLASS_ZABHA_AND_ZACAS,
INSN_CLASS_H,
+ INSN_CLASS_XANDESPERF,
INSN_CLASS_XCVALU,
INSN_CLASS_XCVBI,
INSN_CLASS_XCVBITMANIP,
diff --git a/ld/emultempl/riscvelf.em b/ld/emultempl/riscvelf.em
index 78e1fcde68e..3e7884e9e21 100644
--- a/ld/emultempl/riscvelf.em
+++ b/ld/emultempl/riscvelf.em
@@ -81,7 +81,7 @@ riscv_elf_before_allocation (void)
ENABLE_RELAXATION;
}
- link_info.relax_pass = 2;
+ link_info.relax_pass = 4;
}
static void
diff --git a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
index b0d510ac8da..b7c6926848d 100644
--- a/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
+++ b/ld/testsuite/ld-riscv-elf/ld-riscv-elf.exp
@@ -179,6 +179,9 @@ if [istarget "riscv*-*-*"] {
"-march=rv64i -mabi=lp64" {weakref64.s} \
{{objdump -d weakref64.d}} "weakref64"]]
+ run_dump_test "x-andes-perf-reloc"
+ run_dump_test "x-andes-perf-relax"
+
# The following tests require shared library support.
if ![check_shared_lib_support] {
return
diff --git a/ld/testsuite/ld-riscv-elf/x-andes-perf-relax.d b/ld/testsuite/ld-riscv-elf/x-andes-perf-relax.d
new file mode 100644
index 00000000000..0dc3bba963a
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/x-andes-perf-relax.d
@@ -0,0 +1,14 @@
+#source: x-andes-perf-relax.s
+#as: -march=rv64i_xandesperf
+#ld: -m[riscv_choose_lp64_emul] -Tx-andes-perf-relax.ld
+#objdump: -d
+
+[^:]*: *file format elf64-.*riscv
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+nds.lbgp[ ]+.*[ ]+<foo>
+.*:[ ]+[0-9a-f]+[ ]+nds.lhgp[ ]+.*[ ]+<foo>
+.*:[ ]+[0-9a-f]+[ ]+nds.swgp[ ]+.*[ ]+<foo>
+.*:[ ]+[0-9a-f]+[ ]+nds.sdgp[ ]+.*[ ]+<foo>
diff --git a/ld/testsuite/ld-riscv-elf/x-andes-perf-relax.ld b/ld/testsuite/ld-riscv-elf/x-andes-perf-relax.ld
new file mode 100644
index 00000000000..bf94120b00c
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/x-andes-perf-relax.ld
@@ -0,0 +1,11 @@
+ENTRY(_start)
+SECTIONS
+{
+ .text 0x10000 : {
+ *(.text)
+ }
+ .data : {
+ __global_pointer$ = ALIGN(8);
+ *(.data)
+ }
+}
diff --git a/ld/testsuite/ld-riscv-elf/x-andes-perf-relax.s b/ld/testsuite/ld-riscv-elf/x-andes-perf-relax.s
new file mode 100644
index 00000000000..b6272d88306
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/x-andes-perf-relax.s
@@ -0,0 +1,23 @@
+ .text
+ .globl _start
+ .type _start,@function
+_start:
+ lui a0, %hi(foo)
+ lb a0, %lo(foo)(a0)
+
+.L1:
+ auipc a0, %pcrel_hi(foo)
+ lh a0, %pcrel_lo(.L1)(a0)
+
+ lui a0, %hi(foo)
+ sw a0, %lo(foo)(a0)
+
+.L2:
+ auipc a0, %pcrel_hi(foo)
+ sd a0, %pcrel_lo(.L2)(a0)
+
+ .data
+ .align 3
+ .zero 0x2000
+foo:
+ .dword 0x0
diff --git a/ld/testsuite/ld-riscv-elf/x-andes-perf-reloc.d b/ld/testsuite/ld-riscv-elf/x-andes-perf-reloc.d
new file mode 100644
index 00000000000..226381e67d3
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/x-andes-perf-reloc.d
@@ -0,0 +1,26 @@
+#source: x-andes-perf-reloc.s
+#as: -march=rv64i_xandesperf
+#ld: -m[riscv_choose_lp64_emul]
+#objdump: -d
+
+[^:]*: *file format elf64-.*riscv
+
+Disassembly of section \.text:
+
+[0-9a-f]+ <_start>:
+.*:[ ]+[0-9a-f]+[ ]+nds.bbc[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.bbs[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.beqc[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.bnec[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.addigp[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.lbgp[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.lbugp[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.lhgp[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.lhugp[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.lwgp[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.lwugp[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.ldgp[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.sbgp[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.shgp[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.swgp[ ]+.*[ ]+<_start>
+.*:[ ]+[0-9a-f]+[ ]+nds.sdgp[ ]+.*[ ]+<_start>
diff --git a/ld/testsuite/ld-riscv-elf/x-andes-perf-reloc.s b/ld/testsuite/ld-riscv-elf/x-andes-perf-reloc.s
new file mode 100644
index 00000000000..7172ee5a186
--- /dev/null
+++ b/ld/testsuite/ld-riscv-elf/x-andes-perf-reloc.s
@@ -0,0 +1,20 @@
+ .text
+ .globl _start
+ .type _start,@function
+_start:
+ nds.bbc a0, 0, _start
+ nds.bbs a0, 0, _start
+ nds.beqc a0, 0, _start
+ nds.bnec a0, 0, _start
+ nds.addigp a0, _start
+ nds.lbgp a0, _start
+ nds.lbugp a0, _start
+ nds.lhgp a0, _start
+ nds.lhugp a0, _start
+ nds.lwgp a0, _start
+ nds.lwugp a0, _start
+ nds.ldgp a0, _start
+ nds.sbgp a0, _start
+ nds.shgp a0, _start
+ nds.swgp a0, _start
+ nds.sdgp a0, _start
diff --git a/opcodes/riscv-dis.c b/opcodes/riscv-dis.c
index fa2d44af28f..45a686ec998 100644
--- a/opcodes/riscv-dis.c
+++ b/opcodes/riscv-dis.c
@@ -760,6 +760,95 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
case 'X': /* Vendor-specific operands. */
switch (*++oparg)
{
+ case 'a': /* Vendor-specific (Andes) operands. */
+ switch (*++oparg)
+ {
+ case 'g':
+ info->target = EXTRACT_NDS_BRANCH_IMM10 (l) + pc;
+ (*info->print_address_func) (info->target, info);
+ break;
+ case 'h':
+ print (info->stream, dis_style_immediate, "%d",
+ (int)EXTRACT_NDS_BFO_IMM6H (l));
+ break;
+ case 'i':
+ print (info->stream, dis_style_immediate, "%d",
+ (int)EXTRACT_NDS_BRANCH_IMM7 (l));
+ break;
+ case 'k':
+ print (info->stream, dis_style_immediate, "%d",
+ (int)EXTRACT_NDS_BRANCH_IMM6 (l));
+ break;
+ case 'l':
+ print (info->stream, dis_style_immediate, "%d",
+ (int)EXTRACT_NDS_BFO_IMM6L (l));
+ break;
+ case 'G':
+ switch (*++oparg)
+ {
+ case 'b':
+ maybe_print_address (pd, X_GP, EXTRACT_NDS_LBGP_IMM (l),
+ 0);
+ print (info->stream, dis_style_immediate, "%d",
+ (int)EXTRACT_NDS_LBGP_IMM (l));
+ break;
+ case 'h':
+ maybe_print_address (pd, X_GP, EXTRACT_NDS_LHGP_IMM (l),
+ 0);
+ print (info->stream, dis_style_immediate, "%d",
+ (int)EXTRACT_NDS_LHGP_IMM (l));
+ break;
+ case 'w':
+ maybe_print_address (pd, X_GP, EXTRACT_NDS_LWGP_IMM (l),
+ 0);
+ print (info->stream, dis_style_immediate, "%d",
+ (int)EXTRACT_NDS_LWGP_IMM (l));
+ break;
+ case 'd':
+ maybe_print_address (pd, X_GP, EXTRACT_NDS_LDGP_IMM (l),
+ 0);
+ print (info->stream, dis_style_immediate, "%d",
+ (int)EXTRACT_NDS_LDGP_IMM (l));
+ break;
+ default:
+ goto undefined_modifier;
+ }
+ break;
+ case 'H':
+ switch (*++oparg)
+ {
+ case 'b':
+ maybe_print_address (pd, X_GP, EXTRACT_NDS_SBGP_IMM (l),
+ 0);
+ print (info->stream, dis_style_immediate, "%d",
+ (int)EXTRACT_NDS_SBGP_IMM (l));
+ break;
+ case 'h':
+ maybe_print_address (pd, X_GP, EXTRACT_NDS_SHGP_IMM (l),
+ 0);
+ print (info->stream, dis_style_immediate, "%d",
+ (int)EXTRACT_NDS_SHGP_IMM (l));
+ break;
+ case 'w':
+ maybe_print_address (pd, X_GP, EXTRACT_NDS_SWGP_IMM (l),
+ 0);
+ print (info->stream, dis_style_immediate, "%d",
+ (int)EXTRACT_NDS_SWGP_IMM (l));
+ break;
+ case 'd':
+ maybe_print_address (pd, X_GP, EXTRACT_NDS_SDGP_IMM (l),
+ 0);
+ print (info->stream, dis_style_immediate, "%d",
+ (int)EXTRACT_NDS_SDGP_IMM (l));
+ break;
+ default:
+ goto undefined_modifier;
+ }
+ break;
+ default:
+ goto undefined_modifier;
+ }
+ break;
case 't': /* Vendor-specific (T-head) operands. */
{
size_t n;
diff --git a/opcodes/riscv-opc.c b/opcodes/riscv-opc.c
index e6fe5e9afba..dd713f6fa1b 100644
--- a/opcodes/riscv-opc.c
+++ b/opcodes/riscv-opc.c
@@ -2378,6 +2378,37 @@ const struct riscv_opcode riscv_opcodes[] =
{"hsv.w", 0, INSN_CLASS_H, "t,0(s)", MATCH_HSV_W, MASK_HSV_W, match_opcode, INSN_DREF|INSN_4_BYTE },
{"hsv.d", 64, INSN_CLASS_H, "t,0(s)", MATCH_HSV_D, MASK_HSV_D, match_opcode, INSN_DREF|INSN_8_BYTE },
+/* Vendor-specific (Andes) XAndesPerf instructions. */
+{"nds.bbc", 0, INSN_CLASS_XANDESPERF, "s,Xak,Xag", MATCH_NDS_BBC, MASK_NDS_BBC, match_opcode, INSN_CONDBRANCH},
+{"nds.bbs", 0, INSN_CLASS_XANDESPERF, "s,Xak,Xag", MATCH_NDS_BBS, MASK_NDS_BBS, match_opcode, INSN_CONDBRANCH},
+{"nds.beqc", 0, INSN_CLASS_XANDESPERF, "s,Xai,Xag", MATCH_NDS_BEQC, MASK_NDS_BEQC, match_opcode, INSN_CONDBRANCH},
+{"nds.bnec", 0, INSN_CLASS_XANDESPERF, "s,Xai,Xag", MATCH_NDS_BNEC, MASK_NDS_BNEC, match_opcode, INSN_CONDBRANCH},
+{"nds.bfos", 0, INSN_CLASS_XANDESPERF, "d,s,Xah,Xal", MATCH_NDS_BFOS, MASK_NDS_BFOS, match_opcode, 0},
+{"nds.bfoz", 0, INSN_CLASS_XANDESPERF, "d,s,Xah,Xal", MATCH_NDS_BFOZ, MASK_NDS_BFOZ, match_opcode, 0},
+{"nds.lea.h", 0, INSN_CLASS_XANDESPERF, "d,s,t", MATCH_NDS_LEA_H, MASK_NDS_LEA_H, match_opcode, 0},
+{"nds.lea.w", 0, INSN_CLASS_XANDESPERF, "d,s,t", MATCH_NDS_LEA_W, MASK_NDS_LEA_W, match_opcode, 0},
+{"nds.lea.d", 0, INSN_CLASS_XANDESPERF, "d,s,t", MATCH_NDS_LEA_D, MASK_NDS_LEA_D, match_opcode, 0},
+{"nds.lea.b.ze", 0, INSN_CLASS_XANDESPERF, "d,s,t", MATCH_NDS_LEA_B_ZE, MASK_NDS_LEA_B_ZE, match_opcode, 0},
+{"nds.lea.h.ze", 0, INSN_CLASS_XANDESPERF, "d,s,t", MATCH_NDS_LEA_H_ZE, MASK_NDS_LEA_H_ZE, match_opcode, 0},
+{"nds.lea.w.ze", 0, INSN_CLASS_XANDESPERF, "d,s,t", MATCH_NDS_LEA_W_ZE, MASK_NDS_LEA_W_ZE, match_opcode, 0},
+{"nds.lea.d.ze", 0, INSN_CLASS_XANDESPERF, "d,s,t", MATCH_NDS_LEA_D_ZE, MASK_NDS_LEA_D_ZE, match_opcode, 0},
+{"nds.addigp", 0, INSN_CLASS_XANDESPERF, "d,XaGb", MATCH_NDS_ADDIGP, MASK_NDS_ADDIGP, match_opcode, 0},
+{"nds.lbgp", 0, INSN_CLASS_XANDESPERF, "d,XaGb", MATCH_NDS_LBGP, MASK_NDS_LBGP, match_opcode, INSN_DREF|INSN_1_BYTE},
+{"nds.lbugp", 0, INSN_CLASS_XANDESPERF, "d,XaGb", MATCH_NDS_LBUGP, MASK_NDS_LBUGP, match_opcode, INSN_DREF|INSN_1_BYTE},
+{"nds.lhgp", 0, INSN_CLASS_XANDESPERF, "d,XaGh", MATCH_NDS_LHGP, MASK_NDS_LHGP, match_opcode, INSN_DREF|INSN_2_BYTE},
+{"nds.lhugp", 0, INSN_CLASS_XANDESPERF, "d,XaGh", MATCH_NDS_LHUGP, MASK_NDS_LHUGP, match_opcode, INSN_DREF|INSN_2_BYTE},
+{"nds.lwgp", 0, INSN_CLASS_XANDESPERF, "d,XaGw", MATCH_NDS_LWGP, MASK_NDS_LWGP, match_opcode, INSN_DREF|INSN_4_BYTE},
+{"nds.lwugp", 64, INSN_CLASS_XANDESPERF, "d,XaGw", MATCH_NDS_LWUGP, MASK_NDS_LWUGP, match_opcode, INSN_DREF|INSN_4_BYTE},
+{"nds.ldgp", 64, INSN_CLASS_XANDESPERF, "d,XaGd", MATCH_NDS_LDGP, MASK_NDS_LDGP, match_opcode, INSN_DREF|INSN_8_BYTE},
+{"nds.sbgp", 0, INSN_CLASS_XANDESPERF, "t,XaHb", MATCH_NDS_SBGP, MASK_NDS_SBGP, match_opcode, INSN_DREF|INSN_1_BYTE},
+{"nds.shgp", 0, INSN_CLASS_XANDESPERF, "t,XaHh", MATCH_NDS_SHGP, MASK_NDS_SHGP, match_opcode, INSN_DREF|INSN_2_BYTE},
+{"nds.swgp", 0, INSN_CLASS_XANDESPERF, "t,XaHw", MATCH_NDS_SWGP, MASK_NDS_SWGP, match_opcode, INSN_DREF|INSN_4_BYTE},
+{"nds.sdgp", 64, INSN_CLASS_XANDESPERF, "t,XaHd", MATCH_NDS_SDGP, MASK_NDS_SDGP, match_opcode, INSN_DREF|INSN_8_BYTE},
+{"nds.ffb", 0, INSN_CLASS_XANDESPERF, "d,s,t", MATCH_NDS_FFB, MASK_NDS_FFB, match_opcode, 0},
+{"nds.ffzmism", 0, INSN_CLASS_XANDESPERF, "d,s,t", MATCH_NDS_FFZMISM, MASK_NDS_FFZMISM, match_opcode, 0},
+{"nds.ffmism", 0, INSN_CLASS_XANDESPERF, "d,s,t", MATCH_NDS_FFMISM, MASK_NDS_FFMISM, match_opcode, 0},
+{"nds.flmism", 0, INSN_CLASS_XANDESPERF, "d,s,t", MATCH_NDS_FLMISM, MASK_NDS_FLMISM, match_opcode, 0},
+
/* Vendor-specific (CORE-V) Xcvmac instructions. */
{"cv.mac", 0, INSN_CLASS_XCVMAC, "d,s,t", MATCH_CV_MAC, MASK_CV_MAC, match_opcode, 0},
{"cv.msu", 0, INSN_CLASS_XCVMAC, "d,s,t", MATCH_CV_MSU, MASK_CV_MSU, match_opcode, 0},
--
2.49.0
More information about the Binutils
mailing list