Skip to content

Commit

Permalink
cmov
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-s168 committed May 23, 2024
1 parent a9e5f11 commit 404b517
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 66 deletions.
71 changes: 71 additions & 0 deletions ir/analysis.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ bool vx_IrOp_is_volatile(vx_IrOp *op)
case VX_IR_OP_LOAD:
case VX_IR_OP_STORE:
case VX_IR_OP_PLACE:
case VX_IR_OP_CMOV:
return false;

case VX_IR_OP_LOAD_VOLATILE:
Expand Down Expand Up @@ -171,3 +172,73 @@ vx_IrType *vx_IrBlock_typeof_var(vx_IrBlock *block, vx_IrVar var) {
return decl->outs[i].type;
assert(false);
}

static size_t cost_lut[VX_IR_OP____END] = {
[VX_IR_OP_NOP] = 0,
[VX_IR_OP_IMM] = 1,
[VX_IR_OP_FLATTEN_PLEASE] = 0,
[VX_IR_OP_REINTERPRET] = 0,
[VX_IR_OP_ZEROEXT] = 1,
[VX_IR_OP_SIGNEXT] = 1,
[VX_IR_OP_TOFLT] = 1,
[VX_IR_OP_FROMFLT] = 1,
[VX_IR_OP_BITCAST] = 1,
[VX_IR_OP_LOAD] = 1,
[VX_IR_OP_LOAD_VOLATILE] = 1,
[VX_IR_OP_STORE] = 1,
[VX_IR_OP_STORE_VOLATILE] = 1,
[VX_IR_OP_PLACE] = 0,
[VX_IR_OP_ADD] = 1,
[VX_IR_OP_SUB] = 1,
[VX_IR_OP_MUL] = 1,
[VX_IR_OP_DIV] = 1,
[VX_IR_OP_MOD] = 1,
[VX_IR_OP_GT] = 1,
[VX_IR_OP_GTE] = 1,
[VX_IR_OP_LT] = 1,
[VX_IR_OP_LTE] = 1,
[VX_IR_OP_EQ] = 1,
[VX_IR_OP_NEQ] = 1,
[VX_IR_OP_NOT] = 1,
[VX_IR_OP_AND] = 1,
[VX_IR_OP_OR] = 1,
[VX_IR_OP_BITWISE_NOT] = 1,
[VX_IR_OP_BITWISE_AND] = 1,
[VX_IR_OP_BITIWSE_OR] = 1,
[VX_IR_OP_SHL] = 1,
[VX_IR_OP_FOR] = 1,
[VX_IR_OP_INFINITE] = 1,
[VX_IR_OP_WHILE] = 1,
[VX_IR_OP_CONTINUE] = 1,
[VX_IR_OP_BREAK] = 1,
[VX_IR_OP_FOREACH] = 2,
[VX_IR_OP_FOREACH_UNTIL] = 2,
[VX_IR_OP_REPEAT] = 1,
[VX_CIR_OP_CFOR] = 2,
[VX_IR_OP_IF] = 1,
[VX_IR_OP_CMOV] = 1,
[VX_LIR_OP_LABEL] = 1,
[VX_LIR_GOTO] = 1,
[VX_LIR_COND] = 1,
};

size_t vx_IrOp_inline_cost(vx_IrOp *op) {
size_t total = 0;

for (size_t i = 0; i < op->params_len; i ++)
if (op->params[i].val.type == VX_IR_NAME_BLOCK)
total += vx_IrBlock_inline_cost(op->params[i].val.block);

total += cost_lut[op->id];

return total;
}

size_t vx_IrBlock_inline_cost(const vx_IrBlock *block) {
size_t total = 0;
for (size_t i = 0; i < block->ops_len; i ++) {
vx_IrOp *op = &block->ops[i];
total += vx_IrOp_inline_cost(op);
}
return total;
}
1 change: 1 addition & 0 deletions ir/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const char *vx_IrOpType_names[SSAOPTYPE_LEN] = {
[VX_CIR_OP_CFOR] = "cfor",

[VX_IR_OP_IF] = "if",
[VX_IR_OP_CMOV] = "cmov",

[VX_LIR_OP_LABEL] = "label",
[VX_LIR_GOTO] = "goto",
Expand Down
6 changes: 4 additions & 2 deletions ir/ir.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ vx_IrType *vx_IrBlock_typeof_var(vx_IrBlock *block, vx_IrVar var);

vx_IrVar vx_IrBlock_new_var(vx_IrBlock *block, vx_IrOp *decl);
size_t vx_IrBlock_new_label(vx_IrBlock *block, vx_IrOp *decl);
TRANSFORM_PASS void vx_IrBlock_flatten(vx_IrBlock *block);
void vx_IrBlock_swap_in_at(vx_IrBlock *block, size_t a, size_t b);
void vx_IrBlock_swap_out_at(vx_IrBlock *block, size_t a, size_t b);
void vx_IrBlock_remove_out_at(vx_IrBlock *block, size_t id);
Expand Down Expand Up @@ -298,7 +297,8 @@ typedef enum {
VX_CIR_OP_CFOR, // "start": ()->., "cond": ()->bool, "end": ()->., "do": (counter)->.

// conditional
VX_IR_OP_IF, // "cond": bool, "then": ()->R, ("else": ()->R)
VX_IR_OP_IF, // "cond": ()->bool, "then": ()->R, ("else": ()->R)
VX_IR_OP_CMOV, // "cond": ()->bool, "then": value, "else": value

VX_LIR_OP_LABEL, // "id"
VX_LIR_GOTO, // "id"
Expand Down Expand Up @@ -396,6 +396,7 @@ void vx_IrOp_steal_outs(vx_IrOp *dest, const vx_IrOp *src);
void vx_IrOp_destroy(vx_IrOp *op);
void vx_IrOp_remove_state_at(vx_IrOp *op, size_t id);
bool vx_IrOp_is_volatile(vx_IrOp *op);
size_t vx_IrOp_inline_cost(vx_IrOp *op);
void vx_IrOp_steal_states(vx_IrOp *dest, const vx_IrOp *src);

struct IrStaticIncrement {
Expand All @@ -407,5 +408,6 @@ struct IrStaticIncrement vx_IrOp_detect_static_increment(const vx_IrOp *op);

vx_IrOp *vx_IrBlock_inside_out_vardecl_before(const vx_IrBlock *block, vx_IrVar var, size_t before);
bool vx_IrBlock_is_volatile(const vx_IrBlock *block);
size_t vx_IrBlock_inline_cost(const vx_IrBlock *block);

#endif //IR_H
67 changes: 67 additions & 0 deletions ir/opt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#include "opt.h"
#include "ir.h"

vx_OptConfig vx_g_optconfig = {
.max_total_cmov_inline_cost = 4,
.consteval_iterations = 6,
.loop_simplify = true,
.if_eval = true,
};

static void opt_pre(vx_IrBlock *block) {
// TODO: re-enable
(void) block;
/*
// place immediates into params
vx_opt_inline_vars(vx_IrView_of_all(block), block);
for (size_t i = 0; i < vx_g_optconfig.consteval_iterations; i ++) {
// evaluate constants
vx_opt_constant_eval(vx_IrView_of_all(block), block);
// place results into params
vx_opt_inline_vars(vx_IrView_of_all(block), block);
}
if (block->is_root)
vx_opt_remove_vars(block);
vx_opt_comparisions(vx_IrView_of_all(block), block);
*/
}

void opt(vx_IrBlock *block) {
// TODO: remove opt() calls from opt pass bodies

for (size_t i = 0; i < block->ops_len; i ++) {
vx_IrOp *op = &block->ops[i];

for (size_t i = 0; i < op->params_len; i ++)
if (op->params[i].val.type == VX_IR_VAL_BLOCK)
opt(op->params[i].val.block);
}

opt_pre(block);
vx_opt_join_compute(vx_IrView_of_all(block), block);
if (vx_g_optconfig.if_eval) {
vx_opt_reduce_if(vx_IrView_of_all(block), block);
}
vx_opt_cmov(vx_IrView_of_all(block), block);
opt_pre(block);
if (vx_g_optconfig.loop_simplify) {
vx_opt_reduce_loops(vx_IrView_of_all(block), block);
vx_opt_loop_simplify(vx_IrView_of_all(block), block);
}

for (size_t i = 0; i < block->ops_len; i ++) {
vx_IrOp *op = &block->ops[i];

if (op->id == VX_IR_OP_FLATTEN_PLEASE) {
vx_IrBlock *body = vx_IrOp_param(op, VX_IR_NAME_BLOCK)->block;
opt(body);
}
}
}

void opt_ll(vx_IrBlock *block) {
opt_pre(block);
vx_opt_ll_jumps(vx_IrView_of_all(block), block);
}
42 changes: 12 additions & 30 deletions ir/opt.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,48 +3,30 @@

#include "ir.h"

typedef struct {
size_t max_total_cmov_inline_cost;
size_t consteval_iterations;
bool loop_simplify;
bool if_eval;
} vx_OptConfig;

extern vx_OptConfig vx_g_optconfig;

OPT_PASS void vx_opt_loop_simplify(vx_IrView view, vx_IrBlock *block);
OPT_PASS void vx_opt_comparisions(vx_IrView view, vx_IrBlock *block);
OPT_PASS void vx_opt_constant_eval(vx_IrView view, vx_IrBlock *block);
OPT_PASS void vx_opt_inline_vars(vx_IrView view, vx_IrBlock *block);
OPT_PASS void vx_opt_join_compute(vx_IrView view, vx_IrBlock *block);
OPT_PASS void vx_opt_reduce_if(vx_IrView view, vx_IrBlock *block);
OPT_PASS void vx_opt_reduce_loops(vx_IrView view, vx_IrBlock *block);
OPT_PASS void vx_opt_cmov(vx_IrView view, vx_IrBlock *block);

OPT_PASS void vx_opt_ll_jumps(vx_IrView view, vx_IrBlock *block);

/** Can only be applied to root blocks */
OPT_PASS void vx_opt_remove_vars(vx_IrBlock *block);

#define CONSTEVAL_ITER 6

static void opt_pre(vx_IrBlock *block) {
// place immediates into params
vx_opt_inline_vars(vx_IrView_of_all(block), block);
for (int i = 0; i < CONSTEVAL_ITER; i ++) {
// evaluate constants
vx_opt_constant_eval(vx_IrView_of_all(block), block);
// place results into params
vx_opt_inline_vars(vx_IrView_of_all(block), block);
}

if (block->is_root)
vx_opt_remove_vars(block);

vx_opt_comparisions(vx_IrView_of_all(block), block);
}

static void opt(vx_IrBlock *block) {
opt_pre(block);
vx_opt_join_compute(vx_IrView_of_all(block), block);
vx_opt_reduce_if(vx_IrView_of_all(block), block);
opt_pre(block);
vx_opt_reduce_loops(vx_IrView_of_all(block), block);
vx_opt_loop_simplify(vx_IrView_of_all(block), block);
}

static void opt_ll(vx_IrBlock *block) {
vx_opt_ll_jumps(vx_IrView_of_all(block), block);
}
void opt(vx_IrBlock *block);
void opt_ll(vx_IrBlock *block);

#endif //OPT_H
89 changes: 89 additions & 0 deletions ir/opt/cmov.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include "../opt.h"

static vx_IrVar block_res_as_var(vx_IrBlock *parent, vx_IrBlock *block) {
vx_IrOp *op = vx_IrBlock_add_op_building(parent);
vx_IrOp_init(op, VX_IR_OP_FLATTEN_PLEASE, parent);
vx_IrVar dest = vx_IrBlock_new_var(parent, op);
vx_IrOp_add_param_s(op, VX_IR_NAME_BLOCK, (vx_IrValue) { .type = VX_IR_VAL_BLOCK, .block = block });
vx_IrOp_add_out(op, dest, vx_IrBlock_typeof_var(block, block->outs[0]));
return dest;
}

// convert:
// DEST = if cond=COND, then={
// ^ THEN: non volatile
// }, else={
// ^ ELSE: non volatile
// }
//
// to:
// V0 < THEN
// V1 < ELSE
// DEST = cmov cond=COND, then=V0, else=V1
//
// if:
// cost of then + else is small enough
// exactly one out

void vx_opt_cmov(vx_IrView view, vx_IrBlock *block)
{
for (size_t i = view.start; i < view.end; i ++) {
vx_IrOp *op = &block->ops[i];

if (op->id != VX_IR_OP_IF)
continue;

if (op->outs_len != 1)
continue;

vx_IrValue *pthen = vx_IrOp_param(op, VX_IR_NAME_COND_THEN);
if (!pthen)
continue;

vx_IrValue *pelse = vx_IrOp_param(op, VX_IR_NAME_COND_ELSE);
if (!pelse)
continue;

vx_IrBlock *then = pthen->block;
if (vx_IrBlock_is_volatile(then))
continue;

vx_IrBlock *els = pelse->block;
if (vx_IrBlock_is_volatile(els))
continue;

size_t total_cost = vx_IrBlock_inline_cost(then) + vx_IrBlock_inline_cost(els);
if (total_cost > vx_g_optconfig.max_total_cmov_inline_cost)
continue;

vx_IrBlock *cond = vx_IrOp_param(op, VX_IR_NAME_COND)->block;


vx_IrBlock *body = vx_IrBlock_init_heap(block, i);

vx_IrVar v0 = block_res_as_var(body, then);
vx_IrVar v1 = block_res_as_var(body, els);

vx_IrOp *cmov = vx_IrBlock_add_op_building(body);
vx_IrOp_init(cmov, VX_IR_OP_CMOV, body);
vx_IrVar dest = vx_IrBlock_new_var(body, cmov);
vx_IrOp_add_param_s(cmov, VX_IR_NAME_COND, (vx_IrValue) { .type = VX_IR_VAL_BLOCK, .block = cond });
vx_IrOp_add_param_s(cmov, VX_IR_NAME_COND_THEN, (vx_IrValue) { .type = VX_IR_VAL_VAR, .var = v0 });
vx_IrOp_add_param_s(cmov, VX_IR_NAME_COND_ELSE, (vx_IrValue) { .type = VX_IR_VAL_VAR, .var = v1 });
vx_IrOp_add_out(cmov, dest, vx_IrBlock_typeof_var(then, then->outs[0]));

vx_IrBlock_add_out(body, dest);


vx_IrTypedVar out = op->outs[0];

free(op->params);
op->params = NULL;
op->params_len = 0;
vx_IrOp_destroy(op);
vx_IrOp_init(op, VX_IR_OP_FLATTEN_PLEASE, block);

vx_IrOp_add_param_s(op, VX_IR_NAME_BLOCK, (vx_IrValue) { .type = VX_IR_VAL_BLOCK, .block = body });
vx_IrOp_add_out(op, out.var, out.type);
}
}
28 changes: 0 additions & 28 deletions ir/transform/flatten.c

This file was deleted.

Loading

0 comments on commit 404b517

Please sign in to comment.