aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2021-02-19 07:24:35 +0100
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2021-03-19 23:56:44 +0100
commit752914c764b6d396c8e0a7c4ab207181edf7b00e (patch)
treeae22911750a1e7ba5ea882d5fcf90f81d322665d
parent4ac342d1efdbeda4c8cd3b79d53ae6b15f1f5cfc (diff)
downloadsparse-752914c764b6d396c8e0a7c4ab207181edf7b00e.tar.gz
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 <luc.vanoostenryck@gmail.com>
-rw-r--r--flow.c43
-rw-r--r--flow.h2
2 files changed, 45 insertions, 0 deletions
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);