static int emit_bcc()

in net/bpf_jit_comp32.c [652:720]


static int emit_bcc(u8 op, u8 rd, u8 rs, int rvoff, struct rv_jit_context *ctx)
{
	int e, s = ctx->ninsns;
	bool far = false;
	int off;

	if (op == BPF_JSET) {
		/*
		 * BPF_JSET is a special case: it has no inverse so we always
		 * treat it as a far branch.
		 */
		far = true;
	} else if (!is_13b_int(rvoff)) {
		op = invert_bpf_cond(op);
		far = true;
	}

	/*
	 * For a far branch, the condition is negated and we jump over the
	 * branch itself, and the two instructions from emit_jump_and_link.
	 * For a near branch, just use rvoff.
	 */
	off = far ? 6 : (rvoff >> 1);

	switch (op) {
	case BPF_JEQ:
		emit(rv_beq(rd, rs, off), ctx);
		break;
	case BPF_JGT:
		emit(rv_bgtu(rd, rs, off), ctx);
		break;
	case BPF_JLT:
		emit(rv_bltu(rd, rs, off), ctx);
		break;
	case BPF_JGE:
		emit(rv_bgeu(rd, rs, off), ctx);
		break;
	case BPF_JLE:
		emit(rv_bleu(rd, rs, off), ctx);
		break;
	case BPF_JNE:
		emit(rv_bne(rd, rs, off), ctx);
		break;
	case BPF_JSGT:
		emit(rv_bgt(rd, rs, off), ctx);
		break;
	case BPF_JSLT:
		emit(rv_blt(rd, rs, off), ctx);
		break;
	case BPF_JSGE:
		emit(rv_bge(rd, rs, off), ctx);
		break;
	case BPF_JSLE:
		emit(rv_ble(rd, rs, off), ctx);
		break;
	case BPF_JSET:
		emit(rv_and(RV_REG_T0, rd, rs), ctx);
		emit(rv_beq(RV_REG_T0, RV_REG_ZERO, off), ctx);
		break;
	}

	if (far) {
		e = ctx->ninsns;
		/* Adjust for extra insns. */
		rvoff -= ninsns_rvoff(e - s);
		emit_jump_and_link(RV_REG_ZERO, rvoff, true, ctx);
	}
	return 0;
}