On Wed, 4 Mar 2020 at 03:32, Luke Nelson <lukenels@xxxxxxxxxxxxxxxxx> wrote: > [...] > > > > + 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. > Thanks for clearing that up. *I* prefer the latter, but that's really up to you! Keep the current one, if you prefer that! :-) > > > + 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. > Ok! > > 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. > I like that, but keep the first patch as a refactoring patch only, and then in a *new* patch 2 you add the rv32 specific code (sltu and pseudo instructions + the xlen preprocessor check + copyright-things ;-)). Patch 3 will be the old patch 2. Wdyt? Thanks for working on this! Björn > Thanks! > > Luke