commit 53f1be65ea19367289b852dc6d3f1676d8f3ad35
parent f18b740fb0d49db51a671bf3ab0dac51646bdcac
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sun, 26 Apr 2026 22:41:57 -0700
cc/cg: array element access at non-zero index (§D.5)
Locks in the array-decay + pointer-arithmetic path that cg-push-field
shipped with in §D.1. The cg fixture pushes the arr-typed lval,
cg-load decays it to a ptr-to-elem rval, cg-binop add scales the
index, cg-push-deref produces an element lval. Three writes (1, 2, 4)
and a 3-term sum read back to 7 isolate every index — a wrong scale
or wrong base shows up as a different sum.
Diffstat:
2 files changed, 56 insertions(+), 0 deletions(-)
diff --git a/tests/cc-cg/40-array-index.expected-exit b/tests/cc-cg/40-array-index.expected-exit
@@ -0,0 +1 @@
+7
diff --git a/tests/cc-cg/40-array-index.scm b/tests/cc-cg/40-array-index.scm
@@ -0,0 +1,55 @@
+;; tests/cc-cg/40-array-index.scm — array element access at non-zero
+;; index (§D.5 of docs/CC-PUNCHLIST.md). Models:
+;; int a[3]; a[0]=1; a[1]=2; a[2]=4; return a[0]+a[1]+a[2]; -> 7
+;;
+;; The cg API does the same dance the parser uses for a[i]:
+;; cg-push-sym sym-a ; arr-typed lval
+;; cg-push-imm i ; index rval
+;; cg-binop add ; ptr arithmetic — `cg-load` decays array to
+;; ; ptr, then add scales by elem size
+;; cg-push-deref ; lval int through the computed pointer
+;;
+;; Wait — cg-binop pops both ops; for the lhs we need rval-of-arr,
+;; not the array lval. We therefore call cg-load BEFORE the index
+;; push, so the arr lval decays to a ptr-rval first.
+
+(let* ((cg (cg-init))
+ (arr-ty (%ctype 'arr 12 4 (cons %t-i32 3))))
+ (cg-fn-begin cg "main" '() %t-i32)
+ (let* ((off-a (cg-alloc-slot cg 12 4))
+ (sym-a (%sym "a" 'var 'auto arr-ty off-a)))
+ ;; a[0] = 1
+ (cg-push-sym cg sym-a)
+ (cg-load cg) ; arr lval -> ptr rval (decay)
+ (cg-push-imm cg %t-i32 0)
+ (cg-binop cg 'add) ; ptr + 0
+ (cg-push-deref cg)
+ (cg-push-imm cg %t-i32 1)
+ (cg-assign cg) (cg-pop cg)
+ ;; a[1] = 2
+ (cg-push-sym cg sym-a) (cg-load cg)
+ (cg-push-imm cg %t-i32 1) (cg-binop cg 'add)
+ (cg-push-deref cg)
+ (cg-push-imm cg %t-i32 2)
+ (cg-assign cg) (cg-pop cg)
+ ;; a[2] = 4
+ (cg-push-sym cg sym-a) (cg-load cg)
+ (cg-push-imm cg %t-i32 2) (cg-binop cg 'add)
+ (cg-push-deref cg)
+ (cg-push-imm cg %t-i32 4)
+ (cg-assign cg) (cg-pop cg)
+ ;; return a[0] + a[1] + a[2]
+ (cg-push-sym cg sym-a) (cg-load cg)
+ (cg-push-imm cg %t-i32 0) (cg-binop cg 'add)
+ (cg-push-deref cg) (cg-load cg)
+ (cg-push-sym cg sym-a) (cg-load cg)
+ (cg-push-imm cg %t-i32 1) (cg-binop cg 'add)
+ (cg-push-deref cg) (cg-load cg)
+ (cg-binop cg 'add)
+ (cg-push-sym cg sym-a) (cg-load cg)
+ (cg-push-imm cg %t-i32 2) (cg-binop cg 'add)
+ (cg-push-deref cg) (cg-load cg)
+ (cg-binop cg 'add)
+ (cg-return cg))
+ (cg-fn-end cg)
+ (write-bv-fd 1 (cg-finish cg)))