aboutsummaryrefslogtreecommitdiff
path: root/binutils
diff options
context:
space:
mode:
authorAndrew Waterman <waterman@cs.berkeley.edu>2015-03-30 18:14:33 -0700
committerAndrew Waterman <waterman@cs.berkeley.edu>2015-03-31 12:13:35 -0700
commit0a401fc3ed8e16e233196a22070f5faf9c178e7b (patch)
tree75f879adb1227aaab284522da6a09d32357cbb54 /binutils
parent6285c24a785d664beaf5b45ffb1121c70af7d0ee (diff)
downloadriscv-gnu-toolchain-0a401fc3ed8e16e233196a22070f5faf9c178e7b.zip
riscv-gnu-toolchain-0a401fc3ed8e16e233196a22070f5faf9c178e7b.tar.gz
riscv-gnu-toolchain-0a401fc3ed8e16e233196a22070f5faf9c178e7b.tar.bz2
binutils: produce RVC branches/jumps
Diffstat (limited to 'binutils')
-rw-r--r--binutils/bfd/elfnn-riscv.c18
-rw-r--r--binutils/bfd/elfxx-riscv.c35
-rw-r--r--binutils/gas/config/tc-riscv.c244
-rw-r--r--binutils/include/elf/riscv.h2
-rw-r--r--binutils/include/opcode/riscv.h22
-rw-r--r--binutils/opcodes/riscv-dis.c11
-rw-r--r--binutils/opcodes/riscv-opc.c16
7 files changed, 250 insertions, 98 deletions
diff --git a/binutils/bfd/elfnn-riscv.c b/binutils/bfd/elfnn-riscv.c
index 74f6e0b..53a9235 100644
--- a/binutils/bfd/elfnn-riscv.c
+++ b/binutils/bfd/elfnn-riscv.c
@@ -577,6 +577,8 @@ riscv_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_RISCV_CALL:
case R_RISCV_JAL:
case R_RISCV_BRANCH:
+ case R_RISCV_RVC_BRANCH:
+ case R_RISCV_RVC_JUMP:
case R_RISCV_PCREL_HI20:
/* In shared libs, these relocs are known to bind locally. */
if (info->shared)
@@ -816,6 +818,8 @@ riscv_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info,
case R_RISCV_BRANCH:
case R_RISCV_CALL:
case R_RISCV_JAL:
+ case R_RISCV_RVC_BRANCH:
+ case R_RISCV_RVC_JUMP:
if (info->shared)
break;
/* Fall through. */
@@ -1506,6 +1510,18 @@ perform_relocation (const reloc_howto_type *howto,
value = ENCODE_SBTYPE_IMM (value);
break;
+ case R_RISCV_RVC_BRANCH:
+ if (!VALID_RVC_B_IMM (value))
+ return bfd_reloc_overflow;
+ value = ENCODE_RVC_B_IMM (value);
+ break;
+
+ case R_RISCV_RVC_JUMP:
+ if (!VALID_RVC_J_IMM (value))
+ return bfd_reloc_overflow;
+ value = ENCODE_RVC_J_IMM (value);
+ break;
+
case R_RISCV_32:
case R_RISCV_64:
case R_RISCV_ADD8:
@@ -1776,6 +1792,7 @@ riscv_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
continue;
case R_RISCV_BRANCH:
+ case R_RISCV_RVC_BRANCH:
case R_RISCV_HI20:
/* These require no special handling beyond perform_relocation. */
break;
@@ -1884,6 +1901,7 @@ riscv_elf_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
case R_RISCV_CALL_PLT:
case R_RISCV_CALL:
case R_RISCV_JAL:
+ case R_RISCV_RVC_JUMP:
if (info->shared && h != NULL && h->plt.offset != MINUS_ONE)
{
/* Refer to the PLT entry. */
diff --git a/binutils/bfd/elfxx-riscv.c b/binutils/bfd/elfxx-riscv.c
index e30f3c1..32738a9 100644
--- a/binutils/bfd/elfxx-riscv.c
+++ b/binutils/bfd/elfxx-riscv.c
@@ -639,6 +639,39 @@ static reloc_howto_type howto_table[] =
0, /* src_mask */
0, /* dst_mask */
TRUE), /* pcrel_offset */
+
+ /* 8-bit PC-relative branch offset. */
+ HOWTO (R_RISCV_RVC_BRANCH, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_signed, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_RVC_BRANCH", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_RVC_B_IMM(-1U), /* dst_mask */
+ TRUE), /* pcrel_offset */
+
+ /* 11-bit PC-relative jump offset. */
+ HOWTO (R_RISCV_RVC_JUMP, /* type */
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ TRUE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ /* This needs complex overflow
+ detection, because the upper 36
+ bits must match the PC + 4. */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_RISCV_RVC_JUMP", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ ENCODE_RVC_J_IMM(-1U), /* dst_mask */
+ TRUE), /* pcrel_offset */
};
/* A mapping from BFD reloc types to RISC-V ELF reloc types. */
@@ -686,6 +719,8 @@ static const struct elf_reloc_map riscv_reloc_map[] =
{ BFD_RELOC_RISCV_TLS_GOT_HI20, R_RISCV_TLS_GOT_HI20 },
{ BFD_RELOC_RISCV_TLS_GD_HI20, R_RISCV_TLS_GD_HI20 },
{ BFD_RELOC_RISCV_ALIGN, R_RISCV_ALIGN },
+ { BFD_RELOC_RISCV_RVC_BRANCH, R_RISCV_RVC_BRANCH },
+ { BFD_RELOC_RISCV_RVC_JUMP, R_RISCV_RVC_JUMP },
};
/* Given a BFD reloc type, return a howto structure. */
diff --git a/binutils/gas/config/tc-riscv.c b/binutils/gas/config/tc-riscv.c
index 7f9b518..ddc6c73 100644
--- a/binutils/gas/config/tc-riscv.c
+++ b/binutils/gas/config/tc-riscv.c
@@ -162,14 +162,15 @@ riscv_set_arch (const char* arg)
if (*arg && *arg != 'I')
as_fatal("`I' must be the first ISA subset name specified (got %c)", *arg);
- for (p = arg; *p; p++)
+ for (p = arg; *p; )
{
if (*p == 'X')
{
- char *subset = xstrdup(p + 1), *q = subset;
+ char *subset = xstrdup(p), *q = subset;
- while (ISLOWER(*q))
+ do
q++;
+ while (ISLOWER(*q));
*q = 0;
riscv_add_subset (subset);
@@ -182,6 +183,7 @@ riscv_set_arch (const char* arg)
riscv_add_subset (subset);
if (*p == 'C')
rvc = 1;
+ p++;
}
else
as_fatal("unsupported ISA subset %c", *p);
@@ -229,14 +231,16 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP";
static char *insn_error;
-#define RELAX_BRANCH_ENCODE(uncond, toofar) \
+#define RELAX_BRANCH_ENCODE(uncond, rvc, length) \
((relax_substateT) \
(0xc0000000 \
- | ((toofar) ? 1 : 0) \
- | ((uncond) ? 2 : 0)))
+ | ((uncond) ? 1 : 0) \
+ | ((rvc) ? 2 : 0) \
+ | ((length) << 2)))
#define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000)
-#define RELAX_BRANCH_TOOFAR(i) (((i) & 1) != 0)
-#define RELAX_BRANCH_UNCOND(i) (((i) & 2) != 0)
+#define RELAX_BRANCH_LENGTH(i) (((i) >> 2) & 0xF)
+#define RELAX_BRANCH_RVC(i) (((i) & 2) != 0)
+#define RELAX_BRANCH_UNCOND(i) (((i) & 1) != 0)
/* Is the given value a sign-extended 32-bit value? */
#define IS_SEXT_32BIT_NUM(x) \
@@ -359,37 +363,41 @@ add_relaxed_insn (struct riscv_cl_insn *insn, int max_chars, int var,
subtype, symbol, offset, NULL);
}
-/* Compute the length of a branch sequence, and adjust the
- RELAX_BRANCH_TOOFAR bit accordingly. If FRAGP is NULL, the
- worst-case length is computed. */
+/* Compute the length of a branch sequence, and adjust the stored length
+ accordingly. If FRAGP is NULL, the worst-case length is returned. */
+
static int
relaxed_branch_length (fragS *fragp, asection *sec, int update)
{
- bfd_boolean toofar = TRUE;
+ int jump, rvc, length = 8;
- if (fragp)
- {
- bfd_boolean uncond = RELAX_BRANCH_UNCOND (fragp->fr_subtype);
+ if (!fragp)
+ return length;
- if (S_IS_DEFINED (fragp->fr_symbol)
- && sec == S_GET_SEGMENT (fragp->fr_symbol))
- {
- offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
- bfd_vma range;
- val -= fragp->fr_address + fragp->fr_fix;
+ jump = RELAX_BRANCH_UNCOND (fragp->fr_subtype);
+ rvc = RELAX_BRANCH_RVC (fragp->fr_subtype);
+ length = RELAX_BRANCH_LENGTH (fragp->fr_subtype);
- if (uncond)
- range = RISCV_JUMP_REACH;
- else
- range = RISCV_BRANCH_REACH;
- toofar = (bfd_vma)(val + range/2) >= range;
- }
+ /* Assume jumps are in range; the linker will catch any that aren't. */
+ length = jump ? 4 : 8;
- if (update && toofar != RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
- fragp->fr_subtype = RELAX_BRANCH_ENCODE (uncond, toofar);
+ if (S_IS_DEFINED (fragp->fr_symbol)
+ && sec == S_GET_SEGMENT (fragp->fr_symbol))
+ {
+ offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset;
+ bfd_vma rvc_range = jump ? RVC_JUMP_REACH : RVC_BRANCH_REACH;
+ val -= fragp->fr_address + fragp->fr_fix;
+
+ if (rvc && (bfd_vma)(val + rvc_range/2) < rvc_range)
+ length = 2;
+ else if ((bfd_vma)(val + RISCV_BRANCH_REACH/2) < RISCV_BRANCH_REACH)
+ length = 4;
}
- return toofar ? 8 : 4;
+ if (update)
+ fragp->fr_subtype = RELAX_BRANCH_ENCODE (jump, rvc, length);
+
+ return length;
}
struct regname {
@@ -545,12 +553,16 @@ validate_riscv_insn (const struct riscv_opcode *opc)
case 'S': USE_BITS (OP_MASK_CRS1, OP_SH_CRS1); break;
case 'c': break; /* RS1, constrained to equal sp */
case 'U': break; /* RS2, constrained to equal RD */
+ case '>': used_bits |= ENCODE_RVC_IMM(-1U); break;
case 'j': used_bits |= ENCODE_RVC_IMM(-1U); break;
case 'k': used_bits |= ENCODE_RVC_LW_IMM(-1U); break;
case 'l': used_bits |= ENCODE_RVC_LD_IMM(-1U); break;
case 'm': used_bits |= ENCODE_RVC_LWSP_IMM(-1U); break;
case 'n': used_bits |= ENCODE_RVC_LDSP_IMM(-1U); break;
case 'u': used_bits |= ENCODE_RVC_IMM(-1U); break;
+ case 'v': used_bits |= ENCODE_RVC_IMM(-1U); break;
+ case 'a': used_bits |= ENCODE_RVC_J_IMM(-1U); break;
+ case 'p': used_bits |= ENCODE_RVC_B_IMM(-1U); break;
default:
as_bad (_("internal: bad RISC-V opcode (unknown operand type `C%c'): %s %s"),
c, opc->name, opc->args);
@@ -709,10 +721,14 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr,
}
reloc_type = BFD_RELOC_UNUSED;
}
- else if (reloc_type == BFD_RELOC_12_PCREL)
+ else if (reloc_type == BFD_RELOC_12_PCREL
+ || reloc_type == BFD_RELOC_RISCV_JMP)
{
- add_relaxed_insn (ip, relaxed_branch_length (NULL, NULL, 0), 4,
- RELAX_BRANCH_ENCODE (0, 0),
+ int j = reloc_type == BFD_RELOC_RISCV_JMP;
+ int best_case = riscv_insn_length (ip->insn_opcode);
+ int worst_case = relaxed_branch_length (NULL, NULL, 0);
+ add_relaxed_insn (ip, worst_case, best_case,
+ RELAX_BRANCH_ENCODE (j, best_case == 2, worst_case),
address_expr->X_add_symbol,
address_expr->X_add_number);
return;
@@ -724,14 +740,10 @@ append_insn (struct riscv_cl_insn *ip, expressionS *address_expr,
howto = bfd_reloc_type_lookup (stdoutput, reloc_type);
if (howto == NULL)
as_bad (_("Unsupported RISC-V relocation number %d"), reloc_type);
-
+
ip->fixp = fix_new_exp (ip->frag, ip->where,
bfd_get_reloc_size (howto),
- address_expr,
- reloc_type == BFD_RELOC_12_PCREL ||
- reloc_type == BFD_RELOC_RISCV_CALL ||
- reloc_type == BFD_RELOC_RISCV_JMP,
- reloc_type);
+ address_expr, FALSE, reloc_type);
/* These relocations can have an addend that won't fit in
4 octets for 64bit assembly. */
@@ -1285,6 +1297,7 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
imm_expr->X_op = O_absent;
*imm_reloc = BFD_RELOC_UNUSED;
+ p = percent_op_itype;
for (args = insn->args;; ++args)
{
@@ -1444,70 +1457,78 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
|| regno != X_SP)
break;
continue;
- case 'j':
- p = percent_op_itype;
+ case '>':
if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
- || !VALID_RVC_IMM (imm_expr->X_add_number))
+ || !VALID_RVC_IMM (imm_expr->X_add_number - 32))
break;
+ ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number);
+rvc_imm_done:
s = expr_end;
imm_expr->X_op = O_absent;
- ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number);
continue;
+ case 'j':
+ if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
+ || imm_expr->X_op != O_constant
+ || !VALID_RVC_IMM (imm_expr->X_add_number))
+ break;
+ ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number);
+ goto rvc_imm_done;
case 'k':
- p = percent_op_itype;
if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
|| !VALID_RVC_LW_IMM (imm_expr->X_add_number))
break;
- s = expr_end;
- imm_expr->X_op = O_absent;
ip->insn_opcode |= ENCODE_RVC_LW_IMM (imm_expr->X_add_number);
- continue;
+ goto rvc_imm_done;
case 'l':
- p = percent_op_itype;
if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
|| !VALID_RVC_LD_IMM (imm_expr->X_add_number))
break;
- s = expr_end;
- imm_expr->X_op = O_absent;
ip->insn_opcode |= ENCODE_RVC_LD_IMM (imm_expr->X_add_number);
- continue;
+ goto rvc_imm_done;
case 'm':
- p = percent_op_itype;
if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
|| !VALID_RVC_LWSP_IMM (imm_expr->X_add_number))
break;
- s = expr_end;
- imm_expr->X_op = O_absent;
ip->insn_opcode |= ENCODE_RVC_LWSP_IMM (imm_expr->X_add_number);
- continue;
+ goto rvc_imm_done;
case 'n':
- p = percent_op_itype;
if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
|| imm_expr->X_op != O_constant
|| !VALID_RVC_LDSP_IMM (imm_expr->X_add_number))
break;
- s = expr_end;
- imm_expr->X_op = O_absent;
ip->insn_opcode |= ENCODE_RVC_LDSP_IMM (imm_expr->X_add_number);
- continue;
+ goto rvc_imm_done;
case 'u':
p = percent_op_utype;
- if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
- || imm_expr->X_op != O_constant
+ if (my_getSmallExpression (imm_expr, imm_reloc, s, p))
+ break;
+rvc_lui:
+ if (imm_expr->X_op != O_constant
|| imm_expr->X_add_number < 0
|| imm_expr->X_add_number >= RISCV_BIGIMM_REACH
|| (imm_expr->X_add_number >= RISCV_RVC_IMM_REACH/2
&& imm_expr->X_add_number <
RISCV_BIGIMM_REACH - RISCV_RVC_IMM_REACH/2))
break;
- s = expr_end;
- imm_expr->X_op = O_absent;
ip->insn_opcode |= ENCODE_RVC_IMM (imm_expr->X_add_number);
- continue;
+ goto rvc_imm_done;
+ case 'v':
+ if (my_getSmallExpression (imm_expr, imm_reloc, s, p)
+ || (imm_expr->X_add_number & (RISCV_IMM_REACH-1))
+ || (int32_t)imm_expr->X_add_number
+ != imm_expr->X_add_number)
+ break;
+ imm_expr->X_add_number
+ = (uint32_t)imm_expr->X_add_number >> RISCV_IMM_BITS;
+ goto rvc_lui;
+ case 'p':
+ goto branch;
+ case 'a':
+ goto jump;
default:
as_bad (_("bad RVC field specifier 'C%c'\n"), *args);
}
@@ -1716,6 +1737,7 @@ alu_op:
continue;
case 'p': /* pc relative offset */
+branch:
*imm_reloc = BFD_RELOC_12_PCREL;
my_getExpression (imm_expr, s);
s = expr_end;
@@ -1737,6 +1759,7 @@ alu_op:
continue;
case 'a': /* 26 bit address */
+jump:
my_getExpression (imm_expr, s);
s = expr_end;
*imm_reloc = BFD_RELOC_RISCV_JMP;
@@ -1779,9 +1802,6 @@ md_assemble (char *str)
expressionS imm_expr;
bfd_reloc_code_real_type imm_reloc = BFD_RELOC_UNUSED;
- imm_expr.X_op = O_absent;
- imm_reloc = BFD_RELOC_UNUSED;
-
riscv_ip (str, &insn, &imm_expr, &imm_reloc);
if (insn_error)
@@ -1994,6 +2014,24 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
}
break;
+ case BFD_RELOC_RISCV_RVC_BRANCH:
+ if (fixP->fx_addsy)
+ {
+ /* Fill in a tentative value to improve objdump readability. */
+ bfd_vma delta = ENCODE_RVC_B_IMM (S_GET_VALUE (fixP->fx_addsy) + *valP);
+ bfd_putl16 (bfd_getl16 (buf) | delta, buf);
+ }
+ break;
+
+ case BFD_RELOC_RISCV_RVC_JUMP:
+ if (fixP->fx_addsy)
+ {
+ /* Fill in a tentative value to improve objdump readability. */
+ bfd_vma delta = ENCODE_RVC_J_IMM (S_GET_VALUE (fixP->fx_addsy) + *valP);
+ bfd_putl16 (bfd_getl16 (buf) | delta, buf);
+ }
+ break;
+
case BFD_RELOC_RISCV_PCREL_LO12_S:
case BFD_RELOC_RISCV_PCREL_LO12_I:
case BFD_RELOC_RISCV_CALL:
@@ -2137,7 +2175,7 @@ s_align (int x ATTRIBUTE_UNUSED)
ex.X_add_number = worst_case_nop_bytes;
fix_new_exp (frag_now, nops - frag_now->fr_literal, 0,
- &ex, TRUE, BFD_RELOC_RISCV_ALIGN);
+ &ex, FALSE, BFD_RELOC_RISCV_ALIGN);
}
else if (alignment)
frag_align (alignment, fill_value, 0);
@@ -2164,13 +2202,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
*reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
-
- if (fixp->fx_pcrel)
- /* At this point, fx_addnumber is "symbol offset - pcrel address".
- Relocations want only the symbol offset. */
- reloc->addend = fixp->fx_addnumber + reloc->address;
- else
- reloc->addend = fixp->fx_addnumber;
+ reloc->addend = fixp->fx_addnumber;
reloc->howto = bfd_reloc_type_lookup (stdoutput, fixp->fx_r_type);
if (reloc->howto == NULL)
@@ -2205,15 +2237,16 @@ riscv_relax_frag (asection *sec, fragS *fragp, long stretch ATTRIBUTE_UNUSED)
return 0;
}
-/* Convert a machine dependent frag. */
+/* Expand far branches to multi-instruction sequences. */
static void
md_convert_frag_branch (fragS *fragp)
{
bfd_byte *buf;
- insn_t insn;
expressionS exp;
fixS *fixp;
+ insn_t insn;
+ int rs1, reloc;
buf = (bfd_byte *)fragp->fr_literal + fragp->fr_fix;
@@ -2221,10 +2254,45 @@ md_convert_frag_branch (fragS *fragp)
exp.X_add_symbol = fragp->fr_symbol;
exp.X_add_number = fragp->fr_offset;
- if (RELAX_BRANCH_TOOFAR (fragp->fr_subtype))
+ gas_assert (fragp->fr_var == RELAX_BRANCH_LENGTH (fragp->fr_subtype));
+
+ if (RELAX_BRANCH_RVC (fragp->fr_subtype))
+ {
+ switch (RELAX_BRANCH_LENGTH (fragp->fr_subtype))
+ {
+ case 8:
+ case 4:
+ /* Expand the RVC branch into a RISC-V one. */
+ insn = bfd_getl16 (buf);
+ rs1 = 8 + ((insn >> OP_SH_CRS1S) & OP_MASK_CRS1S);
+ if ((insn & MASK_C_J) == MATCH_C_J)
+ insn = MATCH_JAL;
+ else if ((insn & MASK_C_BEQZ) == MATCH_C_BEQZ)
+ insn = MATCH_BEQ | (rs1 << OP_SH_RS1);
+ else if ((insn & MASK_C_BNEZ) == MATCH_C_BNEZ)
+ insn = MATCH_BNE | (rs1 << OP_SH_RS1);
+ else
+ abort ();
+ bfd_putl32 (insn, buf);
+ break;
+
+ case 2:
+ /* Just keep the RVC branch. */
+ reloc = RELAX_BRANCH_UNCOND (fragp->fr_subtype)
+ ? BFD_RELOC_RISCV_RVC_JUMP : BFD_RELOC_RISCV_RVC_BRANCH;
+ fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
+ 2, &exp, FALSE, reloc);
+ buf += 2;
+ goto done;
+
+ default:
+ abort();
+ }
+ }
+
+ switch (RELAX_BRANCH_LENGTH (fragp->fr_subtype))
{
- gas_assert (fragp->fr_var == 8);
- /* We could relax JAL to AUIPC/JALR, but we don't do this yet. */
+ case 8:
gas_assert (!RELAX_BRANCH_UNCOND (fragp->fr_subtype));
/* Invert the branch condition. Branch over the jump. */
@@ -2239,17 +2307,23 @@ md_convert_frag_branch (fragS *fragp)
4, &exp, FALSE, BFD_RELOC_RISCV_JMP);
md_number_to_chars ((char *) buf, MATCH_JAL, 4);
buf += 4;
- }
- else
- {
+ break;
+
+ case 4:
+ reloc = RELAX_BRANCH_UNCOND (fragp->fr_subtype)
+ ? BFD_RELOC_RISCV_JMP : BFD_RELOC_12_PCREL;
fixp = fix_new_exp (fragp, buf - (bfd_byte *)fragp->fr_literal,
- 4, &exp, FALSE, BFD_RELOC_12_PCREL);
+ 4, &exp, FALSE, reloc);
buf += 4;
+ break;
+
+ default:
+ abort ();
}
+done:
fixp->fx_file = fragp->fr_file;
fixp->fx_line = fragp->fr_line;
- fixp->fx_pcrel = 1;
gas_assert (buf == (bfd_byte *)fragp->fr_literal
+ fragp->fr_fix + fragp->fr_var);
diff --git a/binutils/include/elf/riscv.h b/binutils/include/elf/riscv.h
index 20ffd1d..a1e9bb6 100644
--- a/binutils/include/elf/riscv.h
+++ b/binutils/include/elf/riscv.h
@@ -74,6 +74,8 @@ START_RELOC_NUMBERS (elf_riscv_reloc_type)
RELOC_NUMBER (R_RISCV_GNU_VTINHERIT, 41)
RELOC_NUMBER (R_RISCV_GNU_VTENTRY, 42)
RELOC_NUMBER (R_RISCV_ALIGN, 43)
+ RELOC_NUMBER (R_RISCV_RVC_BRANCH, 44)
+ RELOC_NUMBER (R_RISCV_RVC_JUMP, 45)
END_RELOC_NUMBERS (R_RISCV_max)
/* Processor specific flags for the ELF header e_flags field. */
diff --git a/binutils/include/opcode/riscv.h b/binutils/include/opcode/riscv.h
index 061345a..b212231 100644
--- a/binutils/include/opcode/riscv.h
+++ b/binutils/include/opcode/riscv.h
@@ -64,15 +64,11 @@ static const char* const riscv_pred_succ[16] = {
"i", "iw", "ir", "irw", "io", "iow", "ior", "iorw",
};
-#define RVC_JUMP_BITS 10
-#define RVC_JUMP_ALIGN_BITS 1
-#define RVC_JUMP_ALIGN (1 << RVC_JUMP_ALIGN_BITS)
-#define RVC_JUMP_REACH ((1ULL<<RVC_JUMP_BITS)*RVC_JUMP_ALIGN)
+#define RVC_JUMP_BITS 11
+#define RVC_JUMP_REACH ((1ULL<<RVC_JUMP_BITS)*RISCV_JUMP_ALIGN)
-#define RVC_BRANCH_BITS 5
-#define RVC_BRANCH_ALIGN_BITS RVC_JUMP_ALIGN_BITS
-#define RVC_BRANCH_ALIGN (1 << RVC_BRANCH_ALIGN_BITS)
-#define RVC_BRANCH_REACH ((1ULL<<RVC_BRANCH_BITS)*RVC_BRANCH_ALIGN)
+#define RVC_BRANCH_BITS 8
+#define RVC_BRANCH_REACH ((1ULL<<RVC_BRANCH_BITS)*RISCV_BRANCH_ALIGN)
#define RV_X(x, s, n) (((x) >> (s)) & ((1<<(n))-1))
#define RV_IMM_SIGN(x) (-(((x) >> 31) & 1))
@@ -97,6 +93,10 @@ static const char* const riscv_pred_succ[16] = {
((RV_X(x, 4, 3) << 2) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 2, 2) << 6))
#define EXTRACT_RVC_LDSP_IMM(x) \
((RV_X(x, 5, 2) << 3) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 2, 3) << 6))
+#define EXTRACT_RVC_B_IMM(x) \
+ ((RV_X(x, 7, 1) << 1) | (RV_X(x, 11, 1) << 2) | (RV_X(x, 5, 2) << 3) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 10, 1) << 6) | (RV_X(x, 8, 1) << 7) | (-RV_X(x, 9, 1) << 8))
+#define EXTRACT_RVC_J_IMM(x) \
+ ((RV_X(x, 7, 1) << 1) | (RV_X(x, 11, 1) << 2) | (RV_X(x, 5, 2) << 3) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 10, 1) << 6) | (RV_X(x, 8, 2) << 7) | (RV_X(x, 2, 2) << 9) | (-RV_X(x, 4, 1) << 11))
#define ENCODE_ITYPE_IMM(x) \
(RV_X(x, 0, 12) << 20)
@@ -118,6 +118,10 @@ static const char* const riscv_pred_succ[16] = {
((RV_X(x, 2, 3) << 4) | (RV_X(x, 5, 1) << 12) | (RV_X(x, 6, 2) << 2))
#define ENCODE_RVC_LDSP_IMM(x) \
((RV_X(x, 3, 2) << 5) | (RV_X(x, 5, 1) << 12) | (RV_X(x, 6, 3) << 2))
+#define ENCODE_RVC_B_IMM(x) \
+ ((RV_X(x, 1, 1) << 7) | (RV_X(x, 2, 1) << 11) | (RV_X(x, 3, 2) << 5) | (RV_X(x, 5, 1) << 12) | (RV_X(x, 6, 1) << 10) | (RV_X(x, 7, 2) << 8))
+#define ENCODE_RVC_J_IMM(x) \
+ ((RV_X(x, 1, 1) << 7) | (RV_X(x, 2, 1) << 11) | (RV_X(x, 3, 2) << 5) | (RV_X(x, 5, 1) << 12) | (RV_X(x, 6, 1) << 10) | (RV_X(x, 7, 2) << 8) | (RV_X(x, 9, 3) << 2))
#define VALID_ITYPE_IMM(x) (EXTRACT_ITYPE_IMM(ENCODE_ITYPE_IMM(x)) == (x))
#define VALID_STYPE_IMM(x) (EXTRACT_STYPE_IMM(ENCODE_STYPE_IMM(x)) == (x))
@@ -129,6 +133,8 @@ static const char* const riscv_pred_succ[16] = {
#define VALID_RVC_LD_IMM(x) (EXTRACT_RVC_LD_IMM(ENCODE_RVC_LD_IMM(x)) == (x))
#define VALID_RVC_LWSP_IMM(x) (EXTRACT_RVC_LWSP_IMM(ENCODE_RVC_LWSP_IMM(x)) == (x))
#define VALID_RVC_LDSP_IMM(x) (EXTRACT_RVC_LDSP_IMM(ENCODE_RVC_LDSP_IMM(x)) == (x))
+#define VALID_RVC_B_IMM(x) (EXTRACT_RVC_B_IMM(ENCODE_RVC_B_IMM(x)) == (x))
+#define VALID_RVC_J_IMM(x) (EXTRACT_RVC_J_IMM(ENCODE_RVC_J_IMM(x)) == (x))
#define RISCV_RTYPE(insn, rd, rs1, rs2) \
((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2))
diff --git a/binutils/opcodes/riscv-dis.c b/binutils/opcodes/riscv-dis.c
index a31ca26..1c84058 100644
--- a/binutils/opcodes/riscv-dis.c
+++ b/binutils/opcodes/riscv-dis.c
@@ -250,10 +250,21 @@ print_insn_args (const char *d, insn_t l, bfd_vma pc, disassemble_info *info)
case 'n':
print (info->stream, "%d", (int)EXTRACT_RVC_LDSP_IMM (l));
break;
+ case 'p':
+ info->target = EXTRACT_RVC_B_IMM (l) + pc;
+ (*info->print_address_func) (info->target, info);
+ break;
+ case 'a':
+ info->target = EXTRACT_RVC_J_IMM (l) + pc;
+ (*info->print_address_func) (info->target, info);
+ break;
case 'u':
print (info->stream, "0x%x",
(int)(EXTRACT_RVC_IMM (l) & (RISCV_BIGIMM_REACH-1)));
break;
+ case '>':
+ print (info->stream, "0x%x", (int)EXTRACT_RVC_IMM (l) & 0x3f);
+ break;
}
break;
diff --git a/binutils/opcodes/riscv-opc.c b/binutils/opcodes/riscv-opc.c
index a71f07b..52c501a 100644
--- a/binutils/opcodes/riscv-opc.c
+++ b/binutils/opcodes/riscv-opc.c
@@ -94,6 +94,7 @@ const char * const riscv_vec_fpr_names[32] =
#define MASK_RS1 (OP_MASK_RS1 << OP_SH_RS1)
#define MASK_RS2 (OP_MASK_RS2 << OP_SH_RS2)
#define MASK_RD (OP_MASK_RD << OP_SH_RD)
+#define MASK_CRS1 (OP_MASK_CRS1 << OP_SH_CRS1)
#define MASK_IMM ENCODE_ITYPE_IMM(-1U)
#define MASK_UIMM ENCODE_UTYPE_IMM(-1U)
#define MASK_RM (OP_MASK_RM << OP_SH_RM)
@@ -127,8 +128,11 @@ const struct riscv_opcode riscv_builtin_opcodes[] =
{"unimp", "I", "", MATCH_CSRRW | (CSR_CYCLE << OP_SH_CSR), 0xffffffffU, match_opcode, 0 }, /* csrw cycle, x0 */
{"sbreak", "C", "", MATCH_C_LI | ENCODE_RVC_IMM(-32U), MASK_C_LI | MASK_RD | ENCODE_RVC_IMM(-1U), match_opcode, 0 },
{"sbreak", "I", "", MATCH_SBREAK, MASK_SBREAK, match_opcode, 0 },
-{"nop", "C", "", MATCH_C_MV, MASK_C_MV | MASK_RD | (OP_MASK_CRS1 << OP_SH_CRS1), match_opcode, 0 },
+{"nop", "C", "", MATCH_C_MV, MASK_C_MV | MASK_RD | MASK_CRS1, match_opcode, 0 },
{"nop", "I", "", MATCH_ADDI, MASK_ADDI | MASK_RD | MASK_RS1 | MASK_IMM, match_opcode, INSN_ALIAS },
+{"lui", "C", "d,Cu", MATCH_C_LUI, MASK_C_LUI, match_opcode, 0 },
+{"lui", "I", "d,u", MATCH_LUI, MASK_LUI, match_opcode, WR_xd },
+{"li", "C", "d,Cv", MATCH_C_LUI, MASK_C_LUI, match_opcode, INSN_ALIAS },
{"li", "C", "d,Cj", MATCH_C_LI, MASK_C_LI, match_opcode, 0 },
{"li", "I", "d,j", MATCH_ADDI, MASK_ADDI | MASK_RS1, match_opcode, INSN_ALIAS|WR_xd }, /* addi */
{"li", "I", "d,I", 0, (int) M_LI, match_never, INSN_MACRO },
@@ -138,6 +142,7 @@ const struct riscv_opcode riscv_builtin_opcodes[] =
{"andi", "I", "d,s,j", MATCH_ANDI, MASK_ANDI, match_opcode, WR_xd|RD_xs1 },
{"and", "I", "d,s,t", MATCH_AND, MASK_AND, match_opcode, WR_xd|RD_xs1|RD_xs2 },
{"and", "I", "d,s,j", MATCH_ANDI, MASK_ANDI, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"beqz", "C", "Cs,Cp", MATCH_C_BEQZ, MASK_C_BEQZ, match_opcode, 0 },
{"beqz", "I", "s,p", MATCH_BEQ, MASK_BEQ | MASK_RS2, match_opcode, INSN_ALIAS|RD_xs1 },
{"beq", "I", "s,t,p", MATCH_BEQ, MASK_BEQ, match_opcode, RD_xs1|RD_xs2 },
{"blez", "I", "t,p", MATCH_BGE, MASK_BGE | MASK_RS1, match_opcode, INSN_ALIAS|RD_xs2 },
@@ -152,6 +157,7 @@ const struct riscv_opcode riscv_builtin_opcodes[] =
{"bltu", "I", "s,t,p", MATCH_BLTU, MASK_BLTU, match_opcode, RD_xs1|RD_xs2 },
{"bgt", "I", "t,s,p", MATCH_BLT, MASK_BLT, match_opcode, INSN_ALIAS|RD_xs1|RD_xs2 },
{"bgtu", "I", "t,s,p", MATCH_BLTU, MASK_BLTU, match_opcode, INSN_ALIAS|RD_xs1|RD_xs2 },
+{"bnez", "C", "Cs,Cp", MATCH_C_BNEZ, MASK_C_BNEZ, match_opcode, 0 },
{"bnez", "I", "s,p", MATCH_BNE, MASK_BNE | MASK_RS2, match_opcode, INSN_ALIAS|RD_xs1 },
{"bne", "I", "s,t,p", MATCH_BNE, MASK_BNE, match_opcode, RD_xs1|RD_xs2 },
{"addi", "C", "d,CU,Cj", MATCH_C_ADDI, MASK_C_ADDI, match_opcode, 0 },
@@ -169,7 +175,7 @@ const struct riscv_opcode riscv_builtin_opcodes[] =
{"la.tls.gd", "I", "d,A", 0, (int) M_LA_TLS_GD, match_never, INSN_MACRO },
{"la.tls.ie", "I", "d,A", 0, (int) M_LA_TLS_IE, match_never, INSN_MACRO },
{"neg", "I", "d,t", MATCH_SUB, MASK_SUB | MASK_RS1, match_opcode, INSN_ALIAS|WR_xd|RD_xs2 }, /* sub 0 */
-{"slli", "C", "d,CU,Cj", MATCH_C_SLLI, MASK_C_SLLI, match_opcode, 0 },
+{"slli", "C", "d,CU,C>", MATCH_C_SLLI, MASK_C_SLLI, match_opcode, 0 },
{"slli", "I", "d,s,>", MATCH_SLLI, MASK_SLLI, match_opcode, WR_xd|RD_xs1 },
{"sll", "C", "d,CU,Cj", MATCH_C_SLLI, MASK_C_SLLI, match_opcode, 0 },
{"sll", "I", "d,s,t", MATCH_SLL, MASK_SLL, match_opcode, WR_xd|RD_xs1|RD_xs2 },
@@ -181,14 +187,16 @@ const struct riscv_opcode riscv_builtin_opcodes[] =
{"sra", "I", "d,s,t", MATCH_SRA, MASK_SRA, match_opcode, WR_xd|RD_xs1|RD_xs2 },
{"sra", "I", "d,s,>", MATCH_SRAI, MASK_SRAI, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
{"sub", "I", "d,s,t", MATCH_SUB, MASK_SUB, match_opcode, WR_xd|RD_xs1|RD_xs2 },
+{"ret", "C", "", MATCH_C_JALR | (X_RA << OP_SH_CRS1), MASK_C_JALR | MASK_RD | MASK_CRS1, match_opcode, INSN_ALIAS },
{"ret", "I", "", MATCH_JALR | (X_RA << OP_SH_RS1), MASK_JALR | MASK_RD | MASK_RS1 | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
+{"j", "C", "Ca", MATCH_C_J, MASK_C_J, match_opcode, 0 },
{"j", "I", "a", MATCH_JAL, MASK_JAL | MASK_RD, match_opcode, INSN_ALIAS },
{"jal", "I", "a", MATCH_JAL | (X_RA << OP_SH_RD), MASK_JAL | MASK_RD, match_opcode, INSN_ALIAS|WR_xd },
{"jal", "I", "d,a", MATCH_JAL, MASK_JAL, match_opcode, WR_xd },
{"call", "I", "c", (X_T0 << OP_SH_RS1) | (X_RA << OP_SH_RD), (int) M_CALL, match_never, INSN_MACRO },
{"tail", "I", "c", (X_T0 << OP_SH_RS1), (int) M_CALL, match_never, INSN_MACRO },
{"jump", "I", "c,s", 0, (int) M_CALL, match_never, INSN_MACRO },
-{"jr", "C", "CS", MATCH_C_JALR, MASK_C_JALR | MASK_RD, match_opcode, 0 },
+{"jr", "C", "CS", MATCH_C_JALR, MASK_C_JALR | MASK_RD, match_opcode, INSN_ALIAS },
{"jr", "I", "s", MATCH_JALR, MASK_JALR | MASK_RD | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
{"jr", "I", "s,j", MATCH_JALR, MASK_JALR | MASK_RD, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
{"jalr", "C", "CS", MATCH_C_JALR | (X_RA << OP_SH_RD), MASK_C_JALR | MASK_RD, match_opcode, 0 },
@@ -209,8 +217,6 @@ const struct riscv_opcode riscv_builtin_opcodes[] =
{"lw", "C", "Cd,Ck(Cs)", MATCH_C_LW, MASK_C_LW, match_opcode, WR_xd|RD_xs1 },
{"lw", "I", "d,o(s)", MATCH_LW, MASK_LW, match_opcode, WR_xd|RD_xs1 },
{"lw", "I", "d,A", 0, (int) M_LW, match_never, INSN_MACRO },
-{"lui", "C", "d,Cu", MATCH_C_LUI, MASK_C_LUI, match_opcode, 0 },
-{"lui", "I", "d,u", MATCH_LUI, MASK_LUI, match_opcode, WR_xd },
{"not", "I", "d,s", MATCH_XORI | MASK_IMM, MASK_XORI | MASK_IMM, match_opcode, INSN_ALIAS|WR_xd|RD_xs1 },
{"ori", "I", "d,s,j", MATCH_ORI, MASK_ORI, match_opcode, WR_xd|RD_xs1 },
{"or", "I", "d,s,t", MATCH_OR, MASK_OR, match_opcode, WR_xd|RD_xs1|RD_xs2 },