<commit_before>#include "jit.h"

#include <search.h>
#include <stdlib.h>

// XXX permit fetch to express failure
int32_t fetch(void *cookie, int32_t addr)
{
    struct sim_state *s = cookie;
    int32_t data;
    s->dispatch_op(s, OP_DATA_READ, addr, (uint32_t*)&data);
    return data;
}

void store(void *cookie, int32_t addr, int32_t value)
{
    struct sim_state *s = cookie;
    s->dispatch_op(s, OP_WRITE, addr, (uint32_t*)&value);
}

static int bb_by_base(const void *a_, const void *b_)
{
    const struct basic_block *a = a_, *b = b_;

    return a->base - b->base;
}

static int pre_insn_hook(struct sim_state *s, const struct element *i, void *ud)
{
    struct ops_state *o = (struct ops_state*)ud;
    if (!o->curr_bb) {
        struct basic_block nb = { .base = i->insn.reladdr };
        struct basic_block **f = tsearch(&nb, &o->basic_blocks, bb_by_base);
        if (*f == &nb) {
            *f = malloc(sizeof **f);
            **f = nb;
        }
        o->curr_bb = *f;
    }

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

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

    return o->ops.pre_insn(s, i, o->nested_ops_data);
}

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

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

    return o->ops.post_insn(s, i, o->nested_ops_data);
}

int jit_run_sim(struct sim_state *s, struct run_ops *ops, void **run_data, void *ops_data)
{
    struct jit_state *js;
    jit_init(&js);
    *run_data = js;
    js->sim_state = s;

    param_get_int(s->conf.params, "tsim.jit.run_count_threshold", &js->run_count_threshold);
<commit_msg>Ensure run_count_threshold is at least 1<commit_after>#include "jit.h"

#include <search.h>
#include <stdlib.h>

// XXX permit fetch to express failure
int32_t fetch(void *cookie, int32_t addr)
{
    struct sim_state *s = cookie;
    int32_t data;
    s->dispatch_op(s, OP_DATA_READ, addr, (uint32_t*)&data);
    return data;
}

void store(void *cookie, int32_t addr, int32_t value)
{
    struct sim_state *s = cookie;
    s->dispatch_op(s, OP_WRITE, addr, (uint32_t*)&value);
}

static int bb_by_base(const void *a_, const void *b_)
{
    const struct basic_block *a = a_, *b = b_;

    return a->base - b->base;
}

static int pre_insn_hook(struct sim_state *s, const struct element *i, void *ud)
{
    struct ops_state *o = (struct ops_state*)ud;
    if (!o->curr_bb) {
        struct basic_block nb = { .base = i->insn.reladdr };
        struct basic_block **f = tsearch(&nb, &o->basic_blocks, bb_by_base);
        if (*f == &nb) {
            *f = malloc(sizeof **f);
            **f = nb;
        }
        o->curr_bb = *f;
    }

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

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

    return o->ops.pre_insn(s, i, o->nested_ops_data);
}

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

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

    return o->ops.post_insn(s, i, o->nested_ops_data);
}

int jit_run_sim(struct sim_state *s, struct run_ops *ops, void **run_data, void *ops_data)
{
    struct jit_state *js;
    jit_init(&js);
    *run_data = js;
    js->sim_state = s;

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

{'fraction_non_alphanumeric': 0.1493948562783661, 'fraction_numerical': 0.011535552193645991, 'mean_word_length': 2.7644128113879005, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 103, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3977840', 'n_tokens_mistral': 2036, 'n_tokens_neox': 1975, 'n_words': 494}