|
@@ -79,23 +79,66 @@ static inline void emit(const u32 insn, struct jit_ctx *ctx)
|
|
|
ctx->idx++;
|
|
|
}
|
|
|
|
|
|
+static inline void emit_a64_mov_i(const int is64, const int reg,
|
|
|
+ const s32 val, struct jit_ctx *ctx)
|
|
|
+{
|
|
|
+ u16 hi = val >> 16;
|
|
|
+ u16 lo = val & 0xffff;
|
|
|
+
|
|
|
+ if (hi & 0x8000) {
|
|
|
+ if (hi == 0xffff) {
|
|
|
+ emit(A64_MOVN(is64, reg, (u16)~lo, 0), ctx);
|
|
|
+ } else {
|
|
|
+ emit(A64_MOVN(is64, reg, (u16)~hi, 16), ctx);
|
|
|
+ if (lo != 0xffff)
|
|
|
+ emit(A64_MOVK(is64, reg, lo, 0), ctx);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ emit(A64_MOVZ(is64, reg, lo, 0), ctx);
|
|
|
+ if (hi)
|
|
|
+ emit(A64_MOVK(is64, reg, hi, 16), ctx);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int i64_i16_blocks(const u64 val, bool inverse)
|
|
|
+{
|
|
|
+ return (((val >> 0) & 0xffff) != (inverse ? 0xffff : 0x0000)) +
|
|
|
+ (((val >> 16) & 0xffff) != (inverse ? 0xffff : 0x0000)) +
|
|
|
+ (((val >> 32) & 0xffff) != (inverse ? 0xffff : 0x0000)) +
|
|
|
+ (((val >> 48) & 0xffff) != (inverse ? 0xffff : 0x0000));
|
|
|
+}
|
|
|
+
|
|
|
static inline void emit_a64_mov_i64(const int reg, const u64 val,
|
|
|
struct jit_ctx *ctx)
|
|
|
{
|
|
|
- u64 tmp = val;
|
|
|
- int shift = 0;
|
|
|
-
|
|
|
- emit(A64_MOVZ(1, reg, tmp & 0xffff, shift), ctx);
|
|
|
- tmp >>= 16;
|
|
|
- shift += 16;
|
|
|
- while (tmp) {
|
|
|
- if (tmp & 0xffff)
|
|
|
- emit(A64_MOVK(1, reg, tmp & 0xffff, shift), ctx);
|
|
|
- tmp >>= 16;
|
|
|
- shift += 16;
|
|
|
+ u64 nrm_tmp = val, rev_tmp = ~val;
|
|
|
+ bool inverse;
|
|
|
+ int shift;
|
|
|
+
|
|
|
+ if (!(nrm_tmp >> 32))
|
|
|
+ return emit_a64_mov_i(0, reg, (u32)val, ctx);
|
|
|
+
|
|
|
+ inverse = i64_i16_blocks(nrm_tmp, true) < i64_i16_blocks(nrm_tmp, false);
|
|
|
+ shift = max(round_down((inverse ? (fls64(rev_tmp) - 1) :
|
|
|
+ (fls64(nrm_tmp) - 1)), 16), 0);
|
|
|
+ if (inverse)
|
|
|
+ emit(A64_MOVN(1, reg, (rev_tmp >> shift) & 0xffff, shift), ctx);
|
|
|
+ else
|
|
|
+ emit(A64_MOVZ(1, reg, (nrm_tmp >> shift) & 0xffff, shift), ctx);
|
|
|
+ shift -= 16;
|
|
|
+ while (shift >= 0) {
|
|
|
+ if (((nrm_tmp >> shift) & 0xffff) != (inverse ? 0xffff : 0x0000))
|
|
|
+ emit(A64_MOVK(1, reg, (nrm_tmp >> shift) & 0xffff, shift), ctx);
|
|
|
+ shift -= 16;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * This is an unoptimized 64 immediate emission used for BPF to BPF call
|
|
|
+ * addresses. It will always do a full 64 bit decomposition as otherwise
|
|
|
+ * more complexity in the last extra pass is required since we previously
|
|
|
+ * reserved 4 instructions for the address.
|
|
|
+ */
|
|
|
static inline void emit_addr_mov_i64(const int reg, const u64 val,
|
|
|
struct jit_ctx *ctx)
|
|
|
{
|
|
@@ -110,26 +153,6 @@ static inline void emit_addr_mov_i64(const int reg, const u64 val,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static inline void emit_a64_mov_i(const int is64, const int reg,
|
|
|
- const s32 val, struct jit_ctx *ctx)
|
|
|
-{
|
|
|
- u16 hi = val >> 16;
|
|
|
- u16 lo = val & 0xffff;
|
|
|
-
|
|
|
- if (hi & 0x8000) {
|
|
|
- if (hi == 0xffff) {
|
|
|
- emit(A64_MOVN(is64, reg, (u16)~lo, 0), ctx);
|
|
|
- } else {
|
|
|
- emit(A64_MOVN(is64, reg, (u16)~hi, 16), ctx);
|
|
|
- emit(A64_MOVK(is64, reg, lo, 0), ctx);
|
|
|
- }
|
|
|
- } else {
|
|
|
- emit(A64_MOVZ(is64, reg, lo, 0), ctx);
|
|
|
- if (hi)
|
|
|
- emit(A64_MOVK(is64, reg, hi, 16), ctx);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static inline int bpf2a64_offset(int bpf_to, int bpf_from,
|
|
|
const struct jit_ctx *ctx)
|
|
|
{
|