162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * BPF JIT compiler for RV32G
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2020 Luke Nelson <luke.r.nels@gmail.com>
662306a36Sopenharmony_ci * Copyright (c) 2020 Xi Wang <xi.wang@gmail.com>
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * The code is based on the BPF JIT compiler for RV64G by Björn Töpel and
962306a36Sopenharmony_ci * the BPF JIT compiler for 32-bit ARM by Shubham Bansal and Mircea Gherzan.
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/bpf.h>
1362306a36Sopenharmony_ci#include <linux/filter.h>
1462306a36Sopenharmony_ci#include "bpf_jit.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/*
1762306a36Sopenharmony_ci * Stack layout during BPF program execution:
1862306a36Sopenharmony_ci *
1962306a36Sopenharmony_ci *                     high
2062306a36Sopenharmony_ci *     RV32 fp =>  +----------+
2162306a36Sopenharmony_ci *                 | saved ra |
2262306a36Sopenharmony_ci *                 | saved fp | RV32 callee-saved registers
2362306a36Sopenharmony_ci *                 |   ...    |
2462306a36Sopenharmony_ci *                 +----------+ <= (fp - 4 * NR_SAVED_REGISTERS)
2562306a36Sopenharmony_ci *                 |  hi(R6)  |
2662306a36Sopenharmony_ci *                 |  lo(R6)  |
2762306a36Sopenharmony_ci *                 |  hi(R7)  | JIT scratch space for BPF registers
2862306a36Sopenharmony_ci *                 |  lo(R7)  |
2962306a36Sopenharmony_ci *                 |   ...    |
3062306a36Sopenharmony_ci *  BPF_REG_FP =>  +----------+ <= (fp - 4 * NR_SAVED_REGISTERS
3162306a36Sopenharmony_ci *                 |          |        - 4 * BPF_JIT_SCRATCH_REGS)
3262306a36Sopenharmony_ci *                 |          |
3362306a36Sopenharmony_ci *                 |   ...    | BPF program stack
3462306a36Sopenharmony_ci *                 |          |
3562306a36Sopenharmony_ci *     RV32 sp =>  +----------+
3662306a36Sopenharmony_ci *                 |          |
3762306a36Sopenharmony_ci *                 |   ...    | Function call stack
3862306a36Sopenharmony_ci *                 |          |
3962306a36Sopenharmony_ci *                 +----------+
4062306a36Sopenharmony_ci *                     low
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cienum {
4462306a36Sopenharmony_ci	/* Stack layout - these are offsets from top of JIT scratch space. */
4562306a36Sopenharmony_ci	BPF_R6_HI,
4662306a36Sopenharmony_ci	BPF_R6_LO,
4762306a36Sopenharmony_ci	BPF_R7_HI,
4862306a36Sopenharmony_ci	BPF_R7_LO,
4962306a36Sopenharmony_ci	BPF_R8_HI,
5062306a36Sopenharmony_ci	BPF_R8_LO,
5162306a36Sopenharmony_ci	BPF_R9_HI,
5262306a36Sopenharmony_ci	BPF_R9_LO,
5362306a36Sopenharmony_ci	BPF_AX_HI,
5462306a36Sopenharmony_ci	BPF_AX_LO,
5562306a36Sopenharmony_ci	/* Stack space for BPF_REG_6 through BPF_REG_9 and BPF_REG_AX. */
5662306a36Sopenharmony_ci	BPF_JIT_SCRATCH_REGS,
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/* Number of callee-saved registers stored to stack: ra, fp, s1--s7. */
6062306a36Sopenharmony_ci#define NR_SAVED_REGISTERS	9
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* Offset from fp for BPF registers stored on stack. */
6362306a36Sopenharmony_ci#define STACK_OFFSET(k)	(-4 - (4 * NR_SAVED_REGISTERS) - (4 * (k)))
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#define TMP_REG_1	(MAX_BPF_JIT_REG + 0)
6662306a36Sopenharmony_ci#define TMP_REG_2	(MAX_BPF_JIT_REG + 1)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#define RV_REG_TCC		RV_REG_T6
6962306a36Sopenharmony_ci#define RV_REG_TCC_SAVED	RV_REG_S7
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic const s8 bpf2rv32[][2] = {
7262306a36Sopenharmony_ci	/* Return value from in-kernel function, and exit value from eBPF. */
7362306a36Sopenharmony_ci	[BPF_REG_0] = {RV_REG_S2, RV_REG_S1},
7462306a36Sopenharmony_ci	/* Arguments from eBPF program to in-kernel function. */
7562306a36Sopenharmony_ci	[BPF_REG_1] = {RV_REG_A1, RV_REG_A0},
7662306a36Sopenharmony_ci	[BPF_REG_2] = {RV_REG_A3, RV_REG_A2},
7762306a36Sopenharmony_ci	[BPF_REG_3] = {RV_REG_A5, RV_REG_A4},
7862306a36Sopenharmony_ci	[BPF_REG_4] = {RV_REG_A7, RV_REG_A6},
7962306a36Sopenharmony_ci	[BPF_REG_5] = {RV_REG_S4, RV_REG_S3},
8062306a36Sopenharmony_ci	/*
8162306a36Sopenharmony_ci	 * Callee-saved registers that in-kernel function will preserve.
8262306a36Sopenharmony_ci	 * Stored on the stack.
8362306a36Sopenharmony_ci	 */
8462306a36Sopenharmony_ci	[BPF_REG_6] = {STACK_OFFSET(BPF_R6_HI), STACK_OFFSET(BPF_R6_LO)},
8562306a36Sopenharmony_ci	[BPF_REG_7] = {STACK_OFFSET(BPF_R7_HI), STACK_OFFSET(BPF_R7_LO)},
8662306a36Sopenharmony_ci	[BPF_REG_8] = {STACK_OFFSET(BPF_R8_HI), STACK_OFFSET(BPF_R8_LO)},
8762306a36Sopenharmony_ci	[BPF_REG_9] = {STACK_OFFSET(BPF_R9_HI), STACK_OFFSET(BPF_R9_LO)},
8862306a36Sopenharmony_ci	/* Read-only frame pointer to access BPF stack. */
8962306a36Sopenharmony_ci	[BPF_REG_FP] = {RV_REG_S6, RV_REG_S5},
9062306a36Sopenharmony_ci	/* Temporary register for blinding constants. Stored on the stack. */
9162306a36Sopenharmony_ci	[BPF_REG_AX] = {STACK_OFFSET(BPF_AX_HI), STACK_OFFSET(BPF_AX_LO)},
9262306a36Sopenharmony_ci	/*
9362306a36Sopenharmony_ci	 * Temporary registers used by the JIT to operate on registers stored
9462306a36Sopenharmony_ci	 * on the stack. Save t0 and t1 to be used as temporaries in generated
9562306a36Sopenharmony_ci	 * code.
9662306a36Sopenharmony_ci	 */
9762306a36Sopenharmony_ci	[TMP_REG_1] = {RV_REG_T3, RV_REG_T2},
9862306a36Sopenharmony_ci	[TMP_REG_2] = {RV_REG_T5, RV_REG_T4},
9962306a36Sopenharmony_ci};
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic s8 hi(const s8 *r)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	return r[0];
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic s8 lo(const s8 *r)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	return r[1];
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic void emit_imm(const s8 rd, s32 imm, struct rv_jit_context *ctx)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	u32 upper = (imm + (1 << 11)) >> 12;
11462306a36Sopenharmony_ci	u32 lower = imm & 0xfff;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (upper) {
11762306a36Sopenharmony_ci		emit(rv_lui(rd, upper), ctx);
11862306a36Sopenharmony_ci		emit(rv_addi(rd, rd, lower), ctx);
11962306a36Sopenharmony_ci	} else {
12062306a36Sopenharmony_ci		emit(rv_addi(rd, RV_REG_ZERO, lower), ctx);
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic void emit_imm32(const s8 *rd, s32 imm, struct rv_jit_context *ctx)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	/* Emit immediate into lower bits. */
12762306a36Sopenharmony_ci	emit_imm(lo(rd), imm, ctx);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* Sign-extend into upper bits. */
13062306a36Sopenharmony_ci	if (imm >= 0)
13162306a36Sopenharmony_ci		emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx);
13262306a36Sopenharmony_ci	else
13362306a36Sopenharmony_ci		emit(rv_addi(hi(rd), RV_REG_ZERO, -1), ctx);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic void emit_imm64(const s8 *rd, s32 imm_hi, s32 imm_lo,
13762306a36Sopenharmony_ci		       struct rv_jit_context *ctx)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	emit_imm(lo(rd), imm_lo, ctx);
14062306a36Sopenharmony_ci	emit_imm(hi(rd), imm_hi, ctx);
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic void __build_epilogue(bool is_tail_call, struct rv_jit_context *ctx)
14462306a36Sopenharmony_ci{
14562306a36Sopenharmony_ci	int stack_adjust = ctx->stack_size;
14662306a36Sopenharmony_ci	const s8 *r0 = bpf2rv32[BPF_REG_0];
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	/* Set return value if not tail call. */
14962306a36Sopenharmony_ci	if (!is_tail_call) {
15062306a36Sopenharmony_ci		emit(rv_addi(RV_REG_A0, lo(r0), 0), ctx);
15162306a36Sopenharmony_ci		emit(rv_addi(RV_REG_A1, hi(r0), 0), ctx);
15262306a36Sopenharmony_ci	}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	/* Restore callee-saved registers. */
15562306a36Sopenharmony_ci	emit(rv_lw(RV_REG_RA, stack_adjust - 4, RV_REG_SP), ctx);
15662306a36Sopenharmony_ci	emit(rv_lw(RV_REG_FP, stack_adjust - 8, RV_REG_SP), ctx);
15762306a36Sopenharmony_ci	emit(rv_lw(RV_REG_S1, stack_adjust - 12, RV_REG_SP), ctx);
15862306a36Sopenharmony_ci	emit(rv_lw(RV_REG_S2, stack_adjust - 16, RV_REG_SP), ctx);
15962306a36Sopenharmony_ci	emit(rv_lw(RV_REG_S3, stack_adjust - 20, RV_REG_SP), ctx);
16062306a36Sopenharmony_ci	emit(rv_lw(RV_REG_S4, stack_adjust - 24, RV_REG_SP), ctx);
16162306a36Sopenharmony_ci	emit(rv_lw(RV_REG_S5, stack_adjust - 28, RV_REG_SP), ctx);
16262306a36Sopenharmony_ci	emit(rv_lw(RV_REG_S6, stack_adjust - 32, RV_REG_SP), ctx);
16362306a36Sopenharmony_ci	emit(rv_lw(RV_REG_S7, stack_adjust - 36, RV_REG_SP), ctx);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	emit(rv_addi(RV_REG_SP, RV_REG_SP, stack_adjust), ctx);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (is_tail_call) {
16862306a36Sopenharmony_ci		/*
16962306a36Sopenharmony_ci		 * goto *(t0 + 4);
17062306a36Sopenharmony_ci		 * Skips first instruction of prologue which initializes tail
17162306a36Sopenharmony_ci		 * call counter. Assumes t0 contains address of target program,
17262306a36Sopenharmony_ci		 * see emit_bpf_tail_call.
17362306a36Sopenharmony_ci		 */
17462306a36Sopenharmony_ci		emit(rv_jalr(RV_REG_ZERO, RV_REG_T0, 4), ctx);
17562306a36Sopenharmony_ci	} else {
17662306a36Sopenharmony_ci		emit(rv_jalr(RV_REG_ZERO, RV_REG_RA, 0), ctx);
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic bool is_stacked(s8 reg)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	return reg < 0;
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_cistatic const s8 *bpf_get_reg64(const s8 *reg, const s8 *tmp,
18662306a36Sopenharmony_ci			       struct rv_jit_context *ctx)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	if (is_stacked(hi(reg))) {
18962306a36Sopenharmony_ci		emit(rv_lw(hi(tmp), hi(reg), RV_REG_FP), ctx);
19062306a36Sopenharmony_ci		emit(rv_lw(lo(tmp), lo(reg), RV_REG_FP), ctx);
19162306a36Sopenharmony_ci		reg = tmp;
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci	return reg;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic void bpf_put_reg64(const s8 *reg, const s8 *src,
19762306a36Sopenharmony_ci			  struct rv_jit_context *ctx)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	if (is_stacked(hi(reg))) {
20062306a36Sopenharmony_ci		emit(rv_sw(RV_REG_FP, hi(reg), hi(src)), ctx);
20162306a36Sopenharmony_ci		emit(rv_sw(RV_REG_FP, lo(reg), lo(src)), ctx);
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic const s8 *bpf_get_reg32(const s8 *reg, const s8 *tmp,
20662306a36Sopenharmony_ci			       struct rv_jit_context *ctx)
20762306a36Sopenharmony_ci{
20862306a36Sopenharmony_ci	if (is_stacked(lo(reg))) {
20962306a36Sopenharmony_ci		emit(rv_lw(lo(tmp), lo(reg), RV_REG_FP), ctx);
21062306a36Sopenharmony_ci		reg = tmp;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci	return reg;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic void bpf_put_reg32(const s8 *reg, const s8 *src,
21662306a36Sopenharmony_ci			  struct rv_jit_context *ctx)
21762306a36Sopenharmony_ci{
21862306a36Sopenharmony_ci	if (is_stacked(lo(reg))) {
21962306a36Sopenharmony_ci		emit(rv_sw(RV_REG_FP, lo(reg), lo(src)), ctx);
22062306a36Sopenharmony_ci		if (!ctx->prog->aux->verifier_zext)
22162306a36Sopenharmony_ci			emit(rv_sw(RV_REG_FP, hi(reg), RV_REG_ZERO), ctx);
22262306a36Sopenharmony_ci	} else if (!ctx->prog->aux->verifier_zext) {
22362306a36Sopenharmony_ci		emit(rv_addi(hi(reg), RV_REG_ZERO, 0), ctx);
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic void emit_jump_and_link(u8 rd, s32 rvoff, bool force_jalr,
22862306a36Sopenharmony_ci			       struct rv_jit_context *ctx)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	s32 upper, lower;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (rvoff && is_21b_int(rvoff) && !force_jalr) {
23362306a36Sopenharmony_ci		emit(rv_jal(rd, rvoff >> 1), ctx);
23462306a36Sopenharmony_ci		return;
23562306a36Sopenharmony_ci	}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	upper = (rvoff + (1 << 11)) >> 12;
23862306a36Sopenharmony_ci	lower = rvoff & 0xfff;
23962306a36Sopenharmony_ci	emit(rv_auipc(RV_REG_T1, upper), ctx);
24062306a36Sopenharmony_ci	emit(rv_jalr(rd, RV_REG_T1, lower), ctx);
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic void emit_alu_i64(const s8 *dst, s32 imm,
24462306a36Sopenharmony_ci			 struct rv_jit_context *ctx, const u8 op)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	const s8 *tmp1 = bpf2rv32[TMP_REG_1];
24762306a36Sopenharmony_ci	const s8 *rd = bpf_get_reg64(dst, tmp1, ctx);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	switch (op) {
25062306a36Sopenharmony_ci	case BPF_MOV:
25162306a36Sopenharmony_ci		emit_imm32(rd, imm, ctx);
25262306a36Sopenharmony_ci		break;
25362306a36Sopenharmony_ci	case BPF_AND:
25462306a36Sopenharmony_ci		if (is_12b_int(imm)) {
25562306a36Sopenharmony_ci			emit(rv_andi(lo(rd), lo(rd), imm), ctx);
25662306a36Sopenharmony_ci		} else {
25762306a36Sopenharmony_ci			emit_imm(RV_REG_T0, imm, ctx);
25862306a36Sopenharmony_ci			emit(rv_and(lo(rd), lo(rd), RV_REG_T0), ctx);
25962306a36Sopenharmony_ci		}
26062306a36Sopenharmony_ci		if (imm >= 0)
26162306a36Sopenharmony_ci			emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx);
26262306a36Sopenharmony_ci		break;
26362306a36Sopenharmony_ci	case BPF_OR:
26462306a36Sopenharmony_ci		if (is_12b_int(imm)) {
26562306a36Sopenharmony_ci			emit(rv_ori(lo(rd), lo(rd), imm), ctx);
26662306a36Sopenharmony_ci		} else {
26762306a36Sopenharmony_ci			emit_imm(RV_REG_T0, imm, ctx);
26862306a36Sopenharmony_ci			emit(rv_or(lo(rd), lo(rd), RV_REG_T0), ctx);
26962306a36Sopenharmony_ci		}
27062306a36Sopenharmony_ci		if (imm < 0)
27162306a36Sopenharmony_ci			emit(rv_ori(hi(rd), RV_REG_ZERO, -1), ctx);
27262306a36Sopenharmony_ci		break;
27362306a36Sopenharmony_ci	case BPF_XOR:
27462306a36Sopenharmony_ci		if (is_12b_int(imm)) {
27562306a36Sopenharmony_ci			emit(rv_xori(lo(rd), lo(rd), imm), ctx);
27662306a36Sopenharmony_ci		} else {
27762306a36Sopenharmony_ci			emit_imm(RV_REG_T0, imm, ctx);
27862306a36Sopenharmony_ci			emit(rv_xor(lo(rd), lo(rd), RV_REG_T0), ctx);
27962306a36Sopenharmony_ci		}
28062306a36Sopenharmony_ci		if (imm < 0)
28162306a36Sopenharmony_ci			emit(rv_xori(hi(rd), hi(rd), -1), ctx);
28262306a36Sopenharmony_ci		break;
28362306a36Sopenharmony_ci	case BPF_LSH:
28462306a36Sopenharmony_ci		if (imm >= 32) {
28562306a36Sopenharmony_ci			emit(rv_slli(hi(rd), lo(rd), imm - 32), ctx);
28662306a36Sopenharmony_ci			emit(rv_addi(lo(rd), RV_REG_ZERO, 0), ctx);
28762306a36Sopenharmony_ci		} else if (imm == 0) {
28862306a36Sopenharmony_ci			/* Do nothing. */
28962306a36Sopenharmony_ci		} else {
29062306a36Sopenharmony_ci			emit(rv_srli(RV_REG_T0, lo(rd), 32 - imm), ctx);
29162306a36Sopenharmony_ci			emit(rv_slli(hi(rd), hi(rd), imm), ctx);
29262306a36Sopenharmony_ci			emit(rv_or(hi(rd), RV_REG_T0, hi(rd)), ctx);
29362306a36Sopenharmony_ci			emit(rv_slli(lo(rd), lo(rd), imm), ctx);
29462306a36Sopenharmony_ci		}
29562306a36Sopenharmony_ci		break;
29662306a36Sopenharmony_ci	case BPF_RSH:
29762306a36Sopenharmony_ci		if (imm >= 32) {
29862306a36Sopenharmony_ci			emit(rv_srli(lo(rd), hi(rd), imm - 32), ctx);
29962306a36Sopenharmony_ci			emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx);
30062306a36Sopenharmony_ci		} else if (imm == 0) {
30162306a36Sopenharmony_ci			/* Do nothing. */
30262306a36Sopenharmony_ci		} else {
30362306a36Sopenharmony_ci			emit(rv_slli(RV_REG_T0, hi(rd), 32 - imm), ctx);
30462306a36Sopenharmony_ci			emit(rv_srli(lo(rd), lo(rd), imm), ctx);
30562306a36Sopenharmony_ci			emit(rv_or(lo(rd), RV_REG_T0, lo(rd)), ctx);
30662306a36Sopenharmony_ci			emit(rv_srli(hi(rd), hi(rd), imm), ctx);
30762306a36Sopenharmony_ci		}
30862306a36Sopenharmony_ci		break;
30962306a36Sopenharmony_ci	case BPF_ARSH:
31062306a36Sopenharmony_ci		if (imm >= 32) {
31162306a36Sopenharmony_ci			emit(rv_srai(lo(rd), hi(rd), imm - 32), ctx);
31262306a36Sopenharmony_ci			emit(rv_srai(hi(rd), hi(rd), 31), ctx);
31362306a36Sopenharmony_ci		} else if (imm == 0) {
31462306a36Sopenharmony_ci			/* Do nothing. */
31562306a36Sopenharmony_ci		} else {
31662306a36Sopenharmony_ci			emit(rv_slli(RV_REG_T0, hi(rd), 32 - imm), ctx);
31762306a36Sopenharmony_ci			emit(rv_srli(lo(rd), lo(rd), imm), ctx);
31862306a36Sopenharmony_ci			emit(rv_or(lo(rd), RV_REG_T0, lo(rd)), ctx);
31962306a36Sopenharmony_ci			emit(rv_srai(hi(rd), hi(rd), imm), ctx);
32062306a36Sopenharmony_ci		}
32162306a36Sopenharmony_ci		break;
32262306a36Sopenharmony_ci	}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	bpf_put_reg64(dst, rd, ctx);
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic void emit_alu_i32(const s8 *dst, s32 imm,
32862306a36Sopenharmony_ci			 struct rv_jit_context *ctx, const u8 op)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	const s8 *tmp1 = bpf2rv32[TMP_REG_1];
33162306a36Sopenharmony_ci	const s8 *rd = bpf_get_reg32(dst, tmp1, ctx);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	switch (op) {
33462306a36Sopenharmony_ci	case BPF_MOV:
33562306a36Sopenharmony_ci		emit_imm(lo(rd), imm, ctx);
33662306a36Sopenharmony_ci		break;
33762306a36Sopenharmony_ci	case BPF_ADD:
33862306a36Sopenharmony_ci		if (is_12b_int(imm)) {
33962306a36Sopenharmony_ci			emit(rv_addi(lo(rd), lo(rd), imm), ctx);
34062306a36Sopenharmony_ci		} else {
34162306a36Sopenharmony_ci			emit_imm(RV_REG_T0, imm, ctx);
34262306a36Sopenharmony_ci			emit(rv_add(lo(rd), lo(rd), RV_REG_T0), ctx);
34362306a36Sopenharmony_ci		}
34462306a36Sopenharmony_ci		break;
34562306a36Sopenharmony_ci	case BPF_SUB:
34662306a36Sopenharmony_ci		if (is_12b_int(-imm)) {
34762306a36Sopenharmony_ci			emit(rv_addi(lo(rd), lo(rd), -imm), ctx);
34862306a36Sopenharmony_ci		} else {
34962306a36Sopenharmony_ci			emit_imm(RV_REG_T0, imm, ctx);
35062306a36Sopenharmony_ci			emit(rv_sub(lo(rd), lo(rd), RV_REG_T0), ctx);
35162306a36Sopenharmony_ci		}
35262306a36Sopenharmony_ci		break;
35362306a36Sopenharmony_ci	case BPF_AND:
35462306a36Sopenharmony_ci		if (is_12b_int(imm)) {
35562306a36Sopenharmony_ci			emit(rv_andi(lo(rd), lo(rd), imm), ctx);
35662306a36Sopenharmony_ci		} else {
35762306a36Sopenharmony_ci			emit_imm(RV_REG_T0, imm, ctx);
35862306a36Sopenharmony_ci			emit(rv_and(lo(rd), lo(rd), RV_REG_T0), ctx);
35962306a36Sopenharmony_ci		}
36062306a36Sopenharmony_ci		break;
36162306a36Sopenharmony_ci	case BPF_OR:
36262306a36Sopenharmony_ci		if (is_12b_int(imm)) {
36362306a36Sopenharmony_ci			emit(rv_ori(lo(rd), lo(rd), imm), ctx);
36462306a36Sopenharmony_ci		} else {
36562306a36Sopenharmony_ci			emit_imm(RV_REG_T0, imm, ctx);
36662306a36Sopenharmony_ci			emit(rv_or(lo(rd), lo(rd), RV_REG_T0), ctx);
36762306a36Sopenharmony_ci		}
36862306a36Sopenharmony_ci		break;
36962306a36Sopenharmony_ci	case BPF_XOR:
37062306a36Sopenharmony_ci		if (is_12b_int(imm)) {
37162306a36Sopenharmony_ci			emit(rv_xori(lo(rd), lo(rd), imm), ctx);
37262306a36Sopenharmony_ci		} else {
37362306a36Sopenharmony_ci			emit_imm(RV_REG_T0, imm, ctx);
37462306a36Sopenharmony_ci			emit(rv_xor(lo(rd), lo(rd), RV_REG_T0), ctx);
37562306a36Sopenharmony_ci		}
37662306a36Sopenharmony_ci		break;
37762306a36Sopenharmony_ci	case BPF_LSH:
37862306a36Sopenharmony_ci		if (is_12b_int(imm)) {
37962306a36Sopenharmony_ci			emit(rv_slli(lo(rd), lo(rd), imm), ctx);
38062306a36Sopenharmony_ci		} else {
38162306a36Sopenharmony_ci			emit_imm(RV_REG_T0, imm, ctx);
38262306a36Sopenharmony_ci			emit(rv_sll(lo(rd), lo(rd), RV_REG_T0), ctx);
38362306a36Sopenharmony_ci		}
38462306a36Sopenharmony_ci		break;
38562306a36Sopenharmony_ci	case BPF_RSH:
38662306a36Sopenharmony_ci		if (is_12b_int(imm)) {
38762306a36Sopenharmony_ci			emit(rv_srli(lo(rd), lo(rd), imm), ctx);
38862306a36Sopenharmony_ci		} else {
38962306a36Sopenharmony_ci			emit_imm(RV_REG_T0, imm, ctx);
39062306a36Sopenharmony_ci			emit(rv_srl(lo(rd), lo(rd), RV_REG_T0), ctx);
39162306a36Sopenharmony_ci		}
39262306a36Sopenharmony_ci		break;
39362306a36Sopenharmony_ci	case BPF_ARSH:
39462306a36Sopenharmony_ci		if (is_12b_int(imm)) {
39562306a36Sopenharmony_ci			emit(rv_srai(lo(rd), lo(rd), imm), ctx);
39662306a36Sopenharmony_ci		} else {
39762306a36Sopenharmony_ci			emit_imm(RV_REG_T0, imm, ctx);
39862306a36Sopenharmony_ci			emit(rv_sra(lo(rd), lo(rd), RV_REG_T0), ctx);
39962306a36Sopenharmony_ci		}
40062306a36Sopenharmony_ci		break;
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	bpf_put_reg32(dst, rd, ctx);
40462306a36Sopenharmony_ci}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_cistatic void emit_alu_r64(const s8 *dst, const s8 *src,
40762306a36Sopenharmony_ci			 struct rv_jit_context *ctx, const u8 op)
40862306a36Sopenharmony_ci{
40962306a36Sopenharmony_ci	const s8 *tmp1 = bpf2rv32[TMP_REG_1];
41062306a36Sopenharmony_ci	const s8 *tmp2 = bpf2rv32[TMP_REG_2];
41162306a36Sopenharmony_ci	const s8 *rd = bpf_get_reg64(dst, tmp1, ctx);
41262306a36Sopenharmony_ci	const s8 *rs = bpf_get_reg64(src, tmp2, ctx);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	switch (op) {
41562306a36Sopenharmony_ci	case BPF_MOV:
41662306a36Sopenharmony_ci		emit(rv_addi(lo(rd), lo(rs), 0), ctx);
41762306a36Sopenharmony_ci		emit(rv_addi(hi(rd), hi(rs), 0), ctx);
41862306a36Sopenharmony_ci		break;
41962306a36Sopenharmony_ci	case BPF_ADD:
42062306a36Sopenharmony_ci		if (rd == rs) {
42162306a36Sopenharmony_ci			emit(rv_srli(RV_REG_T0, lo(rd), 31), ctx);
42262306a36Sopenharmony_ci			emit(rv_slli(hi(rd), hi(rd), 1), ctx);
42362306a36Sopenharmony_ci			emit(rv_or(hi(rd), RV_REG_T0, hi(rd)), ctx);
42462306a36Sopenharmony_ci			emit(rv_slli(lo(rd), lo(rd), 1), ctx);
42562306a36Sopenharmony_ci		} else {
42662306a36Sopenharmony_ci			emit(rv_add(lo(rd), lo(rd), lo(rs)), ctx);
42762306a36Sopenharmony_ci			emit(rv_sltu(RV_REG_T0, lo(rd), lo(rs)), ctx);
42862306a36Sopenharmony_ci			emit(rv_add(hi(rd), hi(rd), hi(rs)), ctx);
42962306a36Sopenharmony_ci			emit(rv_add(hi(rd), hi(rd), RV_REG_T0), ctx);
43062306a36Sopenharmony_ci		}
43162306a36Sopenharmony_ci		break;
43262306a36Sopenharmony_ci	case BPF_SUB:
43362306a36Sopenharmony_ci		emit(rv_sub(RV_REG_T1, hi(rd), hi(rs)), ctx);
43462306a36Sopenharmony_ci		emit(rv_sltu(RV_REG_T0, lo(rd), lo(rs)), ctx);
43562306a36Sopenharmony_ci		emit(rv_sub(hi(rd), RV_REG_T1, RV_REG_T0), ctx);
43662306a36Sopenharmony_ci		emit(rv_sub(lo(rd), lo(rd), lo(rs)), ctx);
43762306a36Sopenharmony_ci		break;
43862306a36Sopenharmony_ci	case BPF_AND:
43962306a36Sopenharmony_ci		emit(rv_and(lo(rd), lo(rd), lo(rs)), ctx);
44062306a36Sopenharmony_ci		emit(rv_and(hi(rd), hi(rd), hi(rs)), ctx);
44162306a36Sopenharmony_ci		break;
44262306a36Sopenharmony_ci	case BPF_OR:
44362306a36Sopenharmony_ci		emit(rv_or(lo(rd), lo(rd), lo(rs)), ctx);
44462306a36Sopenharmony_ci		emit(rv_or(hi(rd), hi(rd), hi(rs)), ctx);
44562306a36Sopenharmony_ci		break;
44662306a36Sopenharmony_ci	case BPF_XOR:
44762306a36Sopenharmony_ci		emit(rv_xor(lo(rd), lo(rd), lo(rs)), ctx);
44862306a36Sopenharmony_ci		emit(rv_xor(hi(rd), hi(rd), hi(rs)), ctx);
44962306a36Sopenharmony_ci		break;
45062306a36Sopenharmony_ci	case BPF_MUL:
45162306a36Sopenharmony_ci		emit(rv_mul(RV_REG_T0, hi(rs), lo(rd)), ctx);
45262306a36Sopenharmony_ci		emit(rv_mul(hi(rd), hi(rd), lo(rs)), ctx);
45362306a36Sopenharmony_ci		emit(rv_mulhu(RV_REG_T1, lo(rd), lo(rs)), ctx);
45462306a36Sopenharmony_ci		emit(rv_add(hi(rd), hi(rd), RV_REG_T0), ctx);
45562306a36Sopenharmony_ci		emit(rv_mul(lo(rd), lo(rd), lo(rs)), ctx);
45662306a36Sopenharmony_ci		emit(rv_add(hi(rd), hi(rd), RV_REG_T1), ctx);
45762306a36Sopenharmony_ci		break;
45862306a36Sopenharmony_ci	case BPF_LSH:
45962306a36Sopenharmony_ci		emit(rv_addi(RV_REG_T0, lo(rs), -32), ctx);
46062306a36Sopenharmony_ci		emit(rv_blt(RV_REG_T0, RV_REG_ZERO, 8), ctx);
46162306a36Sopenharmony_ci		emit(rv_sll(hi(rd), lo(rd), RV_REG_T0), ctx);
46262306a36Sopenharmony_ci		emit(rv_addi(lo(rd), RV_REG_ZERO, 0), ctx);
46362306a36Sopenharmony_ci		emit(rv_jal(RV_REG_ZERO, 16), ctx);
46462306a36Sopenharmony_ci		emit(rv_addi(RV_REG_T1, RV_REG_ZERO, 31), ctx);
46562306a36Sopenharmony_ci		emit(rv_srli(RV_REG_T0, lo(rd), 1), ctx);
46662306a36Sopenharmony_ci		emit(rv_sub(RV_REG_T1, RV_REG_T1, lo(rs)), ctx);
46762306a36Sopenharmony_ci		emit(rv_srl(RV_REG_T0, RV_REG_T0, RV_REG_T1), ctx);
46862306a36Sopenharmony_ci		emit(rv_sll(hi(rd), hi(rd), lo(rs)), ctx);
46962306a36Sopenharmony_ci		emit(rv_or(hi(rd), RV_REG_T0, hi(rd)), ctx);
47062306a36Sopenharmony_ci		emit(rv_sll(lo(rd), lo(rd), lo(rs)), ctx);
47162306a36Sopenharmony_ci		break;
47262306a36Sopenharmony_ci	case BPF_RSH:
47362306a36Sopenharmony_ci		emit(rv_addi(RV_REG_T0, lo(rs), -32), ctx);
47462306a36Sopenharmony_ci		emit(rv_blt(RV_REG_T0, RV_REG_ZERO, 8), ctx);
47562306a36Sopenharmony_ci		emit(rv_srl(lo(rd), hi(rd), RV_REG_T0), ctx);
47662306a36Sopenharmony_ci		emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx);
47762306a36Sopenharmony_ci		emit(rv_jal(RV_REG_ZERO, 16), ctx);
47862306a36Sopenharmony_ci		emit(rv_addi(RV_REG_T1, RV_REG_ZERO, 31), ctx);
47962306a36Sopenharmony_ci		emit(rv_slli(RV_REG_T0, hi(rd), 1), ctx);
48062306a36Sopenharmony_ci		emit(rv_sub(RV_REG_T1, RV_REG_T1, lo(rs)), ctx);
48162306a36Sopenharmony_ci		emit(rv_sll(RV_REG_T0, RV_REG_T0, RV_REG_T1), ctx);
48262306a36Sopenharmony_ci		emit(rv_srl(lo(rd), lo(rd), lo(rs)), ctx);
48362306a36Sopenharmony_ci		emit(rv_or(lo(rd), RV_REG_T0, lo(rd)), ctx);
48462306a36Sopenharmony_ci		emit(rv_srl(hi(rd), hi(rd), lo(rs)), ctx);
48562306a36Sopenharmony_ci		break;
48662306a36Sopenharmony_ci	case BPF_ARSH:
48762306a36Sopenharmony_ci		emit(rv_addi(RV_REG_T0, lo(rs), -32), ctx);
48862306a36Sopenharmony_ci		emit(rv_blt(RV_REG_T0, RV_REG_ZERO, 8), ctx);
48962306a36Sopenharmony_ci		emit(rv_sra(lo(rd), hi(rd), RV_REG_T0), ctx);
49062306a36Sopenharmony_ci		emit(rv_srai(hi(rd), hi(rd), 31), ctx);
49162306a36Sopenharmony_ci		emit(rv_jal(RV_REG_ZERO, 16), ctx);
49262306a36Sopenharmony_ci		emit(rv_addi(RV_REG_T1, RV_REG_ZERO, 31), ctx);
49362306a36Sopenharmony_ci		emit(rv_slli(RV_REG_T0, hi(rd), 1), ctx);
49462306a36Sopenharmony_ci		emit(rv_sub(RV_REG_T1, RV_REG_T1, lo(rs)), ctx);
49562306a36Sopenharmony_ci		emit(rv_sll(RV_REG_T0, RV_REG_T0, RV_REG_T1), ctx);
49662306a36Sopenharmony_ci		emit(rv_srl(lo(rd), lo(rd), lo(rs)), ctx);
49762306a36Sopenharmony_ci		emit(rv_or(lo(rd), RV_REG_T0, lo(rd)), ctx);
49862306a36Sopenharmony_ci		emit(rv_sra(hi(rd), hi(rd), lo(rs)), ctx);
49962306a36Sopenharmony_ci		break;
50062306a36Sopenharmony_ci	case BPF_NEG:
50162306a36Sopenharmony_ci		emit(rv_sub(lo(rd), RV_REG_ZERO, lo(rd)), ctx);
50262306a36Sopenharmony_ci		emit(rv_sltu(RV_REG_T0, RV_REG_ZERO, lo(rd)), ctx);
50362306a36Sopenharmony_ci		emit(rv_sub(hi(rd), RV_REG_ZERO, hi(rd)), ctx);
50462306a36Sopenharmony_ci		emit(rv_sub(hi(rd), hi(rd), RV_REG_T0), ctx);
50562306a36Sopenharmony_ci		break;
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	bpf_put_reg64(dst, rd, ctx);
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_cistatic void emit_alu_r32(const s8 *dst, const s8 *src,
51262306a36Sopenharmony_ci			 struct rv_jit_context *ctx, const u8 op)
51362306a36Sopenharmony_ci{
51462306a36Sopenharmony_ci	const s8 *tmp1 = bpf2rv32[TMP_REG_1];
51562306a36Sopenharmony_ci	const s8 *tmp2 = bpf2rv32[TMP_REG_2];
51662306a36Sopenharmony_ci	const s8 *rd = bpf_get_reg32(dst, tmp1, ctx);
51762306a36Sopenharmony_ci	const s8 *rs = bpf_get_reg32(src, tmp2, ctx);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	switch (op) {
52062306a36Sopenharmony_ci	case BPF_MOV:
52162306a36Sopenharmony_ci		emit(rv_addi(lo(rd), lo(rs), 0), ctx);
52262306a36Sopenharmony_ci		break;
52362306a36Sopenharmony_ci	case BPF_ADD:
52462306a36Sopenharmony_ci		emit(rv_add(lo(rd), lo(rd), lo(rs)), ctx);
52562306a36Sopenharmony_ci		break;
52662306a36Sopenharmony_ci	case BPF_SUB:
52762306a36Sopenharmony_ci		emit(rv_sub(lo(rd), lo(rd), lo(rs)), ctx);
52862306a36Sopenharmony_ci		break;
52962306a36Sopenharmony_ci	case BPF_AND:
53062306a36Sopenharmony_ci		emit(rv_and(lo(rd), lo(rd), lo(rs)), ctx);
53162306a36Sopenharmony_ci		break;
53262306a36Sopenharmony_ci	case BPF_OR:
53362306a36Sopenharmony_ci		emit(rv_or(lo(rd), lo(rd), lo(rs)), ctx);
53462306a36Sopenharmony_ci		break;
53562306a36Sopenharmony_ci	case BPF_XOR:
53662306a36Sopenharmony_ci		emit(rv_xor(lo(rd), lo(rd), lo(rs)), ctx);
53762306a36Sopenharmony_ci		break;
53862306a36Sopenharmony_ci	case BPF_MUL:
53962306a36Sopenharmony_ci		emit(rv_mul(lo(rd), lo(rd), lo(rs)), ctx);
54062306a36Sopenharmony_ci		break;
54162306a36Sopenharmony_ci	case BPF_DIV:
54262306a36Sopenharmony_ci		emit(rv_divu(lo(rd), lo(rd), lo(rs)), ctx);
54362306a36Sopenharmony_ci		break;
54462306a36Sopenharmony_ci	case BPF_MOD:
54562306a36Sopenharmony_ci		emit(rv_remu(lo(rd), lo(rd), lo(rs)), ctx);
54662306a36Sopenharmony_ci		break;
54762306a36Sopenharmony_ci	case BPF_LSH:
54862306a36Sopenharmony_ci		emit(rv_sll(lo(rd), lo(rd), lo(rs)), ctx);
54962306a36Sopenharmony_ci		break;
55062306a36Sopenharmony_ci	case BPF_RSH:
55162306a36Sopenharmony_ci		emit(rv_srl(lo(rd), lo(rd), lo(rs)), ctx);
55262306a36Sopenharmony_ci		break;
55362306a36Sopenharmony_ci	case BPF_ARSH:
55462306a36Sopenharmony_ci		emit(rv_sra(lo(rd), lo(rd), lo(rs)), ctx);
55562306a36Sopenharmony_ci		break;
55662306a36Sopenharmony_ci	case BPF_NEG:
55762306a36Sopenharmony_ci		emit(rv_sub(lo(rd), RV_REG_ZERO, lo(rd)), ctx);
55862306a36Sopenharmony_ci		break;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	bpf_put_reg32(dst, rd, ctx);
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic int emit_branch_r64(const s8 *src1, const s8 *src2, s32 rvoff,
56562306a36Sopenharmony_ci			   struct rv_jit_context *ctx, const u8 op)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	int e, s = ctx->ninsns;
56862306a36Sopenharmony_ci	const s8 *tmp1 = bpf2rv32[TMP_REG_1];
56962306a36Sopenharmony_ci	const s8 *tmp2 = bpf2rv32[TMP_REG_2];
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	const s8 *rs1 = bpf_get_reg64(src1, tmp1, ctx);
57262306a36Sopenharmony_ci	const s8 *rs2 = bpf_get_reg64(src2, tmp2, ctx);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/*
57562306a36Sopenharmony_ci	 * NO_JUMP skips over the rest of the instructions and the
57662306a36Sopenharmony_ci	 * emit_jump_and_link, meaning the BPF branch is not taken.
57762306a36Sopenharmony_ci	 * JUMP skips directly to the emit_jump_and_link, meaning
57862306a36Sopenharmony_ci	 * the BPF branch is taken.
57962306a36Sopenharmony_ci	 *
58062306a36Sopenharmony_ci	 * The fallthrough case results in the BPF branch being taken.
58162306a36Sopenharmony_ci	 */
58262306a36Sopenharmony_ci#define NO_JUMP(idx) (6 + (2 * (idx)))
58362306a36Sopenharmony_ci#define JUMP(idx) (2 + (2 * (idx)))
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	switch (op) {
58662306a36Sopenharmony_ci	case BPF_JEQ:
58762306a36Sopenharmony_ci		emit(rv_bne(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
58862306a36Sopenharmony_ci		emit(rv_bne(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
58962306a36Sopenharmony_ci		break;
59062306a36Sopenharmony_ci	case BPF_JGT:
59162306a36Sopenharmony_ci		emit(rv_bgtu(hi(rs1), hi(rs2), JUMP(2)), ctx);
59262306a36Sopenharmony_ci		emit(rv_bltu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
59362306a36Sopenharmony_ci		emit(rv_bleu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
59462306a36Sopenharmony_ci		break;
59562306a36Sopenharmony_ci	case BPF_JLT:
59662306a36Sopenharmony_ci		emit(rv_bltu(hi(rs1), hi(rs2), JUMP(2)), ctx);
59762306a36Sopenharmony_ci		emit(rv_bgtu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
59862306a36Sopenharmony_ci		emit(rv_bgeu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
59962306a36Sopenharmony_ci		break;
60062306a36Sopenharmony_ci	case BPF_JGE:
60162306a36Sopenharmony_ci		emit(rv_bgtu(hi(rs1), hi(rs2), JUMP(2)), ctx);
60262306a36Sopenharmony_ci		emit(rv_bltu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
60362306a36Sopenharmony_ci		emit(rv_bltu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
60462306a36Sopenharmony_ci		break;
60562306a36Sopenharmony_ci	case BPF_JLE:
60662306a36Sopenharmony_ci		emit(rv_bltu(hi(rs1), hi(rs2), JUMP(2)), ctx);
60762306a36Sopenharmony_ci		emit(rv_bgtu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
60862306a36Sopenharmony_ci		emit(rv_bgtu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
60962306a36Sopenharmony_ci		break;
61062306a36Sopenharmony_ci	case BPF_JNE:
61162306a36Sopenharmony_ci		emit(rv_bne(hi(rs1), hi(rs2), JUMP(1)), ctx);
61262306a36Sopenharmony_ci		emit(rv_beq(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
61362306a36Sopenharmony_ci		break;
61462306a36Sopenharmony_ci	case BPF_JSGT:
61562306a36Sopenharmony_ci		emit(rv_bgt(hi(rs1), hi(rs2), JUMP(2)), ctx);
61662306a36Sopenharmony_ci		emit(rv_blt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
61762306a36Sopenharmony_ci		emit(rv_bleu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
61862306a36Sopenharmony_ci		break;
61962306a36Sopenharmony_ci	case BPF_JSLT:
62062306a36Sopenharmony_ci		emit(rv_blt(hi(rs1), hi(rs2), JUMP(2)), ctx);
62162306a36Sopenharmony_ci		emit(rv_bgt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
62262306a36Sopenharmony_ci		emit(rv_bgeu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
62362306a36Sopenharmony_ci		break;
62462306a36Sopenharmony_ci	case BPF_JSGE:
62562306a36Sopenharmony_ci		emit(rv_bgt(hi(rs1), hi(rs2), JUMP(2)), ctx);
62662306a36Sopenharmony_ci		emit(rv_blt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
62762306a36Sopenharmony_ci		emit(rv_bltu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
62862306a36Sopenharmony_ci		break;
62962306a36Sopenharmony_ci	case BPF_JSLE:
63062306a36Sopenharmony_ci		emit(rv_blt(hi(rs1), hi(rs2), JUMP(2)), ctx);
63162306a36Sopenharmony_ci		emit(rv_bgt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
63262306a36Sopenharmony_ci		emit(rv_bgtu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
63362306a36Sopenharmony_ci		break;
63462306a36Sopenharmony_ci	case BPF_JSET:
63562306a36Sopenharmony_ci		emit(rv_and(RV_REG_T0, hi(rs1), hi(rs2)), ctx);
63662306a36Sopenharmony_ci		emit(rv_bne(RV_REG_T0, RV_REG_ZERO, JUMP(2)), ctx);
63762306a36Sopenharmony_ci		emit(rv_and(RV_REG_T0, lo(rs1), lo(rs2)), ctx);
63862306a36Sopenharmony_ci		emit(rv_beq(RV_REG_T0, RV_REG_ZERO, NO_JUMP(0)), ctx);
63962306a36Sopenharmony_ci		break;
64062306a36Sopenharmony_ci	}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci#undef NO_JUMP
64362306a36Sopenharmony_ci#undef JUMP
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	e = ctx->ninsns;
64662306a36Sopenharmony_ci	/* Adjust for extra insns. */
64762306a36Sopenharmony_ci	rvoff -= ninsns_rvoff(e - s);
64862306a36Sopenharmony_ci	emit_jump_and_link(RV_REG_ZERO, rvoff, true, ctx);
64962306a36Sopenharmony_ci	return 0;
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cistatic int emit_bcc(u8 op, u8 rd, u8 rs, int rvoff, struct rv_jit_context *ctx)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	int e, s = ctx->ninsns;
65562306a36Sopenharmony_ci	bool far = false;
65662306a36Sopenharmony_ci	int off;
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	if (op == BPF_JSET) {
65962306a36Sopenharmony_ci		/*
66062306a36Sopenharmony_ci		 * BPF_JSET is a special case: it has no inverse so we always
66162306a36Sopenharmony_ci		 * treat it as a far branch.
66262306a36Sopenharmony_ci		 */
66362306a36Sopenharmony_ci		far = true;
66462306a36Sopenharmony_ci	} else if (!is_13b_int(rvoff)) {
66562306a36Sopenharmony_ci		op = invert_bpf_cond(op);
66662306a36Sopenharmony_ci		far = true;
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	/*
67062306a36Sopenharmony_ci	 * For a far branch, the condition is negated and we jump over the
67162306a36Sopenharmony_ci	 * branch itself, and the two instructions from emit_jump_and_link.
67262306a36Sopenharmony_ci	 * For a near branch, just use rvoff.
67362306a36Sopenharmony_ci	 */
67462306a36Sopenharmony_ci	off = far ? 6 : (rvoff >> 1);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	switch (op) {
67762306a36Sopenharmony_ci	case BPF_JEQ:
67862306a36Sopenharmony_ci		emit(rv_beq(rd, rs, off), ctx);
67962306a36Sopenharmony_ci		break;
68062306a36Sopenharmony_ci	case BPF_JGT:
68162306a36Sopenharmony_ci		emit(rv_bgtu(rd, rs, off), ctx);
68262306a36Sopenharmony_ci		break;
68362306a36Sopenharmony_ci	case BPF_JLT:
68462306a36Sopenharmony_ci		emit(rv_bltu(rd, rs, off), ctx);
68562306a36Sopenharmony_ci		break;
68662306a36Sopenharmony_ci	case BPF_JGE:
68762306a36Sopenharmony_ci		emit(rv_bgeu(rd, rs, off), ctx);
68862306a36Sopenharmony_ci		break;
68962306a36Sopenharmony_ci	case BPF_JLE:
69062306a36Sopenharmony_ci		emit(rv_bleu(rd, rs, off), ctx);
69162306a36Sopenharmony_ci		break;
69262306a36Sopenharmony_ci	case BPF_JNE:
69362306a36Sopenharmony_ci		emit(rv_bne(rd, rs, off), ctx);
69462306a36Sopenharmony_ci		break;
69562306a36Sopenharmony_ci	case BPF_JSGT:
69662306a36Sopenharmony_ci		emit(rv_bgt(rd, rs, off), ctx);
69762306a36Sopenharmony_ci		break;
69862306a36Sopenharmony_ci	case BPF_JSLT:
69962306a36Sopenharmony_ci		emit(rv_blt(rd, rs, off), ctx);
70062306a36Sopenharmony_ci		break;
70162306a36Sopenharmony_ci	case BPF_JSGE:
70262306a36Sopenharmony_ci		emit(rv_bge(rd, rs, off), ctx);
70362306a36Sopenharmony_ci		break;
70462306a36Sopenharmony_ci	case BPF_JSLE:
70562306a36Sopenharmony_ci		emit(rv_ble(rd, rs, off), ctx);
70662306a36Sopenharmony_ci		break;
70762306a36Sopenharmony_ci	case BPF_JSET:
70862306a36Sopenharmony_ci		emit(rv_and(RV_REG_T0, rd, rs), ctx);
70962306a36Sopenharmony_ci		emit(rv_beq(RV_REG_T0, RV_REG_ZERO, off), ctx);
71062306a36Sopenharmony_ci		break;
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (far) {
71462306a36Sopenharmony_ci		e = ctx->ninsns;
71562306a36Sopenharmony_ci		/* Adjust for extra insns. */
71662306a36Sopenharmony_ci		rvoff -= ninsns_rvoff(e - s);
71762306a36Sopenharmony_ci		emit_jump_and_link(RV_REG_ZERO, rvoff, true, ctx);
71862306a36Sopenharmony_ci	}
71962306a36Sopenharmony_ci	return 0;
72062306a36Sopenharmony_ci}
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_cistatic int emit_branch_r32(const s8 *src1, const s8 *src2, s32 rvoff,
72362306a36Sopenharmony_ci			   struct rv_jit_context *ctx, const u8 op)
72462306a36Sopenharmony_ci{
72562306a36Sopenharmony_ci	int e, s = ctx->ninsns;
72662306a36Sopenharmony_ci	const s8 *tmp1 = bpf2rv32[TMP_REG_1];
72762306a36Sopenharmony_ci	const s8 *tmp2 = bpf2rv32[TMP_REG_2];
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	const s8 *rs1 = bpf_get_reg32(src1, tmp1, ctx);
73062306a36Sopenharmony_ci	const s8 *rs2 = bpf_get_reg32(src2, tmp2, ctx);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	e = ctx->ninsns;
73362306a36Sopenharmony_ci	/* Adjust for extra insns. */
73462306a36Sopenharmony_ci	rvoff -= ninsns_rvoff(e - s);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	if (emit_bcc(op, lo(rs1), lo(rs2), rvoff, ctx))
73762306a36Sopenharmony_ci		return -1;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	return 0;
74062306a36Sopenharmony_ci}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_cistatic void emit_call(bool fixed, u64 addr, struct rv_jit_context *ctx)
74362306a36Sopenharmony_ci{
74462306a36Sopenharmony_ci	const s8 *r0 = bpf2rv32[BPF_REG_0];
74562306a36Sopenharmony_ci	const s8 *r5 = bpf2rv32[BPF_REG_5];
74662306a36Sopenharmony_ci	u32 upper = ((u32)addr + (1 << 11)) >> 12;
74762306a36Sopenharmony_ci	u32 lower = addr & 0xfff;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	/* R1-R4 already in correct registers---need to push R5 to stack. */
75062306a36Sopenharmony_ci	emit(rv_addi(RV_REG_SP, RV_REG_SP, -16), ctx);
75162306a36Sopenharmony_ci	emit(rv_sw(RV_REG_SP, 0, lo(r5)), ctx);
75262306a36Sopenharmony_ci	emit(rv_sw(RV_REG_SP, 4, hi(r5)), ctx);
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	/* Backup TCC. */
75562306a36Sopenharmony_ci	emit(rv_addi(RV_REG_TCC_SAVED, RV_REG_TCC, 0), ctx);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/*
75862306a36Sopenharmony_ci	 * Use lui/jalr pair to jump to absolute address. Don't use emit_imm as
75962306a36Sopenharmony_ci	 * the number of emitted instructions should not depend on the value of
76062306a36Sopenharmony_ci	 * addr.
76162306a36Sopenharmony_ci	 */
76262306a36Sopenharmony_ci	emit(rv_lui(RV_REG_T1, upper), ctx);
76362306a36Sopenharmony_ci	emit(rv_jalr(RV_REG_RA, RV_REG_T1, lower), ctx);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	/* Restore TCC. */
76662306a36Sopenharmony_ci	emit(rv_addi(RV_REG_TCC, RV_REG_TCC_SAVED, 0), ctx);
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	/* Set return value and restore stack. */
76962306a36Sopenharmony_ci	emit(rv_addi(lo(r0), RV_REG_A0, 0), ctx);
77062306a36Sopenharmony_ci	emit(rv_addi(hi(r0), RV_REG_A1, 0), ctx);
77162306a36Sopenharmony_ci	emit(rv_addi(RV_REG_SP, RV_REG_SP, 16), ctx);
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic int emit_bpf_tail_call(int insn, struct rv_jit_context *ctx)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	/*
77762306a36Sopenharmony_ci	 * R1 -> &ctx
77862306a36Sopenharmony_ci	 * R2 -> &array
77962306a36Sopenharmony_ci	 * R3 -> index
78062306a36Sopenharmony_ci	 */
78162306a36Sopenharmony_ci	int tc_ninsn, off, start_insn = ctx->ninsns;
78262306a36Sopenharmony_ci	const s8 *arr_reg = bpf2rv32[BPF_REG_2];
78362306a36Sopenharmony_ci	const s8 *idx_reg = bpf2rv32[BPF_REG_3];
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci	tc_ninsn = insn ? ctx->offset[insn] - ctx->offset[insn - 1] :
78662306a36Sopenharmony_ci		ctx->offset[0];
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	/* max_entries = array->map.max_entries; */
78962306a36Sopenharmony_ci	off = offsetof(struct bpf_array, map.max_entries);
79062306a36Sopenharmony_ci	if (is_12b_check(off, insn))
79162306a36Sopenharmony_ci		return -1;
79262306a36Sopenharmony_ci	emit(rv_lw(RV_REG_T1, off, lo(arr_reg)), ctx);
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	/*
79562306a36Sopenharmony_ci	 * if (index >= max_entries)
79662306a36Sopenharmony_ci	 *   goto out;
79762306a36Sopenharmony_ci	 */
79862306a36Sopenharmony_ci	off = ninsns_rvoff(tc_ninsn - (ctx->ninsns - start_insn));
79962306a36Sopenharmony_ci	emit_bcc(BPF_JGE, lo(idx_reg), RV_REG_T1, off, ctx);
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	/*
80262306a36Sopenharmony_ci	 * if (--tcc < 0)
80362306a36Sopenharmony_ci	 *   goto out;
80462306a36Sopenharmony_ci	 */
80562306a36Sopenharmony_ci	emit(rv_addi(RV_REG_TCC, RV_REG_TCC, -1), ctx);
80662306a36Sopenharmony_ci	off = ninsns_rvoff(tc_ninsn - (ctx->ninsns - start_insn));
80762306a36Sopenharmony_ci	emit_bcc(BPF_JSLT, RV_REG_TCC, RV_REG_ZERO, off, ctx);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	/*
81062306a36Sopenharmony_ci	 * prog = array->ptrs[index];
81162306a36Sopenharmony_ci	 * if (!prog)
81262306a36Sopenharmony_ci	 *   goto out;
81362306a36Sopenharmony_ci	 */
81462306a36Sopenharmony_ci	emit(rv_slli(RV_REG_T0, lo(idx_reg), 2), ctx);
81562306a36Sopenharmony_ci	emit(rv_add(RV_REG_T0, RV_REG_T0, lo(arr_reg)), ctx);
81662306a36Sopenharmony_ci	off = offsetof(struct bpf_array, ptrs);
81762306a36Sopenharmony_ci	if (is_12b_check(off, insn))
81862306a36Sopenharmony_ci		return -1;
81962306a36Sopenharmony_ci	emit(rv_lw(RV_REG_T0, off, RV_REG_T0), ctx);
82062306a36Sopenharmony_ci	off = ninsns_rvoff(tc_ninsn - (ctx->ninsns - start_insn));
82162306a36Sopenharmony_ci	emit_bcc(BPF_JEQ, RV_REG_T0, RV_REG_ZERO, off, ctx);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	/*
82462306a36Sopenharmony_ci	 * tcc = temp_tcc;
82562306a36Sopenharmony_ci	 * goto *(prog->bpf_func + 4);
82662306a36Sopenharmony_ci	 */
82762306a36Sopenharmony_ci	off = offsetof(struct bpf_prog, bpf_func);
82862306a36Sopenharmony_ci	if (is_12b_check(off, insn))
82962306a36Sopenharmony_ci		return -1;
83062306a36Sopenharmony_ci	emit(rv_lw(RV_REG_T0, off, RV_REG_T0), ctx);
83162306a36Sopenharmony_ci	/* Epilogue jumps to *(t0 + 4). */
83262306a36Sopenharmony_ci	__build_epilogue(true, ctx);
83362306a36Sopenharmony_ci	return 0;
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic int emit_load_r64(const s8 *dst, const s8 *src, s16 off,
83762306a36Sopenharmony_ci			 struct rv_jit_context *ctx, const u8 size)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	const s8 *tmp1 = bpf2rv32[TMP_REG_1];
84062306a36Sopenharmony_ci	const s8 *tmp2 = bpf2rv32[TMP_REG_2];
84162306a36Sopenharmony_ci	const s8 *rd = bpf_get_reg64(dst, tmp1, ctx);
84262306a36Sopenharmony_ci	const s8 *rs = bpf_get_reg64(src, tmp2, ctx);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	emit_imm(RV_REG_T0, off, ctx);
84562306a36Sopenharmony_ci	emit(rv_add(RV_REG_T0, RV_REG_T0, lo(rs)), ctx);
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	switch (size) {
84862306a36Sopenharmony_ci	case BPF_B:
84962306a36Sopenharmony_ci		emit(rv_lbu(lo(rd), 0, RV_REG_T0), ctx);
85062306a36Sopenharmony_ci		if (!ctx->prog->aux->verifier_zext)
85162306a36Sopenharmony_ci			emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx);
85262306a36Sopenharmony_ci		break;
85362306a36Sopenharmony_ci	case BPF_H:
85462306a36Sopenharmony_ci		emit(rv_lhu(lo(rd), 0, RV_REG_T0), ctx);
85562306a36Sopenharmony_ci		if (!ctx->prog->aux->verifier_zext)
85662306a36Sopenharmony_ci			emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx);
85762306a36Sopenharmony_ci		break;
85862306a36Sopenharmony_ci	case BPF_W:
85962306a36Sopenharmony_ci		emit(rv_lw(lo(rd), 0, RV_REG_T0), ctx);
86062306a36Sopenharmony_ci		if (!ctx->prog->aux->verifier_zext)
86162306a36Sopenharmony_ci			emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx);
86262306a36Sopenharmony_ci		break;
86362306a36Sopenharmony_ci	case BPF_DW:
86462306a36Sopenharmony_ci		emit(rv_lw(lo(rd), 0, RV_REG_T0), ctx);
86562306a36Sopenharmony_ci		emit(rv_lw(hi(rd), 4, RV_REG_T0), ctx);
86662306a36Sopenharmony_ci		break;
86762306a36Sopenharmony_ci	}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	bpf_put_reg64(dst, rd, ctx);
87062306a36Sopenharmony_ci	return 0;
87162306a36Sopenharmony_ci}
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_cistatic int emit_store_r64(const s8 *dst, const s8 *src, s16 off,
87462306a36Sopenharmony_ci			  struct rv_jit_context *ctx, const u8 size,
87562306a36Sopenharmony_ci			  const u8 mode)
87662306a36Sopenharmony_ci{
87762306a36Sopenharmony_ci	const s8 *tmp1 = bpf2rv32[TMP_REG_1];
87862306a36Sopenharmony_ci	const s8 *tmp2 = bpf2rv32[TMP_REG_2];
87962306a36Sopenharmony_ci	const s8 *rd = bpf_get_reg64(dst, tmp1, ctx);
88062306a36Sopenharmony_ci	const s8 *rs = bpf_get_reg64(src, tmp2, ctx);
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	if (mode == BPF_ATOMIC && size != BPF_W)
88362306a36Sopenharmony_ci		return -1;
88462306a36Sopenharmony_ci
88562306a36Sopenharmony_ci	emit_imm(RV_REG_T0, off, ctx);
88662306a36Sopenharmony_ci	emit(rv_add(RV_REG_T0, RV_REG_T0, lo(rd)), ctx);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	switch (size) {
88962306a36Sopenharmony_ci	case BPF_B:
89062306a36Sopenharmony_ci		emit(rv_sb(RV_REG_T0, 0, lo(rs)), ctx);
89162306a36Sopenharmony_ci		break;
89262306a36Sopenharmony_ci	case BPF_H:
89362306a36Sopenharmony_ci		emit(rv_sh(RV_REG_T0, 0, lo(rs)), ctx);
89462306a36Sopenharmony_ci		break;
89562306a36Sopenharmony_ci	case BPF_W:
89662306a36Sopenharmony_ci		switch (mode) {
89762306a36Sopenharmony_ci		case BPF_MEM:
89862306a36Sopenharmony_ci			emit(rv_sw(RV_REG_T0, 0, lo(rs)), ctx);
89962306a36Sopenharmony_ci			break;
90062306a36Sopenharmony_ci		case BPF_ATOMIC: /* Only BPF_ADD supported */
90162306a36Sopenharmony_ci			emit(rv_amoadd_w(RV_REG_ZERO, lo(rs), RV_REG_T0, 0, 0),
90262306a36Sopenharmony_ci			     ctx);
90362306a36Sopenharmony_ci			break;
90462306a36Sopenharmony_ci		}
90562306a36Sopenharmony_ci		break;
90662306a36Sopenharmony_ci	case BPF_DW:
90762306a36Sopenharmony_ci		emit(rv_sw(RV_REG_T0, 0, lo(rs)), ctx);
90862306a36Sopenharmony_ci		emit(rv_sw(RV_REG_T0, 4, hi(rs)), ctx);
90962306a36Sopenharmony_ci		break;
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	return 0;
91362306a36Sopenharmony_ci}
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic void emit_rev16(const s8 rd, struct rv_jit_context *ctx)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	emit(rv_slli(rd, rd, 16), ctx);
91862306a36Sopenharmony_ci	emit(rv_slli(RV_REG_T1, rd, 8), ctx);
91962306a36Sopenharmony_ci	emit(rv_srli(rd, rd, 8), ctx);
92062306a36Sopenharmony_ci	emit(rv_add(RV_REG_T1, rd, RV_REG_T1), ctx);
92162306a36Sopenharmony_ci	emit(rv_srli(rd, RV_REG_T1, 16), ctx);
92262306a36Sopenharmony_ci}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cistatic void emit_rev32(const s8 rd, struct rv_jit_context *ctx)
92562306a36Sopenharmony_ci{
92662306a36Sopenharmony_ci	emit(rv_addi(RV_REG_T1, RV_REG_ZERO, 0), ctx);
92762306a36Sopenharmony_ci	emit(rv_andi(RV_REG_T0, rd, 255), ctx);
92862306a36Sopenharmony_ci	emit(rv_add(RV_REG_T1, RV_REG_T1, RV_REG_T0), ctx);
92962306a36Sopenharmony_ci	emit(rv_slli(RV_REG_T1, RV_REG_T1, 8), ctx);
93062306a36Sopenharmony_ci	emit(rv_srli(rd, rd, 8), ctx);
93162306a36Sopenharmony_ci	emit(rv_andi(RV_REG_T0, rd, 255), ctx);
93262306a36Sopenharmony_ci	emit(rv_add(RV_REG_T1, RV_REG_T1, RV_REG_T0), ctx);
93362306a36Sopenharmony_ci	emit(rv_slli(RV_REG_T1, RV_REG_T1, 8), ctx);
93462306a36Sopenharmony_ci	emit(rv_srli(rd, rd, 8), ctx);
93562306a36Sopenharmony_ci	emit(rv_andi(RV_REG_T0, rd, 255), ctx);
93662306a36Sopenharmony_ci	emit(rv_add(RV_REG_T1, RV_REG_T1, RV_REG_T0), ctx);
93762306a36Sopenharmony_ci	emit(rv_slli(RV_REG_T1, RV_REG_T1, 8), ctx);
93862306a36Sopenharmony_ci	emit(rv_srli(rd, rd, 8), ctx);
93962306a36Sopenharmony_ci	emit(rv_andi(RV_REG_T0, rd, 255), ctx);
94062306a36Sopenharmony_ci	emit(rv_add(RV_REG_T1, RV_REG_T1, RV_REG_T0), ctx);
94162306a36Sopenharmony_ci	emit(rv_addi(rd, RV_REG_T1, 0), ctx);
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic void emit_zext64(const s8 *dst, struct rv_jit_context *ctx)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	const s8 *rd;
94762306a36Sopenharmony_ci	const s8 *tmp1 = bpf2rv32[TMP_REG_1];
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	rd = bpf_get_reg64(dst, tmp1, ctx);
95062306a36Sopenharmony_ci	emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx);
95162306a36Sopenharmony_ci	bpf_put_reg64(dst, rd, ctx);
95262306a36Sopenharmony_ci}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ciint bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
95562306a36Sopenharmony_ci		      bool extra_pass)
95662306a36Sopenharmony_ci{
95762306a36Sopenharmony_ci	bool is64 = BPF_CLASS(insn->code) == BPF_ALU64 ||
95862306a36Sopenharmony_ci		BPF_CLASS(insn->code) == BPF_JMP;
95962306a36Sopenharmony_ci	int s, e, rvoff, i = insn - ctx->prog->insnsi;
96062306a36Sopenharmony_ci	u8 code = insn->code;
96162306a36Sopenharmony_ci	s16 off = insn->off;
96262306a36Sopenharmony_ci	s32 imm = insn->imm;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	const s8 *dst = bpf2rv32[insn->dst_reg];
96562306a36Sopenharmony_ci	const s8 *src = bpf2rv32[insn->src_reg];
96662306a36Sopenharmony_ci	const s8 *tmp1 = bpf2rv32[TMP_REG_1];
96762306a36Sopenharmony_ci	const s8 *tmp2 = bpf2rv32[TMP_REG_2];
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	switch (code) {
97062306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MOV | BPF_X:
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	case BPF_ALU64 | BPF_ADD | BPF_X:
97362306a36Sopenharmony_ci	case BPF_ALU64 | BPF_ADD | BPF_K:
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	case BPF_ALU64 | BPF_SUB | BPF_X:
97662306a36Sopenharmony_ci	case BPF_ALU64 | BPF_SUB | BPF_K:
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	case BPF_ALU64 | BPF_AND | BPF_X:
97962306a36Sopenharmony_ci	case BPF_ALU64 | BPF_OR | BPF_X:
98062306a36Sopenharmony_ci	case BPF_ALU64 | BPF_XOR | BPF_X:
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MUL | BPF_X:
98362306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MUL | BPF_K:
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	case BPF_ALU64 | BPF_LSH | BPF_X:
98662306a36Sopenharmony_ci	case BPF_ALU64 | BPF_RSH | BPF_X:
98762306a36Sopenharmony_ci	case BPF_ALU64 | BPF_ARSH | BPF_X:
98862306a36Sopenharmony_ci		if (BPF_SRC(code) == BPF_K) {
98962306a36Sopenharmony_ci			emit_imm32(tmp2, imm, ctx);
99062306a36Sopenharmony_ci			src = tmp2;
99162306a36Sopenharmony_ci		}
99262306a36Sopenharmony_ci		emit_alu_r64(dst, src, ctx, BPF_OP(code));
99362306a36Sopenharmony_ci		break;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	case BPF_ALU64 | BPF_NEG:
99662306a36Sopenharmony_ci		emit_alu_r64(dst, tmp2, ctx, BPF_OP(code));
99762306a36Sopenharmony_ci		break;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci	case BPF_ALU64 | BPF_DIV | BPF_X:
100062306a36Sopenharmony_ci	case BPF_ALU64 | BPF_DIV | BPF_K:
100162306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MOD | BPF_X:
100262306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MOD | BPF_K:
100362306a36Sopenharmony_ci		goto notsupported;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	case BPF_ALU64 | BPF_MOV | BPF_K:
100662306a36Sopenharmony_ci	case BPF_ALU64 | BPF_AND | BPF_K:
100762306a36Sopenharmony_ci	case BPF_ALU64 | BPF_OR | BPF_K:
100862306a36Sopenharmony_ci	case BPF_ALU64 | BPF_XOR | BPF_K:
100962306a36Sopenharmony_ci	case BPF_ALU64 | BPF_LSH | BPF_K:
101062306a36Sopenharmony_ci	case BPF_ALU64 | BPF_RSH | BPF_K:
101162306a36Sopenharmony_ci	case BPF_ALU64 | BPF_ARSH | BPF_K:
101262306a36Sopenharmony_ci		emit_alu_i64(dst, imm, ctx, BPF_OP(code));
101362306a36Sopenharmony_ci		break;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	case BPF_ALU | BPF_MOV | BPF_X:
101662306a36Sopenharmony_ci		if (imm == 1) {
101762306a36Sopenharmony_ci			/* Special mov32 for zext. */
101862306a36Sopenharmony_ci			emit_zext64(dst, ctx);
101962306a36Sopenharmony_ci			break;
102062306a36Sopenharmony_ci		}
102162306a36Sopenharmony_ci		fallthrough;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	case BPF_ALU | BPF_ADD | BPF_X:
102462306a36Sopenharmony_ci	case BPF_ALU | BPF_SUB | BPF_X:
102562306a36Sopenharmony_ci	case BPF_ALU | BPF_AND | BPF_X:
102662306a36Sopenharmony_ci	case BPF_ALU | BPF_OR | BPF_X:
102762306a36Sopenharmony_ci	case BPF_ALU | BPF_XOR | BPF_X:
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	case BPF_ALU | BPF_MUL | BPF_X:
103062306a36Sopenharmony_ci	case BPF_ALU | BPF_MUL | BPF_K:
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	case BPF_ALU | BPF_DIV | BPF_X:
103362306a36Sopenharmony_ci	case BPF_ALU | BPF_DIV | BPF_K:
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	case BPF_ALU | BPF_MOD | BPF_X:
103662306a36Sopenharmony_ci	case BPF_ALU | BPF_MOD | BPF_K:
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	case BPF_ALU | BPF_LSH | BPF_X:
103962306a36Sopenharmony_ci	case BPF_ALU | BPF_RSH | BPF_X:
104062306a36Sopenharmony_ci	case BPF_ALU | BPF_ARSH | BPF_X:
104162306a36Sopenharmony_ci		if (BPF_SRC(code) == BPF_K) {
104262306a36Sopenharmony_ci			emit_imm32(tmp2, imm, ctx);
104362306a36Sopenharmony_ci			src = tmp2;
104462306a36Sopenharmony_ci		}
104562306a36Sopenharmony_ci		emit_alu_r32(dst, src, ctx, BPF_OP(code));
104662306a36Sopenharmony_ci		break;
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	case BPF_ALU | BPF_MOV | BPF_K:
104962306a36Sopenharmony_ci	case BPF_ALU | BPF_ADD | BPF_K:
105062306a36Sopenharmony_ci	case BPF_ALU | BPF_SUB | BPF_K:
105162306a36Sopenharmony_ci	case BPF_ALU | BPF_AND | BPF_K:
105262306a36Sopenharmony_ci	case BPF_ALU | BPF_OR | BPF_K:
105362306a36Sopenharmony_ci	case BPF_ALU | BPF_XOR | BPF_K:
105462306a36Sopenharmony_ci	case BPF_ALU | BPF_LSH | BPF_K:
105562306a36Sopenharmony_ci	case BPF_ALU | BPF_RSH | BPF_K:
105662306a36Sopenharmony_ci	case BPF_ALU | BPF_ARSH | BPF_K:
105762306a36Sopenharmony_ci		/*
105862306a36Sopenharmony_ci		 * mul,div,mod are handled in the BPF_X case since there are
105962306a36Sopenharmony_ci		 * no RISC-V I-type equivalents.
106062306a36Sopenharmony_ci		 */
106162306a36Sopenharmony_ci		emit_alu_i32(dst, imm, ctx, BPF_OP(code));
106262306a36Sopenharmony_ci		break;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	case BPF_ALU | BPF_NEG:
106562306a36Sopenharmony_ci		/*
106662306a36Sopenharmony_ci		 * src is ignored---choose tmp2 as a dummy register since it
106762306a36Sopenharmony_ci		 * is not on the stack.
106862306a36Sopenharmony_ci		 */
106962306a36Sopenharmony_ci		emit_alu_r32(dst, tmp2, ctx, BPF_OP(code));
107062306a36Sopenharmony_ci		break;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	case BPF_ALU | BPF_END | BPF_FROM_LE:
107362306a36Sopenharmony_ci	{
107462306a36Sopenharmony_ci		const s8 *rd = bpf_get_reg64(dst, tmp1, ctx);
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci		switch (imm) {
107762306a36Sopenharmony_ci		case 16:
107862306a36Sopenharmony_ci			emit(rv_slli(lo(rd), lo(rd), 16), ctx);
107962306a36Sopenharmony_ci			emit(rv_srli(lo(rd), lo(rd), 16), ctx);
108062306a36Sopenharmony_ci			fallthrough;
108162306a36Sopenharmony_ci		case 32:
108262306a36Sopenharmony_ci			if (!ctx->prog->aux->verifier_zext)
108362306a36Sopenharmony_ci				emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx);
108462306a36Sopenharmony_ci			break;
108562306a36Sopenharmony_ci		case 64:
108662306a36Sopenharmony_ci			/* Do nothing. */
108762306a36Sopenharmony_ci			break;
108862306a36Sopenharmony_ci		default:
108962306a36Sopenharmony_ci			pr_err("bpf-jit: BPF_END imm %d invalid\n", imm);
109062306a36Sopenharmony_ci			return -1;
109162306a36Sopenharmony_ci		}
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci		bpf_put_reg64(dst, rd, ctx);
109462306a36Sopenharmony_ci		break;
109562306a36Sopenharmony_ci	}
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	case BPF_ALU | BPF_END | BPF_FROM_BE:
109862306a36Sopenharmony_ci	{
109962306a36Sopenharmony_ci		const s8 *rd = bpf_get_reg64(dst, tmp1, ctx);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci		switch (imm) {
110262306a36Sopenharmony_ci		case 16:
110362306a36Sopenharmony_ci			emit_rev16(lo(rd), ctx);
110462306a36Sopenharmony_ci			if (!ctx->prog->aux->verifier_zext)
110562306a36Sopenharmony_ci				emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx);
110662306a36Sopenharmony_ci			break;
110762306a36Sopenharmony_ci		case 32:
110862306a36Sopenharmony_ci			emit_rev32(lo(rd), ctx);
110962306a36Sopenharmony_ci			if (!ctx->prog->aux->verifier_zext)
111062306a36Sopenharmony_ci				emit(rv_addi(hi(rd), RV_REG_ZERO, 0), ctx);
111162306a36Sopenharmony_ci			break;
111262306a36Sopenharmony_ci		case 64:
111362306a36Sopenharmony_ci			/* Swap upper and lower halves. */
111462306a36Sopenharmony_ci			emit(rv_addi(RV_REG_T0, lo(rd), 0), ctx);
111562306a36Sopenharmony_ci			emit(rv_addi(lo(rd), hi(rd), 0), ctx);
111662306a36Sopenharmony_ci			emit(rv_addi(hi(rd), RV_REG_T0, 0), ctx);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci			/* Swap each half. */
111962306a36Sopenharmony_ci			emit_rev32(lo(rd), ctx);
112062306a36Sopenharmony_ci			emit_rev32(hi(rd), ctx);
112162306a36Sopenharmony_ci			break;
112262306a36Sopenharmony_ci		default:
112362306a36Sopenharmony_ci			pr_err("bpf-jit: BPF_END imm %d invalid\n", imm);
112462306a36Sopenharmony_ci			return -1;
112562306a36Sopenharmony_ci		}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci		bpf_put_reg64(dst, rd, ctx);
112862306a36Sopenharmony_ci		break;
112962306a36Sopenharmony_ci	}
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	case BPF_JMP | BPF_JA:
113262306a36Sopenharmony_ci		rvoff = rv_offset(i, off, ctx);
113362306a36Sopenharmony_ci		emit_jump_and_link(RV_REG_ZERO, rvoff, false, ctx);
113462306a36Sopenharmony_ci		break;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	case BPF_JMP | BPF_CALL:
113762306a36Sopenharmony_ci	{
113862306a36Sopenharmony_ci		bool fixed;
113962306a36Sopenharmony_ci		int ret;
114062306a36Sopenharmony_ci		u64 addr;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci		ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass, &addr,
114362306a36Sopenharmony_ci					    &fixed);
114462306a36Sopenharmony_ci		if (ret < 0)
114562306a36Sopenharmony_ci			return ret;
114662306a36Sopenharmony_ci		emit_call(fixed, addr, ctx);
114762306a36Sopenharmony_ci		break;
114862306a36Sopenharmony_ci	}
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	case BPF_JMP | BPF_TAIL_CALL:
115162306a36Sopenharmony_ci		if (emit_bpf_tail_call(i, ctx))
115262306a36Sopenharmony_ci			return -1;
115362306a36Sopenharmony_ci		break;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	case BPF_JMP | BPF_JEQ | BPF_X:
115662306a36Sopenharmony_ci	case BPF_JMP | BPF_JEQ | BPF_K:
115762306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JEQ | BPF_X:
115862306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JEQ | BPF_K:
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	case BPF_JMP | BPF_JNE | BPF_X:
116162306a36Sopenharmony_ci	case BPF_JMP | BPF_JNE | BPF_K:
116262306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JNE | BPF_X:
116362306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JNE | BPF_K:
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	case BPF_JMP | BPF_JLE | BPF_X:
116662306a36Sopenharmony_ci	case BPF_JMP | BPF_JLE | BPF_K:
116762306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JLE | BPF_X:
116862306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JLE | BPF_K:
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	case BPF_JMP | BPF_JLT | BPF_X:
117162306a36Sopenharmony_ci	case BPF_JMP | BPF_JLT | BPF_K:
117262306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JLT | BPF_X:
117362306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JLT | BPF_K:
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	case BPF_JMP | BPF_JGE | BPF_X:
117662306a36Sopenharmony_ci	case BPF_JMP | BPF_JGE | BPF_K:
117762306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JGE | BPF_X:
117862306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JGE | BPF_K:
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	case BPF_JMP | BPF_JGT | BPF_X:
118162306a36Sopenharmony_ci	case BPF_JMP | BPF_JGT | BPF_K:
118262306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JGT | BPF_X:
118362306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JGT | BPF_K:
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	case BPF_JMP | BPF_JSLE | BPF_X:
118662306a36Sopenharmony_ci	case BPF_JMP | BPF_JSLE | BPF_K:
118762306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSLE | BPF_X:
118862306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSLE | BPF_K:
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	case BPF_JMP | BPF_JSLT | BPF_X:
119162306a36Sopenharmony_ci	case BPF_JMP | BPF_JSLT | BPF_K:
119262306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSLT | BPF_X:
119362306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSLT | BPF_K:
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	case BPF_JMP | BPF_JSGE | BPF_X:
119662306a36Sopenharmony_ci	case BPF_JMP | BPF_JSGE | BPF_K:
119762306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSGE | BPF_X:
119862306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSGE | BPF_K:
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	case BPF_JMP | BPF_JSGT | BPF_X:
120162306a36Sopenharmony_ci	case BPF_JMP | BPF_JSGT | BPF_K:
120262306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSGT | BPF_X:
120362306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSGT | BPF_K:
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	case BPF_JMP | BPF_JSET | BPF_X:
120662306a36Sopenharmony_ci	case BPF_JMP | BPF_JSET | BPF_K:
120762306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSET | BPF_X:
120862306a36Sopenharmony_ci	case BPF_JMP32 | BPF_JSET | BPF_K:
120962306a36Sopenharmony_ci		rvoff = rv_offset(i, off, ctx);
121062306a36Sopenharmony_ci		if (BPF_SRC(code) == BPF_K) {
121162306a36Sopenharmony_ci			s = ctx->ninsns;
121262306a36Sopenharmony_ci			emit_imm32(tmp2, imm, ctx);
121362306a36Sopenharmony_ci			src = tmp2;
121462306a36Sopenharmony_ci			e = ctx->ninsns;
121562306a36Sopenharmony_ci			rvoff -= ninsns_rvoff(e - s);
121662306a36Sopenharmony_ci		}
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_ci		if (is64)
121962306a36Sopenharmony_ci			emit_branch_r64(dst, src, rvoff, ctx, BPF_OP(code));
122062306a36Sopenharmony_ci		else
122162306a36Sopenharmony_ci			emit_branch_r32(dst, src, rvoff, ctx, BPF_OP(code));
122262306a36Sopenharmony_ci		break;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci	case BPF_JMP | BPF_EXIT:
122562306a36Sopenharmony_ci		if (i == ctx->prog->len - 1)
122662306a36Sopenharmony_ci			break;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci		rvoff = epilogue_offset(ctx);
122962306a36Sopenharmony_ci		emit_jump_and_link(RV_REG_ZERO, rvoff, false, ctx);
123062306a36Sopenharmony_ci		break;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	case BPF_LD | BPF_IMM | BPF_DW:
123362306a36Sopenharmony_ci	{
123462306a36Sopenharmony_ci		struct bpf_insn insn1 = insn[1];
123562306a36Sopenharmony_ci		s32 imm_lo = imm;
123662306a36Sopenharmony_ci		s32 imm_hi = insn1.imm;
123762306a36Sopenharmony_ci		const s8 *rd = bpf_get_reg64(dst, tmp1, ctx);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci		emit_imm64(rd, imm_hi, imm_lo, ctx);
124062306a36Sopenharmony_ci		bpf_put_reg64(dst, rd, ctx);
124162306a36Sopenharmony_ci		return 1;
124262306a36Sopenharmony_ci	}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_B:
124562306a36Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_H:
124662306a36Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_W:
124762306a36Sopenharmony_ci	case BPF_LDX | BPF_MEM | BPF_DW:
124862306a36Sopenharmony_ci		if (emit_load_r64(dst, src, off, ctx, BPF_SIZE(code)))
124962306a36Sopenharmony_ci			return -1;
125062306a36Sopenharmony_ci		break;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	/* speculation barrier */
125362306a36Sopenharmony_ci	case BPF_ST | BPF_NOSPEC:
125462306a36Sopenharmony_ci		break;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_B:
125762306a36Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_H:
125862306a36Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_W:
125962306a36Sopenharmony_ci	case BPF_ST | BPF_MEM | BPF_DW:
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_B:
126262306a36Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_H:
126362306a36Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_W:
126462306a36Sopenharmony_ci	case BPF_STX | BPF_MEM | BPF_DW:
126562306a36Sopenharmony_ci		if (BPF_CLASS(code) == BPF_ST) {
126662306a36Sopenharmony_ci			emit_imm32(tmp2, imm, ctx);
126762306a36Sopenharmony_ci			src = tmp2;
126862306a36Sopenharmony_ci		}
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		if (emit_store_r64(dst, src, off, ctx, BPF_SIZE(code),
127162306a36Sopenharmony_ci				   BPF_MODE(code)))
127262306a36Sopenharmony_ci			return -1;
127362306a36Sopenharmony_ci		break;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	case BPF_STX | BPF_ATOMIC | BPF_W:
127662306a36Sopenharmony_ci		if (insn->imm != BPF_ADD) {
127762306a36Sopenharmony_ci			pr_info_once(
127862306a36Sopenharmony_ci				"bpf-jit: not supported: atomic operation %02x ***\n",
127962306a36Sopenharmony_ci				insn->imm);
128062306a36Sopenharmony_ci			return -EFAULT;
128162306a36Sopenharmony_ci		}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci		if (emit_store_r64(dst, src, off, ctx, BPF_SIZE(code),
128462306a36Sopenharmony_ci				   BPF_MODE(code)))
128562306a36Sopenharmony_ci			return -1;
128662306a36Sopenharmony_ci		break;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	/* No hardware support for 8-byte atomics in RV32. */
128962306a36Sopenharmony_ci	case BPF_STX | BPF_ATOMIC | BPF_DW:
129062306a36Sopenharmony_ci		/* Fallthrough. */
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_cinotsupported:
129362306a36Sopenharmony_ci		pr_info_once("bpf-jit: not supported: opcode %02x ***\n", code);
129462306a36Sopenharmony_ci		return -EFAULT;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	default:
129762306a36Sopenharmony_ci		pr_err("bpf-jit: unknown opcode %02x\n", code);
129862306a36Sopenharmony_ci		return -EINVAL;
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	return 0;
130262306a36Sopenharmony_ci}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_civoid bpf_jit_build_prologue(struct rv_jit_context *ctx)
130562306a36Sopenharmony_ci{
130662306a36Sopenharmony_ci	const s8 *fp = bpf2rv32[BPF_REG_FP];
130762306a36Sopenharmony_ci	const s8 *r1 = bpf2rv32[BPF_REG_1];
130862306a36Sopenharmony_ci	int stack_adjust = 0;
130962306a36Sopenharmony_ci	int bpf_stack_adjust =
131062306a36Sopenharmony_ci		round_up(ctx->prog->aux->stack_depth, STACK_ALIGN);
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	/* Make space for callee-saved registers. */
131362306a36Sopenharmony_ci	stack_adjust += NR_SAVED_REGISTERS * sizeof(u32);
131462306a36Sopenharmony_ci	/* Make space for BPF registers on stack. */
131562306a36Sopenharmony_ci	stack_adjust += BPF_JIT_SCRATCH_REGS * sizeof(u32);
131662306a36Sopenharmony_ci	/* Make space for BPF stack. */
131762306a36Sopenharmony_ci	stack_adjust += bpf_stack_adjust;
131862306a36Sopenharmony_ci	/* Round up for stack alignment. */
131962306a36Sopenharmony_ci	stack_adjust = round_up(stack_adjust, STACK_ALIGN);
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	/*
132262306a36Sopenharmony_ci	 * The first instruction sets the tail-call-counter (TCC) register.
132362306a36Sopenharmony_ci	 * This instruction is skipped by tail calls.
132462306a36Sopenharmony_ci	 */
132562306a36Sopenharmony_ci	emit(rv_addi(RV_REG_TCC, RV_REG_ZERO, MAX_TAIL_CALL_CNT), ctx);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	emit(rv_addi(RV_REG_SP, RV_REG_SP, -stack_adjust), ctx);
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	/* Save callee-save registers. */
133062306a36Sopenharmony_ci	emit(rv_sw(RV_REG_SP, stack_adjust - 4, RV_REG_RA), ctx);
133162306a36Sopenharmony_ci	emit(rv_sw(RV_REG_SP, stack_adjust - 8, RV_REG_FP), ctx);
133262306a36Sopenharmony_ci	emit(rv_sw(RV_REG_SP, stack_adjust - 12, RV_REG_S1), ctx);
133362306a36Sopenharmony_ci	emit(rv_sw(RV_REG_SP, stack_adjust - 16, RV_REG_S2), ctx);
133462306a36Sopenharmony_ci	emit(rv_sw(RV_REG_SP, stack_adjust - 20, RV_REG_S3), ctx);
133562306a36Sopenharmony_ci	emit(rv_sw(RV_REG_SP, stack_adjust - 24, RV_REG_S4), ctx);
133662306a36Sopenharmony_ci	emit(rv_sw(RV_REG_SP, stack_adjust - 28, RV_REG_S5), ctx);
133762306a36Sopenharmony_ci	emit(rv_sw(RV_REG_SP, stack_adjust - 32, RV_REG_S6), ctx);
133862306a36Sopenharmony_ci	emit(rv_sw(RV_REG_SP, stack_adjust - 36, RV_REG_S7), ctx);
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	/* Set fp: used as the base address for stacked BPF registers. */
134162306a36Sopenharmony_ci	emit(rv_addi(RV_REG_FP, RV_REG_SP, stack_adjust), ctx);
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	/* Set up BPF frame pointer. */
134462306a36Sopenharmony_ci	emit(rv_addi(lo(fp), RV_REG_SP, bpf_stack_adjust), ctx);
134562306a36Sopenharmony_ci	emit(rv_addi(hi(fp), RV_REG_ZERO, 0), ctx);
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	/* Set up BPF context pointer. */
134862306a36Sopenharmony_ci	emit(rv_addi(lo(r1), RV_REG_A0, 0), ctx);
134962306a36Sopenharmony_ci	emit(rv_addi(hi(r1), RV_REG_ZERO, 0), ctx);
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	ctx->stack_size = stack_adjust;
135262306a36Sopenharmony_ci}
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_civoid bpf_jit_build_epilogue(struct rv_jit_context *ctx)
135562306a36Sopenharmony_ci{
135662306a36Sopenharmony_ci	__build_epilogue(false, ctx);
135762306a36Sopenharmony_ci}
1358