From c3995500f1c3dafd3f2cf3f0eac14e47011ef0b4 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 | 77 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/src/riscv-codegen.c b/src/riscv-codegen.c index b7afe9a8..e58c41bf 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: @@ -307,10 +312,74 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir) } return; case OP_div: - emit(__div(rd, rs1, rs2)); + if (hard_mul_div) + emit(__div(rd, rs1, rs2)); + else { + /* 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, __t1)); + /* 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, __t0, 0)); + /* Handle the correct sign for the quotient */ + emit(__beq(__t5, __zero, 8)); + emit(__sub(rd, __zero, rd)); + } return; case OP_mod: - emit(__mod(rd, rs1, rs2)); + if (hard_mul_div) + emit(__mod(rd, rs1, rs2)); + else { + /* 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(__addi(__t5, __t0, 0)); + /* 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, __t2, 0)); + /* Handle the correct sign for the remainder */ + emit(__beq(__t5, __zero, 8)); + emit(__sub(rd, __zero, rd)); + } return; case OP_lshift: emit(__sll(rd, rs1, rs2));