From 159776304ff215c901344a661ad39662ece36a10 Mon Sep 17 00:00:00 2001 From: Ekaitz Zarraga Date: Wed, 24 Apr 2024 00:37:46 +0200 Subject: [PATCH] riscv: asm: Add branch to label --- riscv64-asm.c | 180 +++++++++++++++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 69 deletions(-) diff --git a/riscv64-asm.c b/riscv64-asm.c index 3c12345a5..355058f5b 100644 --- a/riscv64-asm.c +++ b/riscv64-asm.c @@ -66,8 +66,10 @@ static int asm_parse_csrvar(int t); ST_FUNC int asm_parse_regvar(int t); static void asm_ternary_opcode(TCCState *s1, int token); static void asm_unary_opcode(TCCState *s1, int token); +static void asm_branch_opcode(TCCState *s1, int token, int argc); ST_FUNC void gen_expr32(ExprValue *pe); static void parse_operand(TCCState *s1, Operand *op); +static void parse_branch_offset_operand(TCCState *s1, Operand *op); static void parse_operands(TCCState *s1, Operand *ops, int count); static void parse_mem_access_operands(TCCState *s1, Operand* ops); ST_FUNC void subst_asm_operand(CString *add_str, SValue *sv, int modifier); @@ -220,6 +222,28 @@ static void parse_operand(TCCState *s1, Operand *op) } } +static void parse_branch_offset_operand(TCCState *s1, Operand *op){ + ExprValue e = {0}; + + asm_expr(s1, &e); + op->type = OP_IM32; + op->e = e; + /* compare against unsigned 12-bit maximum */ + if (!op->e.sym) { + if ((int) op->e.v >= -0x1000 && (int) op->e.v < 0x1000) + op->type = OP_IM12S; + } else if (op->e.sym->type.t & (VT_EXTERN | VT_STATIC)) { + greloca(cur_text_section, op->e.sym, ind, R_RISCV_BRANCH, 0); + + /* XXX: Implement far branches */ + + op->type = OP_IM12S; + op->e.v = 0; + } else { + expect("operand"); + } +} + static void parse_operands(TCCState *s1, Operand* ops, int count){ int i; for (i = 0; i < count; i++) { @@ -664,30 +688,6 @@ static void asm_binary_opcode(TCCState* s1, int token) /* slt rd, zero, rs */ asm_emit_r(token, (0xC << 2) | 3 | (2 << 12), &ops[0], &zero, &ops[1]); return; - case TOK_ASM_bnez: - /* bne rs, zero, offset */ - asm_emit_b(token, 0x63 | (1 << 12), &ops[0], &zero, &ops[1]); - return; - case TOK_ASM_beqz: - /* bne rs, zero, offset */ - asm_emit_b(token, 0x63 | (0 << 12), &ops[0], &zero, &ops[1]); - return; - case TOK_ASM_blez: - /* bge rs, zero, offset */ - asm_emit_b(token, 0x63 | (5 << 12), &ops[0], &zero, &ops[1]); - return; - case TOK_ASM_bgez: - /* bge zero, rs, offset */ - asm_emit_b(token, 0x63 | (5 << 12), &zero, &ops[0], &ops[1]); - return; - case TOK_ASM_bltz: - /* blt rs, zero, offset */ - asm_emit_b(token, 0x63 | (4 << 12), &ops[0], &zero, &ops[1]); - return; - case TOK_ASM_bgtz: - /* blt zero, rs, offset */ - asm_emit_b(token, 0x63 | (4 << 12), &zero, &ops[0], &ops[1]); - return; default: expect("binary instruction"); @@ -840,6 +840,74 @@ static void asm_mem_access_opcode(TCCState *s1, int token) } } +static void asm_branch_opcode(TCCState *s1, int token, int argc){ + Operand ops[3]; + Operand zero = {.type = OP_REG}; + parse_operands(s1, &ops[0], argc-1); + if ( tok == ',') next(); else { expect(","); } + parse_branch_offset_operand(s1, &ops[argc-1]); + + switch(token){ + /* branch (RS1, RS2, IMM); B-format */ + case TOK_ASM_beq: + asm_emit_b(token, 0x63 | (0 << 12), ops, ops + 1, ops + 2); + return; + case TOK_ASM_bne: + asm_emit_b(token, 0x63 | (1 << 12), ops, ops + 1, ops + 2); + return; + case TOK_ASM_blt: + asm_emit_b(token, 0x63 | (4 << 12), ops, ops + 1, ops + 2); + return; + case TOK_ASM_bge: + asm_emit_b(token, 0x63 | (5 << 12), ops, ops + 1, ops + 2); + return; + case TOK_ASM_bltu: + asm_emit_b(token, 0x63 | (6 << 12), ops, ops + 1, ops + 2); + return; + case TOK_ASM_bgeu: + asm_emit_b(token, 0x63 | (7 << 12), ops, ops + 1, ops + 2); + return; + /* related pseudoinstructions */ + case TOK_ASM_bgt: + asm_emit_b(token, 0x63 | (4 << 12), ops + 1, ops, ops + 2); + return; + case TOK_ASM_ble: + asm_emit_b(token, 0x63 | (5 << 12), ops + 1, ops, ops + 2); + return; + case TOK_ASM_bgtu: + asm_emit_b(token, 0x63 | (6 << 12), ops + 1, ops, ops + 2); + return; + case TOK_ASM_bleu: + asm_emit_b(token, 0x63 | (7 << 12), ops + 1, ops, ops + 2); + return; + /* shorter pseudoinstructions */ + case TOK_ASM_bnez: + /* bne rs, zero, offset */ + asm_emit_b(token, 0x63 | (1 << 12), &ops[0], &zero, &ops[1]); + return; + case TOK_ASM_beqz: + /* bne rs, zero, offset */ + asm_emit_b(token, 0x63 | (0 << 12), &ops[0], &zero, &ops[1]); + return; + case TOK_ASM_blez: + /* bge rs, zero, offset */ + asm_emit_b(token, 0x63 | (5 << 12), &ops[0], &zero, &ops[1]); + return; + case TOK_ASM_bgez: + /* bge zero, rs, offset */ + asm_emit_b(token, 0x63 | (5 << 12), &zero, &ops[0], &ops[1]); + return; + case TOK_ASM_bltz: + /* blt rs, zero, offset */ + asm_emit_b(token, 0x63 | (4 << 12), &ops[0], &zero, &ops[1]); + return; + case TOK_ASM_bgtz: + /* blt zero, rs, offset */ + asm_emit_b(token, 0x63 | (4 << 12), &zero, &ops[0], &ops[1]); + return; + } +} + static void asm_ternary_opcode(TCCState *s1, int token) { Operand ops[3]; @@ -940,39 +1008,6 @@ static void asm_ternary_opcode(TCCState *s1, int token) asm_emit_i(token, (0x4 << 2) | 3 | (3 << 12), &ops[0], &ops[1], &ops[2]); return; - /* branch (RS1, RS2, IMM); B-format */ - case TOK_ASM_beq: - asm_emit_b(token, 0x63 | (0 << 12), ops, ops + 1, ops + 2); - return; - case TOK_ASM_bne: - asm_emit_b(token, 0x63 | (1 << 12), ops, ops + 1, ops + 2); - return; - case TOK_ASM_blt: - asm_emit_b(token, 0x63 | (4 << 12), ops, ops + 1, ops + 2); - return; - case TOK_ASM_bge: - asm_emit_b(token, 0x63 | (5 << 12), ops, ops + 1, ops + 2); - return; - case TOK_ASM_bltu: - asm_emit_b(token, 0x63 | (6 << 12), ops, ops + 1, ops + 2); - return; - case TOK_ASM_bgeu: - asm_emit_b(token, 0x63 | (7 << 12), ops, ops + 1, ops + 2); - return; - /* related pseudoinstructions */ - case TOK_ASM_bgt: - asm_emit_b(token, 0x63 | (4 << 12), ops + 1, ops, ops + 2); - return; - case TOK_ASM_ble: - asm_emit_b(token, 0x63 | (5 << 12), ops + 1, ops, ops + 2); - return; - case TOK_ASM_bgtu: - asm_emit_b(token, 0x63 | (6 << 12), ops + 1, ops, ops + 2); - return; - case TOK_ASM_bleu: - asm_emit_b(token, 0x63 | (7 << 12), ops + 1, ops, ops + 2); - return; - /* M extension */ case TOK_ASM_div: asm_emit_r(token, 0x33 | (4 << 12) | (1 << 25), ops, ops + 1, ops + 2); @@ -1284,12 +1319,6 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) case TOK_ASM_addw: case TOK_ASM_and: case TOK_ASM_andi: - case TOK_ASM_beq: - case TOK_ASM_bge: - case TOK_ASM_bgeu: - case TOK_ASM_blt: - case TOK_ASM_bltu: - case TOK_ASM_bne: case TOK_ASM_or: case TOK_ASM_ori: case TOK_ASM_sll: @@ -1336,6 +1365,16 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) asm_ternary_opcode(s1, token); return; + /* Branches */ + case TOK_ASM_beq: + case TOK_ASM_bge: + case TOK_ASM_bgeu: + case TOK_ASM_blt: + case TOK_ASM_bltu: + case TOK_ASM_bne: + asm_branch_opcode(s1, token, 3); + break; + /* C extension */ case TOK_ASM_c_ebreak: case TOK_ASM_c_nop: @@ -1411,24 +1450,27 @@ ST_FUNC void asm_opcode(TCCState *s1, int token) case TOK_ASM_snez: case TOK_ASM_sltz: case TOK_ASM_sgtz: + case TOK_ASM_mv: + case TOK_ASM_not: + case TOK_ASM_neg: + case TOK_ASM_negw: + asm_binary_opcode(s1, token); + return; + case TOK_ASM_bnez: case TOK_ASM_beqz: case TOK_ASM_blez: case TOK_ASM_bgez: case TOK_ASM_bltz: case TOK_ASM_bgtz: - case TOK_ASM_mv: - case TOK_ASM_not: - case TOK_ASM_neg: - case TOK_ASM_negw: - asm_binary_opcode(s1, token); + asm_branch_opcode(s1, token, 2); return; case TOK_ASM_bgt: case TOK_ASM_bgtu: case TOK_ASM_ble: case TOK_ASM_bleu: - asm_ternary_opcode(s1, token); + asm_branch_opcode(s1, token, 3); return; /* Atomic operations */