change IR stream to linked list
This commit is contained in:
140
ir.c
140
ir.c
@@ -23,55 +23,81 @@ const char *irinstr_str[IRInstrEnumSize] = {
|
||||
[IRAddrOf] = "addrof",
|
||||
};
|
||||
|
||||
#define IRTOKS_INIT_CAP_LONG 4096
|
||||
#define IRTOKS_INIT_CAP_SHORT 16
|
||||
#define IRLIST_INIT_CAP_LONG 4096
|
||||
#define IRLIST_INIT_CAP_SHORT 16
|
||||
|
||||
static void irtoks_init_with_cap(IRToks *v, size_t cap);
|
||||
static void irlist_init_with_cap(IRList *v, size_t cap);
|
||||
static IRItem *irlist_new_item(IRList *v);
|
||||
|
||||
static void irtoks_init_with_cap(IRToks *v, size_t cap) {
|
||||
v->toks = xmalloc(sizeof(IRTok) * cap);
|
||||
static void irlist_init_with_cap(IRList *v, size_t cap) {
|
||||
v->begin = NULL;
|
||||
v->end = NULL;
|
||||
v->p = pool_new(sizeof(IRItem) * cap);
|
||||
v->index = NULL;
|
||||
v->len = 0;
|
||||
v->cap = cap;
|
||||
}
|
||||
|
||||
void irtoks_init_long(IRToks *v) {
|
||||
irtoks_init_with_cap(v, IRTOKS_INIT_CAP_LONG);
|
||||
|
||||
static IRItem *irlist_new_item(IRList *v) {
|
||||
IRItem *ret = pool_alloc(v->p, sizeof(IRItem));
|
||||
ret->next = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void irtoks_init_short(IRToks *v) {
|
||||
irtoks_init_with_cap(v, IRTOKS_INIT_CAP_SHORT);
|
||||
void irlist_init_long(IRList *v) {
|
||||
irlist_init_with_cap(v, IRLIST_INIT_CAP_LONG);
|
||||
}
|
||||
|
||||
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)
|
||||
free(v->toks[i].CallI.args);
|
||||
void irlist_init_short(IRList *v) {
|
||||
irlist_init_with_cap(v, IRLIST_INIT_CAP_SHORT);
|
||||
}
|
||||
|
||||
void irlist_term(IRList *v) {
|
||||
for (IRItem *i = v->begin; i; i = i->next) {
|
||||
if (i->tok.instr == IRCallInternal && i->tok.CallI.args)
|
||||
free(i->tok.CallI.args);
|
||||
}
|
||||
free(v->toks);
|
||||
pool_term(v->p);
|
||||
}
|
||||
|
||||
void irtoks_app(IRToks *v, IRTok t) {
|
||||
if (v->len+1 > v->cap)
|
||||
v->toks = xrealloc(v->toks, sizeof(IRTok) * (v->cap *= 2));
|
||||
v->toks[v->len++] = t;
|
||||
void irlist_app(IRList *v, IRTok t) {
|
||||
v->index = NULL; /* invalidate index */
|
||||
IRItem *itm = irlist_new_item(v);
|
||||
itm->tok = t;
|
||||
|
||||
if (!v->begin && !v->end)
|
||||
v->begin = v->end = itm;
|
||||
else {
|
||||
v->end->next = itm;
|
||||
v->end = itm;
|
||||
}
|
||||
|
||||
v->len++;
|
||||
}
|
||||
|
||||
void irtoks_eat_irtoks(IRToks *v, IRToks *other, size_t jmp_offset) {
|
||||
if (v->len+other->len > v->cap)
|
||||
v->toks = xrealloc(v->toks, sizeof(IRTok) * (other->len + (v->cap *= 2)));
|
||||
for (size_t i = 0; i < other->len; i++) {
|
||||
void irlist_eat_irlist(IRList *v, IRList *other) {
|
||||
v->index = NULL; /* invalidate index */
|
||||
size_t jmp_offset = v->len-1;
|
||||
for (IRItem *i = other->begin; i; i = i->next) {
|
||||
/* 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;
|
||||
if (i->tok.instr == IRJmp)
|
||||
i->tok.Jmp.iaddr += jmp_offset;
|
||||
else if (i->tok.instr == IRJnz)
|
||||
i->tok.CJmp.iaddr += jmp_offset;
|
||||
|
||||
v->toks[v->len++] = other->toks[i];
|
||||
irlist_app(v, i->tok);
|
||||
}
|
||||
/* We're not calling irtoks_term() because we don't want associated items
|
||||
/* We're not calling irlist_term() because we don't want associated items
|
||||
* (for example function arguments) to get deallocated as well. */
|
||||
free(other->toks);
|
||||
pool_term(other->p);
|
||||
}
|
||||
|
||||
void irlist_update_index(IRList *v) {
|
||||
if (v->index)
|
||||
return;
|
||||
v->index = pool_alloc(v->p, v->len);
|
||||
size_t num_idx = 0;
|
||||
for (IRItem *i = v->begin; i; i = i->next, num_idx++)
|
||||
v->index[num_idx] = i;
|
||||
}
|
||||
|
||||
static void print_irparam(const IRParam *p);
|
||||
@@ -84,17 +110,18 @@ static void print_irparam(const IRParam *p) {
|
||||
}
|
||||
}
|
||||
|
||||
void print_ir(IRToks *v, const BuiltinFunc *builtin_funcs) {
|
||||
for (size_t i = 0; i < v->len; i++) {
|
||||
printf("%04zx ", i);
|
||||
printf("%s", irinstr_str[v->toks[i].instr]);
|
||||
switch (v->toks[i].instr) {
|
||||
void print_ir(IRList *v, const BuiltinFunc *builtin_funcs) {
|
||||
size_t iaddr = 0;
|
||||
for (IRItem *i = v->begin; i; i = i->next, iaddr++) {
|
||||
printf("%04zx ", iaddr);
|
||||
printf("%s", irinstr_str[i->tok.instr]);
|
||||
switch (i->tok.instr) {
|
||||
case IRSet:
|
||||
case IRNeg:
|
||||
case IRNot:
|
||||
case IRAddrOf:
|
||||
printf(" %%%zx ", v->toks[i].Unary.addr);
|
||||
print_irparam(&v->toks[i].Unary.val);
|
||||
printf(" %%%zx ", i->tok.Unary.addr);
|
||||
print_irparam(&i->tok.Unary.val);
|
||||
break;
|
||||
case IRAdd:
|
||||
case IRSub:
|
||||
@@ -106,46 +133,47 @@ void print_ir(IRToks *v, const BuiltinFunc *builtin_funcs) {
|
||||
case IRLe:
|
||||
case IRAnd:
|
||||
case IROr:
|
||||
printf(" %%%zx ", v->toks[i].Binary.addr);
|
||||
print_irparam(&v->toks[i].Binary.lhs);
|
||||
printf(" %%%zx ", i->tok.Binary.addr);
|
||||
print_irparam(&i->tok.Binary.lhs);
|
||||
printf(" ");
|
||||
print_irparam(&v->toks[i].Binary.rhs);
|
||||
print_irparam(&i->tok.Binary.rhs);
|
||||
break;
|
||||
case IRJmp:
|
||||
printf(" %zx", v->toks[i].Jmp.iaddr);
|
||||
printf(" %zx", i->tok.Jmp.iaddr);
|
||||
break;
|
||||
case IRJnz:
|
||||
printf(" ");
|
||||
print_irparam(&v->toks[i].CJmp.condition);
|
||||
printf(" %zx", v->toks[i].CJmp.iaddr);
|
||||
print_irparam(&i->tok.CJmp.condition);
|
||||
printf(" %zx", i->tok.CJmp.iaddr);
|
||||
break;
|
||||
case IRCallInternal: {
|
||||
const BuiltinFunc *f = &builtin_funcs[v->toks[i].CallI.fid];
|
||||
const BuiltinFunc *f = &builtin_funcs[i->tok.CallI.fid];
|
||||
if (f->returns)
|
||||
printf(" %%%zx", v->toks[i].CallI.ret_addr);
|
||||
printf(" %%%zx", i->tok.CallI.ret_addr);
|
||||
printf(" %s", f->name);
|
||||
for (size_t j = 0; j < v->toks[i].CallI.n_args; j++) {
|
||||
for (size_t j = 0; j < i->tok.CallI.n_args; j++) {
|
||||
printf(" ");
|
||||
print_irparam(&v->toks[i].CallI.args[j]);
|
||||
print_irparam(&i->tok.CallI.args[j]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: ASSERT_UNREACHED();
|
||||
}
|
||||
printf(" ; %zu:%zu", v->toks[i].ln, v->toks[i].col);
|
||||
printf(" ; %zu:%zu", i->tok.ln, i->tok.col);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void optimize_ir(IRToks *v) {
|
||||
for (size_t i = 0; i < v->len; i++) {
|
||||
switch (v->toks[i].instr) {
|
||||
void optimize_ir(IRList *v) {
|
||||
irlist_update_index(v);
|
||||
for (IRItem *i = v->begin; i; i = i->next) {
|
||||
switch (i->tok.instr) {
|
||||
case IRJmp: {
|
||||
/* resolve jump chains (esp. produced by if-else-if... statements) */
|
||||
size_t ja = i;
|
||||
while (ja < v->len && v->toks[ja].instr == IRJmp)
|
||||
ja = v->toks[ja].Jmp.iaddr;
|
||||
v->toks[i].Jmp.iaddr = ja;
|
||||
size_t ja = i->tok.Jmp.iaddr;
|
||||
while (ja < v->len && v->index[ja]->tok.instr == IRJmp)
|
||||
ja = v->index[ja]->tok.Jmp.iaddr;
|
||||
i->tok.Jmp.iaddr = ja;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user