Files
moxa/_gi_c/run_jit.c
Sebastien Binet 476a31322d Go get ellipsis (#1)
* gi: rename gi_c into _gi_c

* gi: rename test into _test

* gi: fix README syntax
2018-06-26 10:17:01 +02:00

314 lines
7.1 KiB
C

/* jit runtime for bip */
#include <stdio.h>
#include <lightning.h>
#include "node.h"
#include "run_jit.h"
#include "trace.h"
typedef struct reg_t {
sym_t *sym; /* symbol associated to register */
} reg_t;
static reg_t regs[JIT_V_NUM];
static jit_state_t *_jit; /* XXX: should be in bip_t */
static inline void load(int reg, node_t *n)
{
if (n->type == VAR)
n->reg = n->sym->reg;
if (n->reg) {
if (reg != n->reg)
jit_movr(reg, n->reg);
} else if (n->type == TERM)
jit_movi(reg, n->pv->u.num);
else if (reg != JIT_R0)
jit_movr(reg, JIT_R0);
//else if (0)
// jit_ldi(reg, &n->pv->u.num);
}
static inline int is_if_cond(node_t *n)
{
return (n->anc && n->anc->type == IF && n->anc->child[0] == n);
}
static inline int is_for_cond(node_t *n)
{
return (n->anc && n->anc->type == FOR && n->anc->child[1] == n);
}
static inline int is_while_cond(node_t *n)
{
return (n->anc && n->anc->type == WHILE && n->anc->child[0] == n);
}
static inline int is_cond(node_t *n)
{
return is_if_cond(n) || is_for_cond(n) || is_while_cond(n);
}
static int regalloc(sym_t *sym)
{
int i;
if (sym->reg)
return sym->reg; /* already allocated */
for (i = 0; i < JIT_V_NUM; i++) {
if (regs[i].sym == NULL) {
regs[i].sym = sym;
sym->reg = JIT_V(i);
jit_ldi(sym->reg, &sym->v.u.num);
return i;
}
}
return 0;
}
void j_assign(node_t *n)
{
sym_t *var = n->child[0]->sym;
if (regalloc(var)) {
n->reg = n->child[0]->reg = var->reg;
load(n->reg, n->child[1]);
} else {
load(JIT_R0, n->child[1]);
jit_sti(&n->child[0]->pv->u.num, JIT_R0);
}
return;
}
static int gen_branch(node_t *n, int r1)
{
jit_node_t **plabel;
node_t *c1;
if (!is_cond(n))
return 0;
plabel = (n->anc->nchild == 3) ?
&n->anc->child[2]->label :
&n->anc->label;
c1 = n->child[1];
if (n->sym->jf == j_eq) {
*plabel = (c1->type == TERM) ?
jit_bnei(r1, c1->pv->u.num) :
jit_bner(r1, c1->reg);
} else if (n->sym->jf == j_ne) {
*plabel = (c1->type == TERM) ?
jit_beqi(r1, c1->pv->u.num) :
jit_beqr(r1, c1->reg);
} else if (n->sym->jf == j_le) {
*plabel = (c1->type == TERM) ?
jit_bgti(r1, c1->pv->u.num) :
jit_bgtr(r1, c1->reg);
} else if (n->sym->jf == j_gt) {
*plabel = (c1->type == TERM) ?
jit_blei(r1, c1->pv->u.num) :
jit_bler(r1, c1->reg);
} else if (n->sym->jf == j_lt) {
*plabel = (c1->type == TERM) ?
jit_bgei(r1, c1->pv->u.num) :
jit_bger(r1, c1->reg);
} else if (n->sym->jf == j_ge) {
*plabel = (c1->type == TERM) ?
jit_blti(r1, c1->pv->u.num) :
jit_bltr(r1, c1->reg);
} else {
t_s(n->sym->name);
*plabel = jit_beqi(r1, 0);
}
return 1;
}
#define define_binary_operator(name) \
void j_##name(node_t *n) \
{ \
int r0, r1; \
if (n->anc->type == VAR) \
n->reg = n->anc->reg = n->anc->sym->reg; \
else if (n->anc->type == OP && n->anc->sym->jf == j_assign) \
n->reg = n->anc->reg = n->anc->child[0]->sym->reg; \
if (n->child[0]->type == VAR) \
n->child[0]->reg = n->child[0]->sym->reg; \
if (n->child[1]->type == VAR) \
n->child[1]->reg = n->child[1]->sym->reg; \
r0 = n->anc->reg; \
r1 = n->child[0]->reg; \
load(r1, n->child[0]); \
if (gen_branch(n, r1)) \
return; \
if (n->child[1]->reg) { \
jit_##name##r(r0, r1, JIT_V(n->child[1]->reg)); \
} else if (n->child[1]->type == TERM) { \
jit_##name##i(r0, r1, n->child[1]->pv->u.num); \
} else { \
jit_##name##r(r0, r1, JIT_R0); \
} \
if (0) jit_sti(&n->pv->u.num, JIT_V(n->anc->reg)); \
}
define_binary_operator(add) /* c0 + c1 */
define_binary_operator(sub) /* c0 - c1 */
define_binary_operator(mul) /* c0 * c1 */
define_binary_operator(div) /* c0 / c1 */
define_binary_operator(rem) /* c0 % c1 */
define_binary_operator(lt) /* c0 < c1 */
define_binary_operator(le) /* c0 <= c1 */
define_binary_operator(eq) /* c0 == c1 */
define_binary_operator(ne) /* c0 != c1 */
define_binary_operator(gt) /* c0 > c1 */
define_binary_operator(ge) /* c0 >= c1 */
define_binary_operator(and) /* c0 & c1 */
define_binary_operator(or) /* c0 | c1 */
define_binary_operator(xor) /* c0 ^ c1 */
define_binary_operator(lsh) /* c0 << c1 */
define_binary_operator(rsh) /* c0 >> c1 */
#define define_unary_operator(name) \
void j_##name(node_t *n) \
{ \
jit_ldi(JIT_V0, &n->child[0]->pv->u.num); \
jit_##name##r(JIT_V0, JIT_V0); \
jit_sti(&n->pv->u.num, JIT_V0); \
}
define_unary_operator(neg)
define_unary_operator(com)
static void do_echo_i(int i)
{
printf("%d\n", i);
}
void j_echo(node_t *n)
{
jit_prepare();
load(JIT_R0, n->child[0]);
jit_pushargr(JIT_R0);
jit_finishi((jit_pointer_t)do_echo_i);
}
void j_land(node_t *n)
{
load(JIT_R0, n->child[0]);
n->label = jit_beqi(JIT_R0, 0);
load(JIT_R0, n->child[1]);
jit_patch(n->label);
}
void j_lor(node_t *n)
{
load(JIT_R0, n->child[0]);
n->label = jit_bnei(JIT_R0, 0);
load(JIT_R0, n->child[1]);
jit_patch(n->label);
}
void j_nop(node_t *n)
{
return;
}
void j_inc(node_t *n)
{
// Avoid costly (and useless in loops) load/store between memory and register
//jit_ldi(JIT_V0, &n->child[0]->pv->u.num);
//jit_addi(JIT_V0, JIT_V0, 1);
//jit_sti(&n->child[0]->pv->u.num, JIT_V0);
int reg = n->child[0]->sym->reg;
jit_addi(reg, reg, 1);
}
void j_not(node_t *n)
{
load(JIT_R0, n->child[0]);
jit_eqi(JIT_R0, JIT_R0, 0);
jit_sti(&n->pv->u.num, JIT_R0);
}
/* code generated by postorder traveral of the abstract syntax tree */
static void code_generation(bip_t *ip, node_t *n, void *data)
{
node_t *anc = n->anc;
if (is_leaf(n)) {
if (is_cond(n)) {
load(JIT_R0, n);
if (anc->nchild == 3)
anc->child[2]->label = jit_beqi(JIT_R0, 0);
else
anc->label = jit_beqi(JIT_R0, 0);
}
return;
}
if (n->label)
jit_patch(n->label);
if (is_for_cond(n))
n->label = jit_label();
if (is_while_cond(n))
n->label = jit_label();
n->sym->jf(n);
if (anc == NULL)
return;
if (anc->type == IF) {
if (anc->child[1] == n) { /* in true block */
if (anc->nchild == 3)
anc->child[1]->label = jit_jmpi();
} else if (anc->nchild == 3 && anc->child[2] == n) { /* in false block */
jit_patch_at(n->anc->child[1]->label, jit_label());
}
} else if (anc->type == FOR) {
if (anc->child[3] == n) /* in true block */
jit_patch_at(jit_jmpi(), anc->child[1]->label);
} else if (anc->type == WHILE) {
if (anc->child[1] == n) /* in true block */
jit_patch_at(jit_jmpi(), anc->child[0]->label);
}
}
/* compute necessary space for stack allocation, tag nodes using stack */
static void stack_analysis(bip_t *ip, node_t *n, void *data)
{
if (n->type == OP) {
t_s(n->sym->name);
if (!is_leaf(n->child[0])) {
t_d(n->num);
t_d(ip->prev->num);
t_d(n->child[0]->num);
t_s(n->child[0]->sym->name);
}
if (!is_leaf(n->child[1])) {
t_d(n->num);
t_d(ip->prev->num);
t_d(n->child[1]->num);
t_s(n->child[1]->sym->name);
}
}
ip->prev = n;
}
void run_jit(bip_t *ip, node_t *node)
{
void (*func)(void);
init_jit("b1");
_jit = jit_new_state();
jit_prolog();
tree_walk(ip, node, NULL, stack_analysis, NULL);
tree_walk(ip, node, NULL, code_generation, NULL);
jit_epilog();
func = (void (*)(void))jit_emit();
if (ip->opt.v) {
jit_print();
jit_disassemble();
}
if (!ip->opt.n)
func();
finish_jit();
}