in net/bpf_jit_comp32.c [564:650]
static int emit_branch_r64(const s8 *src1, const s8 *src2, s32 rvoff,
struct rv_jit_context *ctx, const u8 op)
{
int e, s = ctx->ninsns;
const s8 *tmp1 = bpf2rv32[TMP_REG_1];
const s8 *tmp2 = bpf2rv32[TMP_REG_2];
const s8 *rs1 = bpf_get_reg64(src1, tmp1, ctx);
const s8 *rs2 = bpf_get_reg64(src2, tmp2, ctx);
/*
* NO_JUMP skips over the rest of the instructions and the
* emit_jump_and_link, meaning the BPF branch is not taken.
* JUMP skips directly to the emit_jump_and_link, meaning
* the BPF branch is taken.
*
* The fallthrough case results in the BPF branch being taken.
*/
#define NO_JUMP(idx) (6 + (2 * (idx)))
#define JUMP(idx) (2 + (2 * (idx)))
switch (op) {
case BPF_JEQ:
emit(rv_bne(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
emit(rv_bne(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
break;
case BPF_JGT:
emit(rv_bgtu(hi(rs1), hi(rs2), JUMP(2)), ctx);
emit(rv_bltu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
emit(rv_bleu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
break;
case BPF_JLT:
emit(rv_bltu(hi(rs1), hi(rs2), JUMP(2)), ctx);
emit(rv_bgtu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
emit(rv_bgeu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
break;
case BPF_JGE:
emit(rv_bgtu(hi(rs1), hi(rs2), JUMP(2)), ctx);
emit(rv_bltu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
emit(rv_bltu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
break;
case BPF_JLE:
emit(rv_bltu(hi(rs1), hi(rs2), JUMP(2)), ctx);
emit(rv_bgtu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
emit(rv_bgtu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
break;
case BPF_JNE:
emit(rv_bne(hi(rs1), hi(rs2), JUMP(1)), ctx);
emit(rv_beq(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
break;
case BPF_JSGT:
emit(rv_bgt(hi(rs1), hi(rs2), JUMP(2)), ctx);
emit(rv_blt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
emit(rv_bleu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
break;
case BPF_JSLT:
emit(rv_blt(hi(rs1), hi(rs2), JUMP(2)), ctx);
emit(rv_bgt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
emit(rv_bgeu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
break;
case BPF_JSGE:
emit(rv_bgt(hi(rs1), hi(rs2), JUMP(2)), ctx);
emit(rv_blt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
emit(rv_bltu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
break;
case BPF_JSLE:
emit(rv_blt(hi(rs1), hi(rs2), JUMP(2)), ctx);
emit(rv_bgt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
emit(rv_bgtu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
break;
case BPF_JSET:
emit(rv_and(RV_REG_T0, hi(rs1), hi(rs2)), ctx);
emit(rv_bne(RV_REG_T0, RV_REG_ZERO, JUMP(2)), ctx);
emit(rv_and(RV_REG_T0, lo(rs1), lo(rs2)), ctx);
emit(rv_beq(RV_REG_T0, RV_REG_ZERO, NO_JUMP(0)), ctx);
break;
}
#undef NO_JUMP
#undef JUMP
e = ctx->ninsns;
/* Adjust for extra insns. */
rvoff -= ninsns_rvoff(e - s);
emit_jump_and_link(RV_REG_ZERO, rvoff, true, ctx);
return 0;
}