summary refs log tree commit diff
path: root/arm64
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-05-08 14:16:41 -0700
committerQuentin Carbonneaux <quentin@c9x.me>2019-05-15 11:43:50 +0200
commit7837770ba1018d8c3320a9eaf29920ef53ba2791 (patch)
tree737c67fd04f63ccaec288920fd1217a7abe94d58 /arm64
parent8655181f63b5327a68b27da315e889094e9e6251 (diff)
downloadroux-7837770ba1018d8c3320a9eaf29920ef53ba2791.tar.gz
arm64: Handle stack allocations larger than 4095 bytes
In this case, the immediate is too large to use directly in the add/sub
instructions, so move it into a temporary register first.

Also, for clarity, rearrange the if-conditions so that they match the
constraints of the instructions that immediately follow.
Diffstat (limited to 'arm64')
-rw-r--r--arm64/emit.c26
1 files changed, 20 insertions, 6 deletions
diff --git a/arm64/emit.c b/arm64/emit.c
index 7c5b2b6..59e1aae 100644
--- a/arm64/emit.c
+++ b/arm64/emit.c
@@ -382,7 +382,12 @@ arm64_emitfn(Fn *fn, FILE *out)
 			fprintf(e->f, "\tstr\tx%d, [sp, -8]!\n", n);
 	}
 
-	if (e->frame + 16 > 512)
+	if (e->frame + 16 <= 512)
+		fprintf(e->f,
+			"\tstp\tx29, x30, [sp, -%"PRIu64"]!\n",
+			e->frame + 16
+		);
+	else if (e->frame <= 4095)
 		fprintf(e->f,
 			"\tsub\tsp, sp, #%"PRIu64"\n"
 			"\tstp\tx29, x30, [sp, -16]!\n",
@@ -390,8 +395,10 @@ arm64_emitfn(Fn *fn, FILE *out)
 		);
 	else
 		fprintf(e->f,
-			"\tstp\tx29, x30, [sp, -%"PRIu64"]!\n",
-			e->frame + 16
+			"\tmov\tx16, #%"PRIu64"\n"
+			"\tsub\tsp, sp, x16\n"
+			"\tstp\tx29, x30, [sp, -16]!\n",
+			e->frame
 		);
 	fputs("\tadd\tx29, sp, 0\n", e->f);
 	for (o=e->frame+16, r=arm64_rclob; *r>=0; r++)
@@ -418,7 +425,12 @@ arm64_emitfn(Fn *fn, FILE *out)
 			o = e->frame + 16;
 			if (e->fn->vararg)
 				o += 192;
-			if (o > 504)
+			if (o <= 504)
+				fprintf(e->f,
+					"\tldp\tx29, x30, [sp], %"PRIu64"\n",
+					o
+				);
+			else if (o - 16 <= 4095)
 				fprintf(e->f,
 					"\tldp\tx29, x30, [sp], 16\n"
 					"\tadd\tsp, sp, #%"PRIu64"\n",
@@ -426,8 +438,10 @@ arm64_emitfn(Fn *fn, FILE *out)
 				);
 			else
 				fprintf(e->f,
-					"\tldp\tx29, x30, [sp], %"PRIu64"\n",
-					o
+					"\tldp\tx29, x30, [sp], 16\n"
+					"\tmov\tx16, #%"PRIu64"\n"
+					"\tadd\tsp, sp, x16\n",
+					o - 16
 				);
 			fprintf(e->f, "\tret\n");
 			break;