kulp / tenyr
1
#include "jit.h"
2

3
#include <search.h>
4
#include <stdlib.h>
5

6
sim_runner jit_run_sim;
7

8
// XXX permit fetch to express failure
9 1
static int32_t fetch(struct sim_state *s, int32_t addr)
10
{
11
    int32_t data;
12 1
    s->dispatch_op(s, OP_DATA_READ, addr, &data);
13 1
    return data;
14
}
15

16 1
static void store(struct sim_state *s, int32_t addr, int32_t value)
17
{
18 1
    s->dispatch_op(s, OP_WRITE, addr, &value);
19
}
20

21 1
static int bb_by_base(const void *a_, const void *b_)
22
{
23 1
    const struct basic_block *a = a_, *b = b_;
24

25 1
    return a->base - b->base;
26
}
27

28 1
static int pre_insn_hook(struct sim_state *s, const struct element *i, void *ud)
29
{
30 1
    struct ops_state *o = (struct ops_state*)ud;
31 1
    if (!o->curr_bb) {
32 1
        struct basic_block nb = { .base = i->insn.reladdr };
33 1
        struct basic_block **f = tsearch(&nb, &o->basic_blocks, bb_by_base);
34 1
        if (*f == &nb) {
35 1
            *f = malloc(sizeof **f);
36 1
            **f = nb;
37
        }
38 1
        o->curr_bb = *f;
39
    }
40

41 1
    struct basic_block *bb = o->curr_bb;
42 1
    if (bb->compiled)
43 1
        return 1; // indicate to jit_run_sim that JIT should be used
44

45 1
    if (bb->run_count == o->js->run_count_threshold) {
46
        // Cache the instructions we receive so they are ready for compilation
47 1
        if (!bb->cache)
48 1
            bb->cache = calloc((size_t)bb->len, sizeof *bb->cache);
49 1
        bb->cache[i->insn.reladdr - bb->base] = i->insn.u.word;
50 1
    } else if (bb->run_count > o->js->run_count_threshold) {
51 1
        bb->compiled = jit_gen_block(o->js, bb->len, bb->cache);
52 1
        free(bb->cache);
53 1
        return 1; // indicate to jit_run_sim that JIT should be used
54
    }
55

56 1
    return o->ops.pre_insn(s, i, o->nested_ops_data);
57
}
58

59 1
static int post_insn_hook(struct sim_state *s, const struct element *i, void *ud)
60
{
61 1
    struct ops_state *o = (struct ops_state*)ud;
62

63 1
    int dd = i->insn.u.typeany.dd;
64 1
    if ((dd == 0 || dd == 3) && i->insn.u.typeany.z == 0xf) { // P is being updated
65 1
        struct basic_block *bb = o->curr_bb;
66 1
        bb->len = i->insn.reladdr - bb->base + 1;
67 1
        bb->run_count++;
68 1
        o->curr_bb = NULL;
69 1
        o->ops.post_insn(s, i, o->nested_ops_data); // allow hook to run one last time
70 1
        return 1;
71
    }
72

73 1
    return o->ops.post_insn(s, i, o->nested_ops_data);
74
}
75

76 1
int jit_run_sim(struct sim_state *s, const struct run_ops *ops, void **run_data, void *ops_data)
77
{
78
    struct jit_state *js;
79 1
    jit_init(&js);
80 1
    *run_data = js;
81 1
    js->sim_state = s;
82 1
    js->ops.fetch = fetch;
83 1
    js->ops.store = store;
84

85 1
    param_get_int(s->conf.params, "tsim.jit.run_count_threshold", &js->run_count_threshold);
86 1
    if (js->run_count_threshold <= 0)
87 0
        js->run_count_threshold = 1;
88

89 1
    struct ops_state ops_state = { .ops.post_insn = 0 }, *o = &ops_state;
90 1
    o->js = js;
91 1
    o->ops.pre_insn = ops->pre_insn;
92 1
    o->ops.post_insn = ops->post_insn;
93 1
    o->nested_ops_data = ops_data;
94

95 1
    struct run_ops wrappers = { .post_insn = 0 };
96 1
    wrappers.pre_insn = pre_insn_hook;
97 1
    wrappers.post_insn = post_insn_hook;
98

99 1
    int rc = 0;
100
    do {
101 1
        if (o->curr_bb && o->curr_bb->compiled) {
102 1
            o->curr_bb->compiled(s, s->machine.regs);
103 1
            s->insns_executed += (unsigned long)o->curr_bb->len;
104 1
            o->curr_bb->run_count++;
105 1
            o->curr_bb = NULL;
106
        }
107
        // The interpreter has a way to return status, but as of this writing,
108
        // compiled basic blocks do not. Previously, we unconditionally ran the
109
        // interpreter for at least one instruction after running a compiled
110
        // basic block, but this resulted in extra instructions being
111
        // interpreted even at the end of time.
112
        //
113
        // For now, add an explicit check for the normal "end simulation"
114
        // condition (P == halt_addr) and if we hit it, break out without
115
        // trying to run the interpreter again.
116 1
        if (s->machine.regs[15] != s->conf.halt_addr) {
117 1
            rc = s->interp(s, &wrappers, &js->nested_run_data, o);
118 1
            s->pump(s); // no longer a "cycle" but periodic
119
        } else {
120 1
            break;
121
        }
122 1
    } while (rc >= 0);
123

124 1
    jit_fini(js);
125 1
    return 0;
126
}

Read our documentation on viewing source code .

Loading