summary refs log tree commit diff
diff options
context:
space:
mode:
authorQuentin Carbonneaux <quentin@c9x.me>2021-10-25 13:39:20 +0200
committerQuentin Carbonneaux <quentin@c9x.me>2021-10-26 20:31:46 +0200
commitb2a25215fcc71c86e0120c7bac14f679b70a3a3c (patch)
treeb75a1ecb2ee717dfbb0666568dbbad6ea8a03ba7
parentfd33b2ef25ff55217e229666c4d2f0877aac2515 (diff)
downloadroux-b2a25215fcc71c86e0120c7bac14f679b70a3a3c.tar.gz
spill: fix regs assertions
Some arm64 abi tests have been failing
for some time now. This fixes them by
being a bit more careful with liveset
management in spill.c.

A late bsclr() call in spill.c may drop
legitimately live registers in e.g.,

  R12 =w add R12, 1

While it hurts for regs, it does not
matter for ssa temps because those cannot
be both in the arguments & return (by the
ssa invariant). I added a check before
bsclr() to make sure we are clearing
only ssa temps.

One might be surprised that any ssa temp
may be live at this point. The reason why
this is the case is the special handling
of dead return values earlier in spill().
I think that it is the only case where
the return value can be (awkwardly) live
at the same time as the arguments, and I
think this never happens with registers
(i.e., we never have dead register-
assigning instructions). I added an
assert to check the latter invariant.

Finally, there was a simple bug in the
arm64 abi which I fixed: In case the return
happens via a pointer, x8 needs to be marked
live at the beginning of the function. This
was caught by test/abi4.ssa.
-rw-r--r--arm64/abi.c1
-rw-r--r--spill.c6
2 files changed, 6 insertions, 1 deletions
diff --git a/arm64/abi.c b/arm64/abi.c
index d38dcf5..8209944 100644
--- a/arm64/abi.c
+++ b/arm64/abi.c
@@ -448,6 +448,7 @@ selpar(Fn *fn, Ins *i0, Ins *i1)
 		if (cr.class & Cptr) {
 			fn->retr = newtmp("abi", Kl, fn);
 			emit(Ocopy, Kl, fn->retr, TMP(R8), R);
+			fn->reg |= BIT(R8);
 		}
 	}
 
diff --git a/spill.c b/spill.c
index baceccc..4c11d9f 100644
--- a/spill.c
+++ b/spill.c
@@ -428,6 +428,7 @@ spill(Fn *fn)
 				else {
 					/* make sure we have a reg
 					 * for the result */
+					assert(t >= Tmp0 && "dead reg");
 					bsset(v, t);
 					bsset(w, t);
 				}
@@ -476,7 +477,10 @@ spill(Fn *fn)
 			if (!req(i->to, R)) {
 				t = i->to.val;
 				store(i->to, tmp[t].slot);
-				bsclr(v, t);
+				if (t >= Tmp0)
+					/* in case i->to was a
+					 * dead temporary */
+					bsclr(v, t);
 			}
 			emiti(*i);
 			r = v->t[0]; /* Tmp0 is NBit */