static noinline int bpf_jit_insn()

in arch/s390/net/bpf_jit_comp.c [596:1488]


static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
				 int i, bool extra_pass)
{
	struct bpf_insn *insn = &fp->insnsi[i];
	u32 dst_reg = insn->dst_reg;
	u32 src_reg = insn->src_reg;
	int last, insn_count = 1;
	u32 *addrs = jit->addrs;
	s32 imm = insn->imm;
	s16 off = insn->off;
	unsigned int mask;

	switch (insn->code) {
	/*
	 * BPF_MOV
	 */
	case BPF_ALU | BPF_MOV | BPF_X: /* dst = (u32) src */
		/* llgfr %dst,%src */
		EMIT4(0xb9160000, dst_reg, src_reg);
		if (insn_is_zext(&insn[1]))
			insn_count = 2;
		break;
	case BPF_ALU64 | BPF_MOV | BPF_X: /* dst = src */
		/* lgr %dst,%src */
		EMIT4(0xb9040000, dst_reg, src_reg);
		break;
	case BPF_ALU | BPF_MOV | BPF_K: /* dst = (u32) imm */
		/* llilf %dst,imm */
		EMIT6_IMM(0xc00f0000, dst_reg, imm);
		if (insn_is_zext(&insn[1]))
			insn_count = 2;
		break;
	case BPF_ALU64 | BPF_MOV | BPF_K: /* dst = imm */
		/* lgfi %dst,imm */
		EMIT6_IMM(0xc0010000, dst_reg, imm);
		break;
	/*
	 * BPF_LD 64
	 */
	case BPF_LD | BPF_IMM | BPF_DW: /* dst = (u64) imm */
	{
		/* 16 byte instruction that uses two 'struct bpf_insn' */
		u64 imm64;

		imm64 = (u64)(u32) insn[0].imm | ((u64)(u32) insn[1].imm) << 32;
		/* lgrl %dst,imm */
		EMIT6_PCREL_RILB(0xc4080000, dst_reg, _EMIT_CONST_U64(imm64));
		insn_count = 2;
		break;
	}
	/*
	 * BPF_ADD
	 */
	case BPF_ALU | BPF_ADD | BPF_X: /* dst = (u32) dst + (u32) src */
		/* ar %dst,%src */
		EMIT2(0x1a00, dst_reg, src_reg);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_ADD | BPF_X: /* dst = dst + src */
		/* agr %dst,%src */
		EMIT4(0xb9080000, dst_reg, src_reg);
		break;
	case BPF_ALU | BPF_ADD | BPF_K: /* dst = (u32) dst + (u32) imm */
		if (!imm)
			break;
		/* alfi %dst,imm */
		EMIT6_IMM(0xc20b0000, dst_reg, imm);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_ADD | BPF_K: /* dst = dst + imm */
		if (!imm)
			break;
		/* agfi %dst,imm */
		EMIT6_IMM(0xc2080000, dst_reg, imm);
		break;
	/*
	 * BPF_SUB
	 */
	case BPF_ALU | BPF_SUB | BPF_X: /* dst = (u32) dst - (u32) src */
		/* sr %dst,%src */
		EMIT2(0x1b00, dst_reg, src_reg);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_SUB | BPF_X: /* dst = dst - src */
		/* sgr %dst,%src */
		EMIT4(0xb9090000, dst_reg, src_reg);
		break;
	case BPF_ALU | BPF_SUB | BPF_K: /* dst = (u32) dst - (u32) imm */
		if (!imm)
			break;
		/* alfi %dst,-imm */
		EMIT6_IMM(0xc20b0000, dst_reg, -imm);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_SUB | BPF_K: /* dst = dst - imm */
		if (!imm)
			break;
		/* agfi %dst,-imm */
		EMIT6_IMM(0xc2080000, dst_reg, -imm);
		break;
	/*
	 * BPF_MUL
	 */
	case BPF_ALU | BPF_MUL | BPF_X: /* dst = (u32) dst * (u32) src */
		/* msr %dst,%src */
		EMIT4(0xb2520000, dst_reg, src_reg);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_MUL | BPF_X: /* dst = dst * src */
		/* msgr %dst,%src */
		EMIT4(0xb90c0000, dst_reg, src_reg);
		break;
	case BPF_ALU | BPF_MUL | BPF_K: /* dst = (u32) dst * (u32) imm */
		if (imm == 1)
			break;
		/* msfi %r5,imm */
		EMIT6_IMM(0xc2010000, dst_reg, imm);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_MUL | BPF_K: /* dst = dst * imm */
		if (imm == 1)
			break;
		/* msgfi %dst,imm */
		EMIT6_IMM(0xc2000000, dst_reg, imm);
		break;
	/*
	 * BPF_DIV / BPF_MOD
	 */
	case BPF_ALU | BPF_DIV | BPF_X: /* dst = (u32) dst / (u32) src */
	case BPF_ALU | BPF_MOD | BPF_X: /* dst = (u32) dst % (u32) src */
	{
		int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;

		/* lhi %w0,0 */
		EMIT4_IMM(0xa7080000, REG_W0, 0);
		/* lr %w1,%dst */
		EMIT2(0x1800, REG_W1, dst_reg);
		/* dlr %w0,%src */
		EMIT4(0xb9970000, REG_W0, src_reg);
		/* llgfr %dst,%rc */
		EMIT4(0xb9160000, dst_reg, rc_reg);
		if (insn_is_zext(&insn[1]))
			insn_count = 2;
		break;
	}
	case BPF_ALU64 | BPF_DIV | BPF_X: /* dst = dst / src */
	case BPF_ALU64 | BPF_MOD | BPF_X: /* dst = dst % src */
	{
		int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;

		/* lghi %w0,0 */
		EMIT4_IMM(0xa7090000, REG_W0, 0);
		/* lgr %w1,%dst */
		EMIT4(0xb9040000, REG_W1, dst_reg);
		/* dlgr %w0,%dst */
		EMIT4(0xb9870000, REG_W0, src_reg);
		/* lgr %dst,%rc */
		EMIT4(0xb9040000, dst_reg, rc_reg);
		break;
	}
	case BPF_ALU | BPF_DIV | BPF_K: /* dst = (u32) dst / (u32) imm */
	case BPF_ALU | BPF_MOD | BPF_K: /* dst = (u32) dst % (u32) imm */
	{
		int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;

		if (imm == 1) {
			if (BPF_OP(insn->code) == BPF_MOD)
				/* lhgi %dst,0 */
				EMIT4_IMM(0xa7090000, dst_reg, 0);
			break;
		}
		/* lhi %w0,0 */
		EMIT4_IMM(0xa7080000, REG_W0, 0);
		/* lr %w1,%dst */
		EMIT2(0x1800, REG_W1, dst_reg);
		if (!is_first_pass(jit) && can_use_ldisp_for_lit32(jit)) {
			/* dl %w0,<d(imm)>(%l) */
			EMIT6_DISP_LH(0xe3000000, 0x0097, REG_W0, REG_0, REG_L,
				      EMIT_CONST_U32(imm));
		} else {
			/* lgfrl %dst,imm */
			EMIT6_PCREL_RILB(0xc40c0000, dst_reg,
					 _EMIT_CONST_U32(imm));
			jit->seen |= SEEN_LITERAL;
			/* dlr %w0,%dst */
			EMIT4(0xb9970000, REG_W0, dst_reg);
		}
		/* llgfr %dst,%rc */
		EMIT4(0xb9160000, dst_reg, rc_reg);
		if (insn_is_zext(&insn[1]))
			insn_count = 2;
		break;
	}
	case BPF_ALU64 | BPF_DIV | BPF_K: /* dst = dst / imm */
	case BPF_ALU64 | BPF_MOD | BPF_K: /* dst = dst % imm */
	{
		int rc_reg = BPF_OP(insn->code) == BPF_DIV ? REG_W1 : REG_W0;

		if (imm == 1) {
			if (BPF_OP(insn->code) == BPF_MOD)
				/* lhgi %dst,0 */
				EMIT4_IMM(0xa7090000, dst_reg, 0);
			break;
		}
		/* lghi %w0,0 */
		EMIT4_IMM(0xa7090000, REG_W0, 0);
		/* lgr %w1,%dst */
		EMIT4(0xb9040000, REG_W1, dst_reg);
		if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) {
			/* dlg %w0,<d(imm)>(%l) */
			EMIT6_DISP_LH(0xe3000000, 0x0087, REG_W0, REG_0, REG_L,
				      EMIT_CONST_U64(imm));
		} else {
			/* lgrl %dst,imm */
			EMIT6_PCREL_RILB(0xc4080000, dst_reg,
					 _EMIT_CONST_U64(imm));
			jit->seen |= SEEN_LITERAL;
			/* dlgr %w0,%dst */
			EMIT4(0xb9870000, REG_W0, dst_reg);
		}
		/* lgr %dst,%rc */
		EMIT4(0xb9040000, dst_reg, rc_reg);
		break;
	}
	/*
	 * BPF_AND
	 */
	case BPF_ALU | BPF_AND | BPF_X: /* dst = (u32) dst & (u32) src */
		/* nr %dst,%src */
		EMIT2(0x1400, dst_reg, src_reg);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_AND | BPF_X: /* dst = dst & src */
		/* ngr %dst,%src */
		EMIT4(0xb9800000, dst_reg, src_reg);
		break;
	case BPF_ALU | BPF_AND | BPF_K: /* dst = (u32) dst & (u32) imm */
		/* nilf %dst,imm */
		EMIT6_IMM(0xc00b0000, dst_reg, imm);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_AND | BPF_K: /* dst = dst & imm */
		if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) {
			/* ng %dst,<d(imm)>(%l) */
			EMIT6_DISP_LH(0xe3000000, 0x0080,
				      dst_reg, REG_0, REG_L,
				      EMIT_CONST_U64(imm));
		} else {
			/* lgrl %w0,imm */
			EMIT6_PCREL_RILB(0xc4080000, REG_W0,
					 _EMIT_CONST_U64(imm));
			jit->seen |= SEEN_LITERAL;
			/* ngr %dst,%w0 */
			EMIT4(0xb9800000, dst_reg, REG_W0);
		}
		break;
	/*
	 * BPF_OR
	 */
	case BPF_ALU | BPF_OR | BPF_X: /* dst = (u32) dst | (u32) src */
		/* or %dst,%src */
		EMIT2(0x1600, dst_reg, src_reg);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_OR | BPF_X: /* dst = dst | src */
		/* ogr %dst,%src */
		EMIT4(0xb9810000, dst_reg, src_reg);
		break;
	case BPF_ALU | BPF_OR | BPF_K: /* dst = (u32) dst | (u32) imm */
		/* oilf %dst,imm */
		EMIT6_IMM(0xc00d0000, dst_reg, imm);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_OR | BPF_K: /* dst = dst | imm */
		if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) {
			/* og %dst,<d(imm)>(%l) */
			EMIT6_DISP_LH(0xe3000000, 0x0081,
				      dst_reg, REG_0, REG_L,
				      EMIT_CONST_U64(imm));
		} else {
			/* lgrl %w0,imm */
			EMIT6_PCREL_RILB(0xc4080000, REG_W0,
					 _EMIT_CONST_U64(imm));
			jit->seen |= SEEN_LITERAL;
			/* ogr %dst,%w0 */
			EMIT4(0xb9810000, dst_reg, REG_W0);
		}
		break;
	/*
	 * BPF_XOR
	 */
	case BPF_ALU | BPF_XOR | BPF_X: /* dst = (u32) dst ^ (u32) src */
		/* xr %dst,%src */
		EMIT2(0x1700, dst_reg, src_reg);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_XOR | BPF_X: /* dst = dst ^ src */
		/* xgr %dst,%src */
		EMIT4(0xb9820000, dst_reg, src_reg);
		break;
	case BPF_ALU | BPF_XOR | BPF_K: /* dst = (u32) dst ^ (u32) imm */
		if (!imm)
			break;
		/* xilf %dst,imm */
		EMIT6_IMM(0xc0070000, dst_reg, imm);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_XOR | BPF_K: /* dst = dst ^ imm */
		if (!is_first_pass(jit) && can_use_ldisp_for_lit64(jit)) {
			/* xg %dst,<d(imm)>(%l) */
			EMIT6_DISP_LH(0xe3000000, 0x0082,
				      dst_reg, REG_0, REG_L,
				      EMIT_CONST_U64(imm));
		} else {
			/* lgrl %w0,imm */
			EMIT6_PCREL_RILB(0xc4080000, REG_W0,
					 _EMIT_CONST_U64(imm));
			jit->seen |= SEEN_LITERAL;
			/* xgr %dst,%w0 */
			EMIT4(0xb9820000, dst_reg, REG_W0);
		}
		break;
	/*
	 * BPF_LSH
	 */
	case BPF_ALU | BPF_LSH | BPF_X: /* dst = (u32) dst << (u32) src */
		/* sll %dst,0(%src) */
		EMIT4_DISP(0x89000000, dst_reg, src_reg, 0);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_LSH | BPF_X: /* dst = dst << src */
		/* sllg %dst,%dst,0(%src) */
		EMIT6_DISP_LH(0xeb000000, 0x000d, dst_reg, dst_reg, src_reg, 0);
		break;
	case BPF_ALU | BPF_LSH | BPF_K: /* dst = (u32) dst << (u32) imm */
		if (imm == 0)
			break;
		/* sll %dst,imm(%r0) */
		EMIT4_DISP(0x89000000, dst_reg, REG_0, imm);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_LSH | BPF_K: /* dst = dst << imm */
		if (imm == 0)
			break;
		/* sllg %dst,%dst,imm(%r0) */
		EMIT6_DISP_LH(0xeb000000, 0x000d, dst_reg, dst_reg, REG_0, imm);
		break;
	/*
	 * BPF_RSH
	 */
	case BPF_ALU | BPF_RSH | BPF_X: /* dst = (u32) dst >> (u32) src */
		/* srl %dst,0(%src) */
		EMIT4_DISP(0x88000000, dst_reg, src_reg, 0);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_RSH | BPF_X: /* dst = dst >> src */
		/* srlg %dst,%dst,0(%src) */
		EMIT6_DISP_LH(0xeb000000, 0x000c, dst_reg, dst_reg, src_reg, 0);
		break;
	case BPF_ALU | BPF_RSH | BPF_K: /* dst = (u32) dst >> (u32) imm */
		if (imm == 0)
			break;
		/* srl %dst,imm(%r0) */
		EMIT4_DISP(0x88000000, dst_reg, REG_0, imm);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_RSH | BPF_K: /* dst = dst >> imm */
		if (imm == 0)
			break;
		/* srlg %dst,%dst,imm(%r0) */
		EMIT6_DISP_LH(0xeb000000, 0x000c, dst_reg, dst_reg, REG_0, imm);
		break;
	/*
	 * BPF_ARSH
	 */
	case BPF_ALU | BPF_ARSH | BPF_X: /* ((s32) dst) >>= src */
		/* sra %dst,%dst,0(%src) */
		EMIT4_DISP(0x8a000000, dst_reg, src_reg, 0);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_ARSH | BPF_X: /* ((s64) dst) >>= src */
		/* srag %dst,%dst,0(%src) */
		EMIT6_DISP_LH(0xeb000000, 0x000a, dst_reg, dst_reg, src_reg, 0);
		break;
	case BPF_ALU | BPF_ARSH | BPF_K: /* ((s32) dst >> imm */
		if (imm == 0)
			break;
		/* sra %dst,imm(%r0) */
		EMIT4_DISP(0x8a000000, dst_reg, REG_0, imm);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_ARSH | BPF_K: /* ((s64) dst) >>= imm */
		if (imm == 0)
			break;
		/* srag %dst,%dst,imm(%r0) */
		EMIT6_DISP_LH(0xeb000000, 0x000a, dst_reg, dst_reg, REG_0, imm);
		break;
	/*
	 * BPF_NEG
	 */
	case BPF_ALU | BPF_NEG: /* dst = (u32) -dst */
		/* lcr %dst,%dst */
		EMIT2(0x1300, dst_reg, dst_reg);
		EMIT_ZERO(dst_reg);
		break;
	case BPF_ALU64 | BPF_NEG: /* dst = -dst */
		/* lcgr %dst,%dst */
		EMIT4(0xb9030000, dst_reg, dst_reg);
		break;
	/*
	 * BPF_FROM_BE/LE
	 */
	case BPF_ALU | BPF_END | BPF_FROM_BE:
		/* s390 is big endian, therefore only clear high order bytes */
		switch (imm) {
		case 16: /* dst = (u16) cpu_to_be16(dst) */
			/* llghr %dst,%dst */
			EMIT4(0xb9850000, dst_reg, dst_reg);
			if (insn_is_zext(&insn[1]))
				insn_count = 2;
			break;
		case 32: /* dst = (u32) cpu_to_be32(dst) */
			if (!fp->aux->verifier_zext)
				/* llgfr %dst,%dst */
				EMIT4(0xb9160000, dst_reg, dst_reg);
			break;
		case 64: /* dst = (u64) cpu_to_be64(dst) */
			break;
		}
		break;
	case BPF_ALU | BPF_END | BPF_FROM_LE:
		switch (imm) {
		case 16: /* dst = (u16) cpu_to_le16(dst) */
			/* lrvr %dst,%dst */
			EMIT4(0xb91f0000, dst_reg, dst_reg);
			/* srl %dst,16(%r0) */
			EMIT4_DISP(0x88000000, dst_reg, REG_0, 16);
			/* llghr %dst,%dst */
			EMIT4(0xb9850000, dst_reg, dst_reg);
			if (insn_is_zext(&insn[1]))
				insn_count = 2;
			break;
		case 32: /* dst = (u32) cpu_to_le32(dst) */
			/* lrvr %dst,%dst */
			EMIT4(0xb91f0000, dst_reg, dst_reg);
			if (!fp->aux->verifier_zext)
				/* llgfr %dst,%dst */
				EMIT4(0xb9160000, dst_reg, dst_reg);
			break;
		case 64: /* dst = (u64) cpu_to_le64(dst) */
			/* lrvgr %dst,%dst */
			EMIT4(0xb90f0000, dst_reg, dst_reg);
			break;
		}
		break;
	/*
	 * BPF_ST(X)
	 */
	case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src_reg */
		/* stcy %src,off(%dst) */
		EMIT6_DISP_LH(0xe3000000, 0x0072, src_reg, dst_reg, REG_0, off);
		jit->seen |= SEEN_MEM;
		break;
	case BPF_STX | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = src */
		/* sthy %src,off(%dst) */
		EMIT6_DISP_LH(0xe3000000, 0x0070, src_reg, dst_reg, REG_0, off);
		jit->seen |= SEEN_MEM;
		break;
	case BPF_STX | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = src */
		/* sty %src,off(%dst) */
		EMIT6_DISP_LH(0xe3000000, 0x0050, src_reg, dst_reg, REG_0, off);
		jit->seen |= SEEN_MEM;
		break;
	case BPF_STX | BPF_MEM | BPF_DW: /* (u64 *)(dst + off) = src */
		/* stg %src,off(%dst) */
		EMIT6_DISP_LH(0xe3000000, 0x0024, src_reg, dst_reg, REG_0, off);
		jit->seen |= SEEN_MEM;
		break;
	case BPF_ST | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = imm */
		/* lhi %w0,imm */
		EMIT4_IMM(0xa7080000, REG_W0, (u8) imm);
		/* stcy %w0,off(dst) */
		EMIT6_DISP_LH(0xe3000000, 0x0072, REG_W0, dst_reg, REG_0, off);
		jit->seen |= SEEN_MEM;
		break;
	case BPF_ST | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = imm */
		/* lhi %w0,imm */
		EMIT4_IMM(0xa7080000, REG_W0, (u16) imm);
		/* sthy %w0,off(dst) */
		EMIT6_DISP_LH(0xe3000000, 0x0070, REG_W0, dst_reg, REG_0, off);
		jit->seen |= SEEN_MEM;
		break;
	case BPF_ST | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = imm */
		/* llilf %w0,imm  */
		EMIT6_IMM(0xc00f0000, REG_W0, (u32) imm);
		/* sty %w0,off(%dst) */
		EMIT6_DISP_LH(0xe3000000, 0x0050, REG_W0, dst_reg, REG_0, off);
		jit->seen |= SEEN_MEM;
		break;
	case BPF_ST | BPF_MEM | BPF_DW: /* *(u64 *)(dst + off) = imm */
		/* lgfi %w0,imm */
		EMIT6_IMM(0xc0010000, REG_W0, imm);
		/* stg %w0,off(%dst) */
		EMIT6_DISP_LH(0xe3000000, 0x0024, REG_W0, dst_reg, REG_0, off);
		jit->seen |= SEEN_MEM;
		break;
	/*
	 * BPF_STX XADD (atomic_add)
	 */
	case BPF_STX | BPF_XADD | BPF_W: /* *(u32 *)(dst + off) += src */
		/* laal %w0,%src,off(%dst) */
		EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W0, src_reg,
			      dst_reg, off);
		jit->seen |= SEEN_MEM;
		break;
	case BPF_STX | BPF_XADD | BPF_DW: /* *(u64 *)(dst + off) += src */
		/* laalg %w0,%src,off(%dst) */
		EMIT6_DISP_LH(0xeb000000, 0x00ea, REG_W0, src_reg,
			      dst_reg, off);
		jit->seen |= SEEN_MEM;
		break;
	/*
	 * BPF_LDX
	 */
	case BPF_LDX | BPF_MEM | BPF_B: /* dst = *(u8 *)(ul) (src + off) */
		/* llgc %dst,0(off,%src) */
		EMIT6_DISP_LH(0xe3000000, 0x0090, dst_reg, src_reg, REG_0, off);
		jit->seen |= SEEN_MEM;
		if (insn_is_zext(&insn[1]))
			insn_count = 2;
		break;
	case BPF_LDX | BPF_MEM | BPF_H: /* dst = *(u16 *)(ul) (src + off) */
		/* llgh %dst,0(off,%src) */
		EMIT6_DISP_LH(0xe3000000, 0x0091, dst_reg, src_reg, REG_0, off);
		jit->seen |= SEEN_MEM;
		if (insn_is_zext(&insn[1]))
			insn_count = 2;
		break;
	case BPF_LDX | BPF_MEM | BPF_W: /* dst = *(u32 *)(ul) (src + off) */
		/* llgf %dst,off(%src) */
		jit->seen |= SEEN_MEM;
		EMIT6_DISP_LH(0xe3000000, 0x0016, dst_reg, src_reg, REG_0, off);
		if (insn_is_zext(&insn[1]))
			insn_count = 2;
		break;
	case BPF_LDX | BPF_MEM | BPF_DW: /* dst = *(u64 *)(ul) (src + off) */
		/* lg %dst,0(off,%src) */
		jit->seen |= SEEN_MEM;
		EMIT6_DISP_LH(0xe3000000, 0x0004, dst_reg, src_reg, REG_0, off);
		break;
	/*
	 * BPF_JMP / CALL
	 */
	case BPF_JMP | BPF_CALL:
	{
		u64 func;
		bool func_addr_fixed;
		int ret;

		ret = bpf_jit_get_func_addr(fp, insn, extra_pass,
					    &func, &func_addr_fixed);
		if (ret < 0)
			return -1;

		REG_SET_SEEN(BPF_REG_5);
		jit->seen |= SEEN_FUNC;
		/* lgrl %w1,func */
		EMIT6_PCREL_RILB(0xc4080000, REG_W1, _EMIT_CONST_U64(func));
		if (__is_defined(CC_USING_EXPOLINE) && !nospec_disable) {
			/* brasl %r14,__s390_indirect_jump_r1 */
			EMIT6_PCREL_RILB(0xc0050000, REG_14, jit->r1_thunk_ip);
		} else {
			/* basr %r14,%w1 */
			EMIT2(0x0d00, REG_14, REG_W1);
		}
		/* lgr %b0,%r2: load return value into %b0 */
		EMIT4(0xb9040000, BPF_REG_0, REG_2);
		break;
	}
	case BPF_JMP | BPF_TAIL_CALL:
		/*
		 * Implicit input:
		 *  B1: pointer to ctx
		 *  B2: pointer to bpf_array
		 *  B3: index in bpf_array
		 */
		jit->seen |= SEEN_TAIL_CALL;

		/*
		 * if (index >= array->map.max_entries)
		 *         goto out;
		 */

		/* llgf %w1,map.max_entries(%b2) */
		EMIT6_DISP_LH(0xe3000000, 0x0016, REG_W1, REG_0, BPF_REG_2,
			      offsetof(struct bpf_array, map.max_entries));
		/* if ((u32)%b3 >= (u32)%w1) goto out; */
		if (!is_first_pass(jit) && can_use_rel(jit, jit->labels[0])) {
			/* clrj %b3,%w1,0xa,label0 */
			EMIT6_PCREL_LABEL(0xec000000, 0x0077, BPF_REG_3,
					  REG_W1, 0, 0xa);
		} else {
			/* clr %b3,%w1 */
			EMIT2(0x1500, BPF_REG_3, REG_W1);
			/* brcl 0xa,label0 */
			EMIT6_PCREL_RILC(0xc0040000, 0xa, jit->labels[0]);
		}

		/*
		 * if (tail_call_cnt++ > MAX_TAIL_CALL_CNT)
		 *         goto out;
		 */

		if (jit->seen & SEEN_STACK)
			off = STK_OFF_TCCNT + STK_OFF + fp->aux->stack_depth;
		else
			off = STK_OFF_TCCNT;
		/* lhi %w0,1 */
		EMIT4_IMM(0xa7080000, REG_W0, 1);
		/* laal %w1,%w0,off(%r15) */
		EMIT6_DISP_LH(0xeb000000, 0x00fa, REG_W1, REG_W0, REG_15, off);
		if (!is_first_pass(jit) && can_use_rel(jit, jit->labels[0])) {
			/* clij %w1,MAX_TAIL_CALL_CNT,0x2,label0 */
			EMIT6_PCREL_IMM_LABEL(0xec000000, 0x007f, REG_W1,
					      MAX_TAIL_CALL_CNT, 0, 0x2);
		} else {
			/* clfi %w1,MAX_TAIL_CALL_CNT */
			EMIT6_IMM(0xc20f0000, REG_W1, MAX_TAIL_CALL_CNT);
			/* brcl 0x2,label0 */
			EMIT6_PCREL_RILC(0xc0040000, 0x2, jit->labels[0]);
		}

		/*
		 * prog = array->ptrs[index];
		 * if (prog == NULL)
		 *         goto out;
		 */

		/* llgfr %r1,%b3: %r1 = (u32) index */
		EMIT4(0xb9160000, REG_1, BPF_REG_3);
		/* sllg %r1,%r1,3: %r1 *= 8 */
		EMIT6_DISP_LH(0xeb000000, 0x000d, REG_1, REG_1, REG_0, 3);
		/* ltg %r1,prog(%b2,%r1) */
		EMIT6_DISP_LH(0xe3000000, 0x0002, REG_1, BPF_REG_2,
			      REG_1, offsetof(struct bpf_array, ptrs));
		if (!is_first_pass(jit) && can_use_rel(jit, jit->labels[0])) {
			/* brc 0x8,label0 */
			EMIT4_PCREL_RIC(0xa7040000, 0x8, jit->labels[0]);
		} else {
			/* brcl 0x8,label0 */
			EMIT6_PCREL_RILC(0xc0040000, 0x8, jit->labels[0]);
		}

		/*
		 * Restore registers before calling function
		 */
		save_restore_regs(jit, REGS_RESTORE, fp->aux->stack_depth);

		/*
		 * goto *(prog->bpf_func + tail_call_start);
		 */

		/* lg %r1,bpf_func(%r1) */
		EMIT6_DISP_LH(0xe3000000, 0x0004, REG_1, REG_1, REG_0,
			      offsetof(struct bpf_prog, bpf_func));
		/* bc 0xf,tail_call_start(%r1) */
		_EMIT4(0x47f01000 + jit->tail_call_start);
		/* out: */
		jit->labels[0] = jit->prg;
		break;
	case BPF_JMP | BPF_EXIT: /* return b0 */
		last = (i == fp->len - 1) ? 1 : 0;
		if (last)
			break;
		/* j <exit> */
		EMIT4_PCREL(0xa7f40000, jit->exit_ip - jit->prg);
		break;
	/*
	 * Branch relative (number of skipped instructions) to offset on
	 * condition.
	 *
	 * Condition code to mask mapping:
	 *
	 * CC | Description	   | Mask
	 * ------------------------------
	 * 0  | Operands equal	   |	8
	 * 1  | First operand low  |	4
	 * 2  | First operand high |	2
	 * 3  | Unused		   |	1
	 *
	 * For s390x relative branches: ip = ip + off_bytes
	 * For BPF relative branches:	insn = insn + off_insns + 1
	 *
	 * For example for s390x with offset 0 we jump to the branch
	 * instruction itself (loop) and for BPF with offset 0 we
	 * branch to the instruction behind the branch.
	 */
	case BPF_JMP | BPF_JA: /* if (true) */
		mask = 0xf000; /* j */
		goto branch_oc;
	case BPF_JMP | BPF_JSGT | BPF_K: /* ((s64) dst > (s64) imm) */
	case BPF_JMP32 | BPF_JSGT | BPF_K: /* ((s32) dst > (s32) imm) */
		mask = 0x2000; /* jh */
		goto branch_ks;
	case BPF_JMP | BPF_JSLT | BPF_K: /* ((s64) dst < (s64) imm) */
	case BPF_JMP32 | BPF_JSLT | BPF_K: /* ((s32) dst < (s32) imm) */
		mask = 0x4000; /* jl */
		goto branch_ks;
	case BPF_JMP | BPF_JSGE | BPF_K: /* ((s64) dst >= (s64) imm) */
	case BPF_JMP32 | BPF_JSGE | BPF_K: /* ((s32) dst >= (s32) imm) */
		mask = 0xa000; /* jhe */
		goto branch_ks;
	case BPF_JMP | BPF_JSLE | BPF_K: /* ((s64) dst <= (s64) imm) */
	case BPF_JMP32 | BPF_JSLE | BPF_K: /* ((s32) dst <= (s32) imm) */
		mask = 0xc000; /* jle */
		goto branch_ks;
	case BPF_JMP | BPF_JGT | BPF_K: /* (dst_reg > imm) */
	case BPF_JMP32 | BPF_JGT | BPF_K: /* ((u32) dst_reg > (u32) imm) */
		mask = 0x2000; /* jh */
		goto branch_ku;
	case BPF_JMP | BPF_JLT | BPF_K: /* (dst_reg < imm) */
	case BPF_JMP32 | BPF_JLT | BPF_K: /* ((u32) dst_reg < (u32) imm) */
		mask = 0x4000; /* jl */
		goto branch_ku;
	case BPF_JMP | BPF_JGE | BPF_K: /* (dst_reg >= imm) */
	case BPF_JMP32 | BPF_JGE | BPF_K: /* ((u32) dst_reg >= (u32) imm) */
		mask = 0xa000; /* jhe */
		goto branch_ku;
	case BPF_JMP | BPF_JLE | BPF_K: /* (dst_reg <= imm) */
	case BPF_JMP32 | BPF_JLE | BPF_K: /* ((u32) dst_reg <= (u32) imm) */
		mask = 0xc000; /* jle */
		goto branch_ku;
	case BPF_JMP | BPF_JNE | BPF_K: /* (dst_reg != imm) */
	case BPF_JMP32 | BPF_JNE | BPF_K: /* ((u32) dst_reg != (u32) imm) */
		mask = 0x7000; /* jne */
		goto branch_ku;
	case BPF_JMP | BPF_JEQ | BPF_K: /* (dst_reg == imm) */
	case BPF_JMP32 | BPF_JEQ | BPF_K: /* ((u32) dst_reg == (u32) imm) */
		mask = 0x8000; /* je */
		goto branch_ku;
	case BPF_JMP | BPF_JSET | BPF_K: /* (dst_reg & imm) */
	case BPF_JMP32 | BPF_JSET | BPF_K: /* ((u32) dst_reg & (u32) imm) */
		mask = 0x7000; /* jnz */
		if (BPF_CLASS(insn->code) == BPF_JMP32) {
			/* llilf %w1,imm (load zero extend imm) */
			EMIT6_IMM(0xc00f0000, REG_W1, imm);
			/* nr %w1,%dst */
			EMIT2(0x1400, REG_W1, dst_reg);
		} else {
			/* lgfi %w1,imm (load sign extend imm) */
			EMIT6_IMM(0xc0010000, REG_W1, imm);
			/* ngr %w1,%dst */
			EMIT4(0xb9800000, REG_W1, dst_reg);
		}
		goto branch_oc;

	case BPF_JMP | BPF_JSGT | BPF_X: /* ((s64) dst > (s64) src) */
	case BPF_JMP32 | BPF_JSGT | BPF_X: /* ((s32) dst > (s32) src) */
		mask = 0x2000; /* jh */
		goto branch_xs;
	case BPF_JMP | BPF_JSLT | BPF_X: /* ((s64) dst < (s64) src) */
	case BPF_JMP32 | BPF_JSLT | BPF_X: /* ((s32) dst < (s32) src) */
		mask = 0x4000; /* jl */
		goto branch_xs;
	case BPF_JMP | BPF_JSGE | BPF_X: /* ((s64) dst >= (s64) src) */
	case BPF_JMP32 | BPF_JSGE | BPF_X: /* ((s32) dst >= (s32) src) */
		mask = 0xa000; /* jhe */
		goto branch_xs;
	case BPF_JMP | BPF_JSLE | BPF_X: /* ((s64) dst <= (s64) src) */
	case BPF_JMP32 | BPF_JSLE | BPF_X: /* ((s32) dst <= (s32) src) */
		mask = 0xc000; /* jle */
		goto branch_xs;
	case BPF_JMP | BPF_JGT | BPF_X: /* (dst > src) */
	case BPF_JMP32 | BPF_JGT | BPF_X: /* ((u32) dst > (u32) src) */
		mask = 0x2000; /* jh */
		goto branch_xu;
	case BPF_JMP | BPF_JLT | BPF_X: /* (dst < src) */
	case BPF_JMP32 | BPF_JLT | BPF_X: /* ((u32) dst < (u32) src) */
		mask = 0x4000; /* jl */
		goto branch_xu;
	case BPF_JMP | BPF_JGE | BPF_X: /* (dst >= src) */
	case BPF_JMP32 | BPF_JGE | BPF_X: /* ((u32) dst >= (u32) src) */
		mask = 0xa000; /* jhe */
		goto branch_xu;
	case BPF_JMP | BPF_JLE | BPF_X: /* (dst <= src) */
	case BPF_JMP32 | BPF_JLE | BPF_X: /* ((u32) dst <= (u32) src) */
		mask = 0xc000; /* jle */
		goto branch_xu;
	case BPF_JMP | BPF_JNE | BPF_X: /* (dst != src) */
	case BPF_JMP32 | BPF_JNE | BPF_X: /* ((u32) dst != (u32) src) */
		mask = 0x7000; /* jne */
		goto branch_xu;
	case BPF_JMP | BPF_JEQ | BPF_X: /* (dst == src) */
	case BPF_JMP32 | BPF_JEQ | BPF_X: /* ((u32) dst == (u32) src) */
		mask = 0x8000; /* je */
		goto branch_xu;
	case BPF_JMP | BPF_JSET | BPF_X: /* (dst & src) */
	case BPF_JMP32 | BPF_JSET | BPF_X: /* ((u32) dst & (u32) src) */
	{
		bool is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32;

		mask = 0x7000; /* jnz */
		/* nrk or ngrk %w1,%dst,%src */
		EMIT4_RRF((is_jmp32 ? 0xb9f40000 : 0xb9e40000),
			  REG_W1, dst_reg, src_reg);
		goto branch_oc;
branch_ks:
		is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32;
		/* cfi or cgfi %dst,imm */
		EMIT6_IMM(is_jmp32 ? 0xc20d0000 : 0xc20c0000,
			  dst_reg, imm);
		if (!is_first_pass(jit) &&
		    can_use_rel(jit, addrs[i + off + 1])) {
			/* brc mask,off */
			EMIT4_PCREL_RIC(0xa7040000,
					mask >> 12, addrs[i + off + 1]);
		} else {
			/* brcl mask,off */
			EMIT6_PCREL_RILC(0xc0040000,
					 mask >> 12, addrs[i + off + 1]);
		}
		break;
branch_ku:
		is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32;
		/* clfi or clgfi %dst,imm */
		EMIT6_IMM(is_jmp32 ? 0xc20f0000 : 0xc20e0000,
			  dst_reg, imm);
		if (!is_first_pass(jit) &&
		    can_use_rel(jit, addrs[i + off + 1])) {
			/* brc mask,off */
			EMIT4_PCREL_RIC(0xa7040000,
					mask >> 12, addrs[i + off + 1]);
		} else {
			/* brcl mask,off */
			EMIT6_PCREL_RILC(0xc0040000,
					 mask >> 12, addrs[i + off + 1]);
		}
		break;
branch_xs:
		is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32;
		if (!is_first_pass(jit) &&
		    can_use_rel(jit, addrs[i + off + 1])) {
			/* crj or cgrj %dst,%src,mask,off */
			EMIT6_PCREL(0xec000000, (is_jmp32 ? 0x0076 : 0x0064),
				    dst_reg, src_reg, i, off, mask);
		} else {
			/* cr or cgr %dst,%src */
			if (is_jmp32)
				EMIT2(0x1900, dst_reg, src_reg);
			else
				EMIT4(0xb9200000, dst_reg, src_reg);
			/* brcl mask,off */
			EMIT6_PCREL_RILC(0xc0040000,
					 mask >> 12, addrs[i + off + 1]);
		}
		break;
branch_xu:
		is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32;
		if (!is_first_pass(jit) &&
		    can_use_rel(jit, addrs[i + off + 1])) {
			/* clrj or clgrj %dst,%src,mask,off */
			EMIT6_PCREL(0xec000000, (is_jmp32 ? 0x0077 : 0x0065),
				    dst_reg, src_reg, i, off, mask);
		} else {
			/* clr or clgr %dst,%src */
			if (is_jmp32)
				EMIT2(0x1500, dst_reg, src_reg);
			else
				EMIT4(0xb9210000, dst_reg, src_reg);
			/* brcl mask,off */
			EMIT6_PCREL_RILC(0xc0040000,
					 mask >> 12, addrs[i + off + 1]);
		}
		break;
branch_oc:
		if (!is_first_pass(jit) &&
		    can_use_rel(jit, addrs[i + off + 1])) {
			/* brc mask,off */
			EMIT4_PCREL_RIC(0xa7040000,
					mask >> 12, addrs[i + off + 1]);
		} else {
			/* brcl mask,off */
			EMIT6_PCREL_RILC(0xc0040000,
					 mask >> 12, addrs[i + off + 1]);
		}
		break;
	}
	default: /* too complex, give up */
		pr_err("Unknown opcode %02x\n", insn->code);
		return -1;
	}
	return insn_count;
}