aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/flow.c
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-08-25 09:40:52 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2018-08-25 14:25:48 +0200
commitfd43eab36ea0bb18942e3a7233db2efed4b84b30 (patch)
tree47162ba3fa25b6d13b1e18e76e3c4c56f6384162 /flow.c
parentdc49365a8026fad63297ffde53ca72e4252f4959 (diff)
parent13cf4aaeef36031fcee071a1efcf9092b7d7cdf7 (diff)
downloadsparse-dev-fd43eab36ea0bb18942e3a7233db2efed4b84b30.tar.gz
Merge branch 'kill-dead-stores' into tip
* fix buggy recursion in kill_dead_stores() * kill dead stores again after memops simplification is done. Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
Diffstat (limited to 'flow.c')
-rw-r--r--flow.c95
1 files changed, 73 insertions, 22 deletions
diff --git a/flow.c b/flow.c
index 9483938f..8bdd5984 100644
--- a/flow.c
+++ b/flow.c
@@ -547,7 +547,21 @@ found:
}
/* Kill a pseudo that is dead on exit from the bb */
-static void kill_dead_stores(pseudo_t pseudo, unsigned long generation, struct basic_block *bb, int local)
+// The context is:
+// * the variable is not global but may have its address used (local/non-local)
+// * the stores are only needed by others functions which would do some
+// loads via the escaped address
+// We start by the terminating BB (normal exit BB + no-return/unreachable)
+// We walkup the BB' intruction backward
+// * we're only concerned by loads, stores & calls
+// * if we reach a call -> we have to stop if var is non-local
+// * if we reach a load of our var -> we have to stop
+// * if we reach a store of our var -> we can kill it, it's dead
+// * we can ignore other stores & loads if the var is local
+// * if we reach another store or load done via non-symbol access
+// (so done via some address calculation) -> we have to stop
+// If we reach the top of the BB we can recurse into the parents BBs.
+static void kill_dead_stores_bb(pseudo_t pseudo, unsigned long generation, struct basic_block *bb, int local)
{
struct instruction *insn;
struct basic_block *parent;
@@ -556,36 +570,33 @@ static void kill_dead_stores(pseudo_t pseudo, unsigned long generation, struct b
return;
bb->generation = generation;
FOR_EACH_PTR_REVERSE(bb->insns, insn) {
- int opcode = insn->opcode;
-
if (!insn->bb)
continue;
- if (opcode != OP_LOAD && opcode != OP_STORE) {
- if (local)
- continue;
- if (opcode == OP_CALL)
+ switch (insn->opcode) {
+ case OP_LOAD:
+ if (insn->src == pseudo)
return;
- continue;
- }
- if (insn->src == pseudo) {
- if (opcode == OP_LOAD)
+ break;
+ case OP_STORE:
+ if (insn->src == pseudo) {
+ kill_instruction_force(insn);
+ continue;
+ }
+ break;
+ case OP_CALL:
+ if (!local)
return;
- kill_instruction_force(insn);
+ default:
continue;
}
- if (local)
- continue;
- if (insn->src->type != PSEUDO_SYM)
+ if (!local && insn->src->type != PSEUDO_SYM)
return;
} END_FOR_EACH_PTR_REVERSE(insn);
FOR_EACH_PTR(bb->parents, parent) {
- struct basic_block *child;
- FOR_EACH_PTR(parent->children, child) {
- if (child && child != bb)
- return;
- } END_FOR_EACH_PTR(child);
- kill_dead_stores(pseudo, generation, parent, local);
+ if (bb_list_size(parent->children) > 1)
+ continue;
+ kill_dead_stores_bb(pseudo, generation, parent, local);
} END_FOR_EACH_PTR(parent);
}
@@ -735,7 +746,7 @@ external_visibility:
struct basic_block *bb;
FOR_EACH_PTR(ep->bbs, bb) {
if (!bb->children)
- kill_dead_stores(pseudo, ++bb_generation, bb, !mod);
+ kill_dead_stores_bb(pseudo, ++bb_generation, bb, !mod);
} END_FOR_EACH_PTR(bb);
}
}
@@ -752,6 +763,46 @@ void simplify_symbol_usage(struct entrypoint *ep)
} END_FOR_EACH_PTR(pseudo);
}
+static struct pseudo_user *first_user(pseudo_t p)
+{
+ struct pseudo_user *pu;
+ FOR_EACH_PTR(p->users, pu) {
+ if (!pu)
+ continue;
+ return pu;
+ } END_FOR_EACH_PTR(pu);
+ return NULL;
+}
+
+void kill_dead_stores(struct entrypoint *ep, pseudo_t addr, int local)
+{
+ unsigned long generation;
+ struct basic_block *bb;
+
+ switch (pseudo_user_list_size(addr->users)) {
+ case 0:
+ return;
+ case 1:
+ if (local) {
+ struct pseudo_user *pu = first_user(addr);
+ struct instruction *insn = pu->insn;
+ if (insn->opcode == OP_STORE) {
+ kill_instruction_force(insn);
+ return;
+ }
+ }
+ default:
+ break;
+ }
+
+ generation = ++bb_generation;
+ FOR_EACH_PTR(ep->bbs, bb) {
+ if (bb->children)
+ continue;
+ kill_dead_stores_bb(addr, generation, bb, local);
+ } END_FOR_EACH_PTR(bb);
+}
+
static void mark_bb_reachable(struct basic_block *bb, unsigned long generation)
{
struct basic_block *child;