Skip to content

Commit 06e24e7

Browse files
committed
Implement some RV64F/D instructions
This patch implements some instructions required by musl 1.1.24.
1 parent 3c631fd commit 06e24e7

File tree

2 files changed

+155
-2
lines changed

2 files changed

+155
-2
lines changed

riscv64-asm.c

Lines changed: 142 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ static void asm_emit_opcode(uint32_t opcode);
6363
static void asm_emit_r(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
6464
static void asm_emit_s(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm);
6565
static void asm_emit_u(int token, uint32_t opcode, const Operand *rd, const Operand *rs2);
66+
static void asm_emit_f(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
67+
static void asm_emit_fb(int token, uint32_t opcode, const Operand *rd, const Operand *rs);
68+
static void asm_emit_fq(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2, const Operand *rs3);
6669
ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg);
6770
static void asm_nullary_opcode(TCCState *s1, int token);
6871
ST_FUNC void asm_opcode(TCCState *s1, int token);
@@ -587,6 +590,14 @@ static void asm_binary_opcode(TCCState* s1, int token)
587590
asm_emit_css(token, 2 | (5 << 13), ops, ops + 1);
588591
return;
589592

593+
/* F/D extension */
594+
case TOK_ASM_fsqrt_d:
595+
asm_emit_fb(token, 0x53 | (11 << 27) | (1 << 25) | (7 << 12), ops, ops + 1);
596+
return;
597+
case TOK_ASM_fsqrt_s:
598+
asm_emit_fb(token, 0x53 | (11 << 27) | (0 << 25) | (7 << 12), ops, ops + 1);
599+
return;
600+
590601
/* pseudoinstructions */
591602
/* rd, sym */
592603
case TOK_ASM_la:
@@ -682,6 +693,15 @@ static void asm_binary_opcode(TCCState* s1, int token)
682693
asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &zero, &ops[1]);
683694
return;
684695

696+
case TOK_ASM_fabs_d:
697+
/* fsgnjx.d rd, rs, rs */
698+
asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (2 << 12), &ops[0], &ops[1], &ops[1]);
699+
return;
700+
case TOK_ASM_fabs_s:
701+
/* fsgnjx.s rd, rs, rs */
702+
asm_emit_f(token, 0x53 | (4 << 27) | (0 << 25) | (2 << 12), &ops[0], &ops[1], &ops[1]);
703+
return;
704+
685705
default:
686706
expect("binary instruction");
687707
}
@@ -709,6 +729,73 @@ static void asm_emit_r(int token, uint32_t opcode, const Operand* rd, const Oper
709729
gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg));
710730
}
711731

732+
/* caller: Add rounding mode, fmt, funct5 to opcode */
733+
static void asm_emit_f(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2)
734+
{
735+
if (rd->type != OP_REG || !REG_IS_FLOAT(rd->reg)) {
736+
tcc_error("'%s': Expected destination operand that is a floating-point register", get_tok_str(token, NULL));
737+
}
738+
if (rs1->type != OP_REG || !REG_IS_FLOAT(rs1->reg)) {
739+
tcc_error("'%s': Expected first source operand that is a floating-point register", get_tok_str(token, NULL));
740+
}
741+
if (rs2->type != OP_REG || !REG_IS_FLOAT(rs2->reg)) {
742+
tcc_error("'%s': Expected second source operand that is a floating-point register", get_tok_str(token, NULL));
743+
}
744+
/* F-type instruction:
745+
31...27 funct5
746+
26...25 fmt
747+
24...20 rs2
748+
19...15 rs1
749+
14...12 rm
750+
11...7 rd
751+
6...0 opcode = OP-FP */
752+
gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg));
753+
}
754+
/* caller: Add rounding mode, fmt, funct5 to opcode */
755+
static void asm_emit_fb(int token, uint32_t opcode, const Operand* rd, const Operand* rs)
756+
{
757+
if (rd->type != OP_REG || !REG_IS_FLOAT(rd->reg)) {
758+
tcc_error("'%s': Expected destination operand that is a floating-point register", get_tok_str(token, NULL));
759+
}
760+
if (rs->type != OP_REG || !REG_IS_FLOAT(rs->reg)) {
761+
tcc_error("'%s': Expected source operand that is a floating-point register", get_tok_str(token, NULL));
762+
}
763+
/* F-type instruction:
764+
31...27 funct5
765+
26...25 fmt
766+
24...20 rs2 = 0
767+
19...15 rs1 = rs
768+
14...12 rm
769+
11...7 rd
770+
6...0 opcode = OP-FP */
771+
gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs->reg) | ENCODE_RS2(0));
772+
}
773+
/* caller: Add rounding mode, fmt to opcode */
774+
static void asm_emit_fq(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2, const Operand* rs3)
775+
{
776+
if (rd->type != OP_REG || !REG_IS_FLOAT(rd->reg)) {
777+
tcc_error("'%s': Expected destination operand that is a floating-point register", get_tok_str(token, NULL));
778+
}
779+
if (rs1->type != OP_REG || !REG_IS_FLOAT(rs1->reg)) {
780+
tcc_error("'%s': Expected first source operand that is a floating-point register", get_tok_str(token, NULL));
781+
}
782+
if (rs2->type != OP_REG || !REG_IS_FLOAT(rs2->reg)) {
783+
tcc_error("'%s': Expected second source operand that is a floating-point register", get_tok_str(token, NULL));
784+
}
785+
if (rs3->type != OP_REG || !REG_IS_FLOAT(rs3->reg)) {
786+
tcc_error("'%s': Expected third source operand that is a floating-point register", get_tok_str(token, NULL));
787+
}
788+
/* F-type instruction:
789+
31...27 rs3
790+
26...25 fmt
791+
24...20 rs2
792+
19...15 rs1
793+
14...12 rm
794+
11...7 rd
795+
6...0 opcode */
796+
gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | (REG_VALUE(rs3->reg) << 27));
797+
}
798+
712799
/* caller: Add funct3 into opcode */
713800
static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2)
714801
{
@@ -1089,11 +1176,49 @@ static void asm_ternary_opcode(TCCState *s1, int token)
10891176
asm_emit_cs(token, 6 << 13, ops, ops + 1, ops + 2);
10901177
return;
10911178

1179+
/* F/D extension */
1180+
case TOK_ASM_fsgnj_d:
1181+
asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2);
1182+
return;
1183+
case TOK_ASM_fsgnj_s:
1184+
asm_emit_f(token, 0x53 | (4 << 27) | (0 << 25) | (0 << 12), ops, ops + 1, ops + 2);
1185+
return;
1186+
case TOK_ASM_fmax_d:
1187+
asm_emit_f(token, 0x53 | (5 << 27) | (1 << 25) | (1 << 12), ops, ops + 1, ops + 2);
1188+
return;
1189+
case TOK_ASM_fmax_s:
1190+
asm_emit_f(token, 0x53 | (5 << 27) | (0 << 25) | (1 << 12), ops, ops + 1, ops + 2);
1191+
return;
1192+
case TOK_ASM_fmin_d:
1193+
asm_emit_f(token, 0x53 | (5 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2);
1194+
return;
1195+
case TOK_ASM_fmin_s:
1196+
asm_emit_f(token, 0x53 | (5 << 27) | (0 << 25) | (0 << 12), ops, ops + 1, ops + 2);
1197+
return;
1198+
10921199
default:
10931200
expect("ternary instruction");
10941201
}
10951202
}
10961203

1204+
static void asm_quaternary_opcode(TCCState *s1, int token)
1205+
{
1206+
Operand ops[4];
1207+
parse_operands(s1, &ops[0], 4);
1208+
1209+
switch (token) {
1210+
case TOK_ASM_fmadd_d:
1211+
asm_emit_fq(token, 0x43 | (1 << 25) | (7 << 12), ops, ops + 1, ops + 2, ops + 3);
1212+
return;
1213+
case TOK_ASM_fmadd_s:
1214+
asm_emit_fq(token, 0x43 | (0 << 25) | (7 << 12), ops, ops + 1, ops + 2, ops + 3);
1215+
return;
1216+
1217+
default:
1218+
expect("quaternary instruction");
1219+
}
1220+
}
1221+
10971222
static void asm_atomic_opcode(TCCState *s1, int token)
10981223
{
10991224
Operand ops[3];
@@ -1271,6 +1396,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
12711396

12721397
case TOK_ASM_lui:
12731398
case TOK_ASM_auipc:
1399+
case TOK_ASM_fsqrt_s:
1400+
case TOK_ASM_fsqrt_d:
12741401
asm_binary_opcode(s1, token);
12751402
return;
12761403

@@ -1349,8 +1476,19 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
13491476
case TOK_ASM_csrrsi:
13501477
case TOK_ASM_csrrw:
13511478
case TOK_ASM_csrrwi:
1479+
/* F/D extension */
1480+
case TOK_ASM_fsgnj_d:
1481+
case TOK_ASM_fsgnj_s:
1482+
case TOK_ASM_fmax_s:
1483+
case TOK_ASM_fmax_d:
1484+
case TOK_ASM_fmin_s:
1485+
case TOK_ASM_fmin_d:
13521486
asm_ternary_opcode(s1, token);
13531487
return;
1488+
case TOK_ASM_fmadd_d:
1489+
case TOK_ASM_fmadd_s:
1490+
asm_quaternary_opcode(s1, token);
1491+
return;
13541492

13551493
/* Branches */
13561494
case TOK_ASM_beq:
@@ -1441,6 +1579,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
14411579
case TOK_ASM_not:
14421580
case TOK_ASM_neg:
14431581
case TOK_ASM_negw:
1582+
case TOK_ASM_fabs_s:
1583+
case TOK_ASM_fabs_d:
14441584
asm_binary_opcode(s1, token);
14451585
return;
14461586

@@ -1556,7 +1696,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
15561696
if ((sv->type.t & VT_BTYPE) == VT_FLOAT ||
15571697
(sv->type.t & VT_BTYPE) == VT_DOUBLE) {
15581698
/* floating point register */
1559-
reg = TOK_ASM_f0 + reg;
1699+
reg = TOK_ASM_f0 + REG_VALUE(reg);
15601700
} else {
15611701
/* general purpose register */
15621702
reg = TOK_ASM_x0 + reg;
@@ -1570,7 +1710,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
15701710
if ((sv->type.t & VT_BTYPE) == VT_FLOAT ||
15711711
(sv->type.t & VT_BTYPE) == VT_DOUBLE) {
15721712
/* floating point register */
1573-
reg = TOK_ASM_f0 + reg;
1713+
reg = TOK_ASM_f0 + REG_VALUE(reg);
15741714
} else {
15751715
/* general purpose register */
15761716
reg = TOK_ASM_x0 + reg;

riscv64-tok.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,19 @@
266266
DEF_ASM(remw)
267267
DEF_ASM(remuw)
268268

269+
/* "F"/"D" Extension for Single/Double-Precision Floating Point Arithmetic, V2.2 */
270+
/* enough implemented for musl */
271+
DEF_ASM_WITH_SUFFIX(fsgnj, s)
272+
DEF_ASM_WITH_SUFFIX(fsgnj, d)
273+
DEF_ASM_WITH_SUFFIX(fmadd, s)
274+
DEF_ASM_WITH_SUFFIX(fmadd, d)
275+
DEF_ASM_WITH_SUFFIX(fmax, s)
276+
DEF_ASM_WITH_SUFFIX(fmax, d)
277+
DEF_ASM_WITH_SUFFIX(fmin, s)
278+
DEF_ASM_WITH_SUFFIX(fmin, d)
279+
DEF_ASM_WITH_SUFFIX(fsqrt, s)
280+
DEF_ASM_WITH_SUFFIX(fsqrt, d)
281+
269282
/* "C" Extension for Compressed Instructions, V2.0 */
270283
DEF_ASM_WITH_SUFFIX(c, nop)
271284
/* Loads */

0 commit comments

Comments
 (0)