compiler

Unnamed Compiled Systems Language Project
git clone http://frotz.net/git/compiler.git
Log | Files | Refs

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:
Mdocs/notebook.md | 25+++++++++++++++++++++++++
Mdocs/todo.md | 10++++++----
Msrc/compiler.c | 24+++++++++++++++++++++---
Mtest/1030-flow-control.log | 4++++
Mtest/1030-flow-control.src | 12++++++++++++
Atest/2030-err-bad-break.src | 4++++
Atest/2031-err-bad-continue.src | 4++++
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; +}