summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2021-03-11 18:57:33 -0800
committerQuentin Carbonneaux <quentin@c9x.me>2021-03-12 17:09:10 +0100
commita2962bb1ec4f14197d8c6901fb27ee44a439cd15 (patch)
tree14f4df2f63aa176ab52511b6fc3a94ac86609f59
parent9c4e4bc68afa23e1e22dcf939cd7647a0a615c2b (diff)
downloadroux-a2962bb1ec4f14197d8c6901fb27ee44a439cd15.tar.gz
arm64: fix selcall call data for return of aggregate in memory
The no-op `copy R0` is necessary in order to trigger dopm in spill.c
and rega.c, which assume that a call is always followed by one or
more copies from registers. However, the arm64 ABI does not actually
return the caller-passed pointer as in x86_64. This causes an
assertion failure

	qbe: aarch64: Assertion failed: r == T.rglob || b == fn->start (spill.c: spill: 470)

for the following test program

	type :t = { l 3 }
	function $f() {
	@start.1
	@start.2
		%ret =:t call $g()
		ret
	}

The assertion failure only triggers when the block containing the
call is not the first block, because the check is skipped for the
first block (since some registers may have been used for arguments).

To fix this, set R0 in the call data so that spill/rega can see
that this dummy "return" register was generated by the call. This
matches qbe's existing behavior when the function returns void,
another case where no register is used for the function result.
-rw-r--r--arm64/abi.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/arm64/abi.c b/arm64/abi.c
index f5b605a..eef47bc 100644
--- a/arm64/abi.c
+++ b/arm64/abi.c
@@ -352,7 +352,7 @@ selcall(Fn *fn, Ins *i0, Ins *i1, Insl **ilp)
 		stkblob(i1->to, &cr, fn, ilp);
 		cty |= (cr.nfp << 2) | cr.ngp;
 		if (cr.class & Cptr) {
-			cty |= 1 << 13;
+			cty |= 1 << 13 | 1;
 			emit(Ocopy, Kw, R, TMP(R0), R);
 		} else {
 			sttmps(tmp, cr.cls, cr.nreg, i1->to, fn);