summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2023-01-24 16:59:49 -0500
committerTavian Barnes <tavianator@tavianator.com>2023-01-24 17:19:14 -0500
commit693b5f60dc9787d9237920cc0c87fe0e010194ee (patch)
tree3de5e2784d07f41bdff976407ed885d8adf726a1
parentb922add3a5597020a0ad5357b5fc390b3fae709f (diff)
downloadbfs-693b5f60dc9787d9237920cc0c87fe0e010194ee.tar.xz
opt: Move purity out of the parser
-rw-r--r--src/opt.c62
-rw-r--r--src/parse.c27
2 files changed, 64 insertions, 25 deletions
diff --git a/src/opt.c b/src/opt.c
index 50fcd20..934a4b4 100644
--- a/src/opt.c
+++ b/src/opt.c
@@ -787,6 +787,18 @@ static struct bfs_expr *optimize_access(struct opt_state *state, struct bfs_expr
return expr;
}
+/** Optimize -empty. */
+static struct bfs_expr *optimize_empty(struct opt_state *state, struct bfs_expr *expr) {
+ if (state->ctx->optlevel >= 4) {
+ // Since -empty attempts to open and read directories, it may
+ // have side effects such as reporting permission errors, and
+ // thus shouldn't be re-ordered without aggressive optimizations
+ expr->pure = true;
+ }
+
+ return expr;
+}
+
/** Optimize -gid. */
static struct bfs_expr *optimize_gid(struct opt_state *state, struct bfs_expr *expr) {
struct range *range = &state->facts_when_true.ranges[GID_RANGE];
@@ -832,12 +844,54 @@ static struct bfs_expr *optimize_type(struct opt_state *state, struct bfs_expr *
/** Optimize -xtype. */
static struct bfs_expr *optimize_xtype(struct opt_state *state, struct bfs_expr *expr) {
+ if (state->ctx->optlevel >= 4) {
+ // Since -xtype dereferences symbolic links, it may have side
+ // effects such as reporting permission errors, and thus
+ // shouldn't be re-ordered without aggressive optimizations
+ expr->pure = true;
+ }
+
state->facts_when_true.xtypes &= expr->num;
state->facts_when_false.xtypes &= ~expr->num;
return expr;
}
/**
+ * Table of pure expressions.
+ */
+static bfs_eval_fn *const opt_pure[] = {
+ eval_access,
+ eval_acl,
+ eval_capable,
+ eval_depth,
+ eval_false,
+ eval_flags,
+ eval_fstype,
+ eval_gid,
+ eval_hidden,
+ eval_inum,
+ eval_links,
+ eval_lname,
+ eval_name,
+ eval_newer,
+ eval_nogroup,
+ eval_nouser,
+ eval_path,
+ eval_perm,
+ eval_regex,
+ eval_samefile,
+ eval_size,
+ eval_sparse,
+ eval_time,
+ eval_true,
+ eval_type,
+ eval_uid,
+ eval_used,
+ eval_xattr,
+ eval_xattrname,
+};
+
+/**
* Table of simple predicates.
*/
static const struct {
@@ -885,6 +939,7 @@ static const struct {
} opt_fns[] = {
// Primaries
{eval_access, optimize_access},
+ {eval_empty, optimize_empty},
{eval_gid, optimize_gid},
{eval_samefile, optimize_samefile},
{eval_type, optimize_type},
@@ -902,6 +957,13 @@ static const struct {
* Look up the appropriate optimizer for an expression and call it.
*/
static struct bfs_expr *optimize_expr_lookup(struct opt_state *state, struct bfs_expr *expr) {
+ for (size_t i = 0; i < BFS_COUNTOF(opt_pure); ++i) {
+ if (opt_pure[i] == expr->eval_fn) {
+ expr->pure = true;
+ break;
+ }
+ }
+
for (size_t i = 0; i < BFS_COUNTOF(opt_preds); ++i) {
if (opt_preds[i].eval_fn == expr->eval_fn) {
infer_pred_facts(state, opt_preds[i].pred);
diff --git a/src/parse.c b/src/parse.c
index 51a9d0a..0b4224c 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -85,6 +85,7 @@ struct bfs_expr *bfs_expr_new(bfs_eval_fn *eval_fn, size_t argc, char **argv) {
expr->argv = argv;
expr->persistent_fds = 0;
expr->ephemeral_fds = 0;
+ expr->pure = false;
expr->cost = FAST_COST;
expr->evaluations = 0;
expr->successes = 0;
@@ -92,17 +93,14 @@ struct bfs_expr *bfs_expr_new(bfs_eval_fn *eval_fn, size_t argc, char **argv) {
expr->elapsed.tv_nsec = 0;
if (eval_fn == eval_true) {
- expr->pure = true;
expr->always_true = true;
expr->always_false = false;
expr->probability = 1.0;
} else if (eval_fn == eval_false) {
- expr->pure = true;
expr->always_true = false;
expr->always_false = true;
expr->probability = 0.0;
} else {
- expr->pure = false;
expr->always_true = false;
expr->always_false = false;
expr->probability = 0.5;
@@ -814,11 +812,7 @@ static struct bfs_expr *parse_unary_option(struct parser_state *state) {
*/
static struct bfs_expr *parse_test(struct parser_state *state, bfs_eval_fn *eval_fn, size_t argc) {
char **argv = parser_advance(state, T_TEST, argc);
- struct bfs_expr *expr = bfs_expr_new(eval_fn, argc, argv);
- if (expr) {
- expr->pure = true;
- }
- return expr;
+ return bfs_expr_new(eval_fn, argc, argv);
}
/**
@@ -1344,16 +1338,7 @@ static struct bfs_expr *parse_empty(struct parser_state *state, int arg1, int ar
expr->cost = 2000.0;
expr->probability = 0.01;
-
- if (state->ctx->optlevel < 4) {
- // Since -empty attempts to open and read directories, it may
- // have side effects such as reporting permission errors, and
- // thus shouldn't be re-ordered without aggressive optimizations
- expr->pure = false;
- }
-
expr->ephemeral_fds = 1;
-
return expr;
}
@@ -2030,7 +2015,6 @@ static struct bfs_expr *parse_nohidden(struct parser_state *state, int arg1, int
}
hidden->probability = 0.01;
- hidden->pure = true;
if (parse_exclude(state, hidden) != 0) {
return NULL;
@@ -2766,13 +2750,6 @@ static struct bfs_expr *parse_type(struct parser_state *state, int x, int arg2)
expr->num = types;
expr->probability = probability;
- if (x && state->ctx->optlevel < 4) {
- // Since -xtype dereferences symbolic links, it may have side
- // effects such as reporting permission errors, and thus
- // shouldn't be re-ordered without aggressive optimizations
- expr->pure = false;
- }
-
return expr;
fail: