From 3272b5d83d2e2167eed24748557df88bd66584ee Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Fri, 5 Jan 2018 23:42:24 +0100 Subject: There's actually a chance that, correctly stringified, this will work --- .gitignore | 2 ++ Makefile | 5 ++++ c.y | 5 +++- compiler.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++------------ ir.c | 79 +++++++++++++++++++++++++++++++++++++++++-------- ir.h | 19 ++++++++---- main.c | 11 +++++-- node.c | 5 ++-- node.h | 5 +++- regalloc.c | 33 +++++++++++++++++++++ regalloc.h | 19 ++++++++++++ test/t1.c | 3 +- to_assembly.c | 71 ++++++++++++++++++++++++++++++++++++++++++++ to_assembly.h | 7 +++++ 14 files changed, 316 insertions(+), 43 deletions(-) create mode 100644 regalloc.c create mode 100644 regalloc.h create mode 100644 to_assembly.c create mode 100644 to_assembly.h diff --git a/.gitignore b/.gitignore index b711b6b..a5e0538 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ as1 as2 bison-out ccomp +*.dSYM +old/ diff --git a/Makefile b/Makefile index e206eea..411fbf3 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,11 @@ YAXX = bison CFLAGS = -Wall -Wextra -std=c11 -g -I. -D_GNU_SOURCE LDFLAGS = -lfl +ifeq ($(shell uname), Darwin) + LDFLAGS += -L/usr/local/opt/flex/lib + CFLAGS += -I/usr/local/opt/flex/include +endif + TARGET = ccomp .PHONY: all clean diff --git a/c.y b/c.y index 5aafe26..ee98fe7 100644 --- a/c.y +++ b/c.y @@ -142,8 +142,11 @@ matched_statement: other_statement: var_decl | expression ';' | block + | RETURN ';' { + $$ = node_make_0(N_RETURN); + } | RETURN expression ';' { - $$ = node_make_1(N_RETURN, $2); + $$ = node_make_1(N_RETURNV, $2); } ; expression: atom_expr diff --git a/compiler.c b/compiler.c index 34372f3..ea9f768 100644 --- a/compiler.c +++ b/compiler.c @@ -32,7 +32,7 @@ static bool oper_is_comparison(enum operator oper) { static struct ref compile_expr(struct ir *ir, struct symtab *symtab, struct node *node); static void compile_boolexpr( - struct ir *ir, struct symtab *symtab, struct node *node, char *truedest, char *falsedest) { + struct ir *ir, struct symtab *symtab, struct node *node, const char *truedest, const char *falsedest) { if (node->type == N_BINOP && oper_is_comparison(node->oper)) { struct ref r1 = compile_expr(ir, symtab, node->child1); @@ -51,12 +51,12 @@ static void compile_boolexpr( ir_append(ir, irins_make_jcc(falsedest, condcode)); ir_append(ir, irins_make_name(INS_JMP, truedest)); } else if (node->type == N_BINOP && node->oper == OP_AND) { - char *try2lbl = gen_label_name(); + const char *try2lbl = gen_label_name(); compile_boolexpr(ir, symtab, node->child1, try2lbl, falsedest); ir_append(ir, irins_make_name(INS_LBL, try2lbl)); compile_boolexpr(ir, symtab, node->child2, truedest, falsedest); } else if (node->type == N_BINOP && node->oper == OP_OR) { - char *try2lbl = gen_label_name(); + const char *try2lbl = gen_label_name(); compile_boolexpr(ir, symtab, node->child1, truedest, try2lbl); ir_append(ir, irins_make_name(INS_LBL, try2lbl)); compile_boolexpr(ir, symtab, node->child2, truedest, falsedest); @@ -108,9 +108,9 @@ static struct ref compile_expr(struct ir *ir, struct symtab *symtab, struct node ir_append(ir, irins_make_012(instype, r0, r1, r2)); return r0; } else if (oper_is_comparison(node->oper) || node->oper == OP_AND || node->oper == OP_OR) { - char *truelbl = gen_label_name(); - char *falselbl = gen_label_name(); - char *afterlbl = gen_label_name(); + const char *truelbl = gen_label_name(); + const char *falselbl = gen_label_name(); + const char *afterlbl = gen_label_name(); compile_boolexpr(ir, symtab, node, truelbl, falselbl); struct ref cval = ref_next_register(); ir_append(ir, irins_make_name(INS_LBL, truelbl)); @@ -207,7 +207,7 @@ static struct ref compile_expr(struct ir *ir, struct symtab *symtab, struct node } else { retref = ref_next_register(); struct irins *ins = irins_make_0(INS_CALLV, retref); - ins->name = strdup(node->name); + ins->name = ir_str(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))); @@ -246,38 +246,50 @@ static void compile_node(struct ir *ir, struct symtab *symtab, struct node *node 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(); + struct symbol *sym = symbol_make_var(strdup(node->name), node->rtype); + if (symtab->parent == NULL) sym->ref = ir_reserve_global(ir, 1); + else sym->ref = ref_next_register(); symtab_insert(symtab, sym); ir_append(ir, irins_make_01(INS_MOV, sym->ref, vref)); break; } case N_FUNC_DECL: { + if (memcmp(node->name, "__", 2) == 0) { + fprintf(stderr, "Invalid function name '%s' (cannot start with '__')\n", node->name); + exit(1); + } if (symtab_find(symtab, node->name)) { fprintf(stderr, "Redeclaration of function '%s'\n", node->name); exit(1); } int numparams = node_list_length(node->child1); - struct symbol *sym = symbol_make_func(node->name, node->rtype, numparams); + struct symbol *sym = symbol_make_func(strdup(node->name), node->rtype, numparams); write_func_params(sym->params, node->child1); symtab_insert(symtab_root(symtab), sym); - ir_append(ir, irins_make_name(INS_LBL, strdup(node->name))); + + ir_append(ir, irins_make_name(INS_LBL, 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); + struct symbol *parsym = symbol_make_var(strdup(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); + + // necessary for void functions, to be sure otherwise + ir_append(ir, irins_make(INS_RET)); break; } case N_IF: { - char *thenlbl = gen_label_name(); - char *elselbl = gen_label_name(); - char *afterlbl = gen_label_name(); + const char *thenlbl = gen_label_name(); + const char *elselbl = gen_label_name(); + const char *afterlbl = gen_label_name(); compile_boolexpr(ir, symtab, node->child1, thenlbl, elselbl); ir_append(ir, irins_make_name(INS_LBL, thenlbl)); compile_node(ir, symtab, node->child2); @@ -289,9 +301,9 @@ 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(); + const char *startlbl = gen_label_name(); + const char *bodylbl = gen_label_name(); + const char *afterlbl = gen_label_name(); ir_append(ir, irins_make_name(INS_LBL, startlbl)); compile_boolexpr(ir, symtab, node->child1, bodylbl, afterlbl); ir_append(ir, irins_make_name(INS_LBL, bodylbl)); @@ -301,7 +313,11 @@ static void compile_node(struct ir *ir, struct symtab *symtab, struct node *node break; } - case N_RETURN: { + case N_RETURN: + ir_append(ir, irins_make(INS_RET)); + break; + + case N_RETURNV: { struct ref ref = compile_expr(ir, symtab, node->child1); ir_append(ir, irins_make_1(INS_RETV, ref)); break; @@ -313,9 +329,50 @@ static void compile_node(struct ir *ir, struct symtab *symtab, struct node *node } } +static void compile_data_setup_node(struct ir *ir, struct symtab *symtab, struct node *node) { + switch (node->type) { + case N_LIST: + if (node->child1->type == N_VAR_DECL || node->child1->type == N_VAR_DECL_INIT) { + compile_node(ir, symtab, node->child1); + node_delete_recursive(node->child1); + node->child1 = node_make_0(N_LIST_END); + } + compile_data_setup_node(ir, symtab, node->child2); + break; + + case N_LIST_END: + break; + + case N_VAR_DECL: + case N_VAR_DECL_INIT: + compile_node(ir, symtab, node); + break; + + case N_FUNC_DECL: + break; + + default: + assert(false); + } +} + +static void compile_data_setup(struct ir *ir, struct symtab *symtab, struct node *root) { + struct ref flag = ir_reserve_global(ir, 1); + ir_append(ir, irins_make_12(INS_TEST, flag, flag)); + const char *afterlbl = gen_label_name(); + ir_append(ir, irins_make_jcc(afterlbl, CCNZ)); + + compile_data_setup_node(ir, symtab, root); + + ir_append(ir, irins_make_name(INS_LBL, afterlbl)); + ir_append(ir, irins_make_name(INS_CALL, "main")); + ir_append(ir, irins_make(INS_BRK)); +} + struct ir* compile(struct node *node) { struct ir *ir = ir_make(); struct symtab *symtab = symtab_make(); + compile_data_setup(ir, symtab, node); compile_node(ir, symtab, node); return ir; } diff --git a/ir.c b/ir.c index cf529dd..69a9d64 100644 --- a/ir.c +++ b/ir.c @@ -1,8 +1,29 @@ #include +#include #include #include "ir.h" +static int cap_interned = 32; +static int num_interned = 0; +static char **interned_strings = NULL; + +const char* ir_str(const char *str) { + if (interned_strings == NULL) { + interned_strings = malloc(cap_interned * sizeof(char*)); + } + for (int i = 0; i < num_interned; i++) { + if (strcmp(interned_strings[i], str) == 0) return interned_strings[i]; + } + if (num_interned == cap_interned) { + cap_interned *= 2; + interned_strings = realloc(interned_strings, cap_interned * sizeof(char*)); + } + interned_strings[num_interned++] = strdup(str); + return interned_strings[num_interned - 1]; +} + + struct ir* ir_make(void) { struct ir *ir = malloc(sizeof(struct ir)); ir->cap = 32; @@ -90,7 +111,7 @@ void irins_print(struct irins *ins, FILE *f) { 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_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; @@ -100,6 +121,7 @@ void irins_print(struct irins *ins, FILE *f) { 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; + case INS_BRK: fprintf(f, "\tbrk\n"); break; default: assert(false); } } @@ -110,12 +132,19 @@ struct ref ir_reserve_global(struct ir *ir, int size) { return ref_mem(REG_UNUSED, offset, REFREL_DATA); } -void ir_append(struct ir *ir, struct irins *ins) { +void ir_insert_before(struct ir *ir, int pos, struct irins *ins) { + assert(pos >= 0 && pos <= ir->len); if (ir->len == ir->cap) { ir->cap *= 2; ir->inss = realloc(ir->inss, ir->cap * sizeof(struct irins*)); } - ir->inss[ir->len++] = ins; + memmove(ir->inss + pos + 1, ir->inss + pos, (ir->len - pos) * sizeof(struct irins*)); + ir->inss[pos] = ins; + ir->len++; +} + +void ir_append(struct ir *ir, struct irins *ins) { + ir_insert_before(ir, ir->len, ins); } struct irins* irins_make(enum instype type) { @@ -125,9 +154,9 @@ struct irins* irins_make(enum instype type) { return ins; } -struct irins* irins_make_name(enum instype type, char *name) { +struct irins* irins_make_name(enum instype type, const char *name) { struct irins *ins = irins_make(type); - ins->name = name; + ins->name = ir_str(name); return ins; } @@ -163,23 +192,49 @@ struct irins* irins_make_12(enum instype type, struct ref r1, struct ref r2) { return ins; } -struct irins* irins_make_jcc(char *name, enum condcode condcode) { +struct irins* irins_make_jcc(const char *name, enum condcode condcode) { struct irins *ins = irins_make(INS_JCC); - ins->name = name; + ins->name = ir_str(name); ins->condcode = condcode; return ins; } void irins_delete(struct irins *ins) { - if (ins->name) free(ins->name); free(ins); } -char* gen_label_name(void) { +void irins_which_refs(const struct irins *ins, bool have[3]) { + have[0] = false; have[1] = false; have[2] = false; + switch (ins->type) { + case INS_ADD: have[0] = true; have[1] = true; have[2] = true; break; + case INS_SUB: have[0] = true; have[1] = true; have[2] = true; break; + case INS_MUL: have[0] = true; have[1] = true; have[2] = true; break; + case INS_DIV: have[0] = true; have[1] = true; have[2] = true; break; + case INS_MOD: have[0] = true; have[1] = true; have[2] = true; break; + case INS_NEG: have[0] = true; have[1] = true; break; + case INS_NOT: have[0] = true; have[1] = true; break; + case INS_TEST: have[1] = true; have[2] = true; break; + case INS_PUSH: have[1] = true; break; + case INS_POP: have[0] = true; break; + case INS_CMP: have[1] = true; have[2] = true; break; + case INS_LBL: break; + case INS_JMP: break; + case INS_JCC: break; + case INS_CALL: break; + case INS_CALLV: have[0] = true; break; + case INS_RET: break; + case INS_RETV: have[1] = true; break; + case INS_MOV: have[0] = true; have[1] = true; break; + case INS_BRK: break; + default: assert(false); + } +} + +const char* gen_label_name(void) { static int next = 0; - char *buf = malloc(16); - sprintf(buf, "L%d", next++); - return buf; + static char buf[16]; + sprintf(buf, "__L%d", next++); + return ir_str(buf); } struct ref ref_reg(int reg) { diff --git a/ir.h b/ir.h index e732a3d..5d92eed 100644 --- a/ir.h +++ b/ir.h @@ -26,6 +26,7 @@ enum instype { INS_RET, // return INS_RETV, // return r1 INS_MOV, // r0 = r1 + INS_BRK, // halt }; enum condcode { @@ -64,8 +65,11 @@ struct ref { struct irins { enum instype type; - struct ref r0, r1, r2; - char *name; + union { + struct ref three_refs[3]; + struct {struct ref r0, r1, r2;}; + }; + const char *name; // should be a return value from ir_str() enum condcode condcode; }; @@ -82,22 +86,27 @@ void ir_delete(struct ir *ir); void ir_print(struct ir *ir, FILE *f); void irins_print(struct irins *ins, FILE *f); +const char* ir_str(const char *str); // returns interned string + // returns offset in .data segment struct ref ir_reserve_global(struct ir *ir, int size); +void ir_insert_before(struct ir *ir, int pos, struct irins *ins); 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_name(enum instype type, const 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); struct irins* irins_make_12(enum instype type, struct ref r1, struct ref r2); -struct irins* irins_make_jcc(char *name, enum condcode condcode); +struct irins* irins_make_jcc(const char *name, enum condcode condcode); void irins_delete(struct irins *ins); -char* gen_label_name(void); +void irins_which_refs(const struct irins *ins, bool haveref[3]); + +const char* gen_label_name(void); struct ref ref_reg(int reg); struct ref ref_mem(int reg, int offset, enum refrel rel); diff --git a/main.c b/main.c index 7577012..5588543 100644 --- a/main.c +++ b/main.c @@ -3,6 +3,8 @@ #include #include "compiler.h" #include "node.h" +#include "regalloc.h" +#include "to_assembly.h" extern FILE *yyin; @@ -30,9 +32,14 @@ int main(int argc, char **argv) { printf("\n"); struct ir *ir = compile(root_node); - ir_print(ir, stdout); - type_cache_cleanup(); + ir_print(ir, stdout); printf("\n"); + + struct allocation *alloc = regalloc(ir); + to_assembly(ir, alloc); + allocation_delete(alloc); + + ir_print(ir, stdout); printf("\n"); return result; } diff --git a/node.c b/node.c index b20c38e..f34061c 100644 --- a/node.c +++ b/node.c @@ -66,7 +66,7 @@ static void write_spaces(int num, FILE *f) { for (int i = 0; i < num; i++) fputc(' ', f); } -static const char* node_type_string(enum node_type type) { +const char* node_type_string(enum node_type type) { switch (type) { case N_LIST: return "N_LIST"; break; case N_LIST_END: return "N_LIST_END"; break; @@ -79,6 +79,7 @@ static const char* node_type_string(enum node_type type) { case N_IF: return "N_IF"; break; case N_WHILE: return "N_WHILE"; break; case N_RETURN: return "N_RETURN"; break; + case N_RETURNV: return "N_RETURNV"; break; case N_BINOP: return "N_BINOP"; break; case N_UNOP: return "N_UNOP"; break; case N_CALL: return "N_CALL"; break; @@ -86,7 +87,7 @@ static const char* node_type_string(enum node_type type) { } } -static const char* oper_string(enum operator oper) { +const char* oper_string(enum operator oper) { switch (oper) { case OP_ADD: return "OP_ADD"; case OP_SUB: return "OP_SUB"; diff --git a/node.h b/node.h index 81d0b26..f98257f 100644 --- a/node.h +++ b/node.h @@ -12,7 +12,8 @@ enum node_type { N_FUNC_DECL, // rtype name [params] [body] N_IF, // [cond] [body] [else-body] N_WHILE, // [cond] [body] - N_RETURN, // [value] + N_RETURN, // -- + N_RETURNV, // [value] N_NUM, // value N_VAR, // name N_BINOP, // [left] oper [right] @@ -53,4 +54,6 @@ int node_list_length(struct node *node); void node_delete_recursive(struct node *node); +const char* node_type_string(enum node_type type); +const char* oper_string(enum operator oper); void node_print(const struct node *node, FILE *f, int indent); diff --git a/regalloc.c b/regalloc.c new file mode 100644 index 0000000..cf6e595 --- /dev/null +++ b/regalloc.c @@ -0,0 +1,33 @@ +#include +#include +#include "regalloc.h" + + +struct allocation* regalloc(const struct ir *ir) { + int maxreg = 0; + for (int i = 0; i < ir->len; i++) { + const struct irins *ins = ir->inss[i]; + + bool haveref[3]; + irins_which_refs(ins, haveref); + for (int ri = 0; ri < 3; ri++) { + if (haveref[ri] && ins->three_refs[ri].reg > maxreg) { + maxreg = ins->three_refs[ri].reg; + } + } + } + + struct allocation *alloc = malloc(sizeof(struct allocation)); + alloc->numregs = maxreg + 1; + alloc->allocs = malloc(alloc->numregs * sizeof(struct allocation_record)); + for (int i = 0; i < alloc->numregs; i++) { + alloc->allocs[i].spill = true; // lel + } + + return alloc; +} + +void allocation_delete(struct allocation *alloc) { + free(alloc->allocs); + free(alloc); +} diff --git a/regalloc.h b/regalloc.h new file mode 100644 index 0000000..6ba0470 --- /dev/null +++ b/regalloc.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "ir.h" + + +struct allocation_record { + bool spill; + int reg; // only used if spill == false +}; + +struct allocation { + int numregs; + struct allocation_record *allocs; +}; + +struct allocation* regalloc(const struct ir *ir); + +void allocation_delete(struct allocation *alloc); diff --git a/test/t1.c b/test/t1.c index 33890fb..35a5312 100644 --- a/test/t1.c +++ b/test/t1.c @@ -14,8 +14,9 @@ int fibo(int n) { return b; } -int main(int argc, int **argv) { +void main(int argc, int **argv) { int a = 1; int b = 2 + a * 3; + fibo(5); // holo_dec(a); } diff --git a/to_assembly.c b/to_assembly.c new file mode 100644 index 0000000..ab5c845 --- /dev/null +++ b/to_assembly.c @@ -0,0 +1,71 @@ +#include +#include "to_assembly.h" + + +static bool is_function_label(const char *lbl) { + return memcmp(lbl, "__", 2) != 0; +} + +static void fix_everything(struct ir *ir, const int startidx, struct allocation *ral) { + int spillspace = 0; + + for (int idx = startidx + 1; idx < ir->len; idx++) { + struct irins *ins = ir->inss[idx]; + + if (ins->type == INS_LBL && is_function_label(ins->name)) break; + + if (ins->type == INS_CALLV) { + ins->type = INS_CALL; + ir_insert_before(ir, idx + 1, irins_make_01(INS_MOV, ins->r0, ref_reg(REG_A))); + idx--; + continue; + } + if (ins->type == INS_RETV) { + ir_insert_before(ir, idx, irins_make_01(INS_MOV, ref_reg(REG_A), ins->r1)); + ins->type = INS_RET; + idx--; + continue; + } + + bool haveref[3]; + irins_which_refs(ins, haveref); + for (int ri = 0; ri < 3; ri++) { + struct ref *ref = &ins->three_refs[ri]; + if (haveref[ri] && ref->type == REF_REG && ref->reg >= 0) { + if (ral->allocs[ref->reg].spill) { + *ref = ref_mem(REG_BP, spillspace + 1, REFREL_ZERO); + spillspace++; + } else { + ref->reg = ral->allocs[ref->reg].reg; + } + } + } + } + + if (spillspace == 0) return; + + ir_insert_before(ir, startidx + 1, irins_make_1(INS_PUSH, ref_reg(REG_BP))); + ir_insert_before(ir, startidx + 2, irins_make_01(INS_MOV, ref_reg(REG_BP), ref_reg(REG_SP))); + ir_insert_before(ir, startidx + 3, + irins_make_012(INS_SUB, ref_reg(REG_SP), ref_reg(REG_SP), ref_imm(spillspace))); + + for (int idx = startidx + 1; idx < ir->len; idx++) { + struct irins *ins = ir->inss[idx]; + + if (ins->type == INS_LBL && is_function_label(ins->name)) break; + + if (ins->type == INS_RET) { + ir_insert_before(ir, idx++, irins_make_01(INS_MOV, ref_reg(REG_SP), ref_reg(REG_BP))); + ir_insert_before(ir, idx++, irins_make_0(INS_POP, ref_reg(REG_BP))); + continue; + } + } +} + +void to_assembly(struct ir *ir, struct allocation *ral) { + for (int idx = 0; idx < ir->len; idx++) { + if (ir->inss[idx]->type == INS_LBL && is_function_label(ir->inss[idx]->name)) { + fix_everything(ir, idx, ral); + } + } +} diff --git a/to_assembly.h b/to_assembly.h new file mode 100644 index 0000000..d18c4b7 --- /dev/null +++ b/to_assembly.h @@ -0,0 +1,7 @@ +#pragma once + +#include "ir.h" +#include "regalloc.h" + + +void to_assembly(struct ir *ir, struct allocation *ral); -- cgit v1.2.3-70-g09d2