aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortomsmeding <tom.smeding@gmail.com>2018-01-05 23:42:24 +0100
committertomsmeding <tom.smeding@gmail.com>2018-01-05 23:42:24 +0100
commit3272b5d83d2e2167eed24748557df88bd66584ee (patch)
tree6b8f1574f6d6a44e11b74903516286f6249cb0b7
parenta298cb75c4f586b83b304c7dc66cb555693ea1b8 (diff)
There's actually a chance that, correctly stringified, this will work
-rw-r--r--.gitignore2
-rw-r--r--Makefile5
-rw-r--r--c.y5
-rw-r--r--compiler.c95
-rw-r--r--ir.c79
-rw-r--r--ir.h19
-rw-r--r--main.c11
-rw-r--r--node.c5
-rw-r--r--node.h5
-rw-r--r--regalloc.c33
-rw-r--r--regalloc.h19
-rw-r--r--test/t1.c3
-rw-r--r--to_assembly.c71
-rw-r--r--to_assembly.h7
14 files changed, 316 insertions, 43 deletions
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 <stdlib.h>
+#include <string.h>
#include <assert.h>
#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 <assert.h>
#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 <stdlib.h>
+#include <assert.h>
+#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 <stdbool.h>
+#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 <string.h>
+#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);