From 752914c764b6d396c8e0a7c4ab207181edf7b00e Mon Sep 17 00:00:00 2001 From: Luc Van Oostenryck Date: Fri, 19 Feb 2021 07:24:35 +0100 Subject: add remove_phisources() When a parent is removed from a BB containing one or several phi-nodes, the corresponding phi-sources become irrelevant and need to be removed from the phi-nodes. Add an helper for doing this: remove_phisources(). Signed-off-by: Luc Van Oostenryck --- flow.c | 43 +++++++++++++++++++++++++++++++++++++++++++ flow.h | 2 ++ 2 files changed, 45 insertions(+) diff --git a/flow.c b/flow.c index 8106cfc0..4952562a 100644 --- a/flow.c +++ b/flow.c @@ -22,6 +22,49 @@ unsigned long bb_generation; +/// +// remove phi-sources from a removed edge +// +// :note: It's possible to have several edges between the same BBs. +// It's common with switches but it's also possible with branches. +// This function will only remove a single phi-source per edge. +int remove_phisources(struct basic_block *par, struct basic_block *old) +{ + struct instruction *insn; + int changed = 0; + + FOR_EACH_PTR(old->insns, insn) { + pseudo_t phi; + + if (!insn->bb) + continue; + if (insn->opcode != OP_PHI) + return changed; + + // found a phi-node in the target BB, + // now look after its phi-sources. + FOR_EACH_PTR(insn->phi_list, phi) { + struct instruction *phisrc = phi->def; + + if (phi == VOID) + continue; + assert(phisrc->phi_node == insn); + if (phisrc->bb != par) + continue; + // found a phi-source corresponding to this edge: + // remove it but avoid the recursive killing. + REPLACE_CURRENT_PTR(phi, VOID); + remove_use(&phisrc->src); + phisrc->bb = NULL; + changed |= REPEAT_CSE; + // Only the first one must be removed. + goto next; + } END_FOR_EACH_PTR(phi); +next: ; + } END_FOR_EACH_PTR(insn); + return changed; +} + /* * Dammit, if we have a phi-node followed by a conditional * branch on that phi-node, we should damn well be able to diff --git a/flow.h b/flow.h index 2103a10f..c489ebe0 100644 --- a/flow.h +++ b/flow.h @@ -11,6 +11,8 @@ extern unsigned long bb_generation; struct entrypoint; struct instruction; +extern int remove_phisources(struct basic_block *par, struct basic_block *old); + extern int simplify_flow(struct entrypoint *ep); extern void kill_dead_stores(struct entrypoint *ep, pseudo_t addr, int local); -- cgit 1.2.3-korg