lang/ir.c

150 lines
3.6 KiB
C
Raw Normal View History

2021-12-21 01:18:22 +01:00
#include "ir.h"
#include <stdio.h>
#include <stdlib.h>
const char *irinstr_str[IRInstrEnumSize] = {
[IRSet] = "set",
[IRNeg] = "neg",
[IRAdd] = "add",
[IRSub] = "sub",
[IRMul] = "mul",
[IRDiv] = "div",
2021-12-23 21:06:49 +01:00
[IREq] = "eq",
2021-12-26 12:19:54 +01:00
[IRNeq] = "neq",
2021-12-23 21:06:49 +01:00
[IRLt] = "lt",
[IRLe] = "le",
[IRNot] = "not",
2021-12-23 21:42:09 +01:00
[IRAnd] = "and",
[IROr] = "or",
2021-12-21 13:59:08 +01:00
[IRJmp] = "jmp",
2021-12-21 01:18:22 +01:00
[IRJnz] = "jnz",
2021-12-22 16:09:52 +01:00
[IRCallInternal] = "calli",
2021-12-21 01:18:22 +01:00
};
#define IRTOKS_INIT_CAP_LONG 4096
#define IRTOKS_INIT_CAP_SHORT 16
2021-12-21 01:18:22 +01:00
static void irtoks_init_with_cap(IRToks *v, size_t cap);
2021-12-22 12:57:14 +01:00
static void irtoks_init_with_cap(IRToks *v, size_t cap) {
2021-12-22 13:10:00 +01:00
v->toks = xmalloc(sizeof(IRTok) * cap);
2021-12-21 01:18:22 +01:00
v->len = 0;
v->cap = cap;
}
void irtoks_init_long(IRToks *v) {
irtoks_init_with_cap(v, IRTOKS_INIT_CAP_LONG);
}
void irtoks_init_short(IRToks *v) {
irtoks_init_with_cap(v, IRTOKS_INIT_CAP_SHORT);
2021-12-21 01:18:22 +01:00
}
void irtoks_term(IRToks *v) {
for (size_t i = 0; i < v->len; i++) {
if (v->toks[i].instr == IRCallInternal && v->toks[i].CallI.args)
2021-12-22 16:09:52 +01:00
free(v->toks[i].CallI.args);
2021-12-21 01:18:22 +01:00
}
free(v->toks);
}
void irtoks_app(IRToks *v, IRTok t) {
if (v->len+1 > v->cap)
2021-12-22 13:10:00 +01:00
v->toks = xrealloc(v->toks, sizeof(IRTok) * (v->cap *= 2));
2021-12-21 01:18:22 +01:00
v->toks[v->len++] = t;
}
void irtoks_eat_irtoks(IRToks *v, IRToks *other, size_t jmp_offset) {
if (v->len+other->len > v->cap)
2021-12-22 13:10:00 +01:00
v->toks = xrealloc(v->toks, sizeof(IRTok) * (other->len + (v->cap *= 2)));
for (size_t i = 0; i < other->len; i++) {
/* correct for changed jump addresses */
if (other->toks[i].instr == IRJmp)
other->toks[i].Jmp.iaddr += jmp_offset;
else if (other->toks[i].instr == IRJnz)
other->toks[i].CJmp.iaddr += jmp_offset;
v->toks[v->len++] = other->toks[i];
}
/* We're not calling irtoks_term() because we don't want associated items
* (for example function arguments) to get deallocated as well. */
free(other->toks);
}
2021-12-21 01:18:22 +01:00
static void print_irparam(const IRParam *p);
static void print_irparam(const IRParam *p) {
if (p->kind == IRParamLiteral) {
2021-12-25 12:16:06 +01:00
print_value(&p->Literal, false);
2021-12-21 01:18:22 +01:00
} else if (p->kind == IRParamAddr) {
printf("%%%zd", p->Addr);
}
}
2021-12-22 16:09:52 +01:00
void print_ir(IRToks *v, const BuiltinFunc *builtin_funcs) {
2021-12-21 01:18:22 +01:00
for (size_t i = 0; i < v->len; i++) {
2021-12-21 15:02:53 +01:00
printf("%04zx ", i);
2021-12-21 01:18:22 +01:00
printf("%s", irinstr_str[v->toks[i].instr]);
switch (v->toks[i].instr) {
case IRSet:
case IRNeg:
2021-12-23 21:08:01 +01:00
case IRNot:
2021-12-22 16:09:52 +01:00
printf(" %%%zx ", v->toks[i].Unary.addr);
2021-12-21 01:18:22 +01:00
print_irparam(&v->toks[i].Unary.val);
break;
case IRAdd:
case IRSub:
case IRDiv:
case IRMul:
2021-12-23 21:06:49 +01:00
case IREq:
2021-12-26 12:19:54 +01:00
case IRNeq:
2021-12-23 21:06:49 +01:00
case IRLt:
case IRLe:
2021-12-23 21:42:09 +01:00
case IRAnd:
case IROr:
2021-12-23 20:10:02 +01:00
printf(" %%%zx ", v->toks[i].Binary.addr);
print_irparam(&v->toks[i].Binary.lhs);
2021-12-21 01:18:22 +01:00
printf(" ");
2021-12-23 20:10:02 +01:00
print_irparam(&v->toks[i].Binary.rhs);
2021-12-21 01:18:22 +01:00
break;
2021-12-21 13:59:08 +01:00
case IRJmp:
2021-12-21 15:02:53 +01:00
printf(" %zx", v->toks[i].Jmp.iaddr);
2021-12-21 13:59:08 +01:00
break;
2021-12-21 01:18:22 +01:00
case IRJnz:
printf(" ");
print_irparam(&v->toks[i].CJmp.condition);
2021-12-21 15:02:53 +01:00
printf(" %zx", v->toks[i].CJmp.iaddr);
2021-12-21 01:18:22 +01:00
break;
2021-12-22 16:09:52 +01:00
case IRCallInternal: {
const BuiltinFunc *f = &builtin_funcs[v->toks[i].CallI.fid];
printf(" %s %%%zx", f->name, v->toks[i].CallI.ret_addr);
for (size_t j = 0; j < f->n_args; j++) {
printf(" ");
print_irparam(&v->toks[i].CallI.args[j]);
}
2021-12-21 01:18:22 +01:00
break;
2021-12-22 16:09:52 +01:00
}
default: ASSERT_UNREACHED();
2021-12-21 01:18:22 +01:00
}
printf(" ; %zu:%zu", v->toks[i].ln, v->toks[i].col);
printf("\n");
}
}
void optimize_ir(IRToks *v) {
for (size_t i = 0; i < v->len; i++) {
switch (v->toks[i].instr) {
case IRJmp: {
/* resolve jump chains (esp. produced by if-else-if... statements) */
size_t ja = i;
while (v->toks[ja].instr == IRJmp)
ja = v->toks[ja].Jmp.iaddr;
v->toks[i].Jmp.iaddr = ja;
}
default: break;
}
}
}