riscv: asm: Add branch to label

This commit is contained in:
Ekaitz Zarraga 2024-04-24 00:37:46 +02:00
parent 671d03f944
commit 159776304f

View File

@ -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,12 +1450,6 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
case TOK_ASM_snez:
case TOK_ASM_sltz:
case TOK_ASM_sgtz:
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:
@ -1424,11 +1457,20 @@ ST_FUNC void asm_opcode(TCCState *s1, int token)
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:
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 */