From 17fe9fd226606d4128227fae8a1a45bd6acc401c Mon Sep 17 00:00:00 2001 From: "Dr.Xiao" Date: Thu, 20 Jun 2024 23:19:44 +0800 Subject: [PATCH] Implement division and modulo for RV32I This commit allows shecc to generate a sequence of instructions to perform division or modulo for RISC-V targets with RV32I only. Close #46 --- src/riscv-codegen.c | 62 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/src/riscv-codegen.c b/src/riscv-codegen.c index b7afe9a8..6d10d162 100644 --- a/src/riscv-codegen.c +++ b/src/riscv-codegen.c @@ -50,8 +50,6 @@ void update_elf_offset(ph2_ir_t *ph2_ir) case OP_indirect: case OP_add: case OP_sub: - case OP_div: - case OP_mod: case OP_lshift: case OP_rshift: case OP_gt: @@ -70,6 +68,13 @@ void update_elf_offset(ph2_ir_t *ph2_ir) else elf_offset += 52; return; + case OP_div: + case OP_mod: + if (hard_mul_div) + elf_offset += 4; + else + elf_offset += 104; + return; case OP_load_data_address: case OP_neq: case OP_geq: @@ -152,6 +157,11 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) int rs2 = ph2_ir->src1 + 10; int ofs; + /* Prepare the variables to reuse the same code for + * the instruction sequence of division and modulo. + */ + rv_reg soft_div_rd = __t0, divisor_mask = __t1; + switch (ph2_ir->op) { case OP_define: emit(__lui(__t0, rv_hi(ph2_ir->src0 + 4))); @@ -307,10 +317,52 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) } return; case OP_div: - emit(__div(rd, rs1, rs2)); - return; case OP_mod: - emit(__mod(rd, rs1, rs2)); + if (hard_mul_div) { + if (ph2_ir->op == OP_div) + emit(__div(rd, rs1, rs2)); + else + emit(__mod(rd, rs1, rs2)); + return; + } + /* div/mod emulation */ + if (ph2_ir->op == OP_mod) { + /* If the requested operation is modulo, the result will be stored + * in __t2. The sign of the divisor is irrelevant for determining + * the result's sign. + */ + soft_div_rd = __t2; + divisor_mask = __zero; + } + /* Obtain absolute values of the dividend and divisor */ + emit(__addi(__t2, rs1, 0)); + emit(__addi(__t3, rs2, 0)); + emit(__srai(__t0, __t2, 31)); + emit(__add(__t2, __t2, __t0)); + emit(__xor(__t2, __t2, __t0)); + emit(__srai(__t1, __t3, 31)); + emit(__add(__t3, __t3, __t1)); + emit(__xor(__t3, __t3, __t1)); + emit(__xor(__t5, __t0, divisor_mask)); + /* Unsigned integer division */ + emit(__addi(__t0, __zero, 0)); + emit(__addi(__t1, __zero, 1)); + emit(__beq(__t3, __zero, 48)); + emit(__beq(__t2, __zero, 44)); + emit(__bltu(__t2, __t3, 16)); + emit(__slli(__t3, __t3, 1)); + emit(__slli(__t1, __t1, 1)); + emit(__jal(__zero, -12)); + emit(__bltu(__t2, __t3, 12)); + emit(__sub(__t2, __t2, __t3)); + emit(__add(__t0, __t0, __t1)); + emit(__srli(__t1, __t1, 1)); + emit(__srli(__t3, __t3, 1)); + emit(__bne(__t1, __zero, -20)); + emit(__addi(rd, soft_div_rd, 0)); + /* Handle the correct sign for the quotient or remainder */ + emit(__beq(__t5, __zero, 8)); + emit(__sub(rd, __zero, rd)); return; case OP_lshift: emit(__sll(rd, rs1, rs2));