mirror of
https://github.com/danog/ir.git
synced 2025-01-22 05:31:32 +01:00
Create a sparate pass to remove unreachableble CFG blocks.
SCCP pass removes unreachable blocks before CFG construction. In case of -O0 or -O1 pipeline (without SCCP) it's simpler and faster to unlink unreachable CFG blocks once, then check for reachability in almost any compilation pass. -O2 pipeline (with SCCP) don't need this pass.
This commit is contained in:
parent
3f40e70ac9
commit
6a4e239773
1
ir.h
1
ir.h
@ -579,6 +579,7 @@ void ir_build_def_use_lists(ir_ctx *ctx);
|
|||||||
|
|
||||||
/* CFG - Control Flow Graph (implementation in ir_cfg.c) */
|
/* CFG - Control Flow Graph (implementation in ir_cfg.c) */
|
||||||
int ir_build_cfg(ir_ctx *ctx);
|
int ir_build_cfg(ir_ctx *ctx);
|
||||||
|
int ir_remove_unreachable_blocks(ir_ctx *ctx);
|
||||||
int ir_build_dominators_tree(ir_ctx *ctx);
|
int ir_build_dominators_tree(ir_ctx *ctx);
|
||||||
int ir_find_loops(ir_ctx *ctx);
|
int ir_find_loops(ir_ctx *ctx);
|
||||||
int ir_schedule_blocks(ir_ctx *ctx);
|
int ir_schedule_blocks(ir_ctx *ctx);
|
||||||
|
@ -2331,6 +2331,21 @@ static void ir_emit_if_int(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn)
|
|||||||
ir_backend_data *data = ctx->data;
|
ir_backend_data *data = ctx->data;
|
||||||
dasm_State **Dst = &data->dasm_state;
|
dasm_State **Dst = &data->dasm_state;
|
||||||
|
|
||||||
|
if (IR_IS_CONST_REF(insn->op2)) {
|
||||||
|
uint32_t true_block, false_block, next_block;
|
||||||
|
|
||||||
|
ir_get_true_false_blocks(ctx, b, &true_block, &false_block, &next_block);
|
||||||
|
if (ir_const_is_true(&ctx->ir_base[insn->op2])) {
|
||||||
|
if (true_block != next_block) {
|
||||||
|
| b =>true_block
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (false_block != next_block) {
|
||||||
|
| b =>false_block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
IR_ASSERT(op2_reg != IR_REG_NONE);
|
IR_ASSERT(op2_reg != IR_REG_NONE);
|
||||||
if ((op2_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op2)) {
|
if ((op2_reg & IR_REG_SPILL_LOAD) || IR_IS_CONST_REF(insn->op2)) {
|
||||||
op2_reg &= ~IR_REG_SPILL_LOAD;
|
op2_reg &= ~IR_REG_SPILL_LOAD;
|
||||||
@ -4413,9 +4428,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx)
|
|||||||
|
|
||||||
ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_NUM + 1, sizeof(ir_live_interval*));
|
ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_NUM + 1, sizeof(ir_live_interval*));
|
||||||
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (i = bb->start, insn = ctx->ir_base + i, rule = ctx->rules + i; i <= bb->end;) {
|
for (i = bb->start, insn = ctx->ir_base + i, rule = ctx->rules + i; i <= bb->end;) {
|
||||||
switch (ctx->rules ? *rule : insn->op) {
|
switch (ctx->rules ? *rule : insn->op) {
|
||||||
case IR_START:
|
case IR_START:
|
||||||
@ -4774,9 +4787,7 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ctx->prev_ref[bb->end] == bb->start
|
if (ctx->prev_ref[bb->end] == bb->start
|
||||||
&& bb->successors_count == 1
|
&& bb->successors_count == 1
|
||||||
&& !(bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_DESSA_MOVES))) {
|
&& !(bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_DESSA_MOVES))) {
|
||||||
|
241
ir_cfg.c
241
ir_cfg.c
@ -88,8 +88,9 @@ IR_ALWAYS_INLINE void _ir_add_predecessors(ir_insn *insn, ir_worklist *worklist)
|
|||||||
ir_worklist_push(worklist, ref);
|
ir_worklist_push(worklist, ref);
|
||||||
}
|
}
|
||||||
} else if (insn->op != IR_START && insn->op != IR_ENTRY) {
|
} else if (insn->op != IR_START && insn->op != IR_ENTRY) {
|
||||||
IR_ASSERT(insn->op1);
|
if (EXPECTED(insn->op1)) {
|
||||||
ir_worklist_push(worklist, insn->op1);
|
ir_worklist_push(worklist, insn->op1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,10 +270,12 @@ next_successor:
|
|||||||
bb->predecessors_count = n;
|
bb->predecessors_count = n;
|
||||||
edges_count += n;
|
edges_count += n;
|
||||||
count += n;
|
count += n;
|
||||||
} else {
|
} else if (EXPECTED(insn->op1)) {
|
||||||
bb->predecessors_count = 1;
|
bb->predecessors_count = 1;
|
||||||
edges_count++;
|
edges_count++;
|
||||||
count++;
|
count++;
|
||||||
|
} else {
|
||||||
|
bb->predecessors_count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b++;
|
b++;
|
||||||
@ -335,6 +338,230 @@ next_successor:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ir_remove_predecessor(ir_ctx *ctx, ir_block *bb, uint32_t from)
|
||||||
|
{
|
||||||
|
uint32_t i, *p, *q, n = 0;
|
||||||
|
|
||||||
|
p = q = &ctx->cfg_edges[bb->predecessors];
|
||||||
|
for (i = 0; i < bb->predecessors_count; i++, p++) {
|
||||||
|
if (*p != from) {
|
||||||
|
if (p != q) {
|
||||||
|
*q = *p;
|
||||||
|
}
|
||||||
|
q++;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IR_ASSERT(n != bb->predecessors_count);
|
||||||
|
bb->predecessors_count = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ir_remove_from_use_list(ir_ctx *ctx, ir_ref from, ir_ref ref)
|
||||||
|
{
|
||||||
|
ir_ref j, n, *p, *q, use;
|
||||||
|
ir_use_list *use_list = &ctx->use_lists[from];
|
||||||
|
ir_ref skip = 0;
|
||||||
|
|
||||||
|
n = use_list->count;
|
||||||
|
for (j = 0, p = q = &ctx->use_edges[use_list->refs]; j < n; j++, p++) {
|
||||||
|
use = *p;
|
||||||
|
if (use == ref) {
|
||||||
|
skip++;
|
||||||
|
} else {
|
||||||
|
if (p != q) {
|
||||||
|
*q = use;
|
||||||
|
}
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use_list->count -= skip;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ir_remove_merge_input(ir_ctx *ctx, ir_ref merge, ir_ref from)
|
||||||
|
{
|
||||||
|
ir_ref i, j, n, k, *p, use;
|
||||||
|
ir_insn *use_insn;
|
||||||
|
ir_use_list *use_list;
|
||||||
|
ir_bitset life_inputs;
|
||||||
|
ir_insn *insn = &ctx->ir_base[merge];
|
||||||
|
|
||||||
|
IR_ASSERT(insn->op == IR_MERGE || insn->op == IR_LOOP_BEGIN);
|
||||||
|
n = insn->inputs_count;
|
||||||
|
if (n == 0) {
|
||||||
|
n = 3;
|
||||||
|
}
|
||||||
|
i = 1;
|
||||||
|
life_inputs = ir_bitset_malloc(n + 1);
|
||||||
|
for (j = 1; j <= n; j++) {
|
||||||
|
ir_ref input = ir_insn_op(insn, j);
|
||||||
|
|
||||||
|
if (input != from) {
|
||||||
|
if (i != j) {
|
||||||
|
ir_insn_set_op(insn, i, input);
|
||||||
|
}
|
||||||
|
ir_bitset_incl(life_inputs, j);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i--;
|
||||||
|
if (i == 1) {
|
||||||
|
insn->op = IR_BEGIN;
|
||||||
|
insn->inputs_count = 0;
|
||||||
|
use_list = &ctx->use_lists[merge];
|
||||||
|
for (k = 0, p = &ctx->use_edges[use_list->refs]; k < use_list->count; k++, p++) {
|
||||||
|
use = *p;
|
||||||
|
use_insn = &ctx->ir_base[use];
|
||||||
|
if (use_insn->op == IR_PHI) {
|
||||||
|
/* Convert PHI to COPY */
|
||||||
|
i = 2;
|
||||||
|
for (j = 2; j <= n; j++) {
|
||||||
|
ir_ref input = ir_insn_op(use_insn, j);
|
||||||
|
|
||||||
|
if (ir_bitset_in(life_inputs, j - 1)) {
|
||||||
|
use_insn->op1 = ir_insn_op(use_insn, j);
|
||||||
|
} else if (input > 0) {
|
||||||
|
ir_remove_from_use_list(ctx, input, use);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use_insn->op = IR_COPY;
|
||||||
|
use_insn->op2 = IR_UNUSED;
|
||||||
|
use_insn->op3 = IR_UNUSED;
|
||||||
|
ir_remove_from_use_list(ctx, merge, use);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (i == 2) {
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
insn->inputs_count = i;
|
||||||
|
|
||||||
|
n++;
|
||||||
|
use_list = &ctx->use_lists[merge];
|
||||||
|
for (k = 0, p = &ctx->use_edges[use_list->refs]; k < use_list->count; k++, p++) {
|
||||||
|
use = *p;
|
||||||
|
use_insn = &ctx->ir_base[use];
|
||||||
|
if (use_insn->op == IR_PHI) {
|
||||||
|
i = 2;
|
||||||
|
for (j = 2; j <= n; j++) {
|
||||||
|
ir_ref input = ir_insn_op(use_insn, j);
|
||||||
|
|
||||||
|
if (ir_bitset_in(life_inputs, j - 1)) {
|
||||||
|
IR_ASSERT(input);
|
||||||
|
if (i != j) {
|
||||||
|
ir_insn_set_op(use_insn, i, input);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
} else if (input > 0) {
|
||||||
|
ir_remove_from_use_list(ctx, input, use);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ir_mem_free(life_inputs);
|
||||||
|
ir_remove_from_use_list(ctx, from, merge);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CFG constructed after SCCP pass doesn't have unreachable BBs, otherwise they should be removed */
|
||||||
|
int ir_remove_unreachable_blocks(ir_ctx *ctx)
|
||||||
|
{
|
||||||
|
uint32_t b, *p, i;
|
||||||
|
uint32_t unreachable_count = 0;
|
||||||
|
uint32_t bb_count = ctx->cfg_blocks_count;
|
||||||
|
ir_block *bb = ctx->cfg_blocks + 1;
|
||||||
|
|
||||||
|
for (b = 1; b <= bb_count; b++, bb++) {
|
||||||
|
if (bb->flags & IR_BB_UNREACHABLE) {
|
||||||
|
#if 0
|
||||||
|
do {if (!unreachable_count) ir_dump_cfg(ctx, stderr);} while(0);
|
||||||
|
#endif
|
||||||
|
if (bb->successors_count) {
|
||||||
|
for (i = 0, p = &ctx->cfg_edges[bb->successors]; i < bb->successors_count; i++, p++) {
|
||||||
|
ir_block *succ_bb = &ctx->cfg_blocks[*p];
|
||||||
|
|
||||||
|
if (!(succ_bb->flags & IR_BB_UNREACHABLE)) {
|
||||||
|
ir_remove_predecessor(ctx, succ_bb, b);
|
||||||
|
ir_remove_merge_input(ctx, succ_bb->start, bb->end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ir_ref prev, ref = bb->end;
|
||||||
|
ir_insn *insn = &ctx->ir_base[ref];
|
||||||
|
|
||||||
|
IR_ASSERT(ir_op_flags[insn->op] & IR_OP_FLAG_TERMINATOR);
|
||||||
|
/* remove from terminators list */
|
||||||
|
prev = ctx->ir_base[1].op1;
|
||||||
|
if (prev == ref) {
|
||||||
|
ctx->ir_base[1].op1 = insn->op3;
|
||||||
|
} else {
|
||||||
|
while (prev) {
|
||||||
|
if (ctx->ir_base[prev].op3 == ref) {
|
||||||
|
ctx->ir_base[prev].op3 = insn->op3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev = ctx->ir_base[prev].op3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx->cfg_map[bb->start] = 0;
|
||||||
|
ctx->cfg_map[bb->end] = 0;
|
||||||
|
unreachable_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unreachable_count) {
|
||||||
|
ir_block *dst_bb;
|
||||||
|
uint32_t n = 1;
|
||||||
|
uint32_t *edges;
|
||||||
|
|
||||||
|
dst_bb = bb = ctx->cfg_blocks + 1;
|
||||||
|
for (b = 1; b <= bb_count; b++, bb++) {
|
||||||
|
if (!(bb->flags & IR_BB_UNREACHABLE)) {
|
||||||
|
if (dst_bb != bb) {
|
||||||
|
memcpy(dst_bb, bb, sizeof(ir_block));
|
||||||
|
ctx->cfg_map[dst_bb->start] = n;
|
||||||
|
ctx->cfg_map[dst_bb->end] = n;
|
||||||
|
}
|
||||||
|
dst_bb->successors_count = 0;
|
||||||
|
dst_bb++;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx->cfg_blocks_count = bb_count = n - 1;
|
||||||
|
|
||||||
|
/* Rebuild successor/predecessors control edges */
|
||||||
|
edges = ctx->cfg_edges;
|
||||||
|
bb = ctx->cfg_blocks + 1;
|
||||||
|
for (b = 1; b <= bb_count; b++, bb++) {
|
||||||
|
ir_insn *insn = &ctx->ir_base[bb->start];
|
||||||
|
ir_ref *p, ref;
|
||||||
|
|
||||||
|
if (bb->predecessors_count > 1) {
|
||||||
|
uint32_t *q = edges + bb->predecessors;
|
||||||
|
n = ir_variable_inputs_count(insn);
|
||||||
|
for (p = insn->ops + 1; n > 0; p++, q++, n--) {
|
||||||
|
ref = *p;
|
||||||
|
IR_ASSERT(ref);
|
||||||
|
ir_ref pred_b = ctx->cfg_map[ref];
|
||||||
|
ir_block *pred_bb = &ctx->cfg_blocks[pred_b];
|
||||||
|
*q = pred_b;
|
||||||
|
edges[pred_bb->successors + pred_bb->successors_count++] = b;
|
||||||
|
}
|
||||||
|
} else if (bb->predecessors_count == 1) {
|
||||||
|
ref = insn->op1;
|
||||||
|
IR_ASSERT(ref);
|
||||||
|
IR_ASSERT(IR_OPND_KIND(ir_op_flags[insn->op], 1) == IR_OPND_CONTROL);
|
||||||
|
ir_ref pred_b = ctx->cfg_map[ref];
|
||||||
|
ir_block *pred_bb = &ctx->cfg_blocks[pred_b];
|
||||||
|
edges[bb->predecessors] = pred_b;
|
||||||
|
edges[pred_bb->successors + pred_bb->successors_count++] = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void compute_postnum(const ir_ctx *ctx, uint32_t *cur, uint32_t b)
|
static void compute_postnum(const ir_ctx *ctx, uint32_t *cur, uint32_t b)
|
||||||
{
|
{
|
||||||
uint32_t i, *p;
|
uint32_t i, *p;
|
||||||
@ -387,9 +614,7 @@ int ir_build_dominators_tree(ir_ctx *ctx)
|
|||||||
changed = 0;
|
changed = 0;
|
||||||
/* Iterating in Reverse Post Oorder */
|
/* Iterating in Reverse Post Oorder */
|
||||||
for (b = 2, bb = &blocks[2]; b <= blocks_count; b++, bb++) {
|
for (b = 2, bb = &blocks[2]; b <= blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (bb->predecessors_count == 1) {
|
if (bb->predecessors_count == 1) {
|
||||||
uint32_t idom = 0;
|
uint32_t idom = 0;
|
||||||
uint32_t pred_b = edges[bb->predecessors];
|
uint32_t pred_b = edges[bb->predecessors];
|
||||||
@ -443,9 +668,7 @@ int ir_build_dominators_tree(ir_ctx *ctx)
|
|||||||
|
|
||||||
/* Construct dominators tree */
|
/* Construct dominators tree */
|
||||||
for (b = 2, bb = &blocks[2]; b <= blocks_count; b++, bb++) {
|
for (b = 2, bb = &blocks[2]; b <= blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (bb->flags & IR_BB_ENTRY) {
|
if (bb->flags & IR_BB_ENTRY) {
|
||||||
bb->idom = 0;
|
bb->idom = 0;
|
||||||
bb->dom_depth = 0;
|
bb->dom_depth = 0;
|
||||||
|
@ -273,9 +273,7 @@ int ir_match(ir_ctx *ctx)
|
|||||||
|
|
||||||
ctx->rules = ir_mem_calloc(ctx->insns_count, sizeof(uint32_t));
|
ctx->rules = ir_mem_calloc(ctx->insns_count, sizeof(uint32_t));
|
||||||
for (b = ctx->cfg_blocks_count, bb = ctx->cfg_blocks + b; b > 0; b--, bb--) {
|
for (b = ctx->cfg_blocks_count, bb = ctx->cfg_blocks + b; b > 0; b--, bb--) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (i = bb->end; i > bb->start; i = ctx->prev_ref[i]) {
|
for (i = bb->end; i > bb->start; i = ctx->prev_ref[i]) {
|
||||||
if (!ctx->rules[i]) {
|
if (!ctx->rules[i]) {
|
||||||
ctx->rules[i] = ir_match_insn(ctx, i, bb);
|
ctx->rules[i] = ir_match_insn(ctx, i, bb);
|
||||||
|
@ -711,9 +711,7 @@ static int ir_emit_func(ir_ctx *ctx, FILE *f)
|
|||||||
/* Emit declarations for local variables */
|
/* Emit declarations for local variables */
|
||||||
vars = ir_bitset_malloc(ctx->vregs_count + 1);
|
vars = ir_bitset_malloc(ctx->vregs_count + 1);
|
||||||
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (i = bb->start, insn = ctx->ir_base + i; i <= bb->end;) {
|
for (i = bb->start, insn = ctx->ir_base + i; i <= bb->end;) {
|
||||||
if (ctx->vregs[i]) {
|
if (ctx->vregs[i]) {
|
||||||
if (!ir_bitset_in(vars, ctx->vregs[i])) {
|
if (!ir_bitset_in(vars, ctx->vregs[i])) {
|
||||||
@ -751,9 +749,7 @@ static int ir_emit_func(ir_ctx *ctx, FILE *f)
|
|||||||
ir_mem_free(vars);
|
ir_mem_free(vars);
|
||||||
|
|
||||||
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ctx->prev_ref[bb->end] == bb->start
|
if (ctx->prev_ref[bb->end] == bb->start
|
||||||
&& bb->successors_count == 1
|
&& bb->successors_count == 1
|
||||||
&& !(bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_DESSA_MOVES))) {
|
&& !(bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_DESSA_MOVES))) {
|
||||||
|
13
ir_gcm.c
13
ir_gcm.c
@ -96,6 +96,7 @@ static void ir_gcm_schedule_late(ir_ctx *ctx, uint32_t *_blocks, ir_bitset visit
|
|||||||
q++;
|
q++;
|
||||||
}
|
}
|
||||||
b = _blocks[*q];
|
b = _blocks[*q];
|
||||||
|
IR_ASSERT(b);
|
||||||
}
|
}
|
||||||
lca = !lca ? b : ir_gcm_find_lca(ctx, lca, b);
|
lca = !lca ? b : ir_gcm_find_lca(ctx, lca, b);
|
||||||
}
|
}
|
||||||
@ -191,9 +192,7 @@ int ir_gcm(ir_ctx *ctx)
|
|||||||
/* pin and collect control and control depended (PARAM, VAR, PHI, PI) instructions */
|
/* pin and collect control and control depended (PARAM, VAR, PHI, PI) instructions */
|
||||||
b = ctx->cfg_blocks_count;
|
b = ctx->cfg_blocks_count;
|
||||||
for (bb = ctx->cfg_blocks + b; b > 0; bb--, b--) {
|
for (bb = ctx->cfg_blocks + b; b > 0; bb--, b--) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ref = bb->end;
|
ref = bb->end;
|
||||||
do {
|
do {
|
||||||
insn = &ctx->ir_base[ref];
|
insn = &ctx->ir_base[ref];
|
||||||
@ -450,9 +449,7 @@ int ir_schedule(ir_ctx *ctx)
|
|||||||
scheduled = ir_bitset_malloc(ctx->insns_count);
|
scheduled = ir_bitset_malloc(ctx->insns_count);
|
||||||
used = ir_bitset_malloc(ctx->consts_count + 1);
|
used = ir_bitset_malloc(ctx->consts_count + 1);
|
||||||
for (b = 1, bb = ctx->cfg_blocks + 1; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = ctx->cfg_blocks + 1; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* Schedule BB start */
|
/* Schedule BB start */
|
||||||
i = bb->start;
|
i = bb->start;
|
||||||
ir_bitset_incl(scheduled, i);
|
ir_bitset_incl(scheduled, i);
|
||||||
@ -755,9 +752,7 @@ void ir_build_prev_refs(ir_ctx *ctx)
|
|||||||
ctx->prev_ref = ir_mem_malloc(ctx->insns_count * sizeof(ir_ref));
|
ctx->prev_ref = ir_mem_malloc(ctx->insns_count * sizeof(ir_ref));
|
||||||
prev = 0;
|
prev = 0;
|
||||||
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (i = bb->start, insn = ctx->ir_base + i; i < bb->end;) {
|
for (i = bb->start, insn = ctx->ir_base + i; i < bb->end;) {
|
||||||
ctx->prev_ref[i] = prev;
|
ctx->prev_ref[i] = prev;
|
||||||
n = ir_operands_count(ctx, insn);
|
n = ir_operands_count(ctx, insn);
|
||||||
|
@ -154,6 +154,9 @@ int ir_compile_func(ir_ctx *ctx, int opt_level, uint32_t dump, const char *dump_
|
|||||||
/* Schedule */
|
/* Schedule */
|
||||||
if (opt_level > 0) {
|
if (opt_level > 0) {
|
||||||
ir_build_cfg(ctx);
|
ir_build_cfg(ctx);
|
||||||
|
if (opt_level == 1) {
|
||||||
|
ir_remove_unreachable_blocks(ctx);
|
||||||
|
}
|
||||||
ir_build_dominators_tree(ctx);
|
ir_build_dominators_tree(ctx);
|
||||||
ir_find_loops(ctx);
|
ir_find_loops(ctx);
|
||||||
ir_gcm(ctx);
|
ir_gcm(ctx);
|
||||||
|
16
ir_private.h
16
ir_private.h
@ -680,6 +680,22 @@ extern const char *ir_op_name[IR_LAST_OP];
|
|||||||
#define IR_IS_CONST_OP(op) ((op) > IR_NOP && (op) <= IR_C_FLOAT)
|
#define IR_IS_CONST_OP(op) ((op) > IR_NOP && (op) <= IR_C_FLOAT)
|
||||||
#define IR_IS_FOLDABLE_OP(op) ((op) <= IR_LAST_FOLDABLE_OP)
|
#define IR_IS_FOLDABLE_OP(op) ((op) <= IR_LAST_FOLDABLE_OP)
|
||||||
|
|
||||||
|
IR_ALWAYS_INLINE bool ir_const_is_true(ir_insn *v)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (v->type == IR_BOOL) {
|
||||||
|
return v->val.b;
|
||||||
|
} else if (IR_IS_TYPE_INT(v->type)) {
|
||||||
|
return v->val.i64 != 0;
|
||||||
|
} else if (v->type == IR_DOUBLE) {
|
||||||
|
return v->val.d != 0.0;
|
||||||
|
} else if (v->type == IR_FLOAT) {
|
||||||
|
return v->val.f != 0.0;
|
||||||
|
}
|
||||||
|
IR_ASSERT(0 && "NYI");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* IR OP flags */
|
/* IR OP flags */
|
||||||
#define IR_OP_FLAG_OPERANDS_SHIFT 3
|
#define IR_OP_FLAG_OPERANDS_SHIFT 3
|
||||||
|
|
||||||
|
21
ir_ra.c
21
ir_ra.c
@ -55,9 +55,7 @@ int ir_assign_virtual_registers(ir_ctx *ctx)
|
|||||||
vregs = ir_mem_calloc(ctx->insns_count, sizeof(ir_ref));
|
vregs = ir_mem_calloc(ctx->insns_count, sizeof(ir_ref));
|
||||||
n = 1;
|
n = 1;
|
||||||
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
i = bb->start;
|
i = bb->start;
|
||||||
|
|
||||||
/* skip first instruction */
|
/* skip first instruction */
|
||||||
@ -369,9 +367,7 @@ int ir_compute_live_ranges(ir_ctx *ctx)
|
|||||||
ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_NUM + 1, sizeof(ir_live_interval*));
|
ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_NUM + 1, sizeof(ir_live_interval*));
|
||||||
for (b = ctx->cfg_blocks_count; b > 0; b--) {
|
for (b = ctx->cfg_blocks_count; b > 0; b--) {
|
||||||
bb = &ctx->cfg_blocks[b];
|
bb = &ctx->cfg_blocks[b];
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/* for each successor of b */
|
/* for each successor of b */
|
||||||
#ifdef IR_DEBUG
|
#ifdef IR_DEBUG
|
||||||
ir_bitset_incl(visited, b);
|
ir_bitset_incl(visited, b);
|
||||||
@ -1008,9 +1004,7 @@ int ir_coalesce(ir_ctx *ctx)
|
|||||||
/* Collect a list of blocks which are predecossors to block with phi finctions */
|
/* Collect a list of blocks which are predecossors to block with phi finctions */
|
||||||
ir_worklist_init(&blocks, ctx->cfg_blocks_count + 1);
|
ir_worklist_init(&blocks, ctx->cfg_blocks_count + 1);
|
||||||
for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (bb->predecessors_count > 1) {
|
if (bb->predecessors_count > 1) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
|
||||||
@ -1073,6 +1067,7 @@ int ir_coalesce(ir_ctx *ctx)
|
|||||||
for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
ir_ref i;
|
ir_ref i;
|
||||||
|
|
||||||
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
i = bb->end;
|
i = bb->end;
|
||||||
|
|
||||||
/* skip last instruction */
|
/* skip last instruction */
|
||||||
@ -1141,9 +1136,7 @@ int ir_compute_dessa_moves(ir_ctx *ctx)
|
|||||||
ir_insn *insn;
|
ir_insn *insn;
|
||||||
|
|
||||||
for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (bb->predecessors_count > 1) {
|
if (bb->predecessors_count > 1) {
|
||||||
use_list = &ctx->use_lists[bb->start];
|
use_list = &ctx->use_lists[bb->start];
|
||||||
n = use_list->count;
|
n = use_list->count;
|
||||||
@ -2278,9 +2271,7 @@ static int ir_linear_scan(ir_ctx *ctx)
|
|||||||
if (ctx->flags & IR_LR_HAVE_DESSA_MOVES) {
|
if (ctx->flags & IR_LR_HAVE_DESSA_MOVES) {
|
||||||
/* Add fixed intervals for temporary registers used for DESSA moves */
|
/* Add fixed intervals for temporary registers used for DESSA moves */
|
||||||
for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = &ctx->cfg_blocks[1]; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (bb->flags & IR_BB_DESSA_MOVES) {
|
if (bb->flags & IR_BB_DESSA_MOVES) {
|
||||||
ctx->data = bb;
|
ctx->data = bb;
|
||||||
ir_gen_dessa_moves(ctx, b, ir_fix_dessa_tmps);
|
ir_gen_dessa_moves(ctx, b, ir_fix_dessa_tmps);
|
||||||
|
12
ir_sccp.c
12
ir_sccp.c
@ -136,17 +136,7 @@ static bool ir_sccp_is_true(ir_ctx *ctx, ir_insn *_values, ir_ref a)
|
|||||||
{
|
{
|
||||||
ir_insn *v = IR_IS_CONST_REF(a) ? &ctx->ir_base[a] : &_values[a];
|
ir_insn *v = IR_IS_CONST_REF(a) ? &ctx->ir_base[a] : &_values[a];
|
||||||
|
|
||||||
if (v->type == IR_BOOL) {
|
return ir_const_is_true(v);
|
||||||
return v->val.b;
|
|
||||||
} else if (IR_IS_TYPE_INT(v->type)) {
|
|
||||||
return v->val.i64 != 0;
|
|
||||||
} else if (v->type == IR_DOUBLE) {
|
|
||||||
return v->val.d != 0.0;
|
|
||||||
} else if (v->type == IR_FLOAT) {
|
|
||||||
return v->val.f != 0.0;
|
|
||||||
}
|
|
||||||
IR_ASSERT(0 && "NYI");
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ir_sccp_is_equal(ir_ctx *ctx, ir_insn *_values, ir_ref a, ir_ref b)
|
static bool ir_sccp_is_equal(ir_ctx *ctx, ir_insn *_values, ir_ref a, ir_ref b)
|
||||||
|
@ -187,6 +187,9 @@ int main(int argc, char **argv)
|
|||||||
ir_sccp(&ctx);
|
ir_sccp(&ctx);
|
||||||
}
|
}
|
||||||
ir_build_cfg(&ctx);
|
ir_build_cfg(&ctx);
|
||||||
|
if (opt_level <= 1) {
|
||||||
|
ir_remove_unreachable_blocks(&ctx);
|
||||||
|
}
|
||||||
if (opt_level > 0) {
|
if (opt_level > 0) {
|
||||||
ir_build_dominators_tree(&ctx);
|
ir_build_dominators_tree(&ctx);
|
||||||
ir_find_loops(&ctx);
|
ir_find_loops(&ctx);
|
||||||
|
22
ir_x86.dasc
22
ir_x86.dasc
@ -3992,7 +3992,19 @@ static void ir_emit_if_int(ir_ctx *ctx, uint32_t b, ir_ref def, ir_insn *insn)
|
|||||||
}
|
}
|
||||||
| ASM_REG_REG_OP test, type, op2_reg, op2_reg
|
| ASM_REG_REG_OP test, type, op2_reg, op2_reg
|
||||||
} else if (IR_IS_CONST_REF(insn->op2)) {
|
} else if (IR_IS_CONST_REF(insn->op2)) {
|
||||||
IR_ASSERT(0);
|
uint32_t true_block, false_block, next_block;
|
||||||
|
|
||||||
|
ir_get_true_false_blocks(ctx, b, &true_block, &false_block, &next_block);
|
||||||
|
if (ir_const_is_true(&ctx->ir_base[insn->op2])) {
|
||||||
|
if (true_block != next_block) {
|
||||||
|
| jmp =>true_block
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (false_block != next_block) {
|
||||||
|
| jmp =>false_block
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
int32_t offset = 0;
|
int32_t offset = 0;
|
||||||
|
|
||||||
@ -6885,9 +6897,7 @@ static void ir_allocate_unique_spill_slots(ir_ctx *ctx)
|
|||||||
|
|
||||||
ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_NUM + 1, sizeof(ir_live_interval*));
|
ctx->live_intervals = ir_mem_calloc(ctx->vregs_count + 1 + IR_REG_NUM + 1, sizeof(ir_live_interval*));
|
||||||
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
for (i = bb->start, insn = ctx->ir_base + i, rule = ctx->rules + i; i <= bb->end;) {
|
for (i = bb->start, insn = ctx->ir_base + i, rule = ctx->rules + i; i <= bb->end;) {
|
||||||
switch (ctx->rules ? *rule : insn->op) {
|
switch (ctx->rules ? *rule : insn->op) {
|
||||||
case IR_START:
|
case IR_START:
|
||||||
@ -7263,9 +7273,7 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
for (b = 1, bb = ctx->cfg_blocks + b; b <= ctx->cfg_blocks_count; b++, bb++) {
|
||||||
if (bb->flags & IR_BB_UNREACHABLE) {
|
IR_ASSERT(!(bb->flags & IR_BB_UNREACHABLE));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (ctx->prev_ref[bb->end] == bb->start
|
if (ctx->prev_ref[bb->end] == bb->start
|
||||||
&& bb->successors_count == 1
|
&& bb->successors_count == 1
|
||||||
&& !(bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_DESSA_MOVES))) {
|
&& !(bb->flags & (IR_BB_START|IR_BB_ENTRY|IR_BB_DESSA_MOVES))) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user