diff options
author | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-11-19 18:09:11 +0100 |
---|---|---|
committer | Luc Van Oostenryck <luc.vanoostenryck@gmail.com> | 2020-11-19 18:30:28 +0100 |
commit | 50545fb487ca1478017947a26f4d7dc841b2669f (patch) | |
tree | 1ca0b22febcc395b438d0d8c903c2f0874423052 | |
parent | 349ac6d1489f9b98f67b7f9b94625a60249409e0 (diff) | |
parent | 7cd2ce022575fbd383bb39b54f1e0fa402919da2 (diff) | |
download | sparse-50545fb487ca1478017947a26f4d7dc841b2669f.tar.gz |
Merge branch 'diamond'
* rebuild dominance tree during CFG cleanup
* simplify CBR-CBR on the same condition
-rw-r--r-- | flow.c | 106 | ||||
-rw-r--r-- | optimize.c | 10 |
2 files changed, 114 insertions, 2 deletions
@@ -18,6 +18,7 @@ #include "linearize.h" #include "flow.h" #include "target.h" +#include "flowgraph.h" unsigned long bb_generation; @@ -86,6 +87,34 @@ static int pseudo_truth_value(pseudo_t pseudo) } } +/// +// check if the BB is empty or only contains phi-sources +static int bb_is_trivial(struct basic_block *bb) +{ + struct instruction *insn; + int n = 0; + + FOR_EACH_PTR(bb->insns, insn) { + if (!insn->bb) + continue; + switch (insn->opcode) { + case OP_TERMINATOR ... OP_TERMINATOR_END: + return n ? -1 : 1; + case OP_NOP: + case OP_INLINED_CALL: + continue; + case OP_PHISOURCE: + n++; + continue; + default: + goto out; + } + } END_FOR_EACH_PTR(insn); + +out: + return 0; +} + /* * Does a basic block depend on the pseudos that "src" defines? */ @@ -147,6 +176,81 @@ out: return false; } +/// +// do jump threading in dominated BBs +// @dom: the BB which must dominate the modified BBs. +// @old: the old target BB +// @new: the new target BB +// @return: 0 if no chnages have been made, 1 otherwise. +// +// In all BB dominated by @dom, rewrite branches to @old into branches to @new +static int retarget_bb(struct basic_block *dom, struct basic_block *old, struct basic_block *new) +{ + struct basic_block *bb; + int changed = 0; + + if (new == old) + return 0; + +restart: + FOR_EACH_PTR(old->parents, bb) { + struct instruction *last; + struct multijmp *jmp; + + if (!domtree_dominates(dom, bb)) + continue; + last = last_instruction(bb->insns); + switch (last->opcode) { + case OP_BR: + changed |= rewrite_branch(bb, &last->bb_true, old, new); + break; + case OP_CBR: + changed |= rewrite_branch(bb, &last->bb_true, old, new); + changed |= rewrite_branch(bb, &last->bb_false, old, new); + break; + case OP_SWITCH: + case OP_COMPUTEDGOTO: + FOR_EACH_PTR(last->multijmp_list, jmp) { + changed |= rewrite_branch(bb, &jmp->target, old, new); + } END_FOR_EACH_PTR(jmp); + break; + default: + continue; + } + + // since rewrite_branch() will modify old->parents() the list + // iteration won't work correctly. Several solution exist for + // this but in this case the simplest is to restart the loop. + goto restart; + } END_FOR_EACH_PTR(bb); + return changed; +} + +static int simplify_cbr_cbr(struct instruction *insn) +{ + struct instruction *last; + struct basic_block *bot = insn->bb; + struct basic_block *top = bot->idom; + int changed = 0; + int trivial; + + if (!top) + return 0; + + trivial = bb_is_trivial(bot); + if (trivial == 0) + return 0; + if (trivial < 0) + return 0; + last = last_instruction(top->insns); + if (last->opcode != OP_CBR || last->cond != insn->cond) + return 0; + + changed |= retarget_bb(last->bb_true , bot, insn->bb_true); + changed |= retarget_bb(last->bb_false, bot, insn->bb_false); + return changed; +} + /* * When we reach here, we have: * - a basic block that ends in a conditional branch and @@ -294,6 +398,8 @@ static int simplify_one_branch(struct basic_block *bb, struct instruction *br) { if (simplify_phi_branch(bb, br)) return 1; + if (simplify_cbr_cbr(br)) + return 1; return simplify_branch_branch(bb, br, &br->bb_true, 1) | simplify_branch_branch(bb, br, &br->bb_false, 0); } @@ -47,6 +47,12 @@ static void clean_up_insns(struct entrypoint *ep) } END_FOR_EACH_PTR(bb); } +static void cleanup_cfg(struct entrypoint *ep) +{ + kill_unreachable_bbs(ep); + domtree_build(ep); +} + /// // optimization main loop void optimize(struct entrypoint *ep) @@ -97,7 +103,7 @@ repeat: } while (repeat_phase); pack_basic_blocks(ep); if (repeat_phase & REPEAT_CFG_CLEANUP) - kill_unreachable_bbs(ep); + cleanup_cfg(ep); } while (repeat_phase); vrfy_flow(ep); @@ -117,7 +123,7 @@ repeat: if (simplify_flow(ep)) { clear_liveness(ep); if (repeat_phase & REPEAT_CFG_CLEANUP) - kill_unreachable_bbs(ep); + cleanup_cfg(ep); goto repeat; } |