mirror of
git://repo.or.cz/tinycc.git
synced 2026-06-17 15:44:18 +08:00
Implement some RV64F/D instructions
This patch implements some instructions required by musl 1.1.24.
This commit is contained in:
parent
3c631fdb6d
commit
06e24e7eed
144
riscv64-asm.c
144
riscv64-asm.c
@ -63,6 +63,9 @@ static void asm_emit_opcode(uint32_t opcode);
|
||||
static void asm_emit_r(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
|
||||
static void asm_emit_s(int token, uint32_t opcode, const Operand *rs1, const Operand *rs2, const Operand *imm);
|
||||
static void asm_emit_u(int token, uint32_t opcode, const Operand *rd, const Operand *rs2);
|
||||
static void asm_emit_f(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2);
|
||||
static void asm_emit_fb(int token, uint32_t opcode, const Operand *rd, const Operand *rs);
|
||||
static void asm_emit_fq(int token, uint32_t opcode, const Operand *rd, const Operand *rs1, const Operand *rs2, const Operand *rs3);
|
||||
ST_FUNC void asm_gen_code(ASMOperand *operands, int nb_operands, int nb_outputs, int is_output, uint8_t *clobber_regs, int out_reg);
|
||||
static void asm_nullary_opcode(TCCState *s1, int token);
|
||||
ST_FUNC void asm_opcode(TCCState *s1, int token);
|
||||
@ -587,6 +590,14 @@ static void asm_binary_opcode(TCCState* s1, int token)
|
||||
asm_emit_css(token, 2 | (5 << 13), ops, ops + 1);
|
||||
return;
|
||||
|
||||
/* F/D extension */
|
||||
case TOK_ASM_fsqrt_d:
|
||||
asm_emit_fb(token, 0x53 | (11 << 27) | (1 << 25) | (7 << 12), ops, ops + 1);
|
||||
return;
|
||||
case TOK_ASM_fsqrt_s:
|
||||
asm_emit_fb(token, 0x53 | (11 << 27) | (0 << 25) | (7 << 12), ops, ops + 1);
|
||||
return;
|
||||
|
||||
/* pseudoinstructions */
|
||||
/* rd, sym */
|
||||
case TOK_ASM_la:
|
||||
@ -682,6 +693,15 @@ static void asm_binary_opcode(TCCState* s1, int token)
|
||||
asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &zero, &ops[1]);
|
||||
return;
|
||||
|
||||
case TOK_ASM_fabs_d:
|
||||
/* fsgnjx.d rd, rs, rs */
|
||||
asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (2 << 12), &ops[0], &ops[1], &ops[1]);
|
||||
return;
|
||||
case TOK_ASM_fabs_s:
|
||||
/* fsgnjx.s rd, rs, rs */
|
||||
asm_emit_f(token, 0x53 | (4 << 27) | (0 << 25) | (2 << 12), &ops[0], &ops[1], &ops[1]);
|
||||
return;
|
||||
|
||||
default:
|
||||
expect("binary instruction");
|
||||
}
|
||||
@ -709,6 +729,73 @@ static void asm_emit_r(int token, uint32_t opcode, const Operand* rd, const Oper
|
||||
gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg));
|
||||
}
|
||||
|
||||
/* caller: Add rounding mode, fmt, funct5 to opcode */
|
||||
static void asm_emit_f(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2)
|
||||
{
|
||||
if (rd->type != OP_REG || !REG_IS_FLOAT(rd->reg)) {
|
||||
tcc_error("'%s': Expected destination operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
if (rs1->type != OP_REG || !REG_IS_FLOAT(rs1->reg)) {
|
||||
tcc_error("'%s': Expected first source operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
if (rs2->type != OP_REG || !REG_IS_FLOAT(rs2->reg)) {
|
||||
tcc_error("'%s': Expected second source operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
/* F-type instruction:
|
||||
31...27 funct5
|
||||
26...25 fmt
|
||||
24...20 rs2
|
||||
19...15 rs1
|
||||
14...12 rm
|
||||
11...7 rd
|
||||
6...0 opcode = OP-FP */
|
||||
gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg));
|
||||
}
|
||||
/* caller: Add rounding mode, fmt, funct5 to opcode */
|
||||
static void asm_emit_fb(int token, uint32_t opcode, const Operand* rd, const Operand* rs)
|
||||
{
|
||||
if (rd->type != OP_REG || !REG_IS_FLOAT(rd->reg)) {
|
||||
tcc_error("'%s': Expected destination operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
if (rs->type != OP_REG || !REG_IS_FLOAT(rs->reg)) {
|
||||
tcc_error("'%s': Expected source operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
/* F-type instruction:
|
||||
31...27 funct5
|
||||
26...25 fmt
|
||||
24...20 rs2 = 0
|
||||
19...15 rs1 = rs
|
||||
14...12 rm
|
||||
11...7 rd
|
||||
6...0 opcode = OP-FP */
|
||||
gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs->reg) | ENCODE_RS2(0));
|
||||
}
|
||||
/* caller: Add rounding mode, fmt to opcode */
|
||||
static void asm_emit_fq(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2, const Operand* rs3)
|
||||
{
|
||||
if (rd->type != OP_REG || !REG_IS_FLOAT(rd->reg)) {
|
||||
tcc_error("'%s': Expected destination operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
if (rs1->type != OP_REG || !REG_IS_FLOAT(rs1->reg)) {
|
||||
tcc_error("'%s': Expected first source operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
if (rs2->type != OP_REG || !REG_IS_FLOAT(rs2->reg)) {
|
||||
tcc_error("'%s': Expected second source operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
if (rs3->type != OP_REG || !REG_IS_FLOAT(rs3->reg)) {
|
||||
tcc_error("'%s': Expected third source operand that is a floating-point register", get_tok_str(token, NULL));
|
||||
}
|
||||
/* F-type instruction:
|
||||
31...27 rs3
|
||||
26...25 fmt
|
||||
24...20 rs2
|
||||
19...15 rs1
|
||||
14...12 rm
|
||||
11...7 rd
|
||||
6...0 opcode */
|
||||
gen_le32(opcode | ENCODE_RD(rd->reg) | ENCODE_RS1(rs1->reg) | ENCODE_RS2(rs2->reg) | (REG_VALUE(rs3->reg) << 27));
|
||||
}
|
||||
|
||||
/* caller: Add funct3 into opcode */
|
||||
static void asm_emit_i(int token, uint32_t opcode, const Operand* rd, const Operand* rs1, const Operand* rs2)
|
||||
{
|
||||
@ -1089,11 +1176,49 @@ static void asm_ternary_opcode(TCCState *s1, int token)
|
||||
asm_emit_cs(token, 6 << 13, ops, ops + 1, ops + 2);
|
||||
return;
|
||||
|
||||
/* F/D extension */
|
||||
case TOK_ASM_fsgnj_d:
|
||||
asm_emit_f(token, 0x53 | (4 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2);
|
||||
return;
|
||||
case TOK_ASM_fsgnj_s:
|
||||
asm_emit_f(token, 0x53 | (4 << 27) | (0 << 25) | (0 << 12), ops, ops + 1, ops + 2);
|
||||
return;
|
||||
case TOK_ASM_fmax_d:
|
||||
asm_emit_f(token, 0x53 | (5 << 27) | (1 << 25) | (1 << 12), ops, ops + 1, ops + 2);
|
||||
return;
|
||||
case TOK_ASM_fmax_s:
|
||||
asm_emit_f(token, 0x53 | (5 << 27) | (0 << 25) | (1 << 12), ops, ops + 1, ops + 2);
|
||||
return;
|
||||
case TOK_ASM_fmin_d:
|
||||
asm_emit_f(token, 0x53 | (5 << 27) | (1 << 25) | (0 << 12), ops, ops + 1, ops + 2);
|
||||
return;
|
||||
case TOK_ASM_fmin_s:
|
||||
asm_emit_f(token, 0x53 | (5 << 27) | (0 << 25) | (0 << 12), ops, ops + 1, ops + 2);
|
||||
return;
|
||||
|
||||
default:
|
||||
expect("ternary instruction");
|
||||
}
|
||||
}
|
||||
|
||||
static void asm_quaternary_opcode(TCCState *s1, int token)
|
||||
{
|
||||
Operand ops[4];
|
||||
parse_operands(s1, &ops[0], 4);
|
||||
|
||||
switch (token) {
|
||||
case TOK_ASM_fmadd_d:
|
||||
asm_emit_fq(token, 0x43 | (1 << 25) | (7 << 12), ops, ops + 1, ops + 2, ops + 3);
|
||||
return;
|
||||
case TOK_ASM_fmadd_s:
|
||||
asm_emit_fq(token, 0x43 | (0 << 25) | (7 << 12), ops, ops + 1, ops + 2, ops + 3);
|
||||
return;
|
||||
|
||||
default:
|
||||
expect("quaternary instruction");
|
||||
}
|
||||
}
|
||||
|
||||
static void asm_atomic_opcode(TCCState *s1, int token)
|
||||
{
|
||||
Operand ops[3];
|
||||
@ -1271,6 +1396,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
|
||||
|
||||
case TOK_ASM_lui:
|
||||
case TOK_ASM_auipc:
|
||||
case TOK_ASM_fsqrt_s:
|
||||
case TOK_ASM_fsqrt_d:
|
||||
asm_binary_opcode(s1, token);
|
||||
return;
|
||||
|
||||
@ -1349,8 +1476,19 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
|
||||
case TOK_ASM_csrrsi:
|
||||
case TOK_ASM_csrrw:
|
||||
case TOK_ASM_csrrwi:
|
||||
/* F/D extension */
|
||||
case TOK_ASM_fsgnj_d:
|
||||
case TOK_ASM_fsgnj_s:
|
||||
case TOK_ASM_fmax_s:
|
||||
case TOK_ASM_fmax_d:
|
||||
case TOK_ASM_fmin_s:
|
||||
case TOK_ASM_fmin_d:
|
||||
asm_ternary_opcode(s1, token);
|
||||
return;
|
||||
case TOK_ASM_fmadd_d:
|
||||
case TOK_ASM_fmadd_s:
|
||||
asm_quaternary_opcode(s1, token);
|
||||
return;
|
||||
|
||||
/* Branches */
|
||||
case TOK_ASM_beq:
|
||||
@ -1441,6 +1579,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
|
||||
case TOK_ASM_not:
|
||||
case TOK_ASM_neg:
|
||||
case TOK_ASM_negw:
|
||||
case TOK_ASM_fabs_s:
|
||||
case TOK_ASM_fabs_d:
|
||||
asm_binary_opcode(s1, token);
|
||||
return;
|
||||
|
||||
@ -1556,7 +1696,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
|
||||
if ((sv->type.t & VT_BTYPE) == VT_FLOAT ||
|
||||
(sv->type.t & VT_BTYPE) == VT_DOUBLE) {
|
||||
/* floating point register */
|
||||
reg = TOK_ASM_f0 + reg;
|
||||
reg = TOK_ASM_f0 + REG_VALUE(reg);
|
||||
} else {
|
||||
/* general purpose register */
|
||||
reg = TOK_ASM_x0 + reg;
|
||||
@ -1570,7 +1710,7 @@ ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier)
|
||||
if ((sv->type.t & VT_BTYPE) == VT_FLOAT ||
|
||||
(sv->type.t & VT_BTYPE) == VT_DOUBLE) {
|
||||
/* floating point register */
|
||||
reg = TOK_ASM_f0 + reg;
|
||||
reg = TOK_ASM_f0 + REG_VALUE(reg);
|
||||
} else {
|
||||
/* general purpose register */
|
||||
reg = TOK_ASM_x0 + reg;
|
||||
|
||||
@ -266,6 +266,19 @@
|
||||
DEF_ASM(remw)
|
||||
DEF_ASM(remuw)
|
||||
|
||||
/* "F"/"D" Extension for Single/Double-Precision Floating Point Arithmetic, V2.2 */
|
||||
/* enough implemented for musl */
|
||||
DEF_ASM_WITH_SUFFIX(fsgnj, s)
|
||||
DEF_ASM_WITH_SUFFIX(fsgnj, d)
|
||||
DEF_ASM_WITH_SUFFIX(fmadd, s)
|
||||
DEF_ASM_WITH_SUFFIX(fmadd, d)
|
||||
DEF_ASM_WITH_SUFFIX(fmax, s)
|
||||
DEF_ASM_WITH_SUFFIX(fmax, d)
|
||||
DEF_ASM_WITH_SUFFIX(fmin, s)
|
||||
DEF_ASM_WITH_SUFFIX(fmin, d)
|
||||
DEF_ASM_WITH_SUFFIX(fsqrt, s)
|
||||
DEF_ASM_WITH_SUFFIX(fsqrt, d)
|
||||
|
||||
/* "C" Extension for Compressed Instructions, V2.0 */
|
||||
DEF_ASM_WITH_SUFFIX(c, nop)
|
||||
/* Loads */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user