Re: [PATCH bpf-next v4 2/4] riscv, bpf: add RV32G eBPF JIT

From: Luke Nelson
Date: Tue Mar 03 2020 - 21:32:37 EST


Hi BjÃrn,

Thanks again for the comments, responses below:

On Mon, Mar 2, 2020 at 11:48 PM BjÃrn TÃpel <bjorn.topel@xxxxxxxxx> wrote:
>
> Which are the tests that fail to JIT, and is that due to div/mod +
> xadd?

Yes, all of the cases that fail to JIT are because of unsupported
div/mod or xadd. I'll make that clear in next revision.

>
> > Co-developed-by: Xi Wang <xi.wang@xxxxxxxxx>
> > Signed-off-by: Xi Wang <xi.wang@xxxxxxxxx>
> > Signed-off-by: Luke Nelson <luke.r.nels@xxxxxxxxx>
> > ---
> > arch/riscv/Kconfig | 2 +-
> > arch/riscv/net/Makefile | 7 +-
> > arch/riscv/net/bpf_jit_comp32.c | 1466 +++++++++++++++++++++++++++++++
> > 3 files changed, 1473 insertions(+), 2 deletions(-)
> > create mode 100644 arch/riscv/net/bpf_jit_comp32.c
> [...]
> > +
> > +static const s8 *rv32_bpf_get_reg64(const s8 *reg, const s8 *tmp,
> > + struct rv_jit_context *ctx)
>
> Really a nit, but you're using rv32 as prefix, and also as part of
> many of the functions (e.g. emit_rv32). Everything is this file is
> just for RV32, so maybe remove that implicit information from the
> function name? Just a thought! :-)

I got so used to reading these I never noticed how redundant they
were :) I'll change the next revision to remove all of the "rv32"s
in function names.

> > + case BPF_LSH:
> > + if (imm >= 32) {
> > + emit(rv_slli(hi(rd), lo(rd), imm - 32), ctx);
> > + emit(rv_addi(lo(rd), RV_REG_ZERO, 0), ctx);
> > + } else if (imm == 0) {
> > + /* nop */
>
> Can we get rid of this, and just do if/else if?

imm == 0 has been a tricky case for 32-bit JITs; see 6fa632e719ee
("bpf, x32: Fix bug with ALU64 {LSH, RSH, ARSH} BPF_K shift by 0").
We wanted to make the imm == 0 case explicit and help future readers
see that this case is handled correctly here.

We could do the following if we really wanted to get rid of the
check:

if (imm >= 32) {
...
} else if (imm != 0) {
...
}
/* Do nothing for imm == 0. */

Though it's unclear if this is easier to read.

> > + case BPF_ARSH:
> > + if (is_12b_int(imm)) {
> > + emit(rv_srai(lo(rd), lo(rd), imm), ctx);
> > + } else {
> > + emit_imm(RV_REG_T0, imm, ctx);
> > + emit(rv_sra(lo(rd), lo(rd), RV_REG_T0), ctx);
> > + }
> > + break;
>
> Again nit; I like "early exit" code if possible. Instead of:
>
> if (bleh) {
> foo();
> } else {
> bar();
> }
>
> do:
>
> if (bleh) {
> foo()
> return/break;
> }
> bar();
>
> I find the latter easier to read -- but really a nit, and a matter of
> style. There are number of places where that could be applied in the
> file.

I like "early exit" code, too, and agree that it's easier to read
in general, especially when handling error conditions.

But here we wanted to make it explicit that both branches are
emitting equivalent instruction sequences (under different paths).
Structured control flow seems a better fit for this particular
context.

> At this point of the series, let's introduce the shared code .c-file
> containing implementation for bpf_int_jit_compile() (with build_body
> part of that)and bpf_jit_needs_zext(). That will make it easier to
> catch bugs in both JITs and to avoid code duplication! Also, when
> adding the stronger invariant suggested by Palmer [1], we only need to
> do it in one place.
>
> The pull out refactoring can be a separate commit.

I think the idea of deduplicating bpf_int_jit_compile is good and
will lead to more maintainable JITs. How does the following proposal
for v5 sound?

In patch 1 of this series:

- Factor structs and common helpers to bpf_jit.h (just like v4).

- Factor out bpf_int_jit_compile(), bpf_jit_needs_zext(), and
build_body() to a new file bpf_jit_core.c and tweak the code as in v4.

- Rename emit_insn() and build_{prologue,epilogue}() to bpf_jit_emit_insn()
and bpf_jit_build_{prologue,epilogue}, since these functions are
now extern rather than static.

- Rename bpf_jit_comp.c to bpf_jit_comp64.c to be more explicit
about its contents (as the next patch will add bpf_jit_comp32.c).

Then patch 2 can reuse the new header and won't need to define its
own bpf_int_jit_compile() etc.

Thanks!

Luke