aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
authorLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-06-16 08:31:50 +0200
committerLuc Van Oostenryck <luc.vanoostenryck@gmail.com>2017-06-21 11:28:40 +0200
commit852801f8b966407544326cd1c485f9bc7681a2e6 (patch)
tree2371a2168b9c6c7a343860d2e27331753d3a4514
parentd79853389f55e3645e4a094f091915ea63546d09 (diff)
downloadsparse-dev-852801f8b966407544326cd1c485f9bc7681a2e6.tar.gz
fix: try_to_simplify_bb eargerness
The simplification done by try_to_simplify_bb() (essentially trying to bypass a basic block containing a conditional branch if the branch is controlled by an OP_PHI when the corresponding OP_PHISRC is a constant) can only be done if some conditions are met: 1) The basic block doesn't have some side effects (in which case it must not be bypassed). Checked by bb_has_side_effects(). 2) There may be some pseudos defined in the basic block but no basic blocks may depend on them. Checked by bb_depends_on(). The second condition is efficiently checked using liveness information. However, there is no liveness information done for OP_PHI/OP_PHISRC. So if the basic block contains some other OP_PHI than the controlling one, there will surely be some other BB depending on it but this will not be reflected in the liveness info and bb_depends_on() can then wrongly report that no dependencies exist. Fix this by adding an extra check, verifiying that no other OP_PHI are defined in the BB and avoiding the simplification otherwise. Reported-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Signed-off-by: Luc Van Oostenryck <luc.vanoostenryck@gmail.com>
-rw-r--r--flow.c27
-rw-r--r--validation/crazy03.c33
2 files changed, 60 insertions, 0 deletions
diff --git a/flow.c b/flow.c
index 8a9005aa..c7161d47 100644
--- a/flow.c
+++ b/flow.c
@@ -80,6 +80,31 @@ static int bb_depends_on(struct basic_block *target, struct basic_block *src)
}
/*
+ * This is only to be used by try_to_simplify_bb().
+ * It really should be handled by bb_depends_on(), only
+ * that there is no liveness done on OP_PHI/OP_PHISRC.
+ * So we consider for now that if there is an OP_PHI
+ * then some block in fact depends on this one.
+ * The OP_PHI controling the conditional branch of this bb
+ * is excluded since the branch will be removed.
+ */
+static int bb_defines_phi(struct basic_block *bb, struct instruction *def)
+{
+ struct instruction *insn;
+ FOR_EACH_PTR(bb->insns, insn) {
+ switch (insn->opcode) {
+ case OP_PHI:
+ if (def && insn != def)
+ return 1;
+ continue;
+ default:
+ continue;
+ }
+ } END_FOR_EACH_PTR(insn);
+ return 0;
+}
+
+/*
* When we reach here, we have:
* - a basic block that ends in a conditional branch and
* that has no side effects apart from the pseudos it
@@ -127,6 +152,8 @@ static int try_to_simplify_bb(struct basic_block *bb, struct instruction *first,
target = true ? second->bb_true : second->bb_false;
if (bb_depends_on(target, bb))
continue;
+ if (bb_defines_phi(bb, first))
+ continue;
changed |= rewrite_branch(source, &br->bb_true, bb, target);
changed |= rewrite_branch(source, &br->bb_false, bb, target);
if (changed && !bogus)
diff --git a/validation/crazy03.c b/validation/crazy03.c
new file mode 100644
index 00000000..04203379
--- /dev/null
+++ b/validation/crazy03.c
@@ -0,0 +1,33 @@
+extern char a;
+extern int b;
+extern char *c, *d;
+extern void e(void);
+extern void f(char *);
+
+int g(int h);
+int g(int h)
+{
+ if (h > 1)
+ e();
+ if (h > 1)
+ return 0;
+ for (;;) {
+ if (a) {
+ while (c) ;
+ b = 0;
+ } else {
+ c = (void*)0;
+ b = 1;
+ }
+ if (b) {
+ f(c);
+ continue;
+ }
+ d = c;
+ while (*c++) ;
+ }
+}
+
+/*
+ * check-name: crazy03.c
+ */