summary refs log tree commit diff
diff options
context:
space:
mode:
authorSudipto Mallick <smlckz@disroot.org>2021-07-11 20:38:30 +0000
committerQuentin Carbonneaux <quentin@c9x.me>2021-10-25 18:48:35 +0200
commit5e0ba156116036ba42d7ce8e361004ea20fb2d6b (patch)
treef7320a623e5e6c4b0536e36d4460166d21cd98dd
parent5dbc5dc2c9816821db6e7f1a2903c54a7d549efd (diff)
downloadroux-5e0ba156116036ba42d7ce8e361004ea20fb2d6b.tar.gz
arm64/emit.c: fix move instructions with big immediate values
Fixes #467. It assumes that the stack won't need to grow beyond 2^32 bytes.
If that were to happen, we'd need another or at most two more `movk` instructions.

Signed-off-by: Sudipto Mallick <smlckz@disroot.org>
-rw-r--r--arm64/emit.c86
1 files changed, 71 insertions, 15 deletions
diff --git a/arm64/emit.c b/arm64/emit.c
index eda1079..752b455 100644
--- a/arm64/emit.c
+++ b/arm64/emit.c
@@ -338,15 +338,21 @@ emitins(Ins *i, E *e)
 		assert(rtype(i->arg[0]) == RSlot);
 		rn = rname(i->to.val, Kl);
 		s = slot(i->arg[0].val, e);
-		if (s <= 4095) {
+		if (s <= 4095)
 			fprintf(e->f, "\tadd\t%s, x29, #%"PRIu64"\n", rn, s);
-		} else {
+		else if (s <= 65535)
 			fprintf(e->f,
 				"\tmov\t%s, #%"PRIu64"\n"
 				"\tadd\t%s, x29, %s\n",
 				rn, s, rn, rn
 			);
-		}
+		else
+			fprintf(e->f,
+				"\tmov\t%s, #%"PRIu64"\n"
+				"\tmovk\t%s, #%"PRIu64", lsl #16\n"
+				"\tadd\t%s, x29, %s\n",
+				rn, s & 0xFFFF, rn, s >> 16, rn, rn
+			);
 		break;
 	}
 }
@@ -435,20 +441,45 @@ arm64_emitfn(Fn *fn, FILE *out)
 			"\tstp\tx29, x30, [sp, -16]!\n",
 			e->frame
 		);
-	else
+	else if (e->frame <= 65535)
 		fprintf(e->f,
 			"\tmov\tx16, #%"PRIu64"\n"
 			"\tsub\tsp, sp, x16\n"
 			"\tstp\tx29, x30, [sp, -16]!\n",
 			e->frame
 		);
+	else
+		fprintf(e->f,
+			"\tmov\tx16, #%"PRIu64"\n"
+			"\tmovk\tx16, #%"PRIu64", lsl #16\n"
+			"\tsub\tsp, sp, x16\n"
+			"\tstp\tx29, x30, [sp, -16]!\n",
+			e->frame & 0xFFFF, e->frame >> 16
+		);
 	fputs("\tadd\tx29, sp, 0\n", e->f);
 	for (o=e->frame+16, r=arm64_rclob; *r>=0; r++)
-		if (e->fn->reg & BIT(*r))
-			fprintf(e->f,
-				"\tstr\t%s, [sp, %"PRIu64"]\n",
-				rname(*r, Kx), o -= 8
-			);
+		if (e->fn->reg & BIT(*r)) {
+			if (o <= 32760)
+				fprintf(e->f,
+					"\tstr\t%s, [sp, %"PRIu64"]\n",
+					rname(*r, Kx), o -= 8
+				);
+			else if (o <= 65535)
+				fprintf(e->f,
+					"\tmov\tx16, #%"PRIu64"\n"
+					"\tstr\t%s, [sp, x16]\n",
+					o -= 8, rname(*r, Kx)
+				);
+			else {
+				o -= 8;
+				fprintf(e->f,
+					"\tmov\tx16, #%"PRIu64"\n"
+					"\tmovk\tx16, #%"PRIu64", lsl #16\n"
+					"\tstr\t%s, [sp, x16]\n",
+					o & 0xFFFF, o >> 16, rname(*r, Kx)
+				);
+			}
+		}
 
 	for (lbl=0, b=e->fn->start; b; b=b->link) {
 		if (lbl || b->npred > 1)
@@ -459,11 +490,28 @@ arm64_emitfn(Fn *fn, FILE *out)
 		switch (b->jmp.type) {
 		case Jret0:
 			for (o=e->frame+16, r=arm64_rclob; *r>=0; r++)
-				if (e->fn->reg & BIT(*r))
-					fprintf(e->f,
-						"\tldr\t%s, [sp, %"PRIu64"]\n",
-						rname(*r, Kx), o -= 8
-					);
+				if (e->fn->reg & BIT(*r)) {
+					if (o <= 32760)
+						fprintf(e->f,
+							"\tldr\t%s, [sp, %"PRIu64"]\n",
+							rname(*r, Kx), o -= 8
+						);
+					else if (o <= 65535)
+						fprintf(e->f,
+							"\tmov\tx16, #%"PRIu64"\n"
+							"\tldr\t%s, [sp, x16]\n",
+							o -= 8, rname(*r, Kx)
+						);
+					else {
+						o -= 8;
+						fprintf(e->f,
+							"\tmov\tx16, #%"PRIu64"\n"
+							"\tmovk\tx16, #%"PRIu64", lsl #16\n"
+							"\tldr\t%s, [sp, x16]\n",
+							o & 0xFFFF, o >> 16, rname(*r, Kx)
+						);
+					}
+				}
 			o = e->frame + 16;
 			if (e->fn->vararg)
 				o += 192;
@@ -478,13 +526,21 @@ arm64_emitfn(Fn *fn, FILE *out)
 					"\tadd\tsp, sp, #%"PRIu64"\n",
 					o - 16
 				);
-			else
+			else if (o - 16 <= 65535)
 				fprintf(e->f,
 					"\tldp\tx29, x30, [sp], 16\n"
 					"\tmov\tx16, #%"PRIu64"\n"
 					"\tadd\tsp, sp, x16\n",
 					o - 16
 				);
+			else
+				fprintf(e->f,
+					"\tldp\tx29, x30, [sp], 16\n"
+					"\tmov\tx16, #%"PRIu64"\n"
+					"\tmovk\tx16, #%"PRIu64", lsl #16\n"
+					"\tadd\tsp, sp, x16\n",
+					(o - 16) & 0xFFFF, (o - 16) >> 16
+				);
 			fprintf(e->f, "\tret\n");
 			break;
 		case Jjmp: