[Tarantool-patches] [PATCH luajit] ARM64: Fix IR_SLOAD assembly.

Sergey Kaplun skaplun at tarantool.org
Wed May 14 14:56:56 MSK 2025


From: Mike Pall <mike>

Reported by Gate88.

(cherry picked from commit 6c4826f12c4d33b8b978004bc681eb1eef2be977)

The issue is in the case when IR SLOAD is unused on a trace, persists
only for typecheck, and has the `num` type. In this case, the `dest`
register is `RID_NONE`. Hence, the `fmov` instruction is emitted
unconditionally, where the destination register is `d0` (`RID_NONE &
31`). So, the value of this register is spoiled. If it holds any value
evaluated before and used after this SLOAD, it leads to incorrect
behaviour.

This patch adds the check that the register is in use before emitting
the instruction.

Sergey Kaplun:
* added the description and the test for the problem

Part of tarantool/tarantool#11278
---

Branch: https://github.com/tarantool/luajit/tree/skaplun/lj-903-arm64-unused-number-sload-typecheck
Related issues:
* https://github.com/LuaJIT/LuaJIT/issues/903
* https://github.com/tarantool/tarantool/issues/11278

 src/lj_asm_arm64.h                            |  2 +-
 ...m64-unused-number-sload-typecheck.test.lua | 45 +++++++++++++++++++
 2 files changed, 46 insertions(+), 1 deletion(-)
 create mode 100644 test/tarantool-tests/lj-903-arm64-unused-number-sload-typecheck.test.lua

diff --git a/src/lj_asm_arm64.h b/src/lj_asm_arm64.h
index 554bb60a..9b27473c 100644
--- a/src/lj_asm_arm64.h
+++ b/src/lj_asm_arm64.h
@@ -1177,7 +1177,7 @@ dotypecheck:
       tmp = ra_scratch(as, allow);
       rset_clear(allow, tmp);
     }
-    if (irt_isnum(t) && !(ir->op2 & IRSLOAD_CONVERT))
+    if (ra_hasreg(dest) && irt_isnum(t) && !(ir->op2 & IRSLOAD_CONVERT))
       emit_dn(as, A64I_FMOV_D_R, (dest & 31), tmp);
     /* Need type check, even if the load result is unused. */
     asm_guardcc(as, irt_isnum(t) ? CC_LS : CC_NE);
diff --git a/test/tarantool-tests/lj-903-arm64-unused-number-sload-typecheck.test.lua b/test/tarantool-tests/lj-903-arm64-unused-number-sload-typecheck.test.lua
new file mode 100644
index 00000000..748b88e2
--- /dev/null
+++ b/test/tarantool-tests/lj-903-arm64-unused-number-sload-typecheck.test.lua
@@ -0,0 +1,45 @@
+local tap = require('tap')
+-- Test file to demonstrate the incorrect JIT assembling of unused
+-- `IR_SLOAD` with number type on arm64.
+-- See also https://github.com/LuaJIT/LuaJIT/issue/903.
+local test = tap.test('lj-903-arm64-unused-number-sload-typecheck'):skipcond({
+  ['Test requires JIT enabled'] = not jit.status(),
+})
+
+test:plan(1)
+
+-- Just use any different numbers (but not integers to avoid
+-- integer IR type).
+local SLOT = 0.1
+local MARKER_VALUE = 4.2
+-- XXX: Special mapping to avoid folding and removing always true
+-- comparison.
+local anchor = {marker = MARKER_VALUE}
+
+-- Special function to inline on trace to generate SLOAD
+-- typecheck.
+local function sload_unused(x)
+  return x
+end
+
+-- The additional wrapper to use stackslots in the function.
+local function test_sload()
+  local sload = SLOT
+  for _ = 1, 4 do
+    -- This line should use the `d0` register.
+    local marker = anchor.marker - MARKER_VALUE
+    -- This generates unused IR_SLOAD with typecheck (number).
+    -- Before the patch, it occasionally overwrites the `d0`
+    -- register and causes the execution of the branch.
+    sload_unused(sload)
+    if marker ~= 0 then
+      return false
+    end
+  end
+  return true
+end
+
+jit.opt.start('hotloop=1')
+test:ok(test_sload(), 'correct SLOAD assembling')
+
+test:done(true)
-- 
2.49.0



More information about the Tarantool-patches mailing list