boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

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:
Mcc/parse.scm | 18++++++++++++++++--
Atests/cc-parse/81-void-call.c | 19+++++++++++++++++++
Atests/cc-parse/81-void-call.expected-exit | 1+
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