From a2962bb1ec4f14197d8c6901fb27ee44a439cd15 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Thu, 11 Mar 2021 18:57:33 -0800 Subject: 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. --- arm64/abi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arm64') 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); -- cgit 1.4.1