summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--opt.c17
-rwxr-xr-xtests.sh7
-rw-r--r--tests/test_and_false_or_true.out1
3 files changed, 25 insertions, 0 deletions
diff --git a/opt.c b/opt.c
index dd98ca0..fd2dc3c 100644
--- a/opt.c
+++ b/opt.c
@@ -50,6 +50,7 @@
static char *fake_and_arg = "-a";
static char *fake_or_arg = "-o";
+static char *fake_not_arg = "!";
/**
* A contrained integer range.
@@ -433,6 +434,14 @@ static struct expr *optimize_and_expr(const struct opt_state *state, struct expr
} else if (lhs->always_false) {
debug_opt(state, "-O1: short-circuit: %e <==> %e\n", expr, lhs);
return extract_child_expr(expr, &expr->lhs);
+ } else if (lhs->always_true && rhs == &expr_false) {
+ debug_opt(state, "-O1: strength reduction: %e <==> ", expr);
+ struct expr *ret = extract_child_expr(expr, &expr->lhs);
+ ret = negate_expr(ret, &fake_not_arg);
+ if (ret) {
+ debug_opt(state, "%e\n", ret);
+ }
+ return ret;
} else if (optlevel >= 2 && lhs->pure && rhs == &expr_false) {
debug_opt(state, "-O2: purity: %e <==> %e\n", expr, rhs);
return extract_child_expr(expr, &expr->rhs);
@@ -493,6 +502,14 @@ static struct expr *optimize_or_expr(const struct opt_state *state, struct expr
} else if (rhs == &expr_false) {
debug_opt(state, "-O1: disjunctive syllogism: %e <==> %e\n", expr, lhs);
return extract_child_expr(expr, &expr->lhs);
+ } else if (lhs->always_false && rhs == &expr_true) {
+ debug_opt(state, "-O1: strength reduction: %e <==> ", expr);
+ struct expr *ret = extract_child_expr(expr, &expr->lhs);
+ ret = negate_expr(ret, &fake_not_arg);
+ if (ret) {
+ debug_opt(state, "%e\n", ret);
+ }
+ return ret;
} else if (optlevel >= 2 && lhs->pure && rhs == &expr_true) {
debug_opt(state, "-O2: purity: %e <==> %e\n", expr, rhs);
return extract_child_expr(expr, &expr->rhs);
diff --git a/tests.sh b/tests.sh
index 2df3448..a219812 100755
--- a/tests.sh
+++ b/tests.sh
@@ -609,6 +609,7 @@ gnu_tests=(
test_and_purity
test_not_reachability
test_comma_reachability
+ test_and_false_or_true
)
bfs_tests=(
@@ -2003,6 +2004,12 @@ function test_de_morgan_or() {
bfs_diff basic \( \! -name 'foo' -o \! -type f \)
}
+function test_and_false_or_true() {
+ # Test (-a lhs(always_true) false) <==> (! lhs),
+ # (-a lhs(always_false) true) <==> (! lhs)
+ bfs_diff basic -prune -false -o -true
+}
+
function test_data_flow_depth() {
bfs_diff basic -depth +1 -depth -4
}
diff --git a/tests/test_and_false_or_true.out b/tests/test_and_false_or_true.out
new file mode 100644
index 0000000..15a13db
--- /dev/null
+++ b/tests/test_and_false_or_true.out
@@ -0,0 +1 @@
+basic