[PATCH bpf-next v2 1/8] bpf: Add UHMUL and SHMUL instructions
Yazhou Tang
tangyazhou at zju.edu.cn
Thu Oct 22 00:25:11 PDT 2026
On 10/22/26 01:11, Alexei Starovoitov wrote:
> On Tue, Oct 20, 2026 at 10:40 PM tangyazhou at zju.edu.cn <tangyazhou at zju.edu.cn> wrote:
>
>> +static inline bool bpf_insn_is_hmul(const struct bpf_insn *insn)
>> +{
>> + return BPF_CLASS(insn->code) == BPF_ALU64 &&
>> + BPF_OP(insn->code) == BPF_MUL &&
>> + bpf_is_hmul_variant(insn->off);
>> +}
>
> Patch 5 adds this check to 13 JITs and nfp to opt them out.
> Lets make JITs opt in instead, like bpf_jit_supports_callx().
> The verifier checks it once. x86, arm64 and riscv patches add
> bpf_jit_supports_hmul() that returns true. bpf_prog_is_offloaded()
> covers nfp.
> When JIT is on and it doesn't support them the prog is rejected with
> a message in the log instead of silent fallback to the interpreter.
> Then patch 5 goes away and only arm64 and riscv acks are needed.
Thanks, Alexei. This is a cleaner approach. I'll add
bpf_jit_supports_hmul() as you suggested and remove
the opt-out checks from unsupported JITs in v3.
Apologies for the noise to the other JIT maintainers.
>
> Like:
>
> diff --git a/include/linux/filter.h b/include/linux/filter.h
> index e0218e6..6ee8d1a 100644
> --- a/include/linux/filter.h
> +++ b/include/linux/filter.h
> @@ -152,6 +152,13 @@ struct ctl_table_header;
> #define BPF_ALU32_IMM(OP, DST, IMM) \
> BPF_ALU32_IMM_OFF(OP, DST, IMM, 0)
>
> +static inline bool bpf_insn_is_hmul(const struct bpf_insn *insn)
> +{
> + return BPF_CLASS(insn->code) == BPF_ALU64 &&
> + BPF_OP(insn->code) == BPF_MUL &&
> + (insn->off == BPF_UHMUL || insn->off == BPF_SHMUL);
> +}
> +
> /* Endianess conversion, cpu_to_{l,b}e(), {l,b}e_to_cpu() */
>
> #define BPF_ENDIAN(TYPE, DST, LEN) \
> @@ -1281,6 +1288,7 @@ bool bpf_jit_supports_kfunc_call(void);
> bool bpf_jit_supports_callx(void);
> bool bpf_jit_supports_kfunc_ret_reg_pair(void);
> bool bpf_jit_supports_unwind(void);
> +bool bpf_jit_supports_hmul(void);
> bool bpf_jit_supports_stack_args(void);
> bool bpf_jit_supports_arena_args(void);
> bool bpf_jit_supports_far_kfunc_call(void);
> diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
> index f29b0aa..90c30e5 100644
> --- a/include/uapi/linux/bpf.h
> +++ b/include/uapi/linux/bpf.h
> @@ -34,6 +34,12 @@
> #define BPF_FROM_LE BPF_TO_LE
> #define BPF_FROM_BE BPF_TO_BE
>
> +/* BPF_MUL off values for high-half multiplication; BPF_ALU64 only. */
> +enum bpf_mul_variant {
> + BPF_UHMUL = 1,
> + BPF_SHMUL = 2,
> +};
> +
> /* jmp encodings */
> #define BPF_JNE 0x50 /* jump != */
> #define BPF_JLT 0xa0 /* LT is unsigned, '<' */
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index 3030beb..e17704a 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -3405,6 +3405,12 @@ bool __weak bpf_jit_supports_unwind(void)
> return false;
> }
>
> +/* uhmul and shmul */
> +bool __weak bpf_jit_supports_hmul(void)
> +{
> + return false;
> +}
> +
> /*
> * How this arch places a by-value kfunc argument, or NULL for one that has
> * not opted in and so only takes an argument of a single eightbyte, which
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 5601d20..9a3c97d 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -21194,6 +21194,17 @@ static int fd_array_get_map_idx(struct bpf_verifier_env *env, u32 idx)
> return -EPROTO;
> }
>
> +/* The interpreter supports uhmul and shmul. JITs opt in. */
> +static int check_hmul_jit(struct bpf_verifier_env *env)
> +{
> + if (bpf_prog_is_offloaded(env->prog->aux) ||
> + (env->prog->jit_requested && !bpf_jit_supports_hmul())) {
> + verbose(env, "JIT doesn't support uhmul and shmul\n");
> + return -EOPNOTSUPP;
> + }
> + return 0;
> +}
> +
> static int check_alu_fields(struct bpf_verifier_env *env, struct bpf_insn *insn)
> {
> u8 class = BPF_CLASS(insn->code);
> @@ -21249,6 +21260,13 @@ static int check_alu_fields(struct bpf_verifier_env *env, struct bpf_insn *insn)
> case BPF_MUL:
> case BPF_DIV:
> case BPF_MOD:
> + if (bpf_insn_is_hmul(insn)) {
> + if (BPF_SRC(insn->code) == BPF_X ? insn->imm : insn->src_reg) {
> + verbose(env, "BPF_ALU uses reserved fields\n");
> + return -EINVAL;
> + }
> + return check_hmul_jit(env);
> + }
> if (BPF_SRC(insn->code) == BPF_X) {
> if (insn->imm != 0 || (insn->off != 0 && insn->off != 1) ||
> (insn->off == 1 && opcode != BPF_MOD && opcode != BPF_DIV)) {
>
> pw-bot: cr
More information about the linux-riscv
mailing list