From 6f834087d0553b68b61770c69109894bf3f375ef Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Thu, 15 Aug 2024 00:22:47 +0200 Subject: [PATCH] ARM64: Use movi to materialize FP constants. Thanks to Peter Cawley. #1245 --- src/jit/dis_arm64.lua | 20 ++++++++++++++++++++ src/lj_emit_arm64.h | 14 ++++++++++++++ src/lj_target_arm64.h | 1 + 3 files changed, 35 insertions(+) diff --git a/src/jit/dis_arm64.lua b/src/jit/dis_arm64.lua index 84677666..2741cd2e 100644 --- a/src/jit/dis_arm64.lua +++ b/src/jit/dis_arm64.lua @@ -658,6 +658,10 @@ local map_datafp = { -- Data processing, SIMD and FP. } } } + }, + { -- 010 + shift = 0, mask = 0x81f8fc00, + [0x100e400] = "moviDdG" } } @@ -832,6 +836,20 @@ local function parse_fpimm8(op) return sign * frac * 2^exp end +local function decode_fpmovi(op) + local lo = rshift(op, 5) + local hi = rshift(op, 9) + lo = bor(band(lo, 1) * 0xff, band(lo, 2) * 0x7f80, band(lo, 4) * 0x3fc000, + band(lo, 8) * 0x1fe00000) + hi = bor(band(hi, 1) * 0xff, band(hi, 0x80) * 0x1fe, + band(hi, 0x100) * 0xff00, band(hi, 0x200) * 0x7f8000) + if hi ~= 0 then + return fmt_hex32(hi)..tohex(lo) + else + return fmt_hex32(lo) + end +end + local function prefer_bfx(sf, uns, imms, immr) if imms < immr or imms == 31 or imms == 63 then return false @@ -1131,6 +1149,8 @@ local function disass_ins(ctx) x = 0 elseif p == "F" then x = parse_fpimm8(op) + elseif p == "G" then + x = "#0x"..decode_fpmovi(op) elseif p == "g" or p == "f" or p == "x" or p == "w" or p == "d" or p == "s" then -- These are handled in D/N/M/A. diff --git a/src/lj_emit_arm64.h b/src/lj_emit_arm64.h index 51d0c351..0967f6e4 100644 --- a/src/lj_emit_arm64.h +++ b/src/lj_emit_arm64.h @@ -66,6 +66,17 @@ static uint32_t emit_isfpk64(uint64_t n) return ~0u; } +static uint32_t emit_isfpmovi(uint64_t n) +{ + /* Is every byte either 0x00 or 0xff? */ + if ((n & U64x(01010101,01010101)) * 0xff != n) return 0; + /* Form 8-bit value by taking one bit from each byte. */ + n &= U64x(80402010,08040201); + n = (n * U64x(01010101,01010101)) >> 56; + /* Split into the format expected by movi. */ + return ((n & 0xe0) << 6) | 0x700 | (n & 0x1f); +} + /* -- Emit basic instructions --------------------------------------------- */ static void emit_dnma(ASMState *as, A64Ins ai, Reg rd, Reg rn, Reg rm, Reg ra) @@ -300,6 +311,9 @@ static void emit_loadk64(ASMState *as, Reg r, IRIns *ir) if (fpk != ~0u) { emit_d(as, A64I_FMOV_DI | A64F_FP8(fpk), (r & 31)); return; + } else if ((fpk = emit_isfpmovi(*k))) { + emit_d(as, A64I_MOVI_DI | (fpk << 5), (r & 31)); + return; } } ofs = glofs(as, k); diff --git a/src/lj_target_arm64.h b/src/lj_target_arm64.h index c34f1e59..8ed8851c 100644 --- a/src/lj_target_arm64.h +++ b/src/lj_target_arm64.h @@ -320,6 +320,7 @@ typedef enum A64Ins { A64I_FMOV_R_D = 0x9e660000, A64I_FMOV_D_R = 0x9e670000, A64I_FMOV_DI = 0x1e601000, + A64I_MOVI_DI = 0x2f000400, } A64Ins; #define A64I_BR_AUTH (LJ_ABI_PAUTH ? A64I_BRAAZ : A64I_BR)