commit d4188d73c444566caca6fe76efe02b34b73231ac
parent 177ad45c207d1d09f8bae4d419c8e4ca9d43ecc8
Author: Brian Swetland <swetland@frotz.net>
Date: Sat, 14 Mar 2020 04:58:05 -0700
compiler: handle arrays as function parameters
- we already enforce exact type match (including length)
- this arranges for arrays to be passed as reference types
(invisible pointers, effectively)
- should revisit and see if there's a cleaner way to integrate
with the type/item system
Diffstat:
4 files changed, 56 insertions(+), 12 deletions(-)
diff --git a/docs/todo.md b/docs/todo.md
@@ -2,7 +2,6 @@
### Compiler
-- [ ] support for arrays
- [ ] support for slices & string constants
- [ ] support for globals, init'ing gp
- [ ] support for enums, or convert enums to consts
@@ -10,6 +9,7 @@
- [ ] break/continue to label
- [ ] const / readonly
- [ ] type inference for var definitions
+- [x] support for arrays
- [x] support for pointers
- [x] support for structs
- [x] type definition
diff --git a/src/compiler.c b/src/compiler.c
@@ -341,6 +341,7 @@ void gen_discard(Item val);
// sets up call param #n, consuming val
void gen_param(u32 n, Item val);
+void gen_ref_param(u32 n, Item val);
// call func, consumes parameters and func
void gen_call(Item func);
@@ -999,7 +1000,11 @@ void parse_primary_expr(Item x) {
if (!compatible_type(param->type, y.type)) {
error("incompatible type for parameter '%s'\n", param->name->text);
}
- gen_param(n, &y);
+ if (param->type->kind == tArray) {
+ gen_ref_param(n, &y);
+ } else {
+ gen_param(n, &y);
+ }
param = param->next;
n++;
}
@@ -1845,7 +1850,17 @@ u32 mul_op_to_ins(u32 op) {
// parser does not know internal details like "which register is SP"
// so the backend needs to initialize variable objects for it
void gen_item_from_obj(Item x, Object obj) {
- if ((obj->kind == oParam) || (obj->kind == oVar)) {
+ if (obj->kind == oParam) {
+ if (obj->type->kind == tArray) {
+ // arrays are passed by reference through parameters
+ // maybe this should be better represented?
+ u32 r = get_reg_tmp();
+ emit_mem(LDW, r, SP, obj->value);
+ set_item(x, iRegInd, obj->type, r, 0, 0);
+ } else {
+ set_item(x, iRegInd, obj->type, SP, obj->value, 0);
+ }
+ } else if (obj->kind == oVar) {
set_item(x, iRegInd, obj->type, SP, obj->value, 0);
} else if (obj->kind == oGlobal) {
set_item(x, iRegInd, obj->type, SB, obj->value, 0);
@@ -1906,6 +1921,8 @@ void gen_load_reg(Item x, u32 r) {
}
x->kind = iReg;
x->r = r;
+ x->a = 0;
+ x->b = 0;
gen_trace("load_reg<<<", x, nil);
}
@@ -1944,21 +1961,33 @@ 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();
+void gen_address_reg(Item x, i32 r) {
+ gen_trace_n("address_reg", r, x, nil);
+ if (x->kind != iRegInd) {
+ error("internal error, wrong kind");
}
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;
+ if (r != x->r) {
+ put_reg(x->r);
+ x->r = r;
+ }
}
+// convert RegInd+off to RegInd+0
+// migrate to a tmpreg if not already
+void gen_address(Item x) {
+ if (!is_tmp_reg(x->r)) {
+ gen_address_reg(x, get_reg_tmp());
+ } else {
+ gen_address_reg(x, x->r);
+ }
+}
+
+
void gen_index(Item x, Item idx) {
gen_trace("index", x, idx);
gen_address(x);
@@ -2049,6 +2078,14 @@ void gen_return(Item x) {
add_scope_fixup(find_scope(sFunc));
}
+void gen_ref_param(u32 n, Item val) {
+ gen_trace_n("ref_param", n, val, nil);
+ if (n > 7) {
+ error("gen_ref_param - too many parameters");
+ }
+ gen_address_reg(val, n);
+}
+
void gen_param(u32 n, Item val) {
gen_trace_n("param", n, val, nil);
if (n > 7) {
diff --git a/test/1041-arrays.log b/test/1041-arrays.log
@@ -7,4 +7,12 @@ D 00000020
D 00000040
D 00000080
D 000000ff
+D 00000010
+D 00000020
+D 00000030
+D 00000040
+D 00000050
+D 00000060
+D 00000070
+D 00000080
X 00000008
diff --git a/test/1041-arrays.src b/test/1041-arrays.src
@@ -21,7 +21,6 @@ func start() i32 {
n++;
}
_hexout_(m);
- // todo: pass array refs correctly
- //dump(data);
+ dump(data);
return n;
}