diff --git a/README.md b/README.md index 40339569..a6adbac8 100644 --- a/README.md +++ b/README.md @@ -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] +shecc [-o output] [+m] [--no-libc] [--dump-ir] ``` 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) diff --git a/src/arm-codegen.c b/src/arm-codegen.c index 3421cf1e..e11429d4 100644 --- a/src/arm-codegen.c +++ b/src/arm-codegen.c @@ -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: @@ -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: @@ -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)); diff --git a/src/arm.c b/src/arm.c index c5b3c85f..db6606c0 100644 --- a/src/arm.c +++ b/src/arm.c @@ -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 */ @@ -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) { @@ -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) @@ -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); diff --git a/src/defs.h b/src/defs.h index 00d7e7c0..fc6a64f1 100644 --- a/src/defs.h +++ b/src/defs.h @@ -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 diff --git a/src/globals.c b/src/globals.c index caed9bf5..7ed5bdc0 100644 --- a/src/globals.c +++ b/src/globals.c @@ -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. diff --git a/src/main.c b/src/main.c index 535e09f0..8eebf810 100644 --- a/src/main.c +++ b/src/main.c @@ -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")) { @@ -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] \n"); + printf( + "Usage: shecc [-o output] [+m] [--dump-ir] [--no-libc] " + "\n"); return -1; } diff --git a/tests/driver.sh b/tests/driver.sh index 92eac120..e2cdb2f7 100755 --- a/tests/driver.sh +++ b/tests/driver.sh @@ -592,6 +592,207 @@ int main() } EOF +# Division and modulo for signed integers +try_output 0 "-1 -2" << EOF +int main() +{ + printf("%d %d", -6 / 4, -6 % 4); + return 0; +} +EOF + +try_output 0 "-3 1" << EOF +int main() +{ + printf("%d %d", 7 / -2, 7 % -2); + return 0; +} +EOF + +try_output 0 "12 -1" << EOF +int main() +{ + printf("%d %d", -109 / -9, -109 % -9); + return 0; +} +EOF + +try_output 0 "1365 0" << EOF +int main() +{ + printf("%d %d", 1365 / 1, 1365 % 1); + return 0; +} +EOF + +try_output 0 "-126322567 -8" << EOF +int main() +{ + printf("%d %d", -2147483647 / 17, -2147483647 % 17); + return 0; +} +EOF + +try_output 0 "-1 -1" << EOF +int main() +{ + printf("%d %d", -2147483648 / 2147483647, -2147483648 % 2147483647); + return 0; +} +EOF + +try_output 0 "-2147483648 0" << EOF +int main() +{ + printf("%d %d", -2147483648 / 1, -2147483648 % 1); + return 0; +} +EOF + +try_output 0 "-134217728 0" << EOF +int main() +{ + printf("%d %d", -2147483648 / 16, -2147483648 % 16); + return 0; +} +EOF + +try_output 0 "134217728 0" << EOF +int main() +{ + printf("%d %d", -2147483648 / -16, -2147483648 % -16); + return 0; +} +EOF + +try_output 0 "1 0" << EOF +int main() +{ + printf("%d %d", -2147483648 / -2147483648, -2147483648 % -2147483648); + return 0; +} +EOF + +try_output 0 "-8910720 -128" << EOF +int main() +{ + printf("%d %d", -2147483648 / 241, -2147483648 % 241); + return 0; +} +EOF + +try_output 0 "1" << EOF +int main() +{ + printf("%d", 6 / -2 / -3); + return 0; +} +EOF + +try_output 0 "0" << EOF +int main() +{ + printf("%d", 477 / 37 % -3); + return 0; +} +EOF + +try_output 0 "12" << EOF +int main() +{ + printf("%d", 477 / (37 + 1 / -3)); + return 0; +} +EOF + +try_output 0 "-39" << EOF +int main() +{ + printf("%d", 477 / (37 / -3)); + return 0; +} +EOF + +try_output 0 "2 3" << EOF +int div(int a, int b) +{ + return a / b; +} + +int mod(int a, int b) +{ + return a % b; +} + +int main() +{ + int a = div(4 + 5 + 6, 1 + 2 + 3); + int b = mod(4 + 5 + 6, 1 + 2 + 3); + printf("%d %d", a, b); + return 0; +} +EOF + +try_output 0 "-1422 -3094" << EOF +int div(int a, int b) +{ + return a / b; +} + +int mod(int a, int b) +{ + return a % b; +} + +int main() +{ + int a = div(-4449688, 3127); + int b = mod(-4449688, 3127); + printf("%d %d", a, b); + return 0; +} +EOF + +try_output 0 "-2267573 102" << EOF +int div(int a, int b) +{ + return a / b; +} + +int mod(int a, int b) +{ + return a % b; +} + +int main() +{ + int a = div(333333333, -147); + int b = mod(333333333, -147); + printf("%d %d", a, b); + return 0; +} +EOF + +try_output 0 "104643 -134" << EOF +int div(int a, int b) +{ + return a / b; +} + +int mod(int a, int b) +{ + return a % b; +} + +int main() +{ + int a = div(-104747777, -1001); + int b = mod(-104747777, -1001); + printf("%d %d", a, b); + return 0; +} +EOF + # _Bool size should be equivalent to char, which is 1 byte try_output 0 "1" << EOF int main()