From 671d03f944f160471dca33cdb29b9b99c5ac269d Mon Sep 17 00:00:00 2001 From: Ekaitz Zarraga Date: Tue, 23 Apr 2024 15:01:05 +0200 Subject: [PATCH] riscv: Add full `fence` instruction support This commit adds support for `fence`'s predecessor and successor arguments. --- riscv64-asm.c | 36 ++++++++++++++++++++++++++++++++---- riscv64-tok.h | 24 ++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/riscv64-asm.c b/riscv64-asm.c index 26288605..3c12345a 100644 --- a/riscv64-asm.c +++ b/riscv64-asm.c @@ -132,9 +132,6 @@ static void asm_nullary_opcode(TCCState *s1, int token) switch (token) { // Sync instructions - case TOK_ASM_fence: // I - asm_emit_opcode((0x3 << 2) | 3 | (0 << 12)); - return; case TOK_ASM_fence_i: // I asm_emit_opcode((0x3 << 2) | 3| (1 << 12)); return; @@ -435,6 +432,34 @@ static void asm_emit_u(int token, uint32_t opcode, const Operand* rd, const Oper gen_le32(opcode | ENCODE_RD(rd->reg) | (rs2->e.v << 12)); } +static int parse_fence_operand(){ + int t = tok; + if ( tok == TOK_ASM_or ){ + // we are in a fence instruction, parse as output read + t = TOK_ASM_or_fence; + } + next(); + return t - (TOK_ASM_w_fence - 1); +} + +static void asm_fence_opcode(TCCState *s1, int token){ + // `fence` is both an instruction and a pseudoinstruction: + // `fence` expands to `fence iorw, iorw` + int succ = 0xF, pred = 0xF; + if (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF){ + pred = parse_fence_operand(); + if ( pred > 0xF || pred < 0) { + tcc_error("'%s': Expected first operand that is a valid predecessor operand", get_tok_str(token, NULL)); + } + if ( tok == ',') next(); else expect("','"); + succ = parse_fence_operand(); + if ( succ > 0xF || succ < 0) { + tcc_error("'%s': Expected second operand that is a valid successor operand", get_tok_str(token, NULL)); + } + } + asm_emit_opcode((0x3 << 2) | 3 | (0 << 12) | succ<<20 | pred<<24); +} + static void asm_binary_opcode(TCCState* s1, int token) { static const Operand zero = {.type = OP_REG, .reg = 0}; @@ -1206,7 +1231,6 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) switch (token) { case TOK_ASM_ebreak: case TOK_ASM_ecall: - case TOK_ASM_fence: // XXX: it's missing iorw for pred and succ case TOK_ASM_fence_i: case TOK_ASM_hrts: case TOK_ASM_mrth: @@ -1215,6 +1239,10 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) asm_nullary_opcode(s1, token); return; + case TOK_ASM_fence: + asm_fence_opcode(s1, token); + return; + case TOK_ASM_rdcycle: case TOK_ASM_rdcycleh: case TOK_ASM_rdtime: diff --git a/riscv64-tok.h b/riscv64-tok.h index 67fc91a3..eeaa29c6 100644 --- a/riscv64-tok.h +++ b/riscv64-tok.h @@ -11,6 +11,9 @@ #define DEF_ASM_WITH_SUFFIXES(x, y, z) \ DEF(TOK_ASM_ ## x ## _ ## y ## _ ## z, #x "." #y "." #z) +#define DEF_ASM_FENCE(x) \ + DEF(TOK_ASM_ ## x ## _fence, #x) + /* register */ /* integer */ DEF_ASM(x0) @@ -448,4 +451,25 @@ DEF_ASM_WITH_SUFFIXES(sc, d, rl) DEF_ASM_WITH_SUFFIXES(sc, d, aqrl) +/* `fence` arguments */ +/* NOTE: Order is important */ + DEF_ASM_FENCE(w) + DEF_ASM_FENCE(r) + DEF_ASM_FENCE(rw) + + DEF_ASM_FENCE(o) + DEF_ASM_FENCE(ow) + DEF_ASM_FENCE(or) + DEF_ASM_FENCE(orw) + + DEF_ASM_FENCE(i) + DEF_ASM_FENCE(iw) + DEF_ASM_FENCE(ir) + DEF_ASM_FENCE(irw) + + DEF_ASM_FENCE(io) + DEF_ASM_FENCE(iow) + DEF_ASM_FENCE(ior) + DEF_ASM_FENCE(iorw) + #undef DEF_ASM_WITH_SUFFIX