Skip to content

Commit

Permalink
RISC-V: Supports Zcmp push/pop/popret[z] instructions.
Browse files Browse the repository at this point in the history
  • Loading branch information
pz9115 authored and Mary Bennett committed Oct 2, 2023
1 parent 154e388 commit 54ae5ff
Show file tree
Hide file tree
Showing 7 changed files with 319 additions and 0 deletions.
20 changes: 20 additions & 0 deletions bfd/elfxx-riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1361,6 +1361,8 @@ static struct riscv_supported_ext riscv_supported_std_z_ext[] =
{"zcb", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zcf", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zcd", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zcmp", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{"zcmt", ISA_SPEC_CLASS_DRAFT, 1, 0, 0 },
{NULL, 0, 0, 0, 0}
};

Expand Down Expand Up @@ -2591,6 +2593,8 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps,
case INSN_CLASS_ZCB_AND_ZMMUL:
return (riscv_subset_supports (rps, "zcb")
&& riscv_subset_supports (rps, "zmmul"));
case INSN_CLASS_ZCMP:
return riscv_subset_supports (rps, "zcmp");
case INSN_CLASS_SVINVAL:
return riscv_subset_supports (rps, "svinval");
case INSN_CLASS_H:
Expand Down Expand Up @@ -2847,6 +2851,8 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
return _("zcb' and `zbb");
case INSN_CLASS_ZCB_AND_ZMMUL:
return _("zcb' and `zmmul', or `zcb' and `m");
case INSN_CLASS_ZCMP:
return "zcmp";
case INSN_CLASS_SVINVAL:
return "svinval";
case INSN_CLASS_H:
Expand Down Expand Up @@ -2897,3 +2903,17 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
return NULL;
}
}

/* get base sp adjustment */

int
riscv_get_base_spimm (insn_t opcode, riscv_parse_subset_t *rps)
{
unsigned sp_alignment = 16;
unsigned reg_size = *(rps->xlen) / 8;
unsigned rlist = EXTRACT_BITS (opcode, OP_MASK_RLIST, OP_SH_RLIST);

unsigned min_sp_adj = (rlist - 3) * reg_size + (rlist == 15 ? reg_size : 0);
return ((min_sp_adj / sp_alignment) + (min_sp_adj % sp_alignment != 0))
* sp_alignment;
}
3 changes: 3 additions & 0 deletions bfd/elfxx-riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,6 @@ extern void
bfd_elf32_riscv_set_data_segment_info (struct bfd_link_info *, int *);
extern void
bfd_elf64_riscv_set_data_segment_info (struct bfd_link_info *, int *);

extern int
riscv_get_base_spimm (insn_t, riscv_parse_subset_t *);
192 changes: 192 additions & 0 deletions gas/config/tc-riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,152 @@ arg_lookup (char **s, const char *const *array, size_t size, unsigned *regnop)
return false;
}

/* Map ra and s-register to [4,15], so that we can check if the
reg2 in register list reg1-reg2 or single reg2 is valid or not,
and obtain the corresponding rlist value.
ra - 4
s0 - 5
s1 - 6
....
s10 - 0 (invalid)
s11 - 15
*/

static int
regno_to_rlist (unsigned regno)
{
if (regno == X_RA)
return 4;
else if (regno == X_S0 || regno == X_S1)
return 5 + regno - X_S0;
else if (regno >= X_S2 && regno < X_S10)
return 7 + regno - X_S2;
else if (regno == X_S11)
return 15;

return 0; /* invalid symbol */
}

/* Parse register list, and the parsed rlist value is stored in rlist
argument.
If ABI register names are used (e.g. ra and s0), the register
list could be "{ra}", "{ra, s0}", "{ra, s0-sN}", where 0 < N < 10 or
N == 11.
If numeric register names are used (e.g. x1 and x8), the register list
could be "{x1}", "{x1,x8}", "{x1,x8-x9}", "{x1,x8-x9, x18}" and
"{x1,x8-x9,x18-xN}", where 19 < N < 25 or N == 27.
It will fail if numeric register names and ABI register names are used
at the same time.
*/

static bool
reglist_lookup (char **s, unsigned *rlist)
{
unsigned regno;
/* Use to check if the register format is xreg. */
bool use_xreg = **s == 'x';

/* The first register in register list should be ra. */
if (!reg_lookup (s, RCLASS_GPR, &regno)
|| !(*rlist = regno_to_rlist (regno)) /* update rlist */
|| regno != X_RA)
return FALSE;

/* Skip "whitespace, whitespace" pattern. */
while (ISSPACE (**s))
++ *s;
if (**s == '}')
return TRUE;
else if (**s != ',')
return FALSE;
while (ISSPACE (*++*s))
++ *s;

/* Do not use numeric and abi names at the same time. */
if (use_xreg && **s != 'x')
return FALSE;

/* Reg1 should be s0 or its numeric names x8. */
if (!reg_lookup (s, RCLASS_GPR, &regno)
|| !(*rlist = regno_to_rlist (regno))
|| regno != X_S0)
return FALSE;

/* Skip "whitespace - whitespace" pattern. */
while (ISSPACE (**s))
++ *s;
if (**s == '}')
return TRUE;
else if (**s != '-')
return FALSE;
while (ISSPACE (*++*s))
++ *s;

if (use_xreg && **s != 'x')
return FALSE;

/* Reg2 is x9 if the numeric name is used, otherwise,
it could be any other sN register, where N > 0. */
if (!reg_lookup (s, RCLASS_GPR, &regno)
|| !(*rlist = regno_to_rlist (regno))
|| regno <= X_S0
|| (use_xreg && regno != X_S1))
return FALSE;

/* Skip whitespace */
while (ISSPACE (**s))
++ *s;

/* Check if it is the end of register list. */
if (**s == '}')
return TRUE;
else if (!use_xreg)
return FALSE;

/* Here is not reachable if the abi name is used. */
gas_assert (use_xreg);

/* If the numeric name is used, we need to parse extra
register list, reg3 or reg3-reg4. */

/* Skip ", white space" pattern. */
if (**s != ',')
return FALSE;
while (ISSPACE (*++*s))
++ *s;

if (use_xreg && **s != 'x')
return FALSE;

/* Reg3 should be s2. */
if (!reg_lookup (s, RCLASS_GPR, &regno)
|| !(*rlist = regno_to_rlist (regno))
|| regno != X_S2)
return FALSE;

/* skip "whitespace - whitespace" pattern. */
while (ISSPACE (**s))
++ *s;
if (**s == '}')
return TRUE;
else if (**s != '-')
return FALSE;
while (ISSPACE (*++*s))
++ *s;

/* Reg4 could be any other sN register, where N > 1. */
if (!reg_lookup (s, RCLASS_GPR, &regno)
|| !(*rlist = regno_to_rlist (regno))
|| regno <= X_S2)
return FALSE;

return TRUE;
}

static bool
flt_lookup (float f, const float *array, size_t size, unsigned *regnop)
{
Expand Down Expand Up @@ -1335,6 +1481,17 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
goto unknown_validate_operand;
}
break;
case 'Z': /* Zcmp extension operators. */
switch (*++oparg)
{
/* immediate offset operand for cm.push and cm.pop. */
case 'p': used_bits |= ENCODE_ZCMP_SPIMM (-1U); break;
/* register list operand for cm.push and cm.pop. */
case 'r': USE_BITS (OP_MASK_RLIST, OP_SH_RLIST); break;
default:
goto unknown_validate_operand;
}
break;
default:
goto unknown_validate_operand;
}
Expand Down Expand Up @@ -1369,6 +1526,8 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
case ',': break;
case '(': break;
case ')': break;
case '{': break;
case '}': break;
case '!': break;
case '<': USE_BITS (OP_MASK_SHAMTW, OP_SH_SHAMTW); break;
case '>': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
Expand Down Expand Up @@ -2994,6 +3153,37 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
}
break;

case 'Z': /* Zcmp extension. */
switch (*++oparg)
{
case 'r':
/* we use regno to store reglist value here. */
if (!reglist_lookup (&asarg, &regno))
break;
INSERT_OPERAND (RLIST, *ip, regno);
continue;

case 'p':
if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
|| imm_expr->X_op != O_constant)
break;
/* convert stack adjust of cm.push to a positive offset. */
if (ip->insn_mo->match == MATCH_CM_PUSH)
imm_expr->X_add_number *= -1;
/* subtract base stack adjust. */
imm_expr->X_add_number -=
riscv_get_base_spimm (ip->insn_opcode, &riscv_rps_as);
if (!VALID_ZCMP_SPIMM (imm_expr->X_add_number))
break;
ip->insn_opcode |=
ENCODE_ZCMP_SPIMM (imm_expr->X_add_number);
goto rvc_imm_done;

default:
goto unknown_riscv_ip_operand;
}
break;

default:
goto unknown_riscv_ip_operand;
}
Expand Down Expand Up @@ -3185,6 +3375,8 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,

case '(':
case ')':
case '{':
case '}':
case '[':
case ']':
case '!':
Expand Down
14 changes: 14 additions & 0 deletions include/opcode/riscv-opc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2327,6 +2327,15 @@
#define MASK_WRS_NTO 0xffffffff
#define MATCH_WRS_STO 0x01d00073
#define MASK_WRS_STO 0xffffffff
/* ZCMP instructions. */
#define MATCH_CM_PUSH 0xb802
#define MASK_CM_PUSH 0xff03
#define MATCH_CM_POP 0xba02
#define MASK_CM_POP 0xff03
#define MATCH_CM_POPRET 0xbe02
#define MASK_CM_POPRET 0xff03
#define MATCH_CM_POPRETZ 0xbc02
#define MASK_CM_POPRETZ 0xff03
/* Vendor-specific (CORE-V) Xcvmac instructions. */
#define MATCH_CV_MAC 0x9000302b
#define MASK_CV_MAC 0xfe00707f
Expand Down Expand Up @@ -4078,6 +4087,11 @@ DECLARE_INSN(c_lhu, MATCH_C_LHU, MASK_C_LHU)
DECLARE_INSN(c_lh, MATCH_C_LH, MASK_C_LH)
DECLARE_INSN(c_sb, MATCH_C_SB, MASK_C_SB)
DECLARE_INSN(c_sh, MATCH_C_SH, MASK_C_SH)
/* Zcmp instructions. */
DECLARE_INSN(cm_push, MATCH_CM_PUSH, MASK_CM_PUSH)
DECLARE_INSN(cm_pop, MATCH_CM_POP, MASK_CM_POP)
DECLARE_INSN(cm_popret, MATCH_CM_POPRET, MASK_CM_POPRET)
DECLARE_INSN(cm_popretz, MATCH_CM_POPRETZ, MASK_CM_POPRETZ)
/* Vendor-specific (T-Head) XTheadBa instructions. */
DECLARE_INSN(th_addsl, MATCH_TH_ADDSL, MASK_TH_ADDSL)
/* Vendor-specific (T-Head) XTheadBb instructions. */
Expand Down
21 changes: 21 additions & 0 deletions include/opcode/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ static inline unsigned int riscv_insn_length (insn_t insn)
#define EXTRACT_CV_SIMD_UIMM6(x) \
((RV_X(x, 25, 1)) | (RV_X(x, 20, 5) << 1))

/* Zcmp extension. */
#define EXTRACT_ZCMP_SPIMM(x) \
(RV_X(x, 2, 2) << 4)

#define ENCODE_ITYPE_IMM(x) \
(RV_X(x, 0, 12) << 20)
#define ENCODE_STYPE_IMM(x) \
Expand Down Expand Up @@ -205,6 +209,10 @@ static inline unsigned int riscv_insn_length (insn_t insn)
#define ENCODE_CV_SIMD_UIMM6(x) \
((RV_X(x, 0, 1) << 25) | (RV_X(x, 1, 5) << 20))

/* Zcmp extenison. */
#define ENCODE_ZCMP_SPIMM(x) \
(RV_X(x, 4, 2) << 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))
#define VALID_BTYPE_IMM(x) (EXTRACT_BTYPE_IMM(ENCODE_BTYPE_IMM(x)) == (x))
Expand Down Expand Up @@ -232,6 +240,9 @@ 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))

/* Zcmp extension. */
#define VALID_ZCMP_SPIMM(x) (EXTRACT_ZCMP_SPIMM(ENCODE_ZCMP_SPIMM(x)) == (x))

#define RISCV_RTYPE(insn, rd, rs1, rs2) \
((MATCH_ ## insn) | ((rd) << OP_SH_RD) | ((rs1) << OP_SH_RS1) | ((rs2) << OP_SH_RS2))
#define RISCV_ITYPE(insn, rd, rs1, imm) \
Expand Down Expand Up @@ -304,6 +315,10 @@ static inline unsigned int riscv_insn_length (insn_t insn)
#define OP_MASK_LN 0x1
#define OP_SH_LN 7

/* ZC Specific */
#define OP_MASK_RLIST 0xf
#define OP_SH_RLIST 4

#define OP_MASK_CSR 0xfffU
#define OP_SH_CSR 20

Expand Down Expand Up @@ -379,6 +394,11 @@ static inline unsigned int riscv_insn_length (insn_t insn)
#define X_T0 5
#define X_T1 6
#define X_T2 7
#define X_S0 8
#define X_S1 9
#define X_S2 18
#define X_S10 26
#define X_S11 27
#define X_T3 28

#define NGPR 32
Expand Down Expand Up @@ -491,6 +511,7 @@ enum riscv_insn_class
INSN_CLASS_ZICBOM,
INSN_CLASS_ZICBOP,
INSN_CLASS_ZICBOZ,
INSN_CLASS_ZCMP,
INSN_CLASS_H,
INSN_CLASS_XCVMAC,
INSN_CLASS_XCVALU,
Expand Down
Loading

0 comments on commit 54ae5ff

Please sign in to comment.