Merge branch 'bpf-mips-add-bpf_movsx-support-to-the-jits'

Nicholas Dudar says:

====================
bpf, mips: Add BPF_MOVSX support to the JITs

Add the five MOVSX forms to the MIPS32 and MIPS64 JITs, which currently
emit them as ordinary moves. Patch 1 factors register moves into helpers;
patch 2 adds sign extension.

Use seb/seh on MIPS32 R2+ and doubleword shift pairs on MIPS64, where
normalizing the source for seb/seh would eliminate the instruction saving.
The MIPS64 sequence also matches GCC's generic lowering [1].

This series depends on SDIV/SMOD v4, whose uasm patch adds seb/seh.
This is missing JIT support rather than a regression, hence bpf-next
and no Fixes tag.

Tested the SDIV/SMOD v4 prerequisite and this series with test_bpf under
QEMU Malta on little-endian MIPS32 R1/R2/R6 and MIPS64 R2/R6. All five
MOVSX cases went from failure to JIT pass; all 16 signed DIV/MOD cases
passed on both revisions. Patched pass/fail totals were:

  MIPS32 R2/R6: 1050/12
  MIPS64 R2/R6: 1049/12
  MIPS32 R1:    1045/17

The 12 failures are 8 BSWAP, 3 MEMSX and 1 JMP32_JA. R1's 5 additional
failures also occurred on the prerequisite-only baseline. No other test
outcome changed between the two revisions.

Earlier v2 tests covered both endians and verifier zero-extension
handling. No physical hardware was tested.

Changes in v3:
- Use seb/seh on MIPS32 R2+; retain shift pairs on MIPS64.
- Share the 8/16-bit sign-extension sequence within each backend.
- Apply on top of SDIV/SMOD v4 for the new uasm emitters.

SDIV/SMOD v4: https://lore.kernel.org/bpf/20260911213340.3767930-1-main.kalliope@gmail.com/
v2: https://lore.kernel.org/bpf/20260904111731.673341-1-main.kalliope@gmail.com/
Review: https://lore.kernel.org/bpf/CAM1=_QTN3JJ6jtckf32F8wxBzLDbHSrzUttyMBWNqZKmRe=2rg@mail.gmail.com/
[1] https://github.com/gcc-mirror/gcc/blob/releases/gcc-15.2.0/gcc/config/mips/mips.md#L3921
====================

Link: https://patch.msgid.link/20260912041220.444715-1-main.kalliope@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Alexei Starovoitov 2026-09-22 23:48:53 +00:00
commit 94809ecf9d
No known key found for this signature in database
2 changed files with 119 additions and 7 deletions

View File

@ -190,6 +190,69 @@ static void emit_zext_ver(struct jit_context *ctx, const u8 dst[])
}
}
/* Sign-extend an 8- or 16-bit field into a native register. */
static void emit_movsx_r(struct jit_context *ctx, u8 dst, u8 src, s16 off)
{
int shift;
if (cpu_has_mips32r2 || cpu_has_mips32r6) {
if (off == 8)
emit(ctx, seb, dst, src);
else
emit(ctx, seh, dst, src);
} else {
shift = 32 - off;
emit(ctx, sll, dst, src, shift);
emit(ctx, sra, dst, dst, shift);
}
}
/* Register move operation (32-bit), optionally with sign extension */
static void emit_mov_r32(struct jit_context *ctx, const u8 dst[],
const u8 src[], s16 off)
{
switch (off) {
case 8:
case 16:
emit_movsx_r(ctx, lo(dst), lo(src), off);
break;
default:
/* off == 0 is MOV; the verifier rejects other offsets. */
emit_mov_r(ctx, lo(dst), lo(src));
break;
}
clobber_reg(ctx, lo(dst));
emit_zext_ver(ctx, dst);
}
/* Register move operation (64-bit), optionally with sign extension */
static void emit_mov_r64(struct jit_context *ctx, const u8 dst[],
const u8 src[], s16 off)
{
switch (off) {
case 8:
case 16:
emit_movsx_r(ctx, lo(dst), lo(src), off);
emit(ctx, sra, hi(dst), lo(dst), 31);
break;
case 32:
emit(ctx, move, lo(dst), lo(src));
emit(ctx, sra, hi(dst), lo(dst), 31);
break;
default:
/*
* off == 0 is ordinary MOV. The verifier rejects other
* offsets; defined exceptions require
* bpf_jit_supports_percpu_insn() or bpf_jit_supports_arena(),
* neither implemented by MIPS.
*/
emit_mov_r(ctx, lo(dst), lo(src));
emit_mov_r(ctx, hi(dst), hi(src));
break;
}
clobber_reg64(ctx, dst);
}
/* Load delay slot, if ISA mandates it */
static void emit_load_delay(struct jit_context *ctx)
{
@ -1494,8 +1557,7 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx)
/* Special mov32 for zext */
emit_mov_i(ctx, hi(dst), 0);
} else {
emit_mov_r(ctx, lo(dst), lo(src));
emit_zext_ver(ctx, dst);
emit_mov_r32(ctx, dst, src, off);
}
break;
/* dst = -dst */
@ -1564,8 +1626,7 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx)
break;
/* dst = src (64-bit) */
case BPF_ALU64 | BPF_MOV | BPF_X:
emit_mov_r(ctx, lo(dst), lo(src));
emit_mov_r(ctx, hi(dst), hi(src));
emit_mov_r64(ctx, dst, src, off);
break;
/* dst = -dst (64-bit) */
case BPF_ALU64 | BPF_NEG:

View File

@ -120,6 +120,58 @@ static void emit_zext_ver(struct jit_context *ctx, u8 dst)
emit_zext(ctx, dst);
}
/* Sign-extend an 8- or 16-bit field into a native register. */
static void emit_movsx_r(struct jit_context *ctx, u8 dst, u8 src, s16 off)
{
/* seb/seh would need a sign-extended 32-bit source first. */
int shift = 32 - off;
/* dsll32 and dsra32 add 32 to the shift argument. */
emit(ctx, dsll32, dst, src, shift);
emit(ctx, dsra32, dst, dst, shift);
}
/* Register move operation (32-bit), optionally with sign extension */
static void emit_mov_r32(struct jit_context *ctx, u8 dst, u8 src, s16 off)
{
switch (off) {
case 8:
case 16:
emit_movsx_r(ctx, dst, src, off);
break;
default:
/* off == 0 is MOV; the verifier rejects other offsets. */
emit_mov_r(ctx, dst, src);
break;
}
clobber_reg(ctx, dst);
emit_zext_ver(ctx, dst);
}
/* Register move operation (64-bit), optionally with sign extension */
static void emit_mov_r64(struct jit_context *ctx, u8 dst, u8 src, s16 off)
{
switch (off) {
case 8:
case 16:
emit_movsx_r(ctx, dst, src, off);
break;
case 32:
emit_sext(ctx, dst, src);
break;
default:
/*
* off == 0 is ordinary MOV. The verifier rejects other
* offsets; defined exceptions require
* bpf_jit_supports_percpu_insn() or bpf_jit_supports_arena(),
* neither implemented by MIPS.
*/
emit_mov_r(ctx, dst, src);
break;
}
clobber_reg(ctx, dst);
}
/* dst = imm (64-bit) */
static void emit_mov_i64(struct jit_context *ctx, u8 dst, u64 imm64)
{
@ -681,8 +733,7 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx)
/* Special mov32 for zext */
emit_zext(ctx, dst);
} else {
emit_mov_r(ctx, dst, src);
emit_zext_ver(ctx, dst);
emit_mov_r32(ctx, dst, src, off);
}
break;
/* dst = -dst */
@ -767,7 +818,7 @@ int build_insn(const struct bpf_insn *insn, struct jit_context *ctx)
break;
/* dst = src (64-bit) */
case BPF_ALU64 | BPF_MOV | BPF_X:
emit_mov_r(ctx, dst, src);
emit_mov_r64(ctx, dst, src, off);
break;
/* dst = -dst (64-bit) */
case BPF_ALU64 | BPF_NEG: