aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-05-13 21:53:43 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-05-19 05:27:51 +0200
commit8c24aa51b70cf1fbbb5ff8fbd90f6bdc482d7e2f (patch)
tree9aaa19e9c91e3a3f54c5ac62847003726d61fa3d
parente35efe330c6ae7d154197c29b127560d569016d0 (diff)
downloadsparse-dev-8c24aa51b70cf1fbbb5ff8fbd90f6bdc482d7e2f.tar.gz
fix: kill old branch in insert_branch()
insert_branch() is called after an optimization has detected an opportunity to convert a switch or a conditional branch into an unconditional branch (for example because the condition is a constant). It does this by removing the BB's last instruction and then allocate a new unconditional branch which is added at the end of the BB. The old instruction is simply discarded. Since the discarded instruction is one with a condition we must insure that the associated usage is also removed (for example, by calling kill_instruction()). But currently kill_instruction() is called, just after the call to insert_branch(), only at a single place. The 4 other places where insert_branch() is called do nothing with the removed instruction and it's condition's usage. As consequence, instructions that are dead are not removed since it still wrongly has an user. Fix this by adding a call to kill_instruction() in insert_branch() itself (and make the function description more exact). Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--flow.c1
-rw-r--r--linearize.c3
-rw-r--r--validation/kill-insert-branch.c22
3 files changed, 24 insertions, 2 deletions
diff --git a/flow.c b/flow.c
index 94a8ec74..b3a657cb 100644
--- a/flow.c
+++ b/flow.c
@@ -226,7 +226,6 @@ try_to_rewrite_target:
if (bb_list_size(target->parents) != 1)
return retval;
insert_branch(target, insn, final);
- kill_instruction(insn);
return 1;
}
diff --git a/linearize.c b/linearize.c
index a9f36b82..97c9a113 100644
--- a/linearize.c
+++ b/linearize.c
@@ -646,7 +646,7 @@ static void remove_parent(struct basic_block *child, struct basic_block *parent)
kill_bb(child);
}
-/* Change a "switch" into a branch */
+/* Change a "switch" or a conditional branch into a branch */
void insert_branch(struct basic_block *bb, struct instruction *jmp, struct basic_block *target)
{
struct instruction *br, *old;
@@ -655,6 +655,7 @@ void insert_branch(struct basic_block *bb, struct instruction *jmp, struct basic
/* Remove the switch */
old = delete_last_instruction(&bb->insns);
assert(old == jmp);
+ kill_instruction(old);
br = alloc_instruction(OP_BR, 0);
br->bb = bb;
diff --git a/validation/kill-insert-branch.c b/validation/kill-insert-branch.c
new file mode 100644
index 00000000..e59b5bbc
--- /dev/null
+++ b/validation/kill-insert-branch.c
@@ -0,0 +1,22 @@
+void foo(int a)
+{
+ int b = 1;
+ if (a)
+ b++;
+ if (b)
+ ;
+}
+
+void bar(int a)
+{
+ if (a ? 1 : 2)
+ ;
+}
+
+/*
+ * check-name: kill insert-branch
+ * check-command: test-linearize -Wno-decl $file
+ *
+ * check-output-ignore
+ * check-output-excludes: select\\.
+ */