Merge basic blocks by removing connected END to BEGIN nodes

This commit is contained in:
Dmitry Stogov 2022-10-05 16:29:49 +03:00
parent db8a80e8d5
commit d2a0347b21
4 changed files with 68 additions and 6 deletions

9
ir.h
View File

@ -412,10 +412,11 @@ void ir_strtab_free(ir_strtab *strtab);
#define IR_IRREDUCIBLE_CFG (1<<8) #define IR_IRREDUCIBLE_CFG (1<<8)
#define IR_OPT_FOLDING (1<<16) #define IR_OPT_FOLDING (1<<16)
#define IR_OPT_CODEGEN (1<<17) #define IR_OPT_CFG (1<<17) /* merge BBs, by remove END->BEGIN nodes during CFG construction */
#define IR_OPT_IN_SCCP (1<<18) #define IR_OPT_CODEGEN (1<<18)
#define IR_LINEAR (1<<19) #define IR_OPT_IN_SCCP (1<<19)
#define IR_GEN_NATIVE (1<<20) #define IR_LINEAR (1<<20)
#define IR_GEN_NATIVE (1<<21)
#define IR_GEN_C (1<<22) #define IR_GEN_C (1<<22)
/* x86 related */ /* x86 related */

View File

@ -1,6 +1,44 @@
#include "ir.h" #include "ir.h"
#include "ir_private.h" #include "ir_private.h"
static ir_ref ir_merge_blocks(ir_ctx *ctx, ir_ref end, ir_ref begin)
{
ir_ref prev, next;
ir_use_list *use_list;
ir_ref j, n, *p;
IR_ASSERT(ctx->ir_base[begin].op == IR_BEGIN);
IR_ASSERT(ctx->ir_base[end].op == IR_END);
IR_ASSERT(ctx->ir_base[begin].op1 == end);
IR_ASSERT(ctx->use_lists[end].count == 1);
prev = ctx->ir_base[end].op1;
use_list = &ctx->use_lists[begin];
IR_ASSERT(use_list->count == 1);
next = ctx->use_edges[use_list->refs];
/* remove BEGIN and END */
ctx->ir_base[begin].op = IR_NOP;
ctx->ir_base[begin].op1 = IR_UNUSED;
ctx->use_lists[begin].count = 0;
ctx->ir_base[end].op = IR_NOP;
ctx->ir_base[end].op1 = IR_UNUSED;
ctx->use_lists[end].count = 0;
/* connect their predecessor and successor */
ctx->ir_base[next].op1 = prev;
use_list = &ctx->use_lists[prev];
n = use_list->count;
for (j = 0, p = &ctx->use_edges[use_list->refs]; j < n; j++, p++) {
if (*p == end) {
*p = next;
}
}
return next;
}
int ir_build_cfg(ir_ctx *ctx) int ir_build_cfg(ir_ctx *ctx)
{ {
ir_ref n, j, *p, ref, b; ir_ref n, j, *p, ref, b;
@ -57,6 +95,14 @@ int ir_build_cfg(ir_ctx *ctx)
while (1) { while (1) {
insn = &ctx->ir_base[ref]; insn = &ctx->ir_base[ref];
if (IR_IS_BB_START(insn->op)) { if (IR_IS_BB_START(insn->op)) {
if (insn->op == IR_BEGIN
&& (ctx->flags & IR_OPT_CFG)
&& ctx->ir_base[insn->op1].op == IR_END
&& ctx->use_lists[ref].count == 1) {
ref = ir_merge_blocks(ctx, insn->op1, ref);
ref = ctx->ir_base[ref].op1;
continue;
}
break; break;
} }
ref = insn->op1; // follow connected control blocks untill BB start ref = insn->op1; // follow connected control blocks untill BB start
@ -106,8 +152,23 @@ int ir_build_cfg(ir_ctx *ctx)
break; break;
} }
} }
next_successor:
IR_ASSERT(ref != IR_UNUSED); IR_ASSERT(ref != IR_UNUSED);
if (IR_IS_BB_END(insn->op)) { if (IR_IS_BB_END(insn->op)) {
if (insn->op == IR_END && (ctx->flags & IR_OPT_CFG)) {
ir_ref next;
use_list = &ctx->use_lists[ref];
IR_ASSERT(use_list->count == 1);
next = ctx->use_edges[use_list->refs];
if (ctx->ir_base[next].op == IR_BEGIN
&& ctx->use_lists[next].count == 1) {
ref = ir_merge_blocks(ctx, ref, next);
insn = &ctx->ir_base[ref];
goto next_successor;
}
}
break; break;
} }
} }

View File

@ -353,7 +353,7 @@ int main(int argc, char **argv)
ctx.flags |= mflags; ctx.flags |= mflags;
if (opt_level > 0) { if (opt_level > 0) {
ctx.flags |= IR_OPT_FOLDING | IR_OPT_CODEGEN; ctx.flags |= IR_OPT_FOLDING | IR_OPT_CFG | IR_OPT_CODEGEN;
} }
if (emit_c) { if (emit_c) {
ctx.flags |= IR_GEN_C; ctx.flags |= IR_GEN_C;

View File

@ -169,7 +169,7 @@ int main(int argc, char **argv)
ctx.flags |= IR_FUNCTION; ctx.flags |= IR_FUNCTION;
ctx.flags |= mflags; ctx.flags |= mflags;
if (opt_level > 0) { if (opt_level > 0) {
ctx.flags |= IR_OPT_FOLDING | IR_OPT_CODEGEN; ctx.flags |= IR_OPT_FOLDING | IR_OPT_CFG | IR_OPT_CODEGEN;
} }
ctx.fixed_regset = ~debug_regset; ctx.fixed_regset = ~debug_regset;
gen_mandelbrot(&ctx); gen_mandelbrot(&ctx);