aboutsummaryrefslogtreecommitdiff
path: root/ir.c
diff options
context:
space:
mode:
Diffstat (limited to 'ir.c')
-rw-r--r--ir.c102
1 files changed, 96 insertions, 6 deletions
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) {