Skip to content

Commit

Permalink
js
Browse files Browse the repository at this point in the history
  • Loading branch information
ShawSumma committed Dec 31, 2023
1 parent 0d7368c commit e5221ae
Show file tree
Hide file tree
Showing 13 changed files with 741 additions and 119 deletions.
2 changes: 2 additions & 0 deletions main/minivm.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ int main(int argc, char **argv) {
arg += 7;
if (!strcmp(arg, "src")) {
config->dump_src = true;
} else if (!strcmp(arg, "js")) {
config->dump_js = true;
} else if (!strcmp(arg, "ast")) {
config->dump_ast = true;
} else if (!strcmp(arg, "ir")) {
Expand Down
1 change: 1 addition & 0 deletions vendor/tb/include/tb.h
Original file line number Diff line number Diff line change
Expand Up @@ -1326,6 +1326,7 @@ TB_API void tb_pass_optimize(TB_Passes* p);
// analysis
// print: prints IR in a flattened text form.
TB_API void tb_pass_print(TB_Passes* opt);
TB_API char *tb_pass_js_print(TB_Passes* opt);
// print-dot: prints IR as DOT
TB_API void tb_pass_print_dot(TB_Passes* opt, TB_PrintCallback callback, void* user_data);

Expand Down
6 changes: 0 additions & 6 deletions vendor/tb/src/codegen_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,6 @@ static void compile_function(TB_Passes* restrict p, TB_FunctionOutput* restrict
// in a few of the later stages.
TB_ArenaSavepoint sp = tb_arena_save(arena);
CUIK_TIMED_BLOCK("local") {
int timeline = 4;
FOREACH_N(i, 0, bb_count) {
MachineBB* mbb = &machine_bbs[i];
int bbid = mbb->id;
Expand All @@ -479,9 +478,6 @@ static void compile_function(TB_Passes* restrict p, TB_FunctionOutput* restrict
Set* gen = &mbb->gen;
Set* kill = &mbb->kill;
for (Tile* t = mbb->start; t; t = t->next) {
t->time = timeline;
timeline += 4;

FOREACH_N(j, 0, t->in_count) {
LiveInterval* in_def = t->ins[j].src;
if (in_def && !set_get(kill, in_def->id)) {
Expand All @@ -495,8 +491,6 @@ static void compile_function(TB_Passes* restrict p, TB_FunctionOutput* restrict
ctx.id2interval[interval->id] = interval;
}
}

timeline += 4;
}
}

Expand Down
185 changes: 112 additions & 73 deletions vendor/tb/src/lsra.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,41 +173,75 @@ static Tile* tile_at_time(LSRA* restrict ra, int t) {
void tb__lsra(Ctx* restrict ctx, TB_Arena* arena) {
LSRA ra = { .ctx = ctx, .arena = arena, .spills = ctx->num_regs[0] };

// build intervals from dataflow
CUIK_TIMED_BLOCK("build intervals") {
Set visited = set_create_in_arena(arena, ctx->interval_count);
FOREACH_REVERSE_N(i, 0, ctx->bb_count) {
// create timeline & insert moves
CUIK_TIMED_BLOCK("insert legalizing moves") {
int timeline = 4;
FOREACH_N(i, 0, ctx->bb_count) {
MachineBB* mbb = &ctx->machine_bbs[i];

int bb_start = mbb->start->time;
int bb_end = mbb->end->time + 2;
for (Tile* t = mbb->start; t; t = t->next) {
LiveInterval* interval = t->interval;

// live outs define a full range across the BB (if they're defined
// in the block, the later reverse walk will fix that up)
Set* live_out = &mbb->live_out;
FOREACH_N(j, 0, (ctx->interval_count + 63) / 64) {
uint64_t bits = live_out->data[j];
if (bits == 0) continue;
// insert input copies
FOREACH_N(j, 0, t->in_count) {
LiveInterval* in_def = t->ins[j].src;
RegMask in_mask = t->ins[j].mask;
int hint = fixed_reg_mask(in_mask);

FOREACH_N(k, 0, 64) if (bits & (1ull << k)) {
add_range(&ra, ctx->id2interval[j*64 + k], bb_start, bb_end);
}
}
if (in_def == NULL) {
continue;
}

for (Tile* t = mbb->end; t; t = t->prev) {
LiveInterval* interval = t->interval;
RegMask in_def_mask = in_def->mask;
if (hint >= 0) {
in_def->hint = &ctx->fixed[in_mask.class][hint];
}

int time = t->time;
bool both_fixed = hint >= 0 && in_def_mask.mask == in_mask.mask;

// mark output
if (interval != NULL && interval->mask.mask) {
if (!set_get(&visited, interval->id)) {
set_put(&visited, interval->id);
if (interval->reg < 0) {
dyn_array_put(ra.unhandled, interval);
// we resolve def-use conflicts with a spill move, either when:
// * the use and def classes don't match.
// * the use mask is more constrained than the def.
// * it's on both ends to avoid stretching fixed intervals.
if (in_def_mask.class != in_mask.class || (in_def_mask.mask & in_mask.mask) != in_def_mask.mask || both_fixed) {
if (both_fixed) {
in_def_mask = ctx->normie_mask[in_def_mask.class];
}

TB_OPTDEBUG(REGALLOC)(printf(" TEMP "), tb__print_regmask(in_def_mask), printf(" -> "), tb__print_regmask(in_mask), printf("\n"));

// construct copy (either to a fixed interval or a new masked interval)
Tile* tmp = tb_arena_alloc(arena, sizeof(Tile));
*tmp = (Tile){
.prev = t->prev,
.next = t,
.tag = TILE_SPILL_MOVE,
.time = timeline
};
assert(in_def->dt.raw);
tmp->spill_dt = in_def->dt;
tmp->ins = tb_arena_alloc(tmp_arena, sizeof(Tile*));
tmp->in_count = 1;
tmp->ins[0].src = in_def;
tmp->ins[0].mask = in_def_mask;
t->prev->next = tmp;
t->prev = tmp;

// replace use site with temporary that legalized the constraint
tmp->interval = gimme_interval_for_mask(ctx, arena, &ra, in_mask, in_def->dt);
t->ins[j].src = tmp->interval;

timeline += 2;
}
}

// place on timeline
t->time = timeline;
// 2addr ops will have a bit of room for placing the hypothetical copy
timeline += t->n && ctx->_2addr(t->n) ? 4 : 2;

// insert copy if we're writing to a fixed interval
if (interval && interval->mask.mask) {
// if we're writing to a fixed interval, insert copy
// such that we only guarentee a fixed location at the
// def site.
Expand All @@ -227,7 +261,7 @@ void tb__lsra(Ctx* restrict ctx, TB_Arena* arena) {
.prev = t,
.next = t->next,
.tag = TILE_SPILL_MOVE,
.time = time,
.time = timeline,
};
assert(interval->dt.raw);
tmp->spill_dt = interval->dt;
Expand All @@ -242,9 +276,51 @@ void tb__lsra(Ctx* restrict ctx, TB_Arena* arena) {
tmp->interval = interval;
t->interval = fixed;

// add def range & use range
add_range(&ra, fixed, time, time);
add_use_pos(&ra, fixed, time, false);
// skip this move op
t = tmp;
timeline += 2;
}
}
}

timeline += 2;
}
}

// build intervals from dataflow
CUIK_TIMED_BLOCK("build intervals") {
Set visited = set_create_in_arena(arena, ctx->interval_count);

FOREACH_REVERSE_N(i, 0, ctx->bb_count) {
MachineBB* mbb = &ctx->machine_bbs[i];

int bb_start = mbb->start->time;
int bb_end = mbb->end->time + 2;

// live outs define a full range across the BB (if they're defined
// in the block, the later reverse walk will fix that up)
Set* live_out = &mbb->live_out;
FOREACH_N(j, 0, (ctx->interval_count + 63) / 64) {
uint64_t bits = live_out->data[j];
if (bits == 0) continue;

FOREACH_N(k, 0, 64) if (bits & (1ull << k)) {
add_range(&ra, ctx->id2interval[j*64 + k], bb_start, bb_end);
}
}

for (Tile* t = mbb->end; t; t = t->prev) {
LiveInterval* interval = t->interval;

int time = t->time;

// mark output
if (interval != NULL && interval->mask.mask) {
if (!set_get(&visited, interval->id)) {
set_put(&visited, interval->id);
if (interval->reg < 0) {
dyn_array_put(ra.unhandled, interval);
}
}

if (interval->range_count == 1) {
Expand Down Expand Up @@ -285,51 +361,14 @@ void tb__lsra(Ctx* restrict ctx, TB_Arena* arena) {
}

int use_time = time;
bool both_fixed = hint >= 0 && in_def_mask.mask == in_mask.mask;

// we resolve def-use conflicts with a spill move, either when:
// * the use and def classes don't match.
// * the use mask is more constrained than the def.
// * it's on both ends to avoid stretching fixed intervals.
if (in_def_mask.class != in_mask.class || (in_def_mask.mask & in_mask.mask) != in_def_mask.mask || both_fixed) {
if (both_fixed) {
in_def_mask = ctx->normie_mask[in_def_mask.class];
if (_2addr) {
if (j != 0) {
// extend
use_time += 2;
} else if (interval->hint == NULL) {
// hint as copy
interval->hint = in_def;
}

TB_OPTDEBUG(REGALLOC)(printf(" TEMP "), tb__print_regmask(in_def_mask), printf(" -> "), tb__print_regmask(in_mask), printf("\n"));

// construct copy (either to a fixed interval or a new masked interval)
Tile* tmp = tb_arena_alloc(arena, sizeof(Tile));
*tmp = (Tile){
.prev = t->prev,
.next = t,
.tag = TILE_SPILL_MOVE,
.time = time,
};
assert(in_def->dt.raw);
tmp->spill_dt = in_def->dt;
tmp->ins = tb_arena_alloc(tmp_arena, sizeof(Tile*));
tmp->in_count = 1;
tmp->ins[0].src = in_def;
tmp->ins[0].mask = in_def_mask;
t->prev->next = tmp;
t->prev = tmp;

// replace use site with temporary that legalized the constraint
tmp->interval = gimme_interval_for_mask(ctx, arena, &ra, in_mask, in_def->dt);
t->ins[j].src = tmp->interval;

// insert fixed interval use site, def site will be set later
add_range(&ra, tmp->interval, bb_start, use_time);
add_use_pos(&ra, tmp->interval, bb_start, in_mask.may_spill);
} else if (_2addr && j != 0) {
// extend
use_time += 2;
}

// hint as copy
if (_2addr && j == 0 && interval->hint == NULL) {
interval->hint = in_def;
}

add_range(&ra, in_def, bb_start, use_time);
Expand Down
72 changes: 43 additions & 29 deletions vendor/tb/src/opt/fold.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ static bool is_zero(TB_Node* n) {
return n->type == TB_INTEGER_CONST && i->value == 0;
}

static bool is_one(TB_Node* n) {
TB_NodeInt* i = TB_NODE_GET_EXTRA(n);
return n->type == TB_INTEGER_CONST && i->value == 1;
}

static bool inverted_cmp(TB_Node* n, TB_Node* n2) {
switch (n->type) {
case TB_CMP_EQ: return n2->type == TB_CMP_NE && n2->inputs[1] == n->inputs[1] && n2->inputs[2] == n->inputs[2];
Expand Down Expand Up @@ -835,41 +840,50 @@ static TB_Node* ideal_int_div(TB_Passes* restrict opt, TB_Function* f, TB_Node*
// a * 0 => 0
// a / 0 => poison
static TB_Node* identity_int_binop(TB_Passes* restrict opt, TB_Function* f, TB_Node* n) {
if (!is_zero(n->inputs[2])) return n;

switch (n->type) {
default: return n;
uint64_t b;
if (!get_int_const(n->inputs[2], &b)) {
return n;
}

case TB_SHL:
case TB_SHR:
case TB_ADD:
case TB_SUB:
case TB_XOR:
if (n->type == TB_MUL && b == 1) {
return n->inputs[1];
} else if (b == 0) {
switch (n->type) {
default: return n;

case TB_MUL:
return n->inputs[0];

case TB_UDIV:
case TB_SDIV:
case TB_UMOD:
case TB_SMOD:
return make_poison(f, n->dt);

// (cmp.ne a 0) => a
case TB_CMP_NE: {
// walk up extension
TB_Node* src = n->inputs[1];
if (src->type == TB_ZERO_EXT) {
src = src->inputs[1];
}
case TB_SHL:
case TB_SHR:
case TB_ADD:
case TB_SUB:
case TB_XOR:
return n->inputs[1];

case TB_MUL:
return n->inputs[0];

case TB_UDIV:
case TB_SDIV:
case TB_UMOD:
case TB_SMOD:
return make_poison(f, n->dt);

// (cmp.ne a 0) => a
case TB_CMP_NE: {
// walk up extension
TB_Node* src = n->inputs[1];
if (src->type == TB_ZERO_EXT) {
src = src->inputs[1];
}

if (src->dt.type == TB_INT && src->dt.data == 1) {
return src;
}

if (src->dt.type == TB_INT && src->dt.data == 1) {
return src;
return n;
}

return n;
}
} else {
return n;
}
}

Expand Down
1 change: 1 addition & 0 deletions vendor/tb/src/opt/optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ static bool slow_dommy(TB_CFG* cfg, TB_Node* expected_dom, TB_Node* bb) {
#include "loop.h"
#include "branches.h"
#include "print.h"
#include "print_js.h"
#include "mem2reg.h"
#include "gcm.h"
#include "libcalls.h"
Expand Down
6 changes: 3 additions & 3 deletions vendor/tb/src/opt/peeps.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ static const NodeVtable vtables[TB_NODE_TYPE_MAX] = {
[TB_OR] = { ideal_int_binop, identity_int_binop, sccp_bits },
[TB_XOR] = { ideal_int_binop, identity_int_binop, sccp_bits },
// shift
[TB_SHL] = { ideal_int_binop, NULL, sccp_shift },
[TB_SHR] = { ideal_int_binop, NULL, sccp_shift },
[TB_SAR] = { ideal_int_binop, NULL, sccp_shift },
[TB_SHL] = { ideal_int_binop, identity_int_binop, sccp_shift },
[TB_SHR] = { ideal_int_binop, identity_int_binop, sccp_shift },
[TB_SAR] = { ideal_int_binop, identity_int_binop, sccp_shift },
// unary
[TB_NEG] = { NULL, NULL, sccp_unary },
[TB_NOT] = { NULL, NULL, sccp_unary },
Expand Down
Loading

0 comments on commit e5221ae

Please sign in to comment.