commit 8c437ccf5bf48827620a07779665c2f94fdce6a5
parent 717c8d80de226bc1c453b4d88b50e2c84961e1bd
Author: Brian Swetland <swetland@frotz.net>
Date: Mon, 6 Dec 2021 02:19:08 -0800
compiler2: progress, fibbonaci test runs now
- correctly save temporary registers across function calls
- adjust codegen trace code a little
- reorganize AST node kinds and document them a bit more
- wrap IFELSE (formerly IF) in IF (new) wrapper so it can
live in the statements list without incident
Diffstat:
2 files changed, 97 insertions(+), 37 deletions(-)
diff --git a/src/codegen-risc5-simple.c b/src/codegen-risc5-simple.c
@@ -16,13 +16,15 @@ bool is_tmp_reg(u32 n) {
return (n >= tmp_reg_first) && (n <= tmp_reg_last);
}
-u32 regbits;
+u32 regbits = 0;
+u32 regcount = 0;
u32 get_reg_tmp() {
u32 n = tmp_reg_first;
while (n <= tmp_reg_last) {
if (!(regbits & (1 << n))) {
regbits |= (1 << n);
+ regcount++;
return n;
}
n++;
@@ -41,6 +43,11 @@ void put_reg(u32 r) {
error("freeing non-allocated register %u\n", r);
}
regbits = regbits & (~(1 << r));
+ regcount--;
+}
+
+bool is_reg_busy(u32 r) {
+ return regbits & (1 << r);
}
void emit(u32 ins) {
@@ -203,15 +210,16 @@ u32 loop_continue = 0;
Fixup loop_exit = nil;
Fixup func_exit = nil;
-void gen_trace(str msg) {
-}
-
void gen_block(Ast node);
u32 gen_expr(Ast node);
Ast err_last_func = nil;
Ast err_ast = nil;
+void gen_trace(str msg) {
+// fprintf(stderr, "%p %p %s\n", err_last_func, err_ast, msg);
+}
+
void dump_error_ctxt() {
fprintf(stderr, "\n");
if (err_last_func) {
@@ -236,7 +244,7 @@ void sym_get_loc(Symbol sym, u32* base, i32* offset) {
}
u32 gen_assign(Symbol sym, Ast expr) {
- gen_trace("gen_assign()\n");
+ gen_trace("gen_assign()");
u32 base;
i32 offset;
sym_get_loc(sym, &base, &offset);
@@ -246,8 +254,39 @@ u32 gen_assign(Symbol sym, Ast expr) {
return r;
}
+u32 reg_save(u32 base) {
+ u32 r = tmp_reg_first;
+ u32 n = 0;
+ while (r <= tmp_reg_last) {
+ if (regbits & (1 << r)) {
+ emit_mem(STW, r, SP, base + n);
+ n += 4;
+ }
+ r++;
+ }
+ u32 mask = regbits;
+ regbits = 0;
+ return mask;
+}
+
+void reg_restore(u32 base, u32 mask) {
+ if (regbits != 0) {
+ error("register restore collision");
+ }
+ regbits = mask;
+ u32 r = tmp_reg_first;
+ u32 n = 0;
+ while (r <= tmp_reg_last) {
+ if (regbits & (1 << r)) {
+ emit_mem(LDW, r, SP, base + n);
+ n += 4;
+ }
+ r++;
+ }
+}
+
u32 gen_call(Ast node) {
- gen_trace("gen_call()\n");
+ gen_trace("gen_call()");
Symbol sym = node->c0->sym;
Ast arg = node->c2;
@@ -256,23 +295,27 @@ u32 gen_call(Ast node) {
emit_movi(R11, 0xffff0000);
emit_mem(STW, r, R11, 0x100 + sym->value * 4);
put_reg(r);
- } else if (sym->type->len > 0) {
- // XXX: must save regs
- emit_opi(SUB, SP, SP, 4 * sym->type->len);
- u32 n = 0;
- while (arg != nil) {
- u32 r = gen_expr(arg);
- emit_mem(STW, r, SP, 4 * n);
- put_reg(r);
- arg = arg->c2;
- n = n + 1;
- }
- gen_branch_sym(AL|L, sym);
- emit_opi(ADD, SP, SP, 4 * sym->type->len);
- // XXX: must restore regs
} else {
- // no args
- gen_branch_sym(AL|L, sym);
+ u32 sizeregs = 4 * regcount;
+ if ((sym->type->len > 0) || (sizeregs > 0)) {
+ u32 sizeargs = 4 * sym->type->len;
+ emit_opi(SUB, SP, SP, sizeregs + sizeargs);
+ u32 mask = reg_save(sizeargs);
+ u32 n = 0;
+ while (arg != nil) {
+ u32 r = gen_expr(arg);
+ emit_mem(STW, r, SP, 4 * n);
+ put_reg(r);
+ arg = arg->c2;
+ n = n + 1;
+ }
+ gen_branch_sym(AL|L, sym);
+ reg_restore(sizeargs, mask);
+ emit_opi(ADD, SP, SP, sizeregs + sizeargs);
+ } else {
+ // no args or temporaries to save
+ gen_branch_sym(AL|L, sym);
+ }
}
// return is in r0, if it exists
// stash it somewhere where it won't get stomped
@@ -287,7 +330,7 @@ u32 gen_lexpr(Ast node) {
}
u32 gen_binop(Ast node, u32 op) {
- gen_trace( "gen_binop()\n");
+ gen_trace( "gen_binop()");
u32 left = gen_expr(node->c0);
u32 right = gen_expr(node->c1);
u32 res = get_reg_tmp();
@@ -298,7 +341,7 @@ u32 gen_binop(Ast node, u32 op) {
}
u32 gen_relop(Ast node, u32 cc) {
- gen_trace("gen_relop()\n");
+ gen_trace("gen_relop()");
u32 left = gen_expr(node->c0);
u32 right = gen_expr(node->c1);
u32 res = get_reg_tmp();
@@ -313,7 +356,7 @@ u32 gen_relop(Ast node, u32 cc) {
u32 gen_expr(Ast node) {
err_ast = node;
- gen_trace("gen_expr()\n");
+ gen_trace("gen_expr()");
if (node->kind == AST_U32) {
u32 r = get_reg_tmp();
emit_movi(r, node->ival);
@@ -369,6 +412,7 @@ u32 gen_expr(Ast node) {
}
void gen_while(Ast node) {
+ gen_trace("gen_while()");
// save branch targets
u32 old_loop_continue = loop_continue;
Fixup old_loop_exit = loop_exit;
@@ -397,6 +441,10 @@ void gen_while(Ast node) {
}
void gen_if_else(Ast node) {
+ gen_trace("gen_if()");
+ // IF contains one or more IFELSE nodes
+ node = node->c0;
+
// compute if expr
// branch ahead if false;
u32 r = gen_expr(node->c0);
@@ -412,7 +460,8 @@ void gen_if_else(Ast node) {
while (node != nil) {
fixup_branch_fwd(l0_br_false);
- if (node->kind == AST_IF) { // ifelse ...
+ if (node->kind == AST_IFELSE) { // ifelse ...
+ gen_trace("gen_ifelse()");
r = gen_expr(node->c0);
emit_mov(R11, r); // set z flag
put_reg(r);
@@ -421,6 +470,7 @@ void gen_if_else(Ast node) {
gen_block(node->c1);
node = node->c2;
} else { // else ...
+ gen_trace("gen_else()");
gen_block(node);
return;
}
diff --git a/src/compiler2.c b/src/compiler2.c
@@ -61,35 +61,43 @@ struct StringRec {
};
enum {
+// expression parts
AST_NAME,
AST_U32,
AST_STRING,
AST_BINOP, // c0=EXPR c1=EXPR
AST_UNOP, // c0=EXPR
+ AST_DEREF,
+ AST_INDEX,
+// container of statements
AST_BLOCK, // c0=STMT
+// statements (chained into a list by c2)
AST_EXPR, // c0=EXPR
AST_CALL, // c0=NAME c2=EXPR*
AST_WHILE, // c0=EXPR c1=BLOCK
- AST_IF, // c0=EXPR c1=BLOCKthen c2=BLOCKelse
+ AST_IF, // c0=IFELSE
AST_RETURN, // c0=EXPR
AST_BREAK,
AST_CONTINUE,
- AST_LOCAL, // c0=NAME c1=EXPR?
+// sub-part of if
+ AST_IFELSE, // c0=EXPR c1=BLOCKthen c2=BLOCKelse|IFELSE
+// top node
AST_PROGRAM, // c2=(TYPEDEF | ENUMDEF | FUNC | GLOBAL)*
+// program components (chained into a list by c2)
AST_TYPEDEF,
AST_ENUMDEF, // c2=FIELD*
AST_FUNC, // c0=BLOCK
AST_GLOBAL, // c0=EXPR
+ AST_LOCAL, // c0=NAME c1=EXPR?
AST_FIELD,
- AST_DEREF,
- AST_INDEX,
};
-str ast_kind[AST_INDEX + 1] = {
- "NAME", "U32", "STR", "BINOP", "UNOP", "BLOCK", "EXPR",
- "CALL", "WHILE", "IF", "RETURN", "BREAK", "CONTINUE",
+str ast_kind[AST_FIELD + 1] = {
+ "NAME", "U32", "STR", "BINOP", "UNOP", "DEREF", "INDEX",
+ "BLOCK", "EXPR", "CALL", "WHILE", "IF",
+ "RETURN", "BREAK", "CONTINUE", "IFELSE"
"LOCAL", "PROGRAM", "TYPEDEF", "ENUMDEF", "FUNCDEF",
- "GLOBAL", "FIELD", "DEREF", "INDEX"
+ "GLOBAL", "LOCAL", "FIELD",
};
struct AstRec {
@@ -1330,7 +1338,9 @@ Ast parse_while() {
Ast parse_if() {
// if expr { block }
- Ast ifnode = ast_make_simple(AST_IF, 0);
+ Ast node = ast_make_simple(AST_IF, 0);
+ Ast ifnode = ast_make_simple(AST_IFELSE, 0);
+ node->c0 = ifnode;
ifnode->c0 = parse_expr();
require(tOBRACE);
scope_push(SCOPE_BLOCK, nil);
@@ -1342,7 +1352,7 @@ Ast parse_if() {
if (ctx.tok == tIF) {
// ... if expr { block }
next();
- Ast ifelse = ast_make_simple(AST_IF, 0);
+ Ast ifelse = ast_make_simple(AST_IFELSE, 0);
ifelse->c0 = parse_expr();
require(tOBRACE);
scope_push(SCOPE_BLOCK, nil);
@@ -1359,7 +1369,7 @@ Ast parse_if() {
break;
}
}
- return ifnode;
+ return node;
}
Ast parse_return() {