commit 733201001ee4b7198a384c764d4110e85afba737
parent c562293046d7bf431615d75bb41393db83b99197
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sat, 9 May 2026 12:22:36 -0700
cg: add cg_tail_call and CG_CALL_TAIL flag on CGCallDesc
Interface-only. Lets the parser/opt mark a call as a sibling call so
the AArch64 backend (and others) can lower as caller-epilogue + B/BR
instead of BL+RET. Must-tail semantics: legality is the caller's job;
the backend panics if it cannot honor the request.
Diffstat:
2 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/src/arch/arch.h b/src/arch/arch.h
@@ -268,12 +268,24 @@ typedef struct CGFuncDesc {
SrcLoc loc;
} CGFuncDesc;
+typedef enum CGCallFlag {
+ CG_CALL_NONE = 0,
+ /* Sibling call. The target emits the caller's epilogue, transfers
+ * control to the callee (B/JUMP26 for direct, BR Xn for indirect), and
+ * does NOT emit a return-style continuation. CG will not invoke
+ * target->ret afterwards. The target panics if it cannot honor the
+ * request — legality is the caller's responsibility (see cg_tail_call). */
+ CG_CALL_TAIL = 1u << 0,
+} CGCallFlag;
+
typedef struct CGCallDesc {
const Type* fn_type;
const ABIFuncInfo* abi;
Operand callee;
const CGABIValue* args;
u32 nargs;
+ u16 flags; /* CGCallFlag */
+ u16 pad;
CGABIValue ret;
} CGCallDesc;
diff --git a/src/cg/cg.h b/src/cg/cg.h
@@ -56,6 +56,14 @@ void cg_convert(CG*, const Type* dst); /* picks ConvKind from sr
* index source of truth). */
void cg_call(CG*, u32 nargs, const Type* fn_type); /* stack: [..., callee, arg0..argN-1]
→ result (if non-void) */
+/* Sibling call: pops [callee, arg0..argN-1], lowers as a tail call. The
+ * caller's epilogue runs and control transfers to the callee, whose RET
+ * returns to the caller's caller. cg_tail_call implicitly terminates the
+ * function — the parser must NOT follow it with cg_ret. v1 has must-tail
+ * semantics: legality (ABI-compatible return, args fit in registers, no
+ * caller-frame pointer escapes via byval) is the caller's responsibility;
+ * the backend panics if it cannot honor the tail request. */
+void cg_tail_call(CG*, u32 nargs, const Type* fn_type);
void cg_ret (CG*, int has_value);
/* ----- C declarations and global initializers -----