diff options
| author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2004-11-30 22:06:53 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-07 21:05:20 -0700 |
| commit | 2b63dc96defe142d9961805666f23de2d209b8a7 (patch) | |
| tree | d25f7d7335c878ba23fe7764d8096c61c74dca73 /flow.c | |
| parent | 9af72d9408e378d742599b6891bbe72306e61478 (diff) | |
| download | sparse-dev-2b63dc96defe142d9961805666f23de2d209b8a7.tar.gz | |
Implement conditional branch following when simplifying branches.
Diffstat (limited to 'flow.c')
| -rw-r--r-- | flow.c | 55 |
1 files changed, 50 insertions, 5 deletions
@@ -145,13 +145,10 @@ static int bb_has_side_effects(struct basic_block *bb) return 0; } -static int simplify_phi_branch(struct basic_block *bb, struct instruction *br) +static int simplify_phi_branch(struct basic_block *bb, struct instruction *br, pseudo_t cond) { - pseudo_t cond = br->cond; struct instruction *def; - if (!cond || cond->type != PSEUDO_REG) - return 0; def = cond->def; if (def->bb != bb || def->opcode != OP_PHI) return 0; @@ -160,6 +157,50 @@ static int simplify_phi_branch(struct basic_block *bb, struct instruction *br) return try_to_simplify_bb(bb, def, br); } +static int simplify_branch_branch(struct basic_block *bb, struct instruction *br, + pseudo_t cond, struct basic_block **target_p, int true) +{ + struct basic_block *target = *target_p, *final; + struct instruction *insn; + + if (target == bb) + return 0; + insn = last_instruction(target->insns); + if (!insn || insn->opcode != OP_BR || insn->cond != cond) + return 0; + /* + * Ahhah! We've found a branch to a branch on the same conditional! + * Now we just need to see if we can rewrite the branch.. + */ + final = true ? insn->bb_true : insn->bb_false; + if (bb_has_side_effects(target)) + goto try_to_rewrite_target; + if (bb_depends_on(final, target)) + goto try_to_rewrite_target; + return rewrite_branch(bb, target_p, target, final); + +try_to_rewrite_target: + /* + * If we're the only parent, at least we can rewrite the + * now-known second branch. + */ + if (bb_list_size(target->parents) != 1) + return 0; + insert_branch(target, insn, final); + return 1; +} + +static int simplify_one_branch(struct basic_block *bb, struct instruction *br, pseudo_t cond) +{ + if (simplify_phi_branch(bb, br, cond)) + return 1; + if (simplify_branch_branch(bb, br, cond, &br->bb_true, 1)) + return 1; + if (simplify_branch_branch(bb, br, cond, &br->bb_false, 0)) + return 1; + return 0; +} + static int simplify_branch_nodes(struct entrypoint *ep) { int changed = 0; @@ -167,10 +208,14 @@ static int simplify_branch_nodes(struct entrypoint *ep) FOR_EACH_PTR(ep->bbs, bb) { struct instruction *br = last_instruction(bb->insns); + pseudo_t cond; if (!br || br->opcode != OP_BR || !br->bb_false) continue; - changed |= simplify_phi_branch(bb, br); + cond = br->cond; + if (!cond || cond->type != PSEUDO_REG) + continue; + changed |= simplify_one_branch(bb, br, cond); } END_FOR_EACH_PTR(bb); return changed; } |
