Commit Diff


commit - 4efc4256d0461a3fbc9abdb3443dc7aa73e763c3
commit + 0d35c07dfc7e6b341aadc64a253738b6285b9e6a
blob - 8566d7c50703dc2618f31bc44f94e28fa8129567
blob + fbd52308aca953b521e52120d240c43707f30f48
--- cc/irc/irc.c
+++ cc/irc/irc.c
@@ -335,8 +335,8 @@ struct expr {
 		long i;
 		double f;
 		struct {
-			int num;
-			int off;
+			struct regimm num;
+			int off;	// only valid if ri.is_imm
 		} alloca;
 		struct {
 			int l;
@@ -826,10 +826,11 @@ struct expr *e;
 			error ("the result of alloca must be stored in a far or stack pointer");
 
 		e->type = EX_ALLOCA;
-		expect (TK_INT);
-		e->alloca.num = lval.i;
-		stalloc (fn, sizeof_dt (dt->inner) * e->alloca.num);
-		e->alloca.off = fn->stoff;
+		regimm (&e->alloca.num, &default_dt);
+		if (e->alloca.num.is_imm) {
+			stalloc (fn, sizeof_dt (dt->inner) * e->alloca.num.imm);
+			e->alloca.off = fn->stoff;
+		}
 		expect (';');
 	} else if (strcmp (lval.s, "ptradd") == 0) {
 		e->type = EX_PTRADD;
@@ -1245,7 +1246,8 @@ struct expr *e;
 		printf ("$%d", e->reg);
 		break;
 	case EX_ALLOCA:
-		printf ("alloca %d", e->alloca.num);
+		printf ("alloca ");
+		print_ri (&e->alloca.num);
 		break;
 	case EX_ADD:
 		printf ("add $%d, ", e->bin.l);
@@ -2166,7 +2168,14 @@ struct expr *e;
 			puts ("\tmov dx, ss");
 			// fallthrough
 		case DT_SPTR:
-			printf ("\tlea ax, [bp + %d]\n", e->alloca.off);
+			if (e->alloca.num.is_imm) {
+				printf ("\tlea ax, [bp + %d]\n", e->alloca.off);
+			} else {
+				loadw (NULL, AX, &fn->regs[e->alloca.num.reg]);
+				cmul ("ax", sizeof_dt (dt->inner));
+				puts ("\tsub sp, ax");
+				puts ("\tmov ax, sp");
+			}
 			break;
 		default:
 			abort ();
blob - 1d6a10ae6bf33408ac50b80ade2bedfd35342862
blob + 08dc0947bade90c0785e263d4809546f818db9ad
--- cc/irc/test.ir
+++ cc/irc/test.ir
@@ -225,3 +225,9 @@ fn fcmp (): word {
 	nop;
 	ret 0;
 }
+
+fn alloca_reg ($0: word): word {
+	let $1: ^word = alloca $0;
+	let $2: word = read $1, 5;
+	ret $2;
+}