Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate a sequence of instructions for divisions on Arm targets #126

Merged
merged 1 commit into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,12 @@ Run `make` and you should see this:

File `out/shecc` is the first stage compiler. Its usage:
```
shecc [-o output] [--no-libc] [--dump-ir] <infile.c>
shecc [-o output] [+m] [--no-libc] [--dump-ir] <infile.c>
```

Compiler options:
- `-o` : output file name (default: out.elf)
- `+m` : Enable hardware multiplication and division instructions (default: disabled)
- `--no-libc` : Exclude embedded C library (default: embedded)
- `--dump-ir` : Dump intermediate representation (IR)

Expand Down
88 changes: 82 additions & 6 deletions src/arm-codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ void update_elf_offset(ph2_ir_t *ph2_ir)
case OP_add:
case OP_sub:
case OP_mul:
case OP_div:
case OP_lshift:
case OP_rshift:
case OP_bit_and:
Expand All @@ -85,11 +84,24 @@ void update_elf_offset(ph2_ir_t *ph2_ir)
case OP_bit_not:
elf_offset += 4;
return;
case OP_div:
if (hard_mul_div) {
elf_offset += 4;
} else {
elf_offset += 104;
}
return;
case OP_mod:
if (hard_mul_div) {
elf_offset += 12;
} else {
elf_offset += 104;
}
return;
case OP_load_data_address:
elf_offset += 8;
return;
case OP_address_of_func:
case OP_mod:
case OP_eq:
case OP_neq:
case OP_gt:
Expand Down Expand Up @@ -323,12 +335,76 @@ void emit_ph2_ir(ph2_ir_t *ph2_ir)
emit(__mul(__AL, rd, rn, rm));
return;
case OP_div:
emit(__div(__AL, rd, rm, rn));
if (hard_mul_div) {
emit(__div(__AL, rd, rm, rn));
} else {
/* Obtain absoulte values of dividend and divisor */
emit(__srl_amt(__AL, 0, arith_rs, __r8, rn, 31));
emit(__add_r(__AL, rn, rn, __r8));
emit(__eor_r(__AL, rn, rn, __r8));
emit(__srl_amt(__AL, 0, arith_rs, __r9, rm, 31));
emit(__add_r(__AL, rm, rm, __r9));
emit(__eor_r(__AL, rm, rm, __r9));
emit(__eor_r(__AL, __r10, __r8, __r9));
/* Unsigned integer division */
emit(__zero(__r9));
emit(__mov_i(__AL, __r8, 1));
emit(__cmp_i(__AL, rm, 0));
emit(__b(__EQ, 52));
emit(__cmp_i(__AL, rn, 0));
emit(__b(__EQ, 44));
emit(__cmp_r(__AL, rm, rn));
emit(__sll_amt(__CC, 0, logic_ls, rm, rm, 1));
emit(__sll_amt(__CC, 0, logic_ls, __r8, __r8, 1));
emit(__b(__CC, -12));
emit(__cmp_r(__AL, rn, rm));
emit(__sub_r(__CS, rn, rn, rm));
emit(__add_r(__CS, __r9, __r9, __r8));
emit(__srl_amt(__AL, 1, logic_rs, __r8, __r8, 1));
emit(__srl_amt(__CC, 0, logic_rs, rm, rm, 1));
emit(__b(__CC, -20));
emit(__mov_r(__AL, rd, __r9));
/* Handle the correct sign for quotient */
emit(__cmp_i(__AL, __r10, 0));
emit(__rsb_i(__NE, rd, 0, rd));
}
return;
case OP_mod:
emit(__div(__AL, __r8, rm, rn));
emit(__mul(__AL, __r8, rm, __r8));
emit(__sub_r(__AL, rd, rn, __r8));
if (hard_mul_div) {
emit(__div(__AL, __r8, rm, rn));
emit(__mul(__AL, __r8, rm, __r8));
emit(__sub_r(__AL, rd, rn, __r8));
} else {
/* Obtain absoulte values of dividend and divisor */
emit(__srl_amt(__AL, 0, arith_rs, __r8, rn, 31));
emit(__add_r(__AL, rn, rn, __r8));
emit(__eor_r(__AL, rn, rn, __r8));
emit(__srl_amt(__AL, 0, arith_rs, __r9, rm, 31));
emit(__add_r(__AL, rm, rm, __r9));
emit(__eor_r(__AL, rm, rm, __r9));
emit(__mov_r(__AL, __r10, __r8));
/* Unsigned integer division */
emit(__zero(__r9));
emit(__mov_i(__AL, __r8, 1));
emit(__cmp_i(__AL, rm, 0));
emit(__b(__EQ, 52));
emit(__cmp_i(__AL, rn, 0));
emit(__b(__EQ, 44));
emit(__cmp_r(__AL, rm, rn));
emit(__sll_amt(__CC, 0, logic_ls, rm, rm, 1));
emit(__sll_amt(__CC, 0, logic_ls, __r8, __r8, 1));
emit(__b(__CC, -12));
emit(__cmp_r(__AL, rn, rm));
emit(__sub_r(__CS, rn, rn, rm));
emit(__add_r(__CS, __r9, __r9, __r8));
emit(__srl_amt(__AL, 1, logic_rs, __r8, __r8, 1));
emit(__srl_amt(__CC, 0, logic_rs, rm, rm, 1));
emit(__b(__CC, -20));
emit(__mov_r(__AL, rd, rn));
/* Handle the correct sign for remainder */
emit(__cmp_i(__AL, __r10, 0));
emit(__rsb_i(__NE, rd, 0, rd));
}
return;
case OP_lshift:
emit(__sll(__AL, rd, rn, rm));
Expand Down
37 changes: 37 additions & 0 deletions src/arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ typedef enum {
typedef enum {
__EQ = 0, /* Equal */
__NE = 1, /* Not equal */
__CS = 2, /* Unsigned higher or same */
__CC = 3, /* Unsigned lower */
__LS = 9, /* unsigned lower or same */
__GE = 10, /* Signed greater than or equal */
__LT = 11, /* Signed less than */
__GT = 12, /* Signed greater than */
Expand Down Expand Up @@ -74,6 +77,13 @@ typedef enum {
__pc = 15 /* program counter, r15 */
} arm_reg;

typedef enum {
logic_ls = 0, /* Logical left shift */
logic_rs = 1, /* Logical right shift */
arith_rs = 2, /* Arithmetic right shift */
rotat_rs = 3 /* Rotate right shift */
} shfit_type;

arm_cond_t arm_get_cond(opcode_t op)
{
switch (op) {
Expand Down Expand Up @@ -186,12 +196,34 @@ int __srl(arm_cond_t cond, arm_reg rd, arm_reg rm, arm_reg rs)
rm + (1 << 4) + (1 << 5) + (rs << 8));
}

int __srl_amt(arm_cond_t cond,
int s,
shfit_type shift,
arm_reg rd,
arm_reg rm,
int amt)
{
return arm_encode(cond, s + (arm_mov << 1) + (0 << 5), 0, rd,
rm + (0 << 4) + (shift << 5) + (amt << 7));
}

int __sll(arm_cond_t cond, arm_reg rd, arm_reg rm, arm_reg rs)
{
return arm_encode(cond, 0 + (arm_mov << 1) + (0 << 5), 0, rd,
rm + (1 << 4) + (0 << 5) + (rs << 8));
}

int __sll_amt(arm_cond_t cond,
int s,
shfit_type shift,
arm_reg rd,
arm_reg rm,
int amt)
{
return arm_encode(cond, s + (arm_mov << 1) + (0 << 5), 0, rd,
rm + (0 << 4) + (shift << 5) + (amt << 7));
}

int __add_i(arm_cond_t cond, arm_reg rd, arm_reg rs, int imm)
{
if (imm >= 0)
Expand Down Expand Up @@ -288,6 +320,11 @@ int __cmp_r(arm_cond_t cond, arm_reg r1, arm_reg r2)
return __mov(cond, 0, arm_cmp, 1, r1, 0, r2);
}

int __cmp_i(arm_cond_t cond, arm_reg rn, int imm)
{
return __mov(cond, 1, arm_cmp, 1, rn, 0, imm);
}

int __teq(arm_reg rd)
{
return __mov(__AL, 1, arm_teq, 1, rd, 0, 0);
Expand Down
2 changes: 1 addition & 1 deletion src/defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#define MAX_BB_DOM_SUCC 64
#define MAX_GLOBAL_IR 256
#define MAX_LABEL 4096
#define MAX_SOURCE 278528
#define MAX_SOURCE 327680
#define MAX_CODE 262144
#define MAX_DATA 262144
#define MAX_SYMTAB 65536
Expand Down
1 change: 1 addition & 0 deletions src/globals.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ int find_trie(trie_t *trie, char *name)
/* options */

int dump_ir = 0;
int hard_mul_div = 0;

/**
* find_type() - Find the type by the given name.
Expand Down
6 changes: 5 additions & 1 deletion src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ int main(int argc, char *argv[])
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "--dump-ir"))
dump_ir = 1;
else if (!strcmp(argv[i], "+m"))
hard_mul_div = 1;
else if (!strcmp(argv[i], "--no-libc"))
libc = 0;
else if (!strcmp(argv[i], "-o")) {
Expand All @@ -66,7 +68,9 @@ int main(int argc, char *argv[])

if (!in) {
printf("Missing source file!\n");
printf("Usage: shecc [-o output] [--dump-ir] [--no-libc] <input.c>\n");
printf(
"Usage: shecc [-o output] [+m] [--dump-ir] [--no-libc] "
"<input.c>\n");
return -1;
}

Expand Down
Loading