From 554d2c3d4b040223b3edd935bd4cbfb7ffde120b Mon Sep 17 00:00:00 2001 From: "alexander.nutz" Date: Wed, 18 Sep 2024 15:07:31 +0200 Subject: [PATCH] new opt pass --- build.c | 1 + ir/analysis.c | 6 +++ ir/opt.c | 1 + ir/opt.h | 1 + ir/opt/if_opts.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 104 insertions(+) create mode 100644 ir/opt/if_opts.c diff --git a/build.c b/build.c index 379a2aa..b32bd64 100644 --- a/build.c +++ b/build.c @@ -58,6 +58,7 @@ struct CompileData target_lib_files[] = { SP(CT_C, "ir/opt/ll_binary.c"), SP(CT_C, "ir/opt/simple_patterns.c"), SP(CT_C, "ir/opt/ll_sched.c"), + SP(CT_C, "ir/opt/if_opts.c"), DIR("build/ir/transform"), SP(CT_C, "ir/transform/single_assign_conditional.c"), diff --git a/ir/analysis.c b/ir/analysis.c index b8d04bf..f33e62a 100644 --- a/ir/analysis.c +++ b/ir/analysis.c @@ -243,6 +243,12 @@ bool vx_IrOpType_hasEffect(vx_IrOpType type) bool vx_IrOp_endsFlow(vx_IrOp *op) { + if (op->id == VX_IR_OP_IF) + { + vx_IrBlock* pthen = vx_IrOp_param(op, VX_IR_NAME_COND_THEN)->block; + vx_IrBlock* pelse = vx_IrOp_param(op, VX_IR_NAME_COND_ELSE)->block; + return vx_IrBlock_endsFlow(pthen) && vx_IrBlock_endsFlow(pelse); + } return vx_IrOpType__entries[op->id].endsFlow.a; } diff --git a/ir/opt.c b/ir/opt.c index 138492e..ef95858 100644 --- a/ir/opt.c +++ b/ir/opt.c @@ -39,6 +39,7 @@ void opt(vx_IrBlock *block) { vx_opt_join_compute(block); if (vx_g_optconfig.if_eval) { vx_opt_reduce_if(block); + vx_opt_if_opts(block); } vx_opt_cmov(block); opt_pre(block); diff --git a/ir/opt.h b/ir/opt.h index ea5ffb3..e5296c4 100644 --- a/ir/opt.h +++ b/ir/opt.h @@ -23,6 +23,7 @@ OPT_PASS void vx_opt_cmov(vx_IrBlock *block); OPT_PASS void vx_opt_vars(vx_IrBlock *block); OPT_PASS void vx_opt_ll_jumps(vx_IrBlock *block); OPT_PASS void vx_opt_simple_patterns(vx_IrBlock* block); +OPT_PASS void vx_opt_if_opts(vx_IrBlock* block); OPT_PASS void vx_opt_ll_dce(vx_IrBlock *block); OPT_PASS void vx_opt_ll_condtailcall(vx_IrBlock *block); diff --git a/ir/opt/if_opts.c b/ir/opt/if_opts.c new file mode 100644 index 0000000..76ed80b --- /dev/null +++ b/ir/opt/if_opts.c @@ -0,0 +1,95 @@ +#include "../opt.h" + +// TODO: move to ir/transform.c +static vx_IrVar genIntoVar(vx_IrBlock* block, vx_IrValue val) +{ + vx_IrOp* op = vx_IrBlock_addOpBuilding(block); + vx_IrOp_init(op, VX_IR_OP_IMM, block); + vx_IrBlock* root = vx_IrBlock_root(block); + vx_IrVar var = vx_IrBlock_newVar(root, op); + vx_IrTypeRef ty = vx_IrValue_type(root, val); + vx_IrOp_addOut(op, var, ty.ptr); + vx_IrTypeRef_drop(ty); + vx_IrOp_addParam_s(op, VX_IR_NAME_VALUE, val); + return var; +} + +void vx_opt_if_opts(vx_IrBlock* block) +{ + // move code after if statements that partially end flow into the branch that doesn't end flow + for (vx_IrOp* op = block->first; op; op = op->next) + { + if (op->id != VX_IR_OP_IF) + continue; + + vx_IrBlock* bthen = vx_IrOp_param(op, VX_IR_NAME_COND_THEN)->block; assert(bthen); + vx_IrBlock* belse = vx_IrOp_param(op, VX_IR_NAME_COND_ELSE)->block; assert(belse); + + bool thenEnds = vx_IrBlock_endsFlow(bthen); + bool elseEnds = vx_IrBlock_endsFlow(belse); + + if (thenEnds == elseEnds) + continue; + + vx_IrBlock* notEndingBlk = thenEnds ? belse : bthen; + + vx_IrOp* next = op->next; + op->next = NULL; + + for (vx_IrOp* o = next; o; o = o->next) + o->parent = notEndingBlk; + + { + vx_IrOp* tail = vx_IrBlock_tail(notEndingBlk); + if (tail == NULL) { + notEndingBlk->first = next; + } else { + tail->next = next; + } + } + + for (size_t i = 0; i < op->outs_len; i ++) + vx_IrBlock_renameVar(notEndingBlk, op->outs[i].var, notEndingBlk->outs[i]); + + break; // there is no next anymore + } + + vx_opt_ll_dce(block); // it says ll but also works in ssa + + for (vx_IrOp* op = block->first; op; op = op->next) + { + if (op->id != VX_IR_OP_IF) + continue; + + vx_IrBlock* bthen = vx_IrOp_param(op, VX_IR_NAME_COND_THEN)->block; + vx_IrBlock* belse = vx_IrOp_param(op, VX_IR_NAME_COND_ELSE)->block; + + vx_IrOp* thenLast = vx_IrBlock_tail(bthen); + vx_IrOp* elseLast = vx_IrBlock_tail(belse); + + if (!thenLast) continue; + if (!elseLast) continue; + if (thenLast->id != VX_IR_OP_RETURN) continue; + if (elseLast->id != VX_IR_OP_RETURN) continue; + + vx_IrOp* retInst = vx_IrBlock_insertOpBuildingAfter(op); + vx_IrOp_init(retInst, VX_IR_OP_RETURN, block); + + vx_IrBlock* root = vx_IrBlock_root(block); + size_t numRets = root->outs_len; + for (size_t i = 0; i < numRets; i ++) + { + vx_IrBlock_addOut(bthen, genIntoVar(bthen, thenLast->args[i])); + vx_IrBlock_addOut(belse, genIntoVar(belse, elseLast->args[i])); + + vx_IrVar va = vx_IrBlock_newVar(root, op); + vx_IrOp_addOut(op, va, vx_IrBlock_typeofVar(root, root->outs[i])); + vx_IrOp_addArg(retInst, VX_IR_VALUE_VAR(va)); + } + + vx_IrOp_remove(thenLast); + vx_IrOp_remove(elseLast); + + break; // the next op is going to be the return we just inserted + } +}