compiler

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

commit 177ad45c207d1d09f8bae4d419c8e4ca9d43ecc8
parent 4373894d5d652611c8deae293cd2ea91584c6236
Author: Brian Swetland <swetland@frotz.net>
Date:   Sat, 14 Mar 2020 04:05:08 -0700

compiler: arrays, types, etc

- rename same-numbered error tests
- some array tests
- enforce type compatibility on function params and return
- allow byte to be passed as int32
- support array indexing
- compile time oob checking for const indices
- codegen now knows how to load/store bytes as well as words
- passing arrays as function parameters needs some item/type surgery
  and does not work just yet

Diffstat:
Msrc/compiler.c | 89++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Atest/1041-arrays.log | 10++++++++++
Atest/1041-arrays.src | 27+++++++++++++++++++++++++++
Atest/1103-err-decl-mismatch-array.src | 8++++++++
Rtest/1100-err-decl-mismatch-type.src -> test/2000-err-decl-mismatch-type.src | 0
Rtest/1100-err-decl-mismatch-return.src -> test/2001-err-decl-mismatch-return.src | 0
Rtest/1100-err-decl-mismatch-count.src -> test/2002-err-decl-mismatch-count.src | 0
Rtest/1100-err-array-init-too-large.src -> test/2010-err-array-init-too-large.src | 0
Atest/2011-err-array-oob-const.src | 6++++++
9 files changed, 133 insertions(+), 7 deletions(-)

diff --git a/src/compiler.c b/src/compiler.c @@ -327,6 +327,9 @@ void gen_unary_op(u32 op, Item x); // stores val into var, consuming both void gen_store(Item val, Item var); +// replace array item x with element item (at idx) +void gen_index(Item x, Item idx); + // consume ptr item, transforming into thing-pointed-at void gen_deref_ptr(Item x); @@ -481,7 +484,7 @@ void init_ctx() { make_builtin("_hexout_", biPrintHex32, ctx.type_int32, nil, ctx.type_void); } -bool sametype(Type a, Type b) { +bool same_type(Type a, Type b) { if (a->kind != b->kind) { return false; } @@ -495,7 +498,7 @@ bool sametype(Type a, Type b) { Object b1 = b->first; while ((a1 != nil) && (b1 != nil)) { // check that parameters and fields match - if (!sametype(a1->type, b1->type)) { + if (!same_type(a1->type, b1->type)) { return false; } } @@ -506,6 +509,16 @@ bool sametype(Type a, Type b) { return true; } +// for assignments, etc +bool compatible_type(Type dst, Type src) { + if (dst->kind == tInt32) { + if (src->kind == tByte) { + return true; + } + } + return same_type(dst, src); +} + void error(const char *fmt, ...) { va_list ap; @@ -983,6 +996,9 @@ void parse_primary_expr(Item x) { } ItemRec y; parse_expr(&y); + if (!compatible_type(param->type, y.type)) { + error("incompatible type for parameter '%s'\n", param->name->text); + } gen_param(n, &y); param = param->next; n++; @@ -1003,8 +1019,24 @@ void parse_primary_expr(Item x) { } } else if (ctx.tok == tOBRACK) { next(); + ItemRec y; + parse_expr(&y); require(tCBRACK); - error("<TODO> array deref"); + if (x->type->kind != tArray) { + error("can only use [] with array"); + } + if (x->kind != iRegInd) { + error("internal: cannot index via item kind %u", x->kind); + } + if (y.kind == iConst) { + if (y.a >= x->type->len) { + error("array index out of range"); + } + x->a = x->a + y.a * x->type->base->size; + x->type = x->type->base; + } else { + gen_index(x, &y); + } } else { break; } @@ -1275,7 +1307,7 @@ void parse_return() { x.type = ctx.type_void; } else { parse_expr(&x); - if (!sametype(ctx.fn->type->base, x.type)) { + if (!compatible_type(ctx.fn->type->base, x.type)) { error("return types do not match"); } require(tSEMI); @@ -1601,7 +1633,7 @@ void parse_function() { Object pb = obj->type->first; u32 i = 1; while ((pa != nil) && (pb != nil)) { - if (!sametype(pa->type, pb->type)) { + if (!same_type(pa->type, pb->type)) { error("func '%s' param %u differs from decl", fname->text, i); } pa = pa->next; @@ -1859,7 +1891,13 @@ void gen_load_reg(Item x, u32 r) { } else if (x->kind == iConst) { emit_mov(r, x->a); } else if (x->kind == iRegInd) { - emit_mem(LDW, r, x->r, x->a); + if (x->type->size == 4) { + emit_mem(LDW, r, x->r, x->a); + } else if (x->type->size == 1) { + emit_mem(LDB, r, x->r, x->a); + } else { + error("cannot load a size %u item\n", x->type->size); + } if (x->r != r) { put_reg(x->r); } @@ -1892,7 +1930,13 @@ void gen_store(Item val, Item adr) { gen_trace("gen_store", val, adr); gen_load(val); if (adr->kind == iRegInd) { - emit_mem(STW, val->r, adr->r, adr->a); + if (adr->type->size == 4) { + emit_mem(STW, val->r, adr->r, adr->a); + } else if (adr->type->size == 1) { + emit_mem(STB, val->r, adr->r, adr->a); + } else { + error("cannot store a size %u item\n", adr->type->size); + } put_reg(val->r); put_reg(adr->r); } else { @@ -1900,6 +1944,37 @@ void gen_store(Item val, Item adr) { } } +// convert RegInd+off to RegInd+0 +// migrate to a tmpreg if not already +void gen_address(Item x) { + i32 r = x->r; + if (!is_tmp_reg(r)) { + r = get_reg_tmp(); + } + if (x->a > 0) { + emit_opi_n(ADD, r, x->r, x->a); + } else if(r != x->r) { + emit_op(MOV, r, 0, x->r); + } + x->r = r; +} + +void gen_index(Item x, Item idx) { + gen_trace("index", x, idx); + gen_address(x); + u32 sz = x->type->base->size; + gen_load(idx); + // OPT: use shifts for powers of two + if (sz > 1) { + emit_opi_n(MUL, idx->r, idx->r, sz); + } + // TODO: range check + emit_op(ADD, x->r, x->r, idx->r); + put_reg(idx->r); + x->type = x->type->base; + gen_trace("index<<<", x, nil); +} + void gen_deref_ptr(Item x) { gen_trace("deref_ptr", x, nil); gen_load(x); diff --git a/test/1041-arrays.log b/test/1041-arrays.log @@ -0,0 +1,10 @@ +D 00000001 +D 00000002 +D 00000004 +D 00000008 +D 00000010 +D 00000020 +D 00000040 +D 00000080 +D 000000ff +X 00000008 diff --git a/test/1041-arrays.src b/test/1041-arrays.src @@ -0,0 +1,27 @@ + +var numbers [8]byte = { 1, 2, 4, 8, 16, 32, 64, 128 }; + +var data [8]byte = { 0x10, 0x20, 0x30, 0x40, + 0x50, 0x60, 0x70, 0x80 }; + +func dump(x [8]byte) { + var n i32 = 0; + while (n < 8) { + _hexout_(x[n]); + n++; + } +} + +func start() i32 { + var n i32 = 0; + var m i32 = 0; + while (n < 8) { + _hexout_(numbers[n]); + m = m + numbers[n]; + n++; + } + _hexout_(m); + // todo: pass array refs correctly + //dump(data); + return n; +} diff --git a/test/1103-err-decl-mismatch-array.src b/test/1103-err-decl-mismatch-array.src @@ -0,0 +1,8 @@ + +func a1a1a1(aaa [17]i32) { +} + +func bad() { + var z [10]i32; + a1a1a1(z); +} diff --git a/test/1100-err-decl-mismatch-type.src b/test/2000-err-decl-mismatch-type.src diff --git a/test/1100-err-decl-mismatch-return.src b/test/2001-err-decl-mismatch-return.src diff --git a/test/1100-err-decl-mismatch-count.src b/test/2002-err-decl-mismatch-count.src diff --git a/test/1100-err-array-init-too-large.src b/test/2010-err-array-init-too-large.src diff --git a/test/2011-err-array-oob-const.src b/test/2011-err-array-oob-const.src @@ -0,0 +1,6 @@ + +var blargh [256]byte; + +func bad() { + var n = blarg[256]; +}