aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Smeding <tom.smeding@gmail.com>2018-01-05 17:52:38 +0100
committerTom Smeding <tom.smeding@gmail.com>2018-01-05 17:52:38 +0100
commita298cb75c4f586b83b304c7dc66cb555693ea1b8 (patch)
tree7b620a14b5acb4f7e3e29fcbf36ac11ff660c175
parent9911f9a73c7dc46069199e52f2bc54082d10366c (diff)
Stuff
-rw-r--r--compiler.c70
-rw-r--r--ir.c102
-rw-r--r--ir.h32
-rw-r--r--main.c1
-rw-r--r--test/t1.c2
5 files changed, 181 insertions, 26 deletions
diff --git a/compiler.c b/compiler.c
index 42ad25c..34372f3 100644
--- a/compiler.c
+++ b/compiler.c
@@ -13,6 +13,12 @@ static void write_func_params(struct pair_tn *params, struct node *list) {
write_func_params(params + 1, list->child2);
}
+static void write_node_list(struct node **dest, struct node *list) {
+ if (list->type == N_LIST_END) return;
+ dest[0] = list->child1;
+ write_node_list(dest + 1, list->child2);
+}
+
static bool oper_is_basic_arith(enum operator oper) {
return oper == OP_ADD || oper == OP_SUB || oper == OP_MUL || oper == OP_DIV || oper == OP_MOD;
}
@@ -78,6 +84,10 @@ static struct ref compile_expr(struct ir *ir, struct symtab *symtab, struct node
fprintf(stderr, "Use of undeclared variable '%s'\n", node->name);
exit(1);
}
+ if (sym->stype != ST_VAR) {
+ fprintf(stderr, "Cannot use function name in expression\n");
+ exit(1);
+ }
return sym->ref;
}
@@ -146,12 +156,12 @@ static struct ref compile_expr(struct ir *ir, struct symtab *symtab, struct node
struct ref addr = compile_expr(ir, symtab, node->child1);
struct ref r1;
switch (addr.type) {
- case REF_REG: r1 = ref_mem(addr.reg, 0, false); break;
- case REF_IMM: r1 = ref_mem(-1, addr.imm, false); break;
+ case REF_REG: r1 = ref_mem(addr.reg, 0, REFREL_ZERO); break;
+ case REF_IMM: r1 = ref_mem(REG_UNUSED, addr.imm, REFREL_ZERO); break;
case REF_MEM: {
r1 = ref_next_register();
ir_append(ir, irins_make_01(INS_MOV, r1, addr));
- r1 = ref_mem(r1.reg, 0, false); break;
+ r1 = ref_mem(r1.reg, 0, REFREL_ZERO); break;
break;
}
}
@@ -170,14 +180,38 @@ static struct ref compile_expr(struct ir *ir, struct symtab *symtab, struct node
}
case N_CALL: {
- fprintf(stderr, "function calls not implemented\n");
- exit(1);
- /*struct symbol *sym = symtab_find(symtab, node->name);
+ struct symbol *sym = symtab_find(symtab, node->name);
if (!sym) {
fprintf(stderr, "Call of undeclared function '%s'\n", node->name);
exit(1);
}
- ;*/
+ if (sym->stype != ST_FUNC) {
+ fprintf(stderr, "Cannot call variable\n");
+ exit(1);
+ }
+ if (node_list_length(node->child1) != sym->numparams) {
+ fprintf(stderr, "Invalid number of parameters to function '%s' (typechecker, come on)\n", node->name);
+ exit(1);
+ }
+ struct node **args = malloc(sym->numparams * sizeof(struct node*));
+ write_node_list(args, node->child1);
+ for (int i = sym->numparams - 1; i >= 0; i--) {
+ struct ref r = compile_expr(ir, symtab, args[i]);
+ ir_append(ir, irins_make_1(INS_PUSH, r));
+ }
+ free(args);
+ struct ref retref;
+ if (node->rtype == type_void()) {
+ ir_append(ir, irins_make_name(INS_CALL, node->name));
+ retref = ref_reg(REG_UNUSED); // TODO make nicer; typechecker should've caught usages though
+ } else {
+ retref = ref_next_register();
+ struct irins *ins = irins_make_0(INS_CALLV, retref);
+ ins->name = strdup(node->name);
+ ir_append(ir, ins);
+ }
+ ir_append(ir, irins_make_012(INS_ADD, ref_reg(REG_SP), ref_reg(REG_SP), ref_imm(sym->numparams)));
+ return retref;
}
default:
@@ -209,10 +243,13 @@ static void compile_node(struct ir *ir, struct symtab *symtab, struct node *node
fprintf(stderr, "Redeclaration of variable '%s'\n", node->name);
exit(1);
}
+ struct ref vref;
+ if (node->type == N_VAR_DECL_INIT) vref = compile_expr(ir, symtab, node->child1);
+ else vref = ref_imm(0);
struct symbol *sym = symbol_make_var(node->name, node->rtype);
sym->ref = ref_next_register();
symtab_insert(symtab, sym);
- ir_append(ir, irins_make_01(INS_MOV, sym->ref, ref_imm(node->value)));
+ ir_append(ir, irins_make_01(INS_MOV, sym->ref, vref));
break;
}
@@ -227,17 +264,22 @@ static void compile_node(struct ir *ir, struct symtab *symtab, struct node *node
symtab_insert(symtab_root(symtab), sym);
ir_append(ir, irins_make_name(INS_LBL, strdup(node->name)));
symtab = symtab_sub(symtab);
+ for (int i = 0; i < numparams; i++) {
+ struct symbol *parsym = symbol_make_var(sym->params[i].name, sym->params[i].type);
+ parsym->ref = ref_mem(REG_BP, -2 - i, REFREL_ZERO);
+ symtab_insert(symtab, parsym);
+ }
compile_node(ir, symtab, node->child2);
symtab = symtab_delete_get_parent(symtab);
break;
}
case N_IF: {
+ char *thenlbl = gen_label_name();
char *elselbl = gen_label_name();
char *afterlbl = gen_label_name();
- struct ref condref = compile_expr(ir, symtab, node->child1);
- ir_append(ir, irins_make_12(INS_TEST, condref, condref));
- ir_append(ir, irins_make_jcc(elselbl, CCZ));
+ compile_boolexpr(ir, symtab, node->child1, thenlbl, elselbl);
+ ir_append(ir, irins_make_name(INS_LBL, thenlbl));
compile_node(ir, symtab, node->child2);
ir_append(ir, irins_make_name(INS_JMP, afterlbl));
ir_append(ir, irins_make_name(INS_LBL, elselbl));
@@ -248,11 +290,11 @@ static void compile_node(struct ir *ir, struct symtab *symtab, struct node *node
case N_WHILE: {
char *startlbl = gen_label_name();
+ char *bodylbl = gen_label_name();
char *afterlbl = gen_label_name();
ir_append(ir, irins_make_name(INS_LBL, startlbl));
- struct ref condref = compile_expr(ir, symtab, node->child1);
- ir_append(ir, irins_make_12(INS_TEST, condref, condref));
- ir_append(ir, irins_make_jcc(afterlbl, CCZ));
+ compile_boolexpr(ir, symtab, node->child1, bodylbl, afterlbl);
+ ir_append(ir, irins_make_name(INS_LBL, bodylbl));
compile_node(ir, symtab, node->child2);
ir_append(ir, irins_make_name(INS_JMP, startlbl));
ir_append(ir, irins_make_name(INS_LBL, afterlbl));
diff --git a/ir.c b/ir.c
index 9d28e2f..cf529dd 100644
--- a/ir.c
+++ b/ir.c
@@ -1,5 +1,5 @@
-#include <stdio.h>
#include <stdlib.h>
+#include <assert.h>
#include "ir.h"
@@ -20,10 +20,94 @@ void ir_delete(struct ir *ir) {
free(ir);
}
+void ir_print(struct ir *ir, FILE *f) {
+ fprintf(f, "IR [globspace=%d]\n", ir->globspace);
+ for (int i = 0; i < ir->len; i++) {
+ irins_print(ir->inss[i], f);
+ }
+}
+
+static const char* condcode_show(enum condcode condcode) {
+ switch (condcode) {
+ case CCZ: return "z";
+ case CCNZ: return "nz";
+ case CCL: return "l";
+ case CCG: return "g";
+ case CCLE: return "le";
+ case CCGE: return "ge";
+ default: assert(false);
+ }
+}
+
+static const char* ref_show(struct ref ref) {
+ static char cbuf[3][16];
+ static int cbufi = 0;
+ static const char *special[8] = {"A", "B", "C", "D", "X", "Y", "SP", "BP"};
+
+ const char *suffix;
+ if (ref.rel == REFREL_ZERO) suffix = "";
+ else if (ref.rel == REFREL_DATA) suffix = ":data";
+ else if (ref.rel == REFREL_HEAP) suffix = ":heap";
+ else assert(false);
+
+ switch (ref.type) {
+ case REF_REG:
+ if (ref.reg == REG_UNUSED) return "<<UNUSED?>>";
+ if (ref.reg < 0) return special[-(ref.reg - REG_A)];
+ cbufi = (cbufi + 1) % 3;
+ sprintf(cbuf[cbufi], "t%d", ref.reg);
+ return cbuf[cbufi];
+
+ case REF_MEM:
+ cbufi = (cbufi + 1) % 3;
+ if (ref.reg == REG_UNUSED) {
+ sprintf(cbuf[cbufi], "[%d%s]", ref.offset, suffix);
+ } else if (ref.reg < 0) {
+ sprintf(cbuf[cbufi], "[%s + %d%s]", special[-(ref.reg - REG_A)], ref.offset, suffix);
+ } else {
+ sprintf(cbuf[cbufi], "[t%d + %d%s]", ref.reg, ref.offset, suffix);
+ }
+ return cbuf[cbufi];
+
+ case REF_IMM:
+ cbufi = (cbufi + 1) % 3;
+ sprintf(cbuf[cbufi], "%d", ref.imm);
+ return cbuf[cbufi];
+
+ default:
+ assert(false);
+ }
+}
+
+void irins_print(struct irins *ins, FILE *f) {
+ switch (ins->type) {
+ case INS_ADD: fprintf(f, "\t%s <- %s + %s\n", ref_show(ins->r0), ref_show(ins->r1), ref_show(ins->r2)); break;
+ case INS_SUB: fprintf(f, "\t%s <- %s - %s\n", ref_show(ins->r0), ref_show(ins->r1), ref_show(ins->r2)); break;
+ case INS_MUL: fprintf(f, "\t%s <- %s * %s\n", ref_show(ins->r0), ref_show(ins->r1), ref_show(ins->r2)); break;
+ case INS_DIV: fprintf(f, "\t%s <- %s / %s\n", ref_show(ins->r0), ref_show(ins->r1), ref_show(ins->r2)); break;
+ case INS_MOD: fprintf(f, "\t%s <- %s %% %s\n", ref_show(ins->r0), ref_show(ins->r1), ref_show(ins->r2)); break;
+ case INS_NEG: fprintf(f, "\t%s <- -%s\n", ref_show(ins->r0), ref_show(ins->r1)); break;
+ case INS_NOT: fprintf(f, "\t%s <- !%s\n", ref_show(ins->r0), ref_show(ins->r1)); break;
+ case INS_TEST: fprintf(f, "\ttest %s, %s\n", ref_show(ins->r1), ref_show(ins->r2)); break;
+ case INS_PUSH: fprintf(f, "\tpush %s\n", ref_show(ins->r1)); break;
+ case INS_POP: fprintf(f, "\t%s = pop\n", ref_show(ins->r0)); break;
+ case INS_CMP: fprintf(f, "\tcmp %s, %s\n", ref_show(ins->r1), ref_show(ins->r2)); break;
+ case INS_LBL: fprintf(f, "%s:\n", ins->name); break;
+ case INS_JMP: fprintf(f, "\tjmp %s\n", ins->name); break;
+ case INS_JCC: fprintf(f, "\tj%s %s\n", condcode_show(ins->condcode), ins->name); break;
+ case INS_CALL: fprintf(f, "\tcall %s\n", ins->name); break;
+ case INS_CALLV: fprintf(f, "\t%s <- call %s\n", ref_show(ins->r0), ins->name); break;
+ case INS_RET: fprintf(f, "\tret\n"); break;
+ case INS_RETV: fprintf(f, "\tret %s\n", ref_show(ins->r1)); break;
+ case INS_MOV: fprintf(f, "\t%s <- %s\n", ref_show(ins->r0), ref_show(ins->r1)); break;
+ default: assert(false);
+ }
+}
+
struct ref ir_reserve_global(struct ir *ir, int size) {
int offset = ir->globspace;
ir->globspace += size;
- return ref_mem(-1, offset, true);
+ return ref_mem(REG_UNUSED, offset, REFREL_DATA);
}
void ir_append(struct ir *ir, struct irins *ins) {
@@ -47,6 +131,12 @@ struct irins* irins_make_name(enum instype type, char *name) {
return ins;
}
+struct irins* irins_make_0(enum instype type, struct ref r0) {
+ struct irins *ins = irins_make(type);
+ ins->r0 = r0;
+ return ins;
+}
+
struct irins* irins_make_01(enum instype type, struct ref r0, struct ref r1) {
struct irins *ins = irins_make(type);
ins->r0 = r0;
@@ -93,15 +183,15 @@ char* gen_label_name(void) {
}
struct ref ref_reg(int reg) {
- return (struct ref){REF_REG, reg, 0, false, 0};
+ return (struct ref){REF_REG, reg, 0, REFREL_ZERO, 0};
}
-struct ref ref_mem(int reg, int offset, bool rel_heap) {
- return (struct ref){REF_MEM, reg, offset, rel_heap, 0};
+struct ref ref_mem(int reg, int offset, enum refrel rel) {
+ return (struct ref){REF_MEM, reg, offset, rel, 0};
}
struct ref ref_imm(int imm) {
- return (struct ref){REF_IMM, -1, 0, false, imm};
+ return (struct ref){REF_IMM, REG_UNUSED, 0, REFREL_ZERO, imm};
}
struct ref ref_next_register(void) {
diff --git a/ir.h b/ir.h
index b359d00..e732a3d 100644
--- a/ir.h
+++ b/ir.h
@@ -1,5 +1,6 @@
#pragma once
+#include <stdio.h>
#include <stdbool.h>
@@ -21,6 +22,7 @@ enum instype {
INS_JMP, // jmp name
INS_JCC, // if condcode, jmp name
INS_CALL, // call name
+ INS_CALLV, // r0 = call name
INS_RET, // return
INS_RETV, // return r1
INS_MOV, // r0 = r1
@@ -32,15 +34,31 @@ enum condcode {
enum reftype {
REF_REG, // reg
- REF_MEM, // [reg + offset + (rel_heap ? heap_base : 0)]
+ REF_MEM, // [reg + offset + {0, .data, heap base}[rel]]
REF_IMM, // imm
};
+enum refrel {
+ REFREL_ZERO,
+ REFREL_DATA,
+ REFREL_HEAP,
+};
+
+#define REG_UNUSED (-1)
+#define REG_A (-10)
+#define REG_B (-11)
+#define REG_C (-12)
+#define REG_D (-13)
+#define REG_X (-14)
+#define REG_Y (-15)
+#define REG_SP (-16)
+#define REG_BP (-17)
+
struct ref {
enum reftype type;
- int reg; // if -1 in a REF_MEM, unused
+ int reg; // >=0 for temporary or one of the REG_ constants
int offset;
- bool rel_heap; // whether the heap base address should be added to the offset
+ enum refrel rel;
int imm;
};
@@ -61,13 +79,17 @@ struct ir {
struct ir* ir_make(void);
void ir_delete(struct ir *ir);
-// returns offset
+void ir_print(struct ir *ir, FILE *f);
+void irins_print(struct irins *ins, FILE *f);
+
+// returns offset in .data segment
struct ref ir_reserve_global(struct ir *ir, int size);
void ir_append(struct ir *ir, struct irins *ins);
struct irins* irins_make(enum instype type);
struct irins* irins_make_name(enum instype type, char *name);
+struct irins* irins_make_0(enum instype type, struct ref r0);
struct irins* irins_make_01(enum instype type, struct ref r0, struct ref r1);
struct irins* irins_make_012(enum instype type, struct ref r0, struct ref r1, struct ref r2);
struct irins* irins_make_1(enum instype type, struct ref r1);
@@ -78,6 +100,6 @@ void irins_delete(struct irins *ins);
char* gen_label_name(void);
struct ref ref_reg(int reg);
-struct ref ref_mem(int reg, int offset, bool rel_heap);
+struct ref ref_mem(int reg, int offset, enum refrel rel);
struct ref ref_imm(int imm);
struct ref ref_next_register(void);
diff --git a/main.c b/main.c
index 173c19b..7577012 100644
--- a/main.c
+++ b/main.c
@@ -30,6 +30,7 @@ int main(int argc, char **argv) {
printf("\n");
struct ir *ir = compile(root_node);
+ ir_print(ir, stdout);
type_cache_cleanup();
diff --git a/test/t1.c b/test/t1.c
index 229d5e9..33890fb 100644
--- a/test/t1.c
+++ b/test/t1.c
@@ -17,5 +17,5 @@ int fibo(int n) {
int main(int argc, int **argv) {
int a = 1;
int b = 2 + a * 3;
- holo_dec(a);
+ // holo_dec(a);
}