commit 9c40bcc14c1d4d7eed39d4da9dbe8fc53006a1c2
parent 0fd2a385eff1429fab658443cb8c57f015cc3b1f
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sun, 26 Apr 2026 22:31:45 -0700
cc/cg: add cg-emit-label / cg-goto for goto+labels (§F.4)
cg-emit-label name-bv drops `::user_<name>` so libp1pp's %scope
mechanism prefixes it to `<fn>__user_<name>`. cg-goto emits
`%b(&::user_<name>)`. Forward refs work because resolution is at
emit time.
Drive-by: cg-binop 'le/'ge previously emitted %xori, which is not
defined anywhere in P1/. Replaced with %li(t1,1) %xor(t0,t0,t1).
The first fixture to exercise these cmps is 65-goto.
Diffstat:
3 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/cc/cg.scm b/cc/cg.scm
@@ -589,10 +589,10 @@
((eq? op 'gt) (%cg-emit-cmp cg (if unsigned? "ltu" "lt") 'a1 'a0 't0))
((eq? op 'le)
(%cg-emit-cmp cg (if unsigned? "ltu" "lt") 'a1 'a0 't0)
- (%cg-emit-many cg (list "%xori(t0, t0, 1)\n")))
+ (%cg-emit-many cg (list "%li(t1, 1)\n%xor(t0, t0, t1)\n")))
((eq? op 'ge)
(%cg-emit-cmp cg (if unsigned? "ltu" "lt") 'a0 'a1 't0)
- (%cg-emit-many cg (list "%xori(t0, t0, 1)\n")))
+ (%cg-emit-many cg (list "%li(t1, 1)\n%xor(t0, t0, t1)\n")))
(else (die #f "cg-binop: unknown op" op)))
(%cg-spill-reg cg 't0 result-ty)))))
@@ -735,6 +735,19 @@
(%cg-emit-many cg (list "%continue(" tag ")\n")))
;; --------------------------------------------------------------------
+;; Labels and unconditional goto (§F.4 / CC-CONTRACTS §5.3).
+;; user_<name> namespace keeps the user's label space disjoint from
+;; the compiler-internal ::ret and ::lbl_<n>. Labels resolve through
+;; libp1pp's %scope mechanism, so forward references inside the same
+;; %fn block work without explicit forward declaration.
+;; --------------------------------------------------------------------
+(define (cg-emit-label cg name-bv)
+ (%cg-emit-many cg (list "::user_" name-bv "\n")))
+
+(define (cg-goto cg name-bv)
+ (%cg-emit-many cg (list "%b(&::user_" name-bv ")\n")))
+
+;; --------------------------------------------------------------------
;; switch
;; --------------------------------------------------------------------
(define-record-type swctx
diff --git a/tests/cc-cg/65-goto.expected-exit b/tests/cc-cg/65-goto.expected-exit
@@ -0,0 +1 @@
+3
diff --git a/tests/cc-cg/65-goto.scm b/tests/cc-cg/65-goto.scm
@@ -0,0 +1,57 @@
+;; tests/cc-cg/65-goto.scm — goto + labelled statements, forward and back (§F.4).
+;; Models a counter that uses goto for both forward skip and backward jump:
+;; int main(void) {
+;; int s = 0;
+;; int i = 0;
+;; loop:
+;; if (i >= 3) goto done;
+;; s = s + 1;
+;; i = i + 1;
+;; goto loop;
+;; done:
+;; return s; /* 3 */
+;; }
+;;
+;; Exercises cg-emit-label (drops ::user_<name>) and cg-goto (emits
+;; %b(&::user_<name>)). Forward refs work because libp1pp's %scope
+;; resolves labels at emit time.
+
+(let* ((cg (cg-init))
+ (params (cg-fn-begin cg "main" '() %t-i32))
+ (s-sl (cg-alloc-slot cg 4 4))
+ (i-sl (cg-alloc-slot cg 4 4))
+ (s-sym (%sym "s" 'var 'auto %t-i32 s-sl))
+ (i-sym (%sym "i" 'var 'auto %t-i32 i-sl)))
+ ;; s = 0; i = 0;
+ (cg-push-sym cg s-sym) (cg-push-imm cg %t-i32 0)
+ (cg-assign cg) (cg-pop cg)
+ (cg-push-sym cg i-sym) (cg-push-imm cg %t-i32 0)
+ (cg-assign cg) (cg-pop cg)
+
+ ;; loop:
+ (cg-emit-label cg "loop")
+ ;; if (i >= 3) goto done;
+ (cg-push-sym cg i-sym) (cg-load cg)
+ (cg-push-imm cg %t-i32 3)
+ (cg-binop cg 'ge)
+ (cg-if cg (lambda () (cg-goto cg "done")))
+ ;; s = s + 1;
+ (cg-push-sym cg s-sym)
+ (cg-push-sym cg s-sym) (cg-load cg)
+ (cg-push-imm cg %t-i32 1)
+ (cg-binop cg 'add)
+ (cg-assign cg) (cg-pop cg)
+ ;; i = i + 1;
+ (cg-push-sym cg i-sym)
+ (cg-push-sym cg i-sym) (cg-load cg)
+ (cg-push-imm cg %t-i32 1)
+ (cg-binop cg 'add)
+ (cg-assign cg) (cg-pop cg)
+ ;; goto loop;
+ (cg-goto cg "loop")
+ ;; done:
+ (cg-emit-label cg "done")
+ (cg-push-sym cg s-sym) (cg-load cg)
+ (cg-return cg)
+ (cg-fn-end cg)
+ (write-bv-fd 1 (cg-finish cg)))