Skip to content

Commit

Permalink
RISC-V: Implement common register pair framework
Browse files Browse the repository at this point in the history
This commit implements common framework for aligned register pairs
(using GPRs).  This is particularly useful on following extensions:

-   'Zdinx'
-   'Zqinx' (once proposed but not ratified yet)
-   'Zpsfoperand' (a part of 'P'-extension proposal)

New operand type format is shown below:

1.  'l' (stands for "length")
2.  One of the following:
    '1' for  32-bit data (or less), (RV32: 1 register,  RV64: 1 register)
    '2' for  64-bit data            (RV32: 2 registers, RV64: 1 register)
    '4' for 128-bit data            (RV32: 4 registers, RV64: 2 registers)
3.  One of the following:
    'd' for RD
    's' for RS1
    't' for RS2
    'r' for RS3
    'u' for RS1 and RS2 (where RS1 == RS2)

gas/ChangeLog:

	* config/tc-riscv.c (riscv_ip): Add handling for "l[124][dstru]".
	(validate_riscv_insn): Likewise.

opcodes/ChangeLog:

	* riscv-dis.c (print_insn_args): Add handling for "l[124][dstru]".
  • Loading branch information
a4lg committed Sep 30, 2022
1 parent 1d4c108 commit 6772709
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
72 changes: 72 additions & 0 deletions gas/config/tc-riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1251,6 +1251,30 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
case 'z': break; /* Zero immediate. */
case '[': break; /* Unused operand. */
case ']': break; /* Unused operand. */
case 'l': /* Register pairs. */
switch (*++oparg)
{
case '1':
case '2':
case '4':
break;
default:
goto unknown_validate_operand;
}
switch (*++oparg)
{
case 'd': USE_BITS (OP_MASK_RD, OP_SH_RD); break;
case 's': USE_BITS (OP_MASK_RS1, OP_SH_RS1); break;
case 't': USE_BITS (OP_MASK_RS2, OP_SH_RS2); break;
case 'r': USE_BITS (OP_MASK_RS3, OP_SH_RS3); break;
case 'u': /* RS1 == RS2. */
USE_BITS (OP_MASK_RS1, OP_SH_RS1);
USE_BITS (OP_MASK_RS2, OP_SH_RS2);
break;
default:
goto unknown_validate_operand;
}
break;
case '0': break; /* AMO displacement, must to zero. */
case '1': break; /* Relaxation operand. */
case 'F': /* Funct for .insn directive. */
Expand Down Expand Up @@ -3021,6 +3045,54 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
}
break;

case 'l': /* Register pairs. */
if (reg_lookup (&asarg, RCLASS_GPR, &regno))
{
if (*asarg == ' ')
++asarg;

unsigned dlen;
switch (*++oparg)
{
case '1': dlen = 32; break;
case '2': dlen = 64; break;
case '4': dlen = 128; break;
default:
goto unknown_riscv_ip_operand;
}
char c = *++oparg;

/* Check whether the register number is aligned properly. */
if (!(xlen >= dlen || (regno % (dlen / xlen)) == 0))
break;

/* Now the register number is valid. Insert the number to
the corresponding field(s). */
switch (c)
{
case 'd':
INSERT_OPERAND (RD, *ip, regno);
break;
case 's':
INSERT_OPERAND (RS1, *ip, regno);
break;
case 't':
INSERT_OPERAND (RS2, *ip, regno);
break;
case 'r':
INSERT_OPERAND (RS3, *ip, regno);
break;
case 'u':
INSERT_OPERAND (RS1, *ip, regno);
INSERT_OPERAND (RS2, *ip, regno);
break;
default:
goto unknown_riscv_ip_operand;
}
continue;
}
break;

case 'D': /* Floating point RD. */
case 'S': /* Floating point RS1. */
case 'T': /* Floating point RS2. */
Expand Down
31 changes: 31 additions & 0 deletions opcodes/riscv-dis.c
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,37 @@ print_insn_args (const char *oparg, insn_t l, bfd_vma pc, disassemble_info *info
print (info->stream, dis_style_register, "%s", riscv_gpr_names[0]);
break;

case 'l':
{
unsigned dlen;
int regno;
switch (*++oparg)
{
case '1': dlen = 32; break;
case '2': dlen = 64; break;
case '4': dlen = 128; break;
default:
goto undefined_modifier;
}
switch (*++oparg)
{
case 'd': regno = rd; break;
case 's': regno = rs1; break;
case 't': regno = EXTRACT_OPERAND (RS2, l); break;
case 'r': regno = EXTRACT_OPERAND (RS3, l); break;
case 'u': regno = rs1; break; /* RS1 == RS2. */
default:
goto undefined_modifier;
}
/* Check whether the register number is aligned properly. */
if (xlen >= dlen || (regno % (dlen / xlen)) == 0)
print (info->stream, dis_style_register, "%s",
riscv_gpr_names[regno]);
else
print (info->stream, dis_style_text, "invalid%d", regno);
break;
}

case '>':
print (info->stream, dis_style_immediate, "0x%x",
(int)EXTRACT_OPERAND (SHAMT, l));
Expand Down

0 comments on commit 6772709

Please sign in to comment.