boot2

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

commit ebb3b75ca8d585fa0bd92a7ab7d54555047c3778
parent 85d00e53c1ad94e6f04fab08306e5127eab626e4
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Sun, 26 Apr 2026 22:56:52 -0700

cc/cg+parse: array of fn pointers initialized with names (§L.3)

Composes §E.3 (array list init) with §E.2 (label-ref pieces).
Fn-typed names bound at file scope decay to label-refs in
%const-init-piece, so `fnptr_t tab[] = { f1, f2 };` lays down
&cc__f1 and &cc__f2 in .data.

cc-cg fixture uses a ptr-to-fnptr cast so cg-binop's add path scales
by 8 (the fnptr's pointee size); fn-pointee scaling is -1 and would
silently skip the multiply. cc-parse uses the same pattern via a
typedef.

Diffstat:
Atests/cc-cg/58-fnptr-tab.expected-exit | 1+
Atests/cc-cg/58-fnptr-tab.scm | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Atests/cc-parse/58-fnptr-tab.c | 15+++++++++++++++
Atests/cc-parse/58-fnptr-tab.expected-exit | 1+
4 files changed, 66 insertions(+), 0 deletions(-)

diff --git a/tests/cc-cg/58-fnptr-tab.expected-exit b/tests/cc-cg/58-fnptr-tab.expected-exit @@ -0,0 +1 @@ +21 diff --git a/tests/cc-cg/58-fnptr-tab.scm b/tests/cc-cg/58-fnptr-tab.scm @@ -0,0 +1,49 @@ +;; tests/cc-cg/58-fnptr-tab.scm — array of function pointers initialized +;; with named functions. §L.3. +;; +;; Models: +;; int f1(void) { return 1; } +;; int f2(void) { return 2; } +;; int (*tab[])(void) = { f1, f2 }; +;; int main(void) { return tab[0]() + tab[1]() * 10; } (== 21) +;; +;; tab[i] is read via &tab + i (in fn-ptr units == 8 bytes), then a +;; %callr indirect call. + +(let* ((cg (cg-init)) + (fnty (%ctype 'fn -1 -1 (list %t-i32 '() #f))) + (fnptr (%ctype 'ptr 8 8 fnty))) + ;; int f1(void) { return 1; } + (cg-fn-begin cg "f1" '() %t-i32) + (cg-push-imm cg %t-i32 1) + (cg-return cg) + (cg-fn-end cg) + ;; int f2(void) { return 2; } + (cg-fn-begin cg "f2" '() %t-i32) + (cg-push-imm cg %t-i32 2) + (cg-return cg) + (cg-fn-end cg) + ;; tab[2] = { &f1, &f2 } — two label-ref pieces. + (let* ((aty (%ctype 'arr 16 8 (cons fnptr 2))) + (tab (%sym "tab" 'var 'static aty #f))) + (cg-emit-global cg tab (list (cons 'label-ref "cc__f1") + (cons 'label-ref "cc__f2"))) + ;; int main(void) { return tab[0]() + tab[1]() * 10; } + (cg-fn-begin cg "main" '() %t-i32) + (let ((pp (%ctype 'ptr 8 8 fnptr)) ; ptr to fnptr = pointee size 8 + (emit-call + (lambda (idx ppt) + (cg-push-sym cg tab) (cg-take-addr cg) + (cg-cast cg ppt) ; relabel to ptr-to-fnptr + (cg-push-imm cg %t-i32 idx) + (cg-binop cg 'add) ; ptr arith scales by 8 + (cg-push-deref cg) (cg-load cg) + (cg-call cg 0 #t)))) + (emit-call 0 pp) + (emit-call 1 pp) + (cg-push-imm cg %t-i32 10) + (cg-binop cg 'mul) + (cg-binop cg 'add)) + (cg-return cg) + (cg-fn-end cg)) + (write-bv-fd 1 (cg-finish cg))) diff --git a/tests/cc-parse/58-fnptr-tab.c b/tests/cc-parse/58-fnptr-tab.c @@ -0,0 +1,15 @@ +// tests/cc-parse/58-fnptr-tab.c — array of fn pointers initialised +// with named functions. §L.3. +// +// `int (*tab[])()` is currently outside parse-fn-params (Agent 2), +// so we use an explicit typedef. Member access via tab[i] is also +// pending; read elements via pointer arithmetic over &tab as +// fnptr*. +typedef int (*fnptr_t)(void); +int f1(void) { return 1; } +int f2(void) { return 2; } +fnptr_t tab[] = { f1, f2 }; +int main(void) { + fnptr_t *p = (fnptr_t *)&tab; + return (*(p + 0))() + (*(p + 1))() * 10; +} diff --git a/tests/cc-parse/58-fnptr-tab.expected-exit b/tests/cc-parse/58-fnptr-tab.expected-exit @@ -0,0 +1 @@ +21