From a298cb75c4f586b83b304c7dc66cb555693ea1b8 Mon Sep 17 00:00:00 2001 From: Tom Smeding Date: Fri, 5 Jan 2018 17:52:38 +0100 Subject: Stuff --- compiler.c | 70 +++++++++++++++++++++++++++++++++--------- ir.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- ir.h | 32 ++++++++++++++++--- main.c | 1 + test/t1.c | 2 +- 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 #include +#include #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 "<>"; + 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 #include @@ -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); } -- cgit v1.2.3