From 86d790e134d5a12e569e1d78804bc5a54ca9ed25 Mon Sep 17 00:00:00 2001
From: Tavian Barnes <tavianator@tavianator.com>
Date: Sun, 17 Sep 2017 10:49:00 -0400
Subject: opt: Move some aggressive optimizations back to -O4

---
 eval.c |  9 +--------
 opt.c  | 28 ++++++++++++++++++----------
 2 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/eval.c b/eval.c
index 5196b57..08d2643 100644
--- a/eval.c
+++ b/eval.c
@@ -1091,7 +1091,7 @@ static enum bftw_action cmdline_callback(struct BFTW *ftwbuf, void *ptr) {
 		goto done;
 	}
 
-	if (ftwbuf->depth >= cmdline->maxdepth) {
+	if (cmdline->maxdepth < 0 || ftwbuf->depth >= cmdline->maxdepth) {
 		state.action = BFTW_SKIP_SUBTREE;
 	}
 
@@ -1216,13 +1216,6 @@ int eval_cmdline(const struct cmdline *cmdline) {
 		return EXIT_SUCCESS;
 	}
 
-	if (cmdline->optlevel >= 4 && cmdline->expr->eval == eval_false) {
-		if (cmdline->debug & DEBUG_OPT) {
-			fputs("-O4: skipping evaluation of top-level -false\n", stderr);
-		}
-		return EXIT_SUCCESS;
-	}
-
 	int nopenfd = infer_fdlimit(cmdline);
 
 	struct callback_args args = {
diff --git a/opt.c b/opt.c
index 26aec0b..717af90 100644
--- a/opt.c
+++ b/opt.c
@@ -462,7 +462,7 @@ fail:
 }
 
 /** Optimize an expression in an ignored-result context. */
-static struct expr *ignore_result(const struct opt_state *state, struct expr *expr) {
+static struct expr *ignore_result(const struct opt_state *state, struct expr *expr, int purelevel) {
 	int optlevel = state->cmdline->optlevel;
 
 	if (optlevel >= 1) {
@@ -470,18 +470,18 @@ static struct expr *ignore_result(const struct opt_state *state, struct expr *ex
 			if (expr->eval == eval_not) {
 				debug_opt(state, "-O1: ignored result: %e --> %e\n", expr, expr->rhs);
 				expr = extract_child_expr(expr, &expr->rhs);
-			} else if (optlevel >= 2
+			} else if (optlevel >= purelevel
 			           && (expr->eval == eval_and || expr->eval == eval_or || expr->eval == eval_comma)
 			           && expr->rhs->pure) {
-				debug_opt(state, "-O2: ignored result: %e --> %e\n", expr, expr->lhs);
+				debug_opt(state, "-O%d: ignored result: %e --> %e\n", purelevel, expr, expr->lhs);
 				expr = extract_child_expr(expr, &expr->lhs);
 			} else {
 				break;
 			}
 		}
 
-		if (optlevel >= 2 && expr->pure && expr != &expr_false) {
-			debug_opt(state, "-O2: ignored result: %e --> %e\n", expr, &expr_false);
+		if (optlevel >= purelevel && expr->pure && expr != &expr_false) {
+			debug_opt(state, "-O%d: ignored result: %e --> %e\n", purelevel, expr, &expr_false);
 			free_expr(expr);
 			expr = &expr_false;
 		}
@@ -499,7 +499,7 @@ static struct expr *optimize_comma_expr(const struct opt_state *state, struct ex
 
 	int optlevel = state->cmdline->optlevel;
 	if (optlevel >= 1) {
-		lhs = expr->lhs = ignore_result(state, lhs);
+		lhs = expr->lhs = ignore_result(state, lhs, 2);
 
 		if (expr_never_returns(lhs)) {
 			debug_opt(state, "-O1: reachability: %e <==> %e\n", expr, lhs);
@@ -621,16 +621,24 @@ int optimize_cmdline(struct cmdline *cmdline) {
 		return -1;
 	}
 
-	cmdline->expr = ignore_result(&state, cmdline->expr);
+	cmdline->expr = ignore_result(&state, cmdline->expr, 4);
 
-	if (cmdline->optlevel >= 2) {
+	int minlevel = 2;
+	if (facts_impossible(&facts_when_impure)) {
+		// If we've detected that all side effects are unreachable, the
+		// following optimization will skip the entire traversal, so
+		// only do it at -O4
+		minlevel = 4;
+	}
+
+	if (cmdline->optlevel >= minlevel) {
 		if (facts_when_impure.mindepth > cmdline->mindepth) {
-			debug_opt(&state, "-O2: data flow: mindepth --> %d\n");
+			debug_opt(&state, "-O%d: data flow: mindepth --> %d\n", minlevel, facts_when_impure.mindepth);
 			cmdline->mindepth = facts_when_impure.mindepth;
 		}
 
 		if (facts_when_impure.maxdepth < cmdline->maxdepth) {
-			debug_opt(&state, "-O2: data flow: maxdepth --> %d\n");
+			debug_opt(&state, "-O%d: data flow: maxdepth --> %d\n", minlevel, facts_when_impure.maxdepth);
 			cmdline->maxdepth = facts_when_impure.maxdepth;
 		}
 	}
-- 
cgit v1.2.3