commit bf0cbf2005df3b5c84d48c4efa206567563dfa3a
parent aa0c83900e7fb42f42a0361f46597e9bc5aabbaf
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Fri, 24 Apr 2026 08:09:27 -0700
Require active frame for CALL/CALLR in P1 spec
Previously the spec said call/return correctness didn't depend on a
frame, but the aarch64 and riscv64 backends both lower CALL to a bare
BLR/JALR that clobbers the native link register. A non-leaf caller
without a frame would infinite-loop on RET.
Tighten the contract: any function that issues CALL, CALLR, TAIL, or
TAILR must ENTER a standard frame first. Pure leaves may still omit the
frame. Existing backends are already correct under the new wording.
Diffstat:
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/docs/P1.md b/docs/P1.md
@@ -126,8 +126,9 @@ Callee-saved:
### Call semantics
-A call is valid from any function, including a leaf. Call / return correctness
-does not depend on establishing a frame first.
+A function that issues any `CALL`, `CALLR`, `TAIL`, or `TAILR` must establish a
+standard frame with `ENTER` before its first such op. A leaf that issues none
+of those may omit the frame entirely.
If a function needs any incoming argument after making a call, it must save it
before the call. This matters in particular for `a0`, which is overwritten by
@@ -277,9 +278,7 @@ following control-flow op consumes that target.
`CALL` transfers control to the target most recently loaded by `LA_BR` and
establishes a return continuation such that a subsequent `RET` returns to the
-instruction after the `CALL`. `CALL` is valid whether or not the caller has
-established a standard frame, except that any call using stack-passed argument
-words requires an active standard frame to hold the staged outgoing words.
+instruction after the `CALL`. `CALL` requires an active standard frame.
`CALLR rs` is the register-indirect form of `CALL`. It transfers control to
the code pointer value held in `rs` and establishes the same return