commit 435e53aa0c52fb02d5158f63be5f20a14f5cb746
parent 17ffd9544a46f70900778f1c5958b7d4c1bb3861
Author: Brian Swetland <swetland@frotz.net>
Date: Sun, 15 Mar 2020 07:46:32 -0700
compiler: add support for continue keyword
- and unit tests
- and docs updates
Diffstat:
7 files changed, 76 insertions(+), 7 deletions(-)
diff --git a/docs/notebook.md b/docs/notebook.md
@@ -2,6 +2,31 @@
A place to jot down ideas and/or commentary about the work in progress.
+### 2020 Mar 15 - Non-optimal codegen
+
+1030-flow-control shows inefficient branch patterns around if-x-continue usage:
+
+```text
+000000ac: 88e00004 ldw r8, [sp, 4]
+000000b0: 48840001 and r8, r8, 1
+000000b4: 49000001 mov r9, 1
+000000b8: 08890009 sub r8, r8, r9
+000000bc: e9000002 bne 0xc8
+
+ if ((n & 1) == 1) {
+
+000000c0: e7fffff3 b 0x90
+
+ continue;
+ }
+
+000000c4: e7000000 b 0xc8
+```
+
+This also gets me thinking that adopting the C convention that integer types
+are treated as bools (0 = false, othewise true) would be more efficent in a
+number of places,
+
### 2020 Mar 14 - More questionable codegen
All of these from `demo/life.src`
diff --git a/docs/todo.md b/docs/todo.md
@@ -4,10 +4,10 @@
- [ ] support for slices & string constants
- [ ] support for enums, or convert enums to consts
-- [ ] continue
- [ ] break/continue to label
- [ ] const / readonly
- [ ] type inference for var definitions
+- [x] continue
- [x] support for arrays
- [x] support for pointers
- [x] support for globals, init'ing gp
@@ -23,17 +23,17 @@
### Self-Hosting Cleanup
-- [ ] rewrite lexer to use if/else instead of case
-- [ ] table driven lexing
- [ ] abandon all-source-in-ram approach
- [ ] eliminate #defines
+- [x] rewrite lexer to use if/else instead of case
+- [x] table driven lexing
### Syntax
- [ ] `type Foo struct { ... }` vs `struct Foo { ... }`
- [ ] semicolons - optional? mandatory? eliminate?
- [ ] colon between param/field name and type (RustLike) or not (GoLike)?
-- [ ] naming scheme for PODs
+- [ ] naming scheme for PODs (`i32` vs `int32` vs `int32_t`, etc)
### Optimizations
@@ -44,3 +44,5 @@
### Portability / Modularity
- [ ] RISCV RV32I backend
+- [ ] X86-64 backend
+- [ ] third party writes a backend
diff --git a/src/compiler.c b/src/compiler.c
@@ -305,6 +305,9 @@ struct CtxRec {
u32 data[8192];
u32 pc;
+ // if nonzero, target for continue
+ u32 pc_continue;
+
// The latest pc that a forward branch has been
// fixed up to. cannot safely move code at or
// before this address.
@@ -1299,7 +1302,8 @@ void parse_block();
void parse_while() {
ItemRec x;
- u32 l0_loop = ctx.pc; // for backward branch
+ u32 save = ctx.pc_continue;
+ ctx.pc_continue = ctx.pc; // for backward branch
parse_expr(&x);
u32 l1_br_false = gen_branch_cond(&x, false);
@@ -1307,10 +1311,12 @@ void parse_while() {
require(tOBRACE);
push_scope(sLoop, nil);
parse_block();
- gen_branch_back(l0_loop);
+ gen_branch_back(ctx.pc_continue);
pop_scope();
fixup_branch_fwd(l1_br_false);
+
+ ctx.pc_continue = save;
}
void parse_if() {
@@ -1387,13 +1393,22 @@ void parse_return() {
void parse_break() {
// XXX break-to-labeled-loop support
- require(tSEMI);
gen_branch_fwd();
Scope scope = find_scope(sLoop);
if (scope == nil) {
error("break must be used from inside a looping construct");
}
add_scope_fixup(scope);
+ require(tSEMI);
+}
+
+void parse_continue() {
+ // XXX continue-to-labeled-loop support
+ if (ctx.pc_continue == 0) {
+ error("continue must be used from inside a looping construct");
+ }
+ gen_branch_back(ctx.pc_continue);
+ require(tSEMI);
}
void STORE(u32 val, u32* ptr, u32 n, u32 sz) {
@@ -1575,6 +1590,9 @@ void parse_block() {
} else if (ctx.tok == tBREAK) {
next();
parse_break();
+ } else if (ctx.tok == tCONTINUE) {
+ next();
+ parse_continue();
} else if (ctx.tok == tWHILE) {
next();
parse_while();
diff --git a/test/1030-flow-control.log b/test/1030-flow-control.log
@@ -7,4 +7,8 @@ D 00000006
D 00000005
D 00000004
D 00000003
+D 00000006
+D 00000004
+D 00000002
+D 00000000
X 00000001
diff --git a/test/1030-flow-control.src b/test/1030-flow-control.src
@@ -12,6 +12,16 @@ func count(n i32) {
}
}
+func count_even(n i32) {
+ while (n > 0) {
+ n--;
+ if ((n & 1) == 1) {
+ continue;
+ }
+ _hexout_(n);
+ }
+}
+
func start() i32 {
if (true) {
hex(0x10101010);
@@ -29,5 +39,7 @@ func start() i32 {
count(7);
+ count_even(7);
+
return 1;
}
diff --git a/test/2030-err-bad-break.src b/test/2030-err-bad-break.src
@@ -0,0 +1,4 @@
+
+func nogood() {
+ break;
+}
diff --git a/test/2031-err-bad-continue.src b/test/2031-err-bad-continue.src
@@ -0,0 +1,4 @@
+
+func fail() {
+ continue;
+}