commit f5b4351d0b7b927bdca9c46bd239eed63cdf1fac from: Benjamin Stürz date: Wed Oct 02 18:22:27 2024 UTC irc: implement EX_MUL, EX_{U,S}DIV commit - f22e8bc636ee9525c1abed6c3a29505179154c5f commit + f5b4351d0b7b927bdca9c46bd239eed63cdf1fac blob - ef137958b619da006a9d229384f2c2202a7410a6 blob + 7feb311b05ea66737932a84ea795790d8a38e382 --- cc/irc/TODO +++ cc/irc/TODO @@ -26,3 +26,4 @@ - add `extern` functions - add function pointers - rename DT_FPTR to DT_PTR +- implement builtin functions blob - b0a2545ae11ab216f4c68e86025fb6478323bc7d blob + 7c5d209c4bc5557d64aeb8ed69fda3eab96179a7 --- cc/irc/builtins.asm +++ cc/irc/builtins.asm @@ -27,3 +27,33 @@ __shrq: global __sarq __sarq: ret + +global __muld +; dx:ax val1, stack: val2 +__muld: + ret + +global __mulq +; cx:bx:dx:ax: val1, stack: val2 +__mulq: + ret + +global __divd +; same ABI as __muld +__divd: + ret + +global __divq +; same ABI as __mulq +__divq: + ret + +global __idivd +; same ABI as __muld +__idivd: + ret + +global __idivq +; same ABI as __mulq +__idivq: + ret blob - 922d87540be407302a051ee227727345961f366c blob + d955cd56ace44687676d3abbf3a5fe8e0cb19a49 --- cc/irc/irc.c +++ cc/irc/irc.c @@ -240,6 +240,9 @@ enum expr_type { EX_LSL, // .bin EX_LSR, // .bin EX_ASR, // .bin + EX_MUL, // .bin + EX_UDIV, // .bin + EX_SDIV, // .bin }; struct call { @@ -585,6 +588,12 @@ struct expr *e; expr_bin (fn, dt, e, EX_OR); } else if (strcmp (lval.s, "xor") == 0) { expr_bin (fn, dt, e, EX_XOR); + } else if (strcmp (lval.s, "mul") == 0) { + expr_bin (fn, dt, e, EX_MUL); + } else if (strcmp (lval.s, "udiv") == 0) { + expr_bin (fn, dt, e, EX_UDIV); + } else if (strcmp (lval.s, "sdiv") == 0) { + expr_bin (fn, dt, e, EX_SDIV); } else if (strcmp (lval.s, "lsl") == 0) { expr_shift (fn, dt, e, EX_LSL); } else if (strcmp (lval.s, "lsr") == 0) { @@ -1013,8 +1022,20 @@ struct expr *e; break; case EX_XOR: printf ("xor $%d, ", e->bin.l); + print_ri (&e->bin.r); + break; + case EX_MUL: + printf ("mul $%d, ", e->bin.l); print_ri (&e->bin.r); break; + case EX_UDIV: + printf ("udiv $%d, ", e->bin.l); + print_ri (&e->bin.r); + break; + case EX_SDIV: + printf ("sdiv $%d, ", e->bin.l); + print_ri (&e->bin.r); + break; case EX_PTRADD: printf ("ptradd $%d, ", e->bin.l); print_ri (&e->bin.r); @@ -1347,25 +1368,21 @@ int off; // constant multiply cmul (reg, i) -enum x86_reg16 reg; +char *reg; { - char *r; - int x; + int x = ffs (i); - r = reg16[reg]; - - x = ffs (i); if (x == 0) { - printf ("\txor %s, %s\n", r, r); + printf ("\txor %s, %s\n", reg, reg); return 0; } if (i == (1 << (x - 1))) { - printf ("\tshr %s, %d\n", r, (x - 1)); + printf ("\tshr %s, %d\n", reg, (x - 1)); return 0; } - error ("cmul() not implemented for arbitrary constants"); + printf ("\timul %s, %d\n", reg, i); return 0; } @@ -1474,7 +1491,107 @@ struct regimm *shamt; printf ("\tcall __%sq\n", instr); break; } + + return 0; +} + +call_muldiv (instr, fn, dt, e) +char *instr; +struct func *fn; +struct dtype *dt; +struct expr *e; +{ + struct reg *r = &fn->regs[e->bin.l]; + struct regimm *ri = &e->bin.r; + + switch (dt->type) { + case DT_DWORD: + if (ri->is_imm) { + printf ("\tpush %d\n", (int)((ri->imm >> 16) & 0xffff)); + printf ("\tpush %d\n", (int)(ri->imm & 0xffff)); + } else { + r = &fn->regs[ri->reg]; + printf ("\tpush word [ss:bp + %d + 2]\n", r->off); + printf ("\tpush word [ss:bp + %d + 0]\n", r->off); + } + load ("mov", &fn->regs[e->bin.l]); + printf ("\tcall __%sd\n", instr); + puts ("\tadd sp, 4"); + break; + case DT_QWORD: + if (ri->is_imm) { + printf ("\tpush %d\n", (int)((ri->imm >> 48) & 0xffff)); + printf ("\tpush %d\n", (int)((ri->imm >> 32) & 0xffff)); + printf ("\tpush %d\n", (int)((ri->imm >> 16) & 0xffff)); + printf ("\tpush %d\n", (int)(ri->imm & 0xffff)); + } else { + r = &fn->regs[ri->reg]; + printf ("\tpush word [ss:bp + %d + 6]\n", r->off); + printf ("\tpush word [ss:bp + %d + 4]\n", r->off); + printf ("\tpush word [ss:bp + %d + 2]\n", r->off); + printf ("\tpush word [ss:bp + %d + 0]\n", r->off); + } + load ("mov", &fn->regs[e->bin.l]); + printf ("\tcall __%sq\n", instr); + puts ("\tadd sp, 8"); + break; + default: + abort (); + } + + return 0; +} + +gen_div (fn, dt, e, sign) +struct func *fn; +struct dtype *dt; +struct expr *e; +{ + struct reg *acc = &fn->regs[e->bin.l]; + struct regimm *ri = &e->bin.r; + char *instr = sign ? "idiv" : "div"; + switch (dt->type) { + case DT_NONE: + case DT_LABEL: + case DT_DPTR: + case DT_FPTR: + case DT_SPTR: + abort (); + break; + case DT_BYTE: + loadb ("mov", AL, acc); + if (sign) { + puts ("\tcbw"); + } else { + puts ("\txor dl, dl"); + } + if (ri->is_imm) { + loadimmr ("mov", "cl", (int)ri->imm); + printf ("\t%s cl\n", instr); + } else { + printf ("\t%s byte [ss:bp + %d]\n", instr, fn->regs[ri->reg].off); + } + break; + case DT_WORD: + loadw ("mov", AX, acc); + if (sign) { + puts ("\tcwd"); + } else { + puts ("\txor dx, dx"); + } + if (ri->is_imm) { + loadimmr ("mov", "cx", (int)ri->imm); + printf ("\t%s cx\n", instr); + } else { + printf ("\t%s word [ss:bp + %d]\n", instr, fn->regs[ri->reg].off); + } + break; + case DT_DWORD: + case DT_QWORD: + call_muldiv (instr, fn, dt, e); + break; + } return 0; } @@ -1523,6 +1640,46 @@ struct expr *e; case EX_XOR: alu ("xor", fn, dt, e); break; + case EX_MUL: + r = &fn->regs[e->bin.l]; + ri = &e->bin.r; + switch (dt->type) { + case DT_NONE: + case DT_LABEL: + case DT_DPTR: + case DT_FPTR: + case DT_SPTR: + abort (); + break; + case DT_BYTE: + loadb ("mov", AL, r); + if (ri->is_imm) { + cmul ("al", (int)(ri->imm & 0xff)); + } else { + loadb ("mul", AL, &fn->regs[ri->reg]); + } + break; + case DT_WORD: + loadw ("mov", AX, &fn->regs[e->bin.l]); + if (ri->is_imm) { + cmul ("ax", (int)(ri->imm & 0xffff)); + } else { + loadw ("mul", AX, &fn->regs[ri->reg]); + } + break; + case DT_DWORD: + case DT_QWORD: + // TODO: multiply using FPU + call_muldiv ("mul", fn, dt, e); + break; + } + break; + case EX_UDIV: + gen_div (fn, dt, e, 0); + break; + case EX_SDIV: + gen_div (fn, dt, e, 1); + break; case EX_PTRADD: load ("mov", &fn->regs[e->bin.l]); @@ -1533,7 +1690,7 @@ struct expr *e; printf ("\tadd ax, %d\n", (int)(e->bin.r.imm & 0xffff) * sz); } else { loadw ("mov", CX, &fn->regs[e->bin.r.reg]); - cmul (CX, sz); + cmul ("cx", sz); puts ("\tadd ax, cx"); } break; @@ -1928,6 +2085,7 @@ main (void) puts ("[bits 16]"); puts ("[cpu 286]"); puts ("extern __shld, __shrd, __sard, __shlq, __shrq, __sarq"); + puts ("extern __muld, __mulq, __divd, __divq, __idivd, __idivq"); puts (""); parse (); blob - 8b8808c5e9f1b5b8bc5cfb8027ccbb782ec2992b blob + a40799c281aab31dd6a69cef7462f958a03f0ecd --- cc/irc/test.ir +++ cc/irc/test.ir @@ -159,3 +159,27 @@ fn farptrs (): word { let $2: word = read $1; ret $2; } + +fn multiply ($0: dword, $1: dword): dword { + let $2: dword = mul $0, $1; + ret $2; +} + +fn qmult ($0: qword, $1: qword): qword { + let $2: qword = mul $0, $1; + ret $2; +} + +fn division ($0: word, $1: word): word { + let $2: word = udiv $0, $1; + let $3: word = sdiv $0, $1; + let $4: word = add $2, $3; + ret $4; +} + +fn qdiv ($0: qword, $1: qword): qword { + let $2: qword = udiv $0, $1; + let $3: qword = sdiv $0, $1; + let $4: qword = add $2, $3; + ret $4; +}