Skip to content

Commit fd49591

Browse files
lukenelswilldeacon
authored andcommitted
bpf, arm64: Optimize AND,OR,XOR,JSET BPF_K using arm64 logical immediates
The current code for BPF_{AND,OR,XOR,JSET} BPF_K loads the immediate to a temporary register before use. This patch changes the code to avoid using a temporary register when the BPF immediate is encodable using an arm64 logical immediate instruction. If the encoding fails (due to the immediate not being encodable), it falls back to using a temporary register. Example of generated code for BPF_ALU32_IMM(BPF_AND, R0, 0x80000001): without optimization: 24: mov w10, #0x8000ffff 28: movk w10, #0x1 2c: and w7, w7, w10 with optimization: 24: and w7, w7, #0x80000001 Since the encoding process is quite complex, the JIT reuses existing functionality in arch/arm64/kernel/insn.c for encoding logical immediates rather than duplicate it in the JIT. Co-developed-by: Xi Wang <[email protected]> Signed-off-by: Xi Wang <[email protected]> Signed-off-by: Luke Nelson <[email protected]> Acked-by: Daniel Borkmann <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 579d1b3 commit fd49591

File tree

2 files changed

+43
-8
lines changed

2 files changed

+43
-8
lines changed

arch/arm64/net/bpf_jit.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,4 +189,18 @@
189189
/* Rn & Rm; set condition flags */
190190
#define A64_TST(sf, Rn, Rm) A64_ANDS(sf, A64_ZR, Rn, Rm)
191191

192+
/* Logical (immediate) */
193+
#define A64_LOGIC_IMM(sf, Rd, Rn, imm, type) ({ \
194+
u64 imm64 = (sf) ? (u64)imm : (u64)(u32)imm; \
195+
aarch64_insn_gen_logical_immediate(AARCH64_INSN_LOGIC_##type, \
196+
A64_VARIANT(sf), Rn, Rd, imm64); \
197+
})
198+
/* Rd = Rn OP imm */
199+
#define A64_AND_I(sf, Rd, Rn, imm) A64_LOGIC_IMM(sf, Rd, Rn, imm, AND)
200+
#define A64_ORR_I(sf, Rd, Rn, imm) A64_LOGIC_IMM(sf, Rd, Rn, imm, ORR)
201+
#define A64_EOR_I(sf, Rd, Rn, imm) A64_LOGIC_IMM(sf, Rd, Rn, imm, EOR)
202+
#define A64_ANDS_I(sf, Rd, Rn, imm) A64_LOGIC_IMM(sf, Rd, Rn, imm, AND_SETFLAGS)
203+
/* Rn & imm; set condition flags */
204+
#define A64_TST_I(sf, Rn, imm) A64_ANDS_I(sf, A64_ZR, Rn, imm)
205+
192206
#endif /* _BPF_JIT_H */

arch/arm64/net/bpf_jit_comp.c

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
356356
const bool isdw = BPF_SIZE(code) == BPF_DW;
357357
u8 jmp_cond, reg;
358358
s32 jmp_offset;
359+
u32 a64_insn;
359360

360361
#define check_imm(bits, imm) do { \
361362
if ((((imm) > 0) && ((imm) >> (bits))) || \
@@ -488,18 +489,33 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
488489
break;
489490
case BPF_ALU | BPF_AND | BPF_K:
490491
case BPF_ALU64 | BPF_AND | BPF_K:
491-
emit_a64_mov_i(is64, tmp, imm, ctx);
492-
emit(A64_AND(is64, dst, dst, tmp), ctx);
492+
a64_insn = A64_AND_I(is64, dst, dst, imm);
493+
if (a64_insn != AARCH64_BREAK_FAULT) {
494+
emit(a64_insn, ctx);
495+
} else {
496+
emit_a64_mov_i(is64, tmp, imm, ctx);
497+
emit(A64_AND(is64, dst, dst, tmp), ctx);
498+
}
493499
break;
494500
case BPF_ALU | BPF_OR | BPF_K:
495501
case BPF_ALU64 | BPF_OR | BPF_K:
496-
emit_a64_mov_i(is64, tmp, imm, ctx);
497-
emit(A64_ORR(is64, dst, dst, tmp), ctx);
502+
a64_insn = A64_ORR_I(is64, dst, dst, imm);
503+
if (a64_insn != AARCH64_BREAK_FAULT) {
504+
emit(a64_insn, ctx);
505+
} else {
506+
emit_a64_mov_i(is64, tmp, imm, ctx);
507+
emit(A64_ORR(is64, dst, dst, tmp), ctx);
508+
}
498509
break;
499510
case BPF_ALU | BPF_XOR | BPF_K:
500511
case BPF_ALU64 | BPF_XOR | BPF_K:
501-
emit_a64_mov_i(is64, tmp, imm, ctx);
502-
emit(A64_EOR(is64, dst, dst, tmp), ctx);
512+
a64_insn = A64_EOR_I(is64, dst, dst, imm);
513+
if (a64_insn != AARCH64_BREAK_FAULT) {
514+
emit(a64_insn, ctx);
515+
} else {
516+
emit_a64_mov_i(is64, tmp, imm, ctx);
517+
emit(A64_EOR(is64, dst, dst, tmp), ctx);
518+
}
503519
break;
504520
case BPF_ALU | BPF_MUL | BPF_K:
505521
case BPF_ALU64 | BPF_MUL | BPF_K:
@@ -628,8 +644,13 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx,
628644
goto emit_cond_jmp;
629645
case BPF_JMP | BPF_JSET | BPF_K:
630646
case BPF_JMP32 | BPF_JSET | BPF_K:
631-
emit_a64_mov_i(is64, tmp, imm, ctx);
632-
emit(A64_TST(is64, dst, tmp), ctx);
647+
a64_insn = A64_TST_I(is64, dst, imm);
648+
if (a64_insn != AARCH64_BREAK_FAULT) {
649+
emit(a64_insn, ctx);
650+
} else {
651+
emit_a64_mov_i(is64, tmp, imm, ctx);
652+
emit(A64_TST(is64, dst, tmp), ctx);
653+
}
633654
goto emit_cond_jmp;
634655
/* function call */
635656
case BPF_JMP | BPF_CALL:

0 commit comments

Comments
 (0)