Skip to content

Commit 4f2cb0c

Browse files
committed
Improve the division emulation in the Arm backend
This commit improves the division emulation in the Arm backend to enhance code reusability and eliminate potential issues. Close #135
1 parent 6cdd7e2 commit 4f2cb0c

File tree

2 files changed

+84
-76
lines changed

2 files changed

+84
-76
lines changed

src/arm-codegen.c

Lines changed: 71 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -85,18 +85,16 @@ void update_elf_offset(ph2_ir_t *ph2_ir)
8585
elf_offset += 4;
8686
return;
8787
case OP_div:
88-
if (hard_mul_div) {
89-
elf_offset += 4;
90-
} else {
91-
elf_offset += 104;
92-
}
93-
return;
9488
case OP_mod:
9589
if (hard_mul_div) {
96-
elf_offset += 12;
97-
} else {
98-
elf_offset += 104;
90+
if (ph2_ir->op == OP_div)
91+
elf_offset += 4;
92+
else
93+
elf_offset += 12;
94+
return;
9995
}
96+
/* div/mod emulation's offset */
97+
elf_offset += 116;
10098
return;
10199
case OP_load_data_address:
102100
elf_offset += 8;
@@ -193,6 +191,11 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir)
193191
int rm = ph2_ir->src1;
194192
int ofs;
195193

194+
/* Prepare this variable to reuse the same code for
195+
* the instruction sequence of division and modulo.
196+
*/
197+
arm_reg soft_div_rd = __r8;
198+
196199
switch (ph2_ir->op) {
197200
case OP_define:
198201
emit(__sw(__AL, __lr, __sp, -4));
@@ -335,76 +338,69 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir)
335338
emit(__mul(__AL, rd, rn, rm));
336339
return;
337340
case OP_div:
338-
if (hard_mul_div) {
339-
emit(__div(__AL, rd, rm, rn));
340-
} else {
341-
/* Obtain absolute values of dividend and divisor */
342-
emit(__srl_amt(__AL, 0, arith_rs, __r8, rn, 31));
343-
emit(__add_r(__AL, rn, rn, __r8));
344-
emit(__eor_r(__AL, rn, rn, __r8));
345-
emit(__srl_amt(__AL, 0, arith_rs, __r9, rm, 31));
346-
emit(__add_r(__AL, rm, rm, __r9));
347-
emit(__eor_r(__AL, rm, rm, __r9));
348-
emit(__eor_r(__AL, __r10, __r8, __r9));
349-
/* Unsigned integer division */
350-
emit(__zero(__r9));
351-
emit(__mov_i(__AL, __r8, 1));
352-
emit(__cmp_i(__AL, rm, 0));
353-
emit(__b(__EQ, 52));
354-
emit(__cmp_i(__AL, rn, 0));
355-
emit(__b(__EQ, 44));
356-
emit(__cmp_r(__AL, rm, rn));
357-
emit(__sll_amt(__CC, 0, logic_ls, rm, rm, 1));
358-
emit(__sll_amt(__CC, 0, logic_ls, __r8, __r8, 1));
359-
emit(__b(__CC, -12));
360-
emit(__cmp_r(__AL, rn, rm));
361-
emit(__sub_r(__CS, rn, rn, rm));
362-
emit(__add_r(__CS, __r9, __r9, __r8));
363-
emit(__srl_amt(__AL, 1, logic_rs, __r8, __r8, 1));
364-
emit(__srl_amt(__CC, 0, logic_rs, rm, rm, 1));
365-
emit(__b(__CC, -20));
366-
emit(__mov_r(__AL, rd, __r9));
367-
/* Handle the correct sign for quotient */
368-
emit(__cmp_i(__AL, __r10, 0));
369-
emit(__rsb_i(__NE, rd, 0, rd));
370-
}
371-
return;
372341
case OP_mod:
373342
if (hard_mul_div) {
374-
emit(__div(__AL, __r8, rm, rn));
375-
emit(__mul(__AL, __r8, rm, __r8));
376-
emit(__sub_r(__AL, rd, rn, __r8));
377-
} else {
378-
/* Obtain absolute values of dividend and divisor */
379-
emit(__srl_amt(__AL, 0, arith_rs, __r8, rn, 31));
380-
emit(__add_r(__AL, rn, rn, __r8));
381-
emit(__eor_r(__AL, rn, rn, __r8));
382-
emit(__srl_amt(__AL, 0, arith_rs, __r9, rm, 31));
383-
emit(__add_r(__AL, rm, rm, __r9));
384-
emit(__eor_r(__AL, rm, rm, __r9));
343+
if (ph2_ir->op == OP_div)
344+
emit(__div(__AL, rd, rm, rn));
345+
else {
346+
emit(__div(__AL, __r8, rm, rn));
347+
emit(__mul(__AL, __r8, rm, __r8));
348+
emit(__sub_r(__AL, rd, rn, __r8));
349+
}
350+
return;
351+
}
352+
/* div/mod emulation */
353+
/* Preserve the values of the dividend and divisor */
354+
emit(__stmdb(__AL, 1, __sp, (1 << rn) | (1 << rm)));
355+
/* Obtain absolute values of the dividend and divisor */
356+
emit(__srl_amt(__AL, 0, arith_rs, __r8, rn, 31));
357+
emit(__add_r(__AL, rn, rn, __r8));
358+
emit(__eor_r(__AL, rn, rn, __r8));
359+
emit(__srl_amt(__AL, 0, arith_rs, __r9, rm, 31));
360+
emit(__add_r(__AL, rm, rm, __r9));
361+
emit(__eor_r(__AL, rm, rm, __r9));
362+
if (ph2_ir->op == OP_div)
363+
emit(__eor_r(__AL, __r10, __r8, __r9));
364+
else {
365+
/* If the requested operation is modulo, the result will be stored
366+
* in __r9. The sign of the divisor is irrelevant for determining
367+
* the result's sign.
368+
*/
369+
soft_div_rd = __r9;
385370
emit(__mov_r(__AL, __r10, __r8));
386-
/* Unsigned integer division */
387-
emit(__zero(__r9));
388-
emit(__mov_i(__AL, __r8, 1));
389-
emit(__cmp_i(__AL, rm, 0));
390-
emit(__b(__EQ, 52));
391-
emit(__cmp_i(__AL, rn, 0));
392-
emit(__b(__EQ, 44));
393-
emit(__cmp_r(__AL, rm, rn));
394-
emit(__sll_amt(__CC, 0, logic_ls, rm, rm, 1));
395-
emit(__sll_amt(__CC, 0, logic_ls, __r8, __r8, 1));
396-
emit(__b(__CC, -12));
397-
emit(__cmp_r(__AL, rn, rm));
398-
emit(__sub_r(__CS, rn, rn, rm));
399-
emit(__add_r(__CS, __r9, __r9, __r8));
400-
emit(__srl_amt(__AL, 1, logic_rs, __r8, __r8, 1));
401-
emit(__srl_amt(__CC, 0, logic_rs, rm, rm, 1));
402-
emit(__b(__CC, -20));
403-
emit(__mov_r(__AL, rd, rn));
404-
/* Handle the correct sign for remainder */
405-
emit(__cmp_i(__AL, __r10, 0));
406-
emit(__rsb_i(__NE, rd, 0, rd));
407371
}
372+
/* Unsigned integer division */
373+
emit(__zero(__r8));
374+
emit(__mov_i(__AL, __r9, 1));
375+
emit(__cmp_i(__AL, rm, 0));
376+
emit(__b(__EQ, 52));
377+
emit(__cmp_i(__AL, rn, 0));
378+
emit(__b(__EQ, 44));
379+
emit(__cmp_r(__AL, rm, rn));
380+
emit(__sll_amt(__CC, 0, logic_ls, rm, rm, 1));
381+
emit(__sll_amt(__CC, 0, logic_ls, __r9, __r9, 1));
382+
emit(__b(__CC, -12));
383+
emit(__cmp_r(__AL, rn, rm));
384+
emit(__sub_r(__CS, rn, rn, rm));
385+
emit(__add_r(__CS, __r8, __r8, __r9));
386+
emit(__srl_amt(__AL, 1, logic_rs, __r9, __r9, 1));
387+
emit(__srl_amt(__CC, 0, logic_rs, rm, rm, 1));
388+
emit(__b(__CC, -20));
389+
/* After completing the emulation, the quotient and remainder
390+
* will be stored in __r8 and __r9, respectively.
391+
*
392+
* The original values of the dividend and divisor will be
393+
* restored in rn and rm.
394+
*
395+
* Finally, the result (quotient or remainder) will be stored
396+
* in rd.
397+
*/
398+
emit(__mov_r(__AL, __r9, rn));
399+
emit(__ldm(__AL, 1, __sp, (1 << rn) | (1 << rm)));
400+
emit(__mov_r(__AL, rd, soft_div_rd));
401+
/* Handle the correct sign for the quotient or remainder */
402+
emit(__cmp_i(__AL, __r10, 0));
403+
emit(__rsb_i(__NE, rd, 0, rd));
408404
return;
409405
case OP_lshift:
410406
emit(__sll(__AL, rd, rn, rm));

src/arm.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,13 @@ typedef enum {
3333
arm_sub = 2,
3434
arm_rsb = 3,
3535
arm_add = 4,
36+
arm_ldm = 9,
3637
arm_teq = 9,
3738
arm_cmp = 10,
3839
arm_orr = 12,
3940
arm_mov = 13,
40-
arm_mvn = 15
41+
arm_mvn = 15,
42+
arm_stmdb = 16
4143
} arm_op_t;
4244

4345
/* Condition code
@@ -283,6 +285,16 @@ int __sb(arm_cond_t cond, arm_reg rd, arm_reg rn, int ofs)
283285
return arm_transfer(cond, 0, 1, rn, rd, ofs);
284286
}
285287

288+
int __stmdb(arm_cond_t cond, int w, arm_reg rn, int reg_list)
289+
{
290+
return arm_encode(cond, arm_stmdb + (0x2 << 6) + (w << 1), rn, 0, reg_list);
291+
}
292+
293+
int __ldm(arm_cond_t cond, int w, arm_reg rn, int reg_list)
294+
{
295+
return arm_encode(cond, arm_ldm + (0x2 << 6) + (w << 1), rn, 0, reg_list);
296+
}
297+
286298
int __b(arm_cond_t cond, int ofs)
287299
{
288300
int o = (ofs - 8) >> 2;

0 commit comments

Comments
 (0)