summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2017-07-21 19:09:10 -0400
committerTavian Barnes <tavianator@tavianator.com>2017-07-21 19:09:10 -0400
commit462589f69859354a9c623cad9015821e769beecb (patch)
tree805ab7e0989617098c9311e0386963b37142084c
parent4a245d3885f99169649cc45e2d1abe606c249d22 (diff)
downloadbfs-462589f69859354a9c623cad9015821e769beecb.tar.xz
Fix a couple terrible optimizer bugs
Just because an expression is always true or false, doesn't mean we can execute it more often than it otherwise would be, unless it's also pure. But that's equivalent to being identically -true/-false, so just check that.
-rw-r--r--parse.c4
-rwxr-xr-xtests.sh12
-rw-r--r--tests/test_and_purity.out0
-rw-r--r--tests/test_or_purity.out0
4 files changed, 14 insertions, 2 deletions
diff --git a/parse.c b/parse.c
index d4e945c..61c17a5 100644
--- a/parse.c
+++ b/parse.c
@@ -2568,7 +2568,7 @@ static struct expr *new_and_expr(const struct parser_state *state, struct expr *
debug_opt(state, "-O1: short-circuit: (%s %e %e) <==> %e\n", argv[0], lhs, rhs, lhs);
free_expr(rhs);
return lhs;
- } else if (optlevel >= 2 && rhs->always_false && lhs->pure) {
+ } else if (optlevel >= 2 && lhs->pure && rhs == &expr_false) {
debug_opt(state, "-O2: purity: (%s %e %e) <==> %e\n", argv[0], lhs, rhs, rhs);
free_expr(lhs);
return rhs;
@@ -2664,7 +2664,7 @@ static struct expr *new_or_expr(const struct parser_state *state, struct expr *l
} else if (rhs == &expr_false) {
debug_opt(state, "-O1: disjunctive syllogism: (%s %e %e) <==> %e\n", argv[0], lhs, rhs, lhs);
return lhs;
- } else if (optlevel >= 2 && rhs->always_true && lhs->pure) {
+ } else if (optlevel >= 2 && lhs->pure && rhs == &expr_true) {
debug_opt(state, "-O2: purity: (%s %e %e) <==> %e\n", argv[0], lhs, rhs, rhs);
free_expr(lhs);
return rhs;
diff --git a/tests.sh b/tests.sh
index d7e9287..87724d9 100755
--- a/tests.sh
+++ b/tests.sh
@@ -346,6 +346,8 @@ gnu_tests=(
test_or
test_comma
test_precedence
+ test_and_purity
+ test_or_purity
)
bfs_tests=(
@@ -1232,6 +1234,16 @@ function test_printx() {
bfs_diff weirdnames -printx
}
+function test_and_purity() {
+ # Regression test: (-a lhs(pure) rhs(always_false)) <==> rhs is only valid if rhs is pure
+ bfs_diff basic -name nonexistent \( -print , -false \)
+}
+
+function test_or_purity() {
+ # Regression test: (-o lhs(pure) rhs(always_true)) <==> rhs is only valid if rhs is pure
+ bfs_diff basic -name '*' -o -print
+}
+
passed=0
failed=0
diff --git a/tests/test_and_purity.out b/tests/test_and_purity.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/test_and_purity.out
diff --git a/tests/test_or_purity.out b/tests/test_or_purity.out
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/test_or_purity.out