Skip to content

Commit 923cefe

Browse files
author
Alexei Starovoitov
committed
Merge branch 'dead-code-elimination'
Jakub Kicinski says: ==================== This set adds support for complete removal of dead code. Patch 3 contains all the code removal logic, patches 2 and 4 additionally optimize branches around and to dead code. Patches 6 and 7 allow offload JITs to take advantage of the optimization. After a few small clean ups (8, 9, 10) nfp support is added (11, 12). Removing code directly in the verifier makes it easy to adjust the relevant metadata (line info, subprogram info). JITs for code store constrained architectures would have hard time performing such adjustments at JIT level. Removing subprograms or line info is very hard once BPF core finished the verification. For user space to perform dead code removal it would have to perform the execution simulation/analysis similar to what the verifier does. v3: - fix uninitilized var warning in GCC 6 (buildbot). v4: - simplify the linfo-keeping logic (Yonghong). Instead of trying to figure out that we are removing first instruction of a subprogram, just always keep last dead line info, if first live instruction doesn't have one. v5: - improve comments (Martin Lau). ==================== Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents bbebce8 + 9a06927 commit 923cefe

File tree

12 files changed

+1004
-67
lines changed

12 files changed

+1004
-67
lines changed

drivers/net/ethernet/netronome/nfp/bpf/jit.c

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,7 +1266,7 @@ wrp_alu64_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
12661266
u64 imm = insn->imm; /* sign extend */
12671267

12681268
if (skip) {
1269-
meta->skip = true;
1269+
meta->flags |= FLAG_INSN_SKIP_NOOP;
12701270
return 0;
12711271
}
12721272

@@ -1296,7 +1296,7 @@ wrp_alu32_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
12961296
const struct bpf_insn *insn = &meta->insn;
12971297

12981298
if (skip) {
1299-
meta->skip = true;
1299+
meta->flags |= FLAG_INSN_SKIP_NOOP;
13001300
return 0;
13011301
}
13021302

@@ -3182,7 +3182,7 @@ bpf_to_bpf_call(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta)
31823182
wrp_immed_relo(nfp_prog, imm_b(nfp_prog), 0, RELO_IMMED_REL);
31833183
} else {
31843184
ret_tgt = nfp_prog_current_offset(nfp_prog) + 2;
3185-
emit_br(nfp_prog, BR_UNC, meta->n + 1 + meta->insn.imm, 1);
3185+
emit_br(nfp_prog, BR_UNC, meta->insn.imm, 1);
31863186
offset_br = nfp_prog_current_offset(nfp_prog);
31873187
}
31883188
wrp_immed_relo(nfp_prog, ret_reg(nfp_prog), ret_tgt, RELO_IMMED_REL);
@@ -3395,7 +3395,7 @@ static int nfp_fixup_branches(struct nfp_prog *nfp_prog)
33953395
int err;
33963396

33973397
list_for_each_entry(meta, &nfp_prog->insns, l) {
3398-
if (meta->skip)
3398+
if (meta->flags & FLAG_INSN_SKIP_MASK)
33993399
continue;
34003400
if (BPF_CLASS(meta->insn.code) != BPF_JMP)
34013401
continue;
@@ -3439,7 +3439,7 @@ static int nfp_fixup_branches(struct nfp_prog *nfp_prog)
34393439

34403440
jmp_dst = meta->jmp_dst;
34413441

3442-
if (jmp_dst->skip) {
3442+
if (jmp_dst->flags & FLAG_INSN_SKIP_PREC_DEPENDENT) {
34433443
pr_err("Branch landing on removed instruction!!\n");
34443444
return -ELOOP;
34453445
}
@@ -3689,7 +3689,7 @@ static int nfp_translate(struct nfp_prog *nfp_prog)
36893689
return nfp_prog->error;
36903690
}
36913691

3692-
if (meta->skip) {
3692+
if (meta->flags & FLAG_INSN_SKIP_MASK) {
36933693
nfp_prog->n_translated++;
36943694
continue;
36953695
}
@@ -3737,10 +3737,10 @@ static void nfp_bpf_opt_reg_init(struct nfp_prog *nfp_prog)
37373737
/* Programs start with R6 = R1 but we ignore the skb pointer */
37383738
if (insn.code == (BPF_ALU64 | BPF_MOV | BPF_X) &&
37393739
insn.src_reg == 1 && insn.dst_reg == 6)
3740-
meta->skip = true;
3740+
meta->flags |= FLAG_INSN_SKIP_PREC_DEPENDENT;
37413741

37423742
/* Return as soon as something doesn't match */
3743-
if (!meta->skip)
3743+
if (!(meta->flags & FLAG_INSN_SKIP_MASK))
37443744
return;
37453745
}
37463746
}
@@ -3755,7 +3755,7 @@ static void nfp_bpf_opt_neg_add_sub(struct nfp_prog *nfp_prog)
37553755
list_for_each_entry(meta, &nfp_prog->insns, l) {
37563756
struct bpf_insn insn = meta->insn;
37573757

3758-
if (meta->skip)
3758+
if (meta->flags & FLAG_INSN_SKIP_MASK)
37593759
continue;
37603760

37613761
if (BPF_CLASS(insn.code) != BPF_ALU &&
@@ -3829,7 +3829,7 @@ static void nfp_bpf_opt_ld_mask(struct nfp_prog *nfp_prog)
38293829
if (meta2->flags & FLAG_INSN_IS_JUMP_DST)
38303830
continue;
38313831

3832-
meta2->skip = true;
3832+
meta2->flags |= FLAG_INSN_SKIP_PREC_DEPENDENT;
38333833
}
38343834
}
38353835

@@ -3869,8 +3869,8 @@ static void nfp_bpf_opt_ld_shift(struct nfp_prog *nfp_prog)
38693869
meta3->flags & FLAG_INSN_IS_JUMP_DST)
38703870
continue;
38713871

3872-
meta2->skip = true;
3873-
meta3->skip = true;
3872+
meta2->flags |= FLAG_INSN_SKIP_PREC_DEPENDENT;
3873+
meta3->flags |= FLAG_INSN_SKIP_PREC_DEPENDENT;
38743874
}
38753875
}
38763876

@@ -4065,7 +4065,8 @@ static void nfp_bpf_opt_ldst_gather(struct nfp_prog *nfp_prog)
40654065
}
40664066

40674067
head_ld_meta->paired_st = &head_st_meta->insn;
4068-
head_st_meta->skip = true;
4068+
head_st_meta->flags |=
4069+
FLAG_INSN_SKIP_PREC_DEPENDENT;
40694070
} else {
40704071
head_ld_meta->ldst_gather_len = 0;
40714072
}
@@ -4098,8 +4099,8 @@ static void nfp_bpf_opt_ldst_gather(struct nfp_prog *nfp_prog)
40984099
head_ld_meta = meta1;
40994100
head_st_meta = meta2;
41004101
} else {
4101-
meta1->skip = true;
4102-
meta2->skip = true;
4102+
meta1->flags |= FLAG_INSN_SKIP_PREC_DEPENDENT;
4103+
meta2->flags |= FLAG_INSN_SKIP_PREC_DEPENDENT;
41034104
}
41044105

41054106
head_ld_meta->ldst_gather_len += BPF_LDST_BYTES(ld);
@@ -4124,7 +4125,7 @@ static void nfp_bpf_opt_pkt_cache(struct nfp_prog *nfp_prog)
41244125
if (meta->flags & FLAG_INSN_IS_JUMP_DST)
41254126
cache_avail = false;
41264127

4127-
if (meta->skip)
4128+
if (meta->flags & FLAG_INSN_SKIP_MASK)
41284129
continue;
41294130

41304131
insn = &meta->insn;
@@ -4210,7 +4211,7 @@ static void nfp_bpf_opt_pkt_cache(struct nfp_prog *nfp_prog)
42104211
}
42114212

42124213
list_for_each_entry(meta, &nfp_prog->insns, l) {
4213-
if (meta->skip)
4214+
if (meta->flags & FLAG_INSN_SKIP_MASK)
42144215
continue;
42154216

42164217
if (is_mbpf_load_pkt(meta) && !meta->ldst_gather_len) {
@@ -4246,7 +4247,8 @@ static int nfp_bpf_replace_map_ptrs(struct nfp_prog *nfp_prog)
42464247
u32 id;
42474248

42484249
nfp_for_each_insn_walk2(nfp_prog, meta1, meta2) {
4249-
if (meta1->skip || meta2->skip)
4250+
if (meta1->flags & FLAG_INSN_SKIP_MASK ||
4251+
meta2->flags & FLAG_INSN_SKIP_MASK)
42504252
continue;
42514253

42524254
if (meta1->insn.code != (BPF_LD | BPF_IMM | BPF_DW) ||
@@ -4325,7 +4327,7 @@ int nfp_bpf_jit(struct nfp_prog *nfp_prog)
43254327
return ret;
43264328
}
43274329

4328-
void nfp_bpf_jit_prepare(struct nfp_prog *nfp_prog, unsigned int cnt)
4330+
void nfp_bpf_jit_prepare(struct nfp_prog *nfp_prog)
43294331
{
43304332
struct nfp_insn_meta *meta;
43314333

@@ -4353,7 +4355,7 @@ void nfp_bpf_jit_prepare(struct nfp_prog *nfp_prog, unsigned int cnt)
43534355
else
43544356
dst_idx = meta->n + 1 + meta->insn.off;
43554357

4356-
dst_meta = nfp_bpf_goto_meta(nfp_prog, meta, dst_idx, cnt);
4358+
dst_meta = nfp_bpf_goto_meta(nfp_prog, meta, dst_idx);
43574359

43584360
if (pseudo_call)
43594361
dst_meta->flags |= FLAG_INSN_IS_SUBPROG_START;

drivers/net/ethernet/netronome/nfp/bpf/main.h

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,16 @@ struct nfp_bpf_reg_state {
243243
#define FLAG_INSN_IS_JUMP_DST BIT(0)
244244
#define FLAG_INSN_IS_SUBPROG_START BIT(1)
245245
#define FLAG_INSN_PTR_CALLER_STACK_FRAME BIT(2)
246+
/* Instruction is pointless, noop even on its own */
247+
#define FLAG_INSN_SKIP_NOOP BIT(3)
248+
/* Instruction is optimized out based on preceding instructions */
249+
#define FLAG_INSN_SKIP_PREC_DEPENDENT BIT(4)
250+
/* Instruction is optimized by the verifier */
251+
#define FLAG_INSN_SKIP_VERIFIER_OPT BIT(5)
252+
253+
#define FLAG_INSN_SKIP_MASK (FLAG_INSN_SKIP_NOOP | \
254+
FLAG_INSN_SKIP_PREC_DEPENDENT | \
255+
FLAG_INSN_SKIP_VERIFIER_OPT)
246256

247257
/**
248258
* struct nfp_insn_meta - BPF instruction wrapper
@@ -271,7 +281,6 @@ struct nfp_bpf_reg_state {
271281
* @n: eBPF instruction number
272282
* @flags: eBPF instruction extra optimization flags
273283
* @subprog_idx: index of subprogram to which the instruction belongs
274-
* @skip: skip this instruction (optimized out)
275284
* @double_cb: callback for second part of the instruction
276285
* @l: link on nfp_prog->insns list
277286
*/
@@ -319,7 +328,6 @@ struct nfp_insn_meta {
319328
unsigned short n;
320329
unsigned short flags;
321330
unsigned short subprog_idx;
322-
bool skip;
323331
instr_cb_t double_cb;
324332

325333
struct list_head l;
@@ -407,6 +415,17 @@ static inline bool is_mbpf_div(const struct nfp_insn_meta *meta)
407415
return is_mbpf_alu(meta) && mbpf_op(meta) == BPF_DIV;
408416
}
409417

418+
static inline bool is_mbpf_cond_jump(const struct nfp_insn_meta *meta)
419+
{
420+
u8 op;
421+
422+
if (BPF_CLASS(meta->insn.code) != BPF_JMP)
423+
return false;
424+
425+
op = BPF_OP(meta->insn.code);
426+
return op != BPF_JA && op != BPF_EXIT && op != BPF_CALL;
427+
}
428+
410429
static inline bool is_mbpf_helper_call(const struct nfp_insn_meta *meta)
411430
{
412431
struct bpf_insn insn = meta->insn;
@@ -457,6 +476,7 @@ struct nfp_bpf_subprog_info {
457476
* @subprog_cnt: number of sub-programs, including main function
458477
* @map_records: the map record pointers from bpf->maps_neutral
459478
* @subprog: pointer to an array of objects holding info about sub-programs
479+
* @n_insns: number of instructions on @insns list
460480
* @insns: list of BPF instruction wrappers (struct nfp_insn_meta)
461481
*/
462482
struct nfp_prog {
@@ -489,6 +509,7 @@ struct nfp_prog {
489509
struct nfp_bpf_neutral_map **map_records;
490510
struct nfp_bpf_subprog_info *subprog;
491511

512+
unsigned int n_insns;
492513
struct list_head insns;
493514
};
494515

@@ -505,14 +526,18 @@ struct nfp_bpf_vnic {
505526
};
506527

507528
bool nfp_is_subprog_start(struct nfp_insn_meta *meta);
508-
void nfp_bpf_jit_prepare(struct nfp_prog *nfp_prog, unsigned int cnt);
529+
void nfp_bpf_jit_prepare(struct nfp_prog *nfp_prog);
509530
int nfp_bpf_jit(struct nfp_prog *prog);
510531
bool nfp_bpf_supported_opcode(u8 code);
511532

512533
int nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx,
513534
int prev_insn_idx);
514535
int nfp_bpf_finalize(struct bpf_verifier_env *env);
515536

537+
int nfp_bpf_opt_replace_insn(struct bpf_verifier_env *env, u32 off,
538+
struct bpf_insn *insn);
539+
int nfp_bpf_opt_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt);
540+
516541
extern const struct bpf_prog_offload_ops nfp_bpf_dev_ops;
517542

518543
struct netdev_bpf;
@@ -526,7 +551,7 @@ int nfp_net_bpf_offload(struct nfp_net *nn, struct bpf_prog *prog,
526551

527552
struct nfp_insn_meta *
528553
nfp_bpf_goto_meta(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta,
529-
unsigned int insn_idx, unsigned int n_insns);
554+
unsigned int insn_idx);
530555

531556
void *nfp_bpf_relo_for_vnic(struct nfp_prog *nfp_prog, struct nfp_bpf_vnic *bv);
532557

drivers/net/ethernet/netronome/nfp/bpf/offload.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,9 @@ nfp_prog_prepare(struct nfp_prog *nfp_prog, const struct bpf_insn *prog,
163163

164164
list_add_tail(&meta->l, &nfp_prog->insns);
165165
}
166+
nfp_prog->n_insns = cnt;
166167

167-
nfp_bpf_jit_prepare(nfp_prog, cnt);
168+
nfp_bpf_jit_prepare(nfp_prog);
168169

169170
return 0;
170171
}
@@ -219,6 +220,10 @@ static int nfp_bpf_translate(struct bpf_prog *prog)
219220
unsigned int max_instr;
220221
int err;
221222

223+
/* We depend on dead code elimination succeeding */
224+
if (prog->aux->offload->opt_failed)
225+
return -EINVAL;
226+
222227
max_instr = nn_readw(nn, NFP_NET_CFG_BPF_MAX_LEN);
223228
nfp_prog->__prog_alloc_len = max_instr * sizeof(u64);
224229

@@ -591,6 +596,8 @@ int nfp_net_bpf_offload(struct nfp_net *nn, struct bpf_prog *prog,
591596
const struct bpf_prog_offload_ops nfp_bpf_dev_ops = {
592597
.insn_hook = nfp_verify_insn,
593598
.finalize = nfp_bpf_finalize,
599+
.replace_insn = nfp_bpf_opt_replace_insn,
600+
.remove_insns = nfp_bpf_opt_remove_insns,
594601
.prepare = nfp_bpf_verifier_prep,
595602
.translate = nfp_bpf_translate,
596603
.destroy = nfp_bpf_destroy,

0 commit comments

Comments
 (0)