static void emit_loadimm64()

in net/bpf_jit_comp_64.c [465:614]


static void emit_loadimm64(u64 K, unsigned int dest, struct jit_ctx *ctx)
{
	int all_bits_between_are_set, lowest_bit_set, highest_bit_set;
	unsigned int tmp = bpf2sparc[TMP_REG_1];
	u32 low_bits = (K & 0xffffffff);
	u32 high_bits = (K >> 32);

	/* These two tests also take care of all of the one
	 * instruction cases.
	 */
	if (high_bits == 0xffffffff && (low_bits & 0x80000000))
		return emit_loadimm_sext(K, dest, ctx);
	if (high_bits == 0x00000000)
		return emit_loadimm32(K, dest, ctx);

	analyze_64bit_constant(high_bits, low_bits, &highest_bit_set,
			       &lowest_bit_set, &all_bits_between_are_set);

	/* 1) mov	-1, %reg
	 *    sllx	%reg, shift, %reg
	 * 2) mov	-1, %reg
	 *    srlx	%reg, shift, %reg
	 * 3) mov	some_small_const, %reg
	 *    sllx	%reg, shift, %reg
	 */
	if (((highest_bit_set == 63 || lowest_bit_set == 0) &&
	     all_bits_between_are_set != 0) ||
	    ((highest_bit_set - lowest_bit_set) < 12)) {
		int shift = lowest_bit_set;
		long the_const = -1;

		if ((highest_bit_set != 63 && lowest_bit_set != 0) ||
		    all_bits_between_are_set == 0) {
			the_const =
				create_simple_focus_bits(high_bits, low_bits,
							 lowest_bit_set, 0);
		} else if (lowest_bit_set == 0)
			shift = -(63 - highest_bit_set);

		emit(OR | IMMED | RS1(G0) | S13(the_const) | RD(dest), ctx);
		if (shift > 0)
			emit_alu_K(SLLX, dest, shift, ctx);
		else if (shift < 0)
			emit_alu_K(SRLX, dest, -shift, ctx);

		return;
	}

	/* Now a range of 22 or less bits set somewhere.
	 * 1) sethi	%hi(focus_bits), %reg
	 *    sllx	%reg, shift, %reg
	 * 2) sethi	%hi(focus_bits), %reg
	 *    srlx	%reg, shift, %reg
	 */
	if ((highest_bit_set - lowest_bit_set) < 21) {
		unsigned long focus_bits =
			create_simple_focus_bits(high_bits, low_bits,
						 lowest_bit_set, 10);

		emit(SETHI(focus_bits, dest), ctx);

		/* If lowest_bit_set == 10 then a sethi alone could
		 * have done it.
		 */
		if (lowest_bit_set < 10)
			emit_alu_K(SRLX, dest, 10 - lowest_bit_set, ctx);
		else if (lowest_bit_set > 10)
			emit_alu_K(SLLX, dest, lowest_bit_set - 10, ctx);
		return;
	}

	/* Ok, now 3 instruction sequences.  */
	if (low_bits == 0) {
		emit_loadimm32(high_bits, dest, ctx);
		emit_alu_K(SLLX, dest, 32, ctx);
		return;
	}

	/* We may be able to do something quick
	 * when the constant is negated, so try that.
	 */
	if (const64_is_2insns((~high_bits) & 0xffffffff,
			      (~low_bits) & 0xfffffc00)) {
		/* NOTE: The trailing bits get XOR'd so we need the
		 * non-negated bits, not the negated ones.
		 */
		unsigned long trailing_bits = low_bits & 0x3ff;

		if ((((~high_bits) & 0xffffffff) == 0 &&
		     ((~low_bits) & 0x80000000) == 0) ||
		    (((~high_bits) & 0xffffffff) == 0xffffffff &&
		     ((~low_bits) & 0x80000000) != 0)) {
			unsigned long fast_int = (~low_bits & 0xffffffff);

			if ((is_sethi(fast_int) &&
			     (~high_bits & 0xffffffff) == 0)) {
				emit(SETHI(fast_int, dest), ctx);
			} else if (is_simm13(fast_int)) {
				emit(OR | IMMED | RS1(G0) | S13(fast_int) | RD(dest), ctx);
			} else {
				emit_loadimm64(fast_int, dest, ctx);
			}
		} else {
			u64 n = ((~low_bits) & 0xfffffc00) |
				(((unsigned long)((~high_bits) & 0xffffffff))<<32);
			emit_loadimm64(n, dest, ctx);
		}

		low_bits = -0x400 | trailing_bits;

		emit(XOR | IMMED | RS1(dest) | S13(low_bits) | RD(dest), ctx);
		return;
	}

	/* 1) sethi	%hi(xxx), %reg
	 *    or	%reg, %lo(xxx), %reg
	 *    sllx	%reg, yyy, %reg
	 */
	if ((highest_bit_set - lowest_bit_set) < 32) {
		unsigned long focus_bits =
			create_simple_focus_bits(high_bits, low_bits,
						 lowest_bit_set, 0);

		/* So what we know is that the set bits straddle the
		 * middle of the 64-bit word.
		 */
		sparc_emit_set_const64_quick2(focus_bits, 0, dest,
					      lowest_bit_set, ctx);
		return;
	}

	/* 1) sethi	%hi(high_bits), %reg
	 *    or	%reg, %lo(high_bits), %reg
	 *    sllx	%reg, 32, %reg
	 *    or	%reg, low_bits, %reg
	 */
	if (is_simm13(low_bits) && ((int)low_bits > 0)) {
		sparc_emit_set_const64_quick2(high_bits, low_bits,
					      dest, 32, ctx);
		return;
	}

	/* Oh well, we tried... Do a full 64-bit decomposition.  */
	ctx->tmp_1_used = true;

	emit_loadimm32(high_bits, tmp, ctx);
	emit_loadimm32(low_bits, dest, ctx);
	emit_alu_K(SLLX, tmp, 32, ctx);
	emit(OR | RS1(dest) | RS2(tmp) | RD(dest), ctx);
}