Commit Diff


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;
+}