bpf: Save DFS postorder numbers for program instructions

Dominator intersections and SCEV worklist scheduling need to compare
instructions by their DFS postorder rank. Save per-instruction
postorder numbers alongside the existing postorder sequence.

This commit modifies bpf_compute_postorder() to actually do the DFS
traversal, instead of scheduling traversal of all siblings at once.

Consider a graph:

  A -> B
  A -> C
  C -> B

Old result: C, B, A
DFS result: B, C, A

Fixes: efcda22aa5 ("bpf: compute instructions postorder per subprogram")
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261009-scev-minimal-rebase-v3-21-bcba9bc53ac9@gmail.com
This commit is contained in:
Eduard Zingerman 2026-10-09 03:47:39 -07:00 committed by Alexei Starovoitov
parent 89e72f81a4
commit f414d20879
No known key found for this signature in database
4 changed files with 39 additions and 21 deletions

View File

@ -1036,6 +1036,7 @@ struct bpf_verifier_env {
* see bpf_subprog_info->postorder_start.
*/
int *insn_postorder;
int *postorder_nums;
int cur_stack;
/* current position in the insn_postorder vector */
int cur_postorder;

View File

@ -767,6 +767,11 @@ int bpf_check_cfg(struct bpf_verifier_env *env)
return ret;
}
struct dfs_state {
u32 traversed:1;
u32 next_succ:31;
};
/*
* For each subprogram 'i' fill array env->cfg.insn_subprogram sub-range
* [env->subprog_info[i].postorder_start, env->subprog_info[i+1].postorder_start)
@ -774,43 +779,52 @@ int bpf_check_cfg(struct bpf_verifier_env *env)
*/
int bpf_compute_postorder(struct bpf_verifier_env *env)
{
u32 cur_postorder, i, top, stack_sz, s;
int *stack = NULL, *postorder = NULL, *state = NULL;
struct bpf_iarray *succ;
int *stack = NULL, *postorder = NULL, *postorder_nums = NULL;
int subprog_idx, stack_sz, cur, s, cur_postorder, start;
struct dfs_state *state = NULL;
struct bpf_iarray *succ = NULL;
postorder_nums = kvzalloc_objs(int, env->prog->len, GFP_KERNEL_ACCOUNT);
postorder = kvzalloc_objs(int, env->prog->len, GFP_KERNEL_ACCOUNT);
state = kvzalloc_objs(int, env->prog->len, GFP_KERNEL_ACCOUNT);
stack = kvzalloc_objs(int, env->prog->len, GFP_KERNEL_ACCOUNT);
if (!postorder || !state || !stack) {
state = kvzalloc_objs(struct dfs_state, env->prog->len, GFP_KERNEL_ACCOUNT);
if (!postorder_nums || !postorder || !stack || !state) {
kvfree(postorder_nums);
kvfree(postorder);
kvfree(state);
kvfree(stack);
kvfree(state);
return -ENOMEM;
}
cur_postorder = 0;
for (i = 0; i < env->subprog_cnt; i++) {
env->subprog_info[i].postorder_start = cur_postorder;
stack[0] = env->subprog_info[i].start;
for (subprog_idx = 0; subprog_idx < env->subprog_cnt; subprog_idx++) {
start = env->subprog_info[subprog_idx].start;
env->subprog_info[subprog_idx].postorder_start = cur_postorder;
stack[0] = start;
stack_sz = 1;
state[start].traversed = true;
do {
top = stack[stack_sz - 1];
state[top] |= DISCOVERED;
if (state[top] & EXPLORED) {
postorder[cur_postorder++] = top;
cur = stack[stack_sz - 1];
succ = bpf_insn_successors(env, cur);
if (state[cur].next_succ == succ->cnt) {
postorder_nums[cur] = cur_postorder;
postorder[cur_postorder] = cur;
cur_postorder++;
stack_sz--;
continue;
}
succ = bpf_insn_successors(env, top);
for (s = 0; s < succ->cnt; ++s) {
if (!state[succ->items[s]]) {
stack[stack_sz++] = succ->items[s];
state[succ->items[s]] |= DISCOVERED;
}
s = succ->items[state[cur].next_succ];
if (!state[s].traversed) {
state[s].traversed = true;
state[s].next_succ = 0;
stack[stack_sz] = s;
stack_sz++;
continue;
}
state[top] |= EXPLORED;
state[cur].next_succ++;
} while (stack_sz);
}
env->subprog_info[i].postorder_start = cur_postorder;
env->subprog_info[subprog_idx].postorder_start = cur_postorder;
env->cfg.postorder_nums = postorder_nums;
env->cfg.insn_postorder = postorder;
env->cfg.cur_postorder = cur_postorder;
kvfree(stack);

View File

@ -398,5 +398,7 @@ int bpf_prune_dead_branches(struct bpf_verifier_env *env)
/* recompute postorder, since CFG has changed */
kvfree(env->cfg.insn_postorder);
env->cfg.insn_postorder = NULL;
kvfree(env->cfg.postorder_nums);
env->cfg.postorder_nums = NULL;
return bpf_compute_postorder(env);
}

View File

@ -23221,6 +23221,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
vfree(env->insn_aux_data);
kvfree(env->fd_array);
bpf_stack_liveness_free(env);
kvfree(env->cfg.postorder_nums);
kvfree(env->cfg.insn_postorder);
kvfree(env->scc_info);
kvfree(env->succ);