Skip to content

Commit 9132c81

Browse files
pz9115Nelson Chu
authored andcommitted
RISC-V: Support Zcmp push/pop instructions.
Support zcmp extension push/pop/popret and popret zero instructions. The `reg_list' is a list containing 1 to 13 registers, we can use: "{ra}, {ra, s0}, {ra, s0-s1}, {ra, s0-s2} ... {ra, s0-sN}" to present this feature. Passed gcc/binutils regressions of riscv-gnu-toolchain. Most of work was finished by Sinan Lin. Co-Authored by: Charlie Keaney <charlie.keaney@embecosm.com> Co-Authored by: Mary Bennett <mary.bennett@embecosm.com> Co-Authored by: Nandni Jamnadas <nandni.jamnadas@embecosm.com> Co-Authored by: Sinan Lin <sinan.lin@linux.alibaba.com> Co-Authored by: Simon Cook <simon.cook@embecosm.com> Co-Authored by: Shihua Liao <shihua@iscas.ac.cn> Co-Authored by: Yulong Shi <yulong@iscas.ac.cn> bfd/ChangeLog: * elfxx-riscv.c (riscv_implicit_subset): Imply zca for zcmp. (riscv_supported_std_z_ext): Added zcmp with version 1.0. (riscv_parse_check_conflicts): Zcmp conflicts with d/zcd. (riscv_multi_subset_supports): Handle zcmp. (riscv_multi_subset_supports_ext): Ditto. gas/ChangeLog: * NEWS: Updated. * config/tc-riscv.c (regno_to_reg_list): New function, used to map register to reg_list number. (reglist_lookup): Called reglist_lookup_internal. Return false if reg_list number is zero, which is an invalid value. (reglist_lookup_internal): Parse register list, and return the last register by regno_to_reg_list. (validate_riscv_insn): New operators. (riscv_ip): Ditto. * testsuite/gas/riscv/march-help.l: Updated. * testsuite/gas/riscv/zcmp-push-pop-fail.d: New test. * testsuite/gas/riscv/zcmp-push-pop-fail.l: New test. * testsuite/gas/riscv/zcmp-push-pop-fail.s: New test. * testsuite/gas/riscv/zcmp-push-pop.d: New test. * testsuite/gas/riscv/zcmp-push-pop.s: New test. include/ChangeLog: * opcode/riscv-opc.h (MATCH/MASK_CM_PUSH): New macros for zcmp. (MATCH/MASK_CM_POP): Ditto. (MATCH/MASK_CM_POPRET): Ditto. (MATCH/MASK_CM_POPRETZ): Ditto. (DECLARE_INSN): New declarations for zcmp. * opcode/riscv.h (EXTRACT/ENCODE/VALID_ZCMP_SPIMM): Handle spimm operand for zcmp. (OP_MASK_REG_LIST): Handle operand for zcmp register list. (OP_SH_REG_LIST): Ditto. (ZCMP_SP_ALIGNMENT): New argument, used in riscv_get_sp_base. (X_S0, X_S1, X_S2, X_S10, X_S11): New register numbers. (enum riscv_insn_class): Added INSN_CLASS_ZCMP. (extern riscv_get_sp_base): Added. opcodes/ChangeLog: * riscv-dis.c (print_reg_list): New function, used to get zcmp reg_list field. (riscv_get_spimm): New function, used to get zcmp sp adjustment immediate. (print_insn_args): Handle new operands for zcmp. * riscv-opc.c (riscv_get_sp_base): New function, used by gas and objdump. Get sp base adjustment. (riscv_opcodes): Added zcmp instructions.
1 parent 2bf280a commit 9132c81

File tree

13 files changed

+641
-0
lines changed

13 files changed

+641
-0
lines changed

bfd/elfxx-riscv.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,7 @@ static struct riscv_implicit_subset riscv_implicit_subsets[] =
12671267
{"zcf", "zca",check_implicit_always},
12681268
{"zcd", "zca",check_implicit_always},
12691269
{"zcb", "zca",check_implicit_always},
1270+
{"zcmp", "zca",check_implicit_always},
12701271
{"smaia", "ssaia",check_implicit_always},
12711272
{"smcntrpmf", "zicsr",check_implicit_always},
12721273
{"smstateen", "ssstateen",check_implicit_always},
@@ -1415,6 +1416,7 @@ static struct riscv_supported_ext riscv_supported_std_z_ext[] =
14151416
{"zcb",ISA_SPEC_CLASS_DRAFT,1, 0, 0 },
14161417
{"zcf",ISA_SPEC_CLASS_DRAFT,1, 0, 0 },
14171418
{"zcd",ISA_SPEC_CLASS_DRAFT,1, 0, 0 },
1419+
{"zcmp",ISA_SPEC_CLASS_DRAFT,1, 0, 0 },
14181420
{NULL, 0, 0, 0, 0}
14191421
};
14201422

@@ -2056,6 +2058,13 @@ riscv_parse_check_conflicts (riscv_parse_subset_t *rps)
20562058
rps->error_handler (_("rv%d does not support the `q' extension"), xlen);
20572059
no_conflict = false;
20582060
}
2061+
if (riscv_subset_supports (rps, "zcmp")
2062+
&& riscv_subset_supports (rps, "zcd"))
2063+
{
2064+
rps->error_handler
2065+
(_("zcmp' is incompatible with `d/zcd' extension"));
2066+
no_conflict = false;
2067+
}
20592068
if (riscv_lookup_subset (rps->subset_list, "zcf", &subset)
20602069
&& xlen > 32)
20612070
{
@@ -2645,6 +2654,8 @@ riscv_multi_subset_supports (riscv_parse_subset_t *rps,
26452654
case INSN_CLASS_ZCB_AND_ZMMUL:
26462655
return (riscv_subset_supports (rps, "zcb")
26472656
&& riscv_subset_supports (rps, "zmmul"));
2657+
case INSN_CLASS_ZCMP:
2658+
return riscv_subset_supports (rps, "zcmp");
26482659
case INSN_CLASS_SVINVAL:
26492660
return riscv_subset_supports (rps, "svinval");
26502661
case INSN_CLASS_H:
@@ -2899,6 +2910,8 @@ riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
28992910
return _("zcb' and `zbb");
29002911
case INSN_CLASS_ZCB_AND_ZMMUL:
29012912
return _("zcb' and `zmmul', or `zcb' and `m");
2913+
case INSN_CLASS_ZCMP:
2914+
return "zcmp";
29022915
case INSN_CLASS_SVINVAL:
29032916
return "svinval";
29042917
case INSN_CLASS_H:

gas/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
* Remove support for RISC-V privileged spec 1.9.1, but linker can still
1212
recognize it in case of linking old objects.
1313

14+
* Add support for RISC-V Zcmp extension with version 1.0.
15+
1416
* The base register operand in D(X,B) and D(L,B) may be explicitly omitted
1517
in assembly on s390. It can now be coded as D(X,) or D(L,) instead of D(X,0)
1618
D(X,%r0), D(L,0), and D(L,%r0).

gas/config/tc-riscv.c

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,158 @@ flt_lookup (float f, const float *array, size_t size, unsigned *regnop)
12541254
return false;
12551255
}
12561256

1257+
/* Map ra and s-register to [4,15], so that we can check if the
1258+
reg2 in register list reg1-reg2 or single reg2 is valid or not,
1259+
and obtain the corresponding reg_list value.
1260+
1261+
ra - 4
1262+
s0 - 5
1263+
s1 - 6
1264+
....
1265+
s10 - 0 (invalid)
1266+
s11 - 15. */
1267+
1268+
static int
1269+
regno_to_reg_list (unsigned regno)
1270+
{
1271+
if (regno == X_RA)
1272+
return 4;
1273+
else if (regno == X_S0 || regno == X_S1)
1274+
return 5 + regno - X_S0;
1275+
else if (regno >= X_S2 && regno < X_S10)
1276+
return 7 + regno - X_S2;
1277+
else if (regno == X_S11)
1278+
return 15;
1279+
1280+
/* Invalid symbol. */
1281+
return 0;
1282+
}
1283+
1284+
/* Parse register list, and return the last register by regno_to_reg_list.
1285+
1286+
If ABI register names are used (e.g. ra and s0), the register
1287+
list could be "{ra}", "{ra, s0}", "{ra, s0-sN}", where 0 < N < 10 or
1288+
N == 11.
1289+
1290+
If numeric register names are used (e.g. x1 and x8), the register list
1291+
could be "{x1}", "{x1,x8}", "{x1,x8-x9}", "{x1,x8-x9,x18}" and
1292+
"{x1,x8-x9,x18-xN}", where 19 < N < 25 or N == 27.
1293+
1294+
The numeric and ABI register names cannot be used at the same time.
1295+
1296+
TODO: Report errors for the following cases,
1297+
1. Too many registers in the list.
1298+
2. Cases which return 0.
1299+
3. Illegal formats, for example, {x1,x8-NULL,x18-x24/x18}, {x1-x2,x8}. */
1300+
1301+
static unsigned
1302+
reglist_lookup_internal (char *reglist)
1303+
{
1304+
unsigned regno = 0;
1305+
unsigned reg_list = 0;
1306+
char *regname[3][2] = {{NULL}};
1307+
char *save_tok, *save_subtok;
1308+
unsigned i, j;
1309+
1310+
char *token = strtok_r (reglist, ",", &save_tok);
1311+
for (i = 0; i < 3 && token != NULL;
1312+
token = strtok_r (NULL, ",", &save_tok), i++)
1313+
{
1314+
char *subtoken = strtok_r (token, "-", &save_subtok);
1315+
for (j = 0; j < 2 && subtoken != NULL;
1316+
subtoken = strtok_r (NULL, "-", &save_subtok), j++)
1317+
regname[i][j] = subtoken;
1318+
}
1319+
1320+
bool reg1_numeric = false;
1321+
for (i = 0; i < 3; i++)
1322+
{
1323+
if (regname[i][0] == NULL)
1324+
continue;
1325+
#define REG_TO_REG_LIST(NAME, NUM, LIST) \
1326+
(reg_lookup (&NAME, RCLASS_GPR, &NUM) && (LIST = regno_to_reg_list (NUM)))
1327+
#define REG_NUMERIC(NAME) (NAME[0] == 'x')
1328+
#define REG_CONFLICT(NAME, REG_NUMERIC) \
1329+
((NAME[0] == 'x' && !REG_NUMERIC) || (NAME[0] != 'x' && REG_NUMERIC))
1330+
switch (i)
1331+
{
1332+
case 0:
1333+
reg1_numeric = REG_NUMERIC (regname[i][0]);
1334+
if (!REG_TO_REG_LIST (regname[i][0], regno, reg_list)
1335+
|| regno != X_RA)
1336+
return 0;
1337+
break;
1338+
case 1:
1339+
if (REG_CONFLICT (regname[i][0], reg1_numeric)
1340+
/* The second register should be s0 or its numeric names x8. */
1341+
|| !REG_TO_REG_LIST (regname[i][0], regno, reg_list)
1342+
|| regno != X_S0)
1343+
return 0;
1344+
else if (regname[i][1] == NULL)
1345+
return reg_list;
1346+
1347+
if (REG_CONFLICT (regname[i][1], reg1_numeric)
1348+
/* The third register is x9 if the numeric name is used.
1349+
Otherwise, it could be any other sN register, where N > 0. */
1350+
|| !REG_TO_REG_LIST (regname[i][1], regno, reg_list)
1351+
|| regno <= X_S0
1352+
|| (reg1_numeric && regno != X_S1))
1353+
return 0;
1354+
break;
1355+
case 2:
1356+
/* Must use register numeric names. */
1357+
if (!reg1_numeric
1358+
|| !REG_NUMERIC (regname[i][0])
1359+
/* The fourth register should be s2. */
1360+
|| !REG_TO_REG_LIST (regname[i][0], regno, reg_list)
1361+
|| regno != X_S2)
1362+
return 0;
1363+
else if (regname[i][1] == NULL)
1364+
return reg_list;
1365+
1366+
if (!reg1_numeric
1367+
|| !REG_NUMERIC (regname[i][1])
1368+
/* The fifth register could be any other sN register, where N > 1. */
1369+
|| !REG_TO_REG_LIST (regname[i][1], regno, reg_list)
1370+
|| regno <= X_S2)
1371+
return 0;
1372+
break;
1373+
default:
1374+
return 0;
1375+
}
1376+
#undef REG_TO_REG_LIST
1377+
#undef REG_NUMERIC
1378+
#undef REG_CONFLICT
1379+
}
1380+
return reg_list;
1381+
}
1382+
1383+
/* Parse register list. Return false if REG_LIST is zero, which is an
1384+
invalid value. */
1385+
1386+
static bool
1387+
reglist_lookup (char **s, unsigned *reg_list)
1388+
{
1389+
*reg_list = 0;
1390+
char *reglist = strdup (*s);
1391+
if (reglist != NULL)
1392+
{
1393+
char *token = strtok (reglist, "}");
1394+
if (token != NULL)
1395+
{
1396+
*s += strlen (token);
1397+
*reg_list = reglist_lookup_internal (reglist);
1398+
}
1399+
else
1400+
{
1401+
as_bad (_("cannot find `}' for cm.push/cm.pop"));
1402+
*reg_list = 0;
1403+
}
1404+
}
1405+
free (reglist);
1406+
return *reg_list == 0 ? false : true;
1407+
}
1408+
12571409
#define USE_BITS(mask,shift) (used_bits |= ((insn_t)(mask) << (shift)))
12581410
#define USE_IMM(n, s) \
12591411
(used_bits |= ((insn_t)((1ull<<n)-1) << (s)))
@@ -1370,6 +1522,8 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
13701522
case ',': break;
13711523
case '(': break;
13721524
case ')': break;
1525+
case '{': break;
1526+
case '}': break;
13731527
case '<': USE_BITS (OP_MASK_SHAMTW, OP_SH_SHAMTW); break;
13741528
case '>': USE_BITS (OP_MASK_SHAMT, OP_SH_SHAMT); break;
13751529
case 'A': break; /* Macro operand, must be symbol. */
@@ -1450,6 +1604,10 @@ validate_riscv_insn (const struct riscv_opcode *opc, int length)
14501604
case 'h': used_bits |= ENCODE_ZCB_HALFWORD_UIMM (-1U); break;
14511605
/* halfword immediate operators, load/store halfword insns. */
14521606
case 'b': used_bits |= ENCODE_ZCB_BYTE_UIMM (-1U); break;
1607+
/* Immediate offset operand for cm.push and cm.pop. */
1608+
case 'p': used_bits |= ENCODE_ZCMP_SPIMM (-1U); break;
1609+
/* Register list operand for cm.push and cm.pop. */
1610+
case 'r': USE_BITS (OP_MASK_REG_LIST, OP_SH_REG_LIST); break;
14531611
case 'f': break;
14541612
default:
14551613
goto unknown_validate_operand;
@@ -3206,6 +3364,8 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
32063364
case ')':
32073365
case '[':
32083366
case ']':
3367+
case '{':
3368+
case '}':
32093369
if (*asarg++ == *oparg)
32103370
continue;
32113371
break;
@@ -3661,6 +3821,27 @@ riscv_ip (char *str, struct riscv_cl_insn *ip, expressionS *imm_expr,
36613821
break;
36623822
ip->insn_opcode |= ENCODE_ZCB_BYTE_UIMM (imm_expr->X_add_number);
36633823
goto rvc_imm_done;
3824+
case 'r':
3825+
if (!reglist_lookup (&asarg, &regno))
3826+
break;
3827+
INSERT_OPERAND (REG_LIST, *ip, regno);
3828+
continue;
3829+
case 'p':
3830+
if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
3831+
|| imm_expr->X_op != O_constant)
3832+
break;
3833+
/* Convert stack adjustment of cm.push to a positive
3834+
offset. */
3835+
if (ip->insn_mo->match == MATCH_CM_PUSH)
3836+
imm_expr->X_add_number *= -1;
3837+
/* Subtract base stack adjustment and get spimm. */
3838+
imm_expr->X_add_number -=
3839+
riscv_get_sp_base (ip->insn_opcode, *riscv_rps_as.xlen);
3840+
if (!VALID_ZCMP_SPIMM (imm_expr->X_add_number))
3841+
break;
3842+
ip->insn_opcode |=
3843+
ENCODE_ZCMP_SPIMM (imm_expr->X_add_number);
3844+
goto rvc_imm_done;
36643845
case 'f': /* Operand for matching immediate 255. */
36653846
if (my_getSmallExpression (imm_expr, imm_reloc, asarg, p)
36663847
|| imm_expr->X_op != O_constant

gas/testsuite/gas/riscv/march-help.l

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ All available -march extensions for RISC-V:
8787
zcb 1.0
8888
zcf 1.0
8989
zcd 1.0
90+
zcmp 1.0
9091
smaia 1.0
9192
smcntrpmf 1.0
9293
smepmp 1.0
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
#as: -march=rv64i_zcmp
2+
#source: zcmp-push-pop-fail.s
3+
#error_output: zcmp-push-pop-fail.l
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.*: Assembler messages:
2+
.*: Error: illegal operands `cm.push \{a0\},-64'
3+
.*: Error: illegal operands `cm.pop \{ra,s1\},-64'
4+
.*: Error: illegal operands `cm.popret \{ra,s2-s3\},-64'
5+
.*: Error: illegal operands `cm.popretz \{ra,s0-s10\},-112'
6+
.*: Error: illegal operands `cm.push \{ra\},0'
7+
.*: Error: illegal operands `cm.pop \{ra,s0\},-80'
8+
.*: Error: illegal operands `cm.popret \{ra,s0-s1\},-15'
9+
.*: Error: illegal operands `cm.popretz \{ra,s0-s11\},-165'
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
target:
2+
3+
# reg_list
4+
cm.push {a0}, -64
5+
cm.pop {ra, s1}, -64
6+
cm.popret {ra, s2-s3}, -64
7+
cm.popretz {ra, s0-s10}, -112
8+
9+
# spimm
10+
cm.push {ra}, 0
11+
cm.pop {ra, s0}, -80
12+
cm.popret {ra, s0-s1}, -15
13+
cm.popretz {ra, s0-s11}, -165

0 commit comments

Comments
 (0)