commit 798416f66481be1b1adac24baf7d3ab281f6552d
parent 2d93b00ae781c4fcee00fa1713297f02c5801315
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Mon, 27 Apr 2026 03:10:40 -0700
cc/parse: skip useless spill on void-returning calls
parse-postfix-rest's lparen arm hardcoded has-result?=#t for cg-call,
so void-returning calls would always spill a0 (garbage) to a fresh
frame slot. Determine has-result? from the callee's return type:
for known void returns pass #f and push an imm i32 0 placeholder so
parse's "every expression leaves one opnd" invariant is preserved
without the wasted ST.
The placeholder is a vstack-only opnd — cg-pop discards it without
emitting code, so the discard sites (parse-expr-stmt, comma operator,
for-init/step) stay simple.
Lock-in: tests/cc-parse/81-void-call.c — void inc(int) accumulates
into a global; main calls it twice and returns the sum.
Diffstat:
3 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/cc/parse.scm b/cc/parse.scm
@@ -1384,9 +1384,23 @@
((eq? v 'lparen)
(advance ps) (rval-not-fn! ps)
(let* ((fn-ty (call-fn-type (ps-cg ps)))
- (n (parse-call-args ps fn-ty)))
+ (n (parse-call-args ps fn-ty))
+ ;; has-result? = #f for known void returns. Skips
+ ;; the wasted ST a0 → frame-slot spill that
+ ;; cg-call would otherwise emit for void calls.
+ (has-result?
+ (cond
+ ((not fn-ty) #t)
+ ((eq? (ctype-kind (car (ctype-ext fn-ty))) 'void) #f)
+ (else #t))))
(expect-punct ps 'rparen)
- (cg-call (ps-cg ps) n #t)
+ (cg-call (ps-cg ps) n has-result?)
+ ;; Maintain parse's "one rval per expression" invariant
+ ;; so comma / parse-expr-stmt / for-init/step pop sites
+ ;; stay simple. The placeholder is vstack-only and
+ ;; never materialized (cg-pop is a vstack op, no emit).
+ (cond ((not has-result?)
+ (cg-push-imm (ps-cg ps) %t-i32 0)))
(lp)))
((eq? v 'dot)
(advance ps)
diff --git a/tests/cc-parse/81-void-call.c b/tests/cc-parse/81-void-call.c
@@ -0,0 +1,19 @@
+/* Void-returning function called as an expression statement.
+ *
+ * cg-call has-result?=#f skips the unused a0 → frame-slot spill that
+ * non-void calls always emit. parse-postfix-rest pushes an imm
+ * placeholder onto the vstack so downstream pop sites (expression
+ * statement here, comma, for-init/step) stay uniform.
+ *
+ * Side effects: each inc(N) bumps a global counter by N.
+ */
+
+int g_acc;
+
+void inc(int x) { g_acc = g_acc + x; }
+
+int main(void) {
+ inc(5);
+ inc(7);
+ return g_acc; /* 12 */
+}
diff --git a/tests/cc-parse/81-void-call.expected-exit b/tests/cc-parse/81-void-call.expected-exit
@@ -0,0 +1 @@
+12