<!DOCTYPE html>
<html data-lt-installed="true">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body style="padding-bottom: 1px;">
    <p>Hi, Sergey,</p>
    <p>thanks for the patch! LGTM with a minor comment(s).</p>
    <p>Sergey</p>
    <div class="moz-cite-prefix">On 6/5/26 15:49, Sergey Kaplun wrote:<br>
    </div>
    <blockquote type="cite"
      cite="mid:20260605124909.2709341-1-skaplun@tarantool.org">
      <pre wrap="" class="moz-quote-pre">From: Mike Pall <mike>

Thanks to Sergey Kaplun.

(cherry picked from commit 64b1f10835acc18bf8923adf248dce4894867882)

In the single-number VM, `ipairs_aux()` first adds the 1 to the given
number and only after casts it to an integer. This leads to results
different from Vanilla Lua 5.1 and inconsistent with JIT engine</pre>
    </blockquote>
    <p>s/Vanilla/PUC Rio/</p>
    <p>feel free to ignore</p>
    <blockquote type="cite"
      cite="mid:20260605124909.2709341-1-skaplun@tarantool.org">
      <pre wrap="" class="moz-quote-pre">
recording.

This patch fixes it by casting the value to an integer before addition.

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

Part of tarantool/tarantool#12480
---

Branch: <a class="moz-txt-link-freetext" href="https://github.com/tarantool/luajit/tree/skaplun/lj-1463-ipairs-aux-consistency">https://github.com/tarantool/luajit/tree/skaplun/lj-1463-ipairs-aux-consistency</a>
Related issues:
* <a class="moz-txt-link-freetext" href="https://github.com/LuaJIT/LuaJIT/issues/1463">https://github.com/LuaJIT/LuaJIT/issues/1463</a>
* <a class="moz-txt-link-freetext" href="https://github.com/tarantool/tarantool/issues/12480">https://github.com/tarantool/tarantool/issues/12480</a>

 src/vm_x64.dasc                               |  8 ++---
 src/vm_x86.dasc                               |  7 ++--
 .../lj-1463-ipairs-aux-consistency.test.lua   | 32 +++++++++++++++++++
 3 files changed, 38 insertions(+), 9 deletions(-)
 create mode 100644 test/tarantool-tests/lj-1463-ipairs-aux-consistency.test.lua

diff --git a/src/vm_x64.dasc b/src/vm_x64.dasc
index 6ac88d70..1bd3c855 100644
--- a/src/vm_x64.dasc
+++ b/src/vm_x64.dasc
@@ -1476,17 +1476,15 @@ static void build_subroutines(BuildCtx *ctx)
   |  checkint RA, ->fff_fallback
   |.else
   |  checknumtp [BASE+8], ->fff_fallback
-  |  movsd xmm0, qword [BASE+8]
+  |  cvttsd2si RAd, qword [BASE+8]
   |.endif
   |  mov PC, [BASE-8]
-  |.if DUALNUM
   |  add RAd, 1
+  |.if DUALNUM
   |  setint ITYPE, RA
   |  mov [BASE-16], ITYPE
   |.else
-  |  sseconst_1 xmm1, TMPR
-  |  addsd xmm0, xmm1
-  |  cvttsd2si RAd, xmm0
+  |  cvtsi2sd xmm0, RAd
   |  movsd qword [BASE-16], xmm0
   |.endif
   |  cmp RAd, <a class="moz-txt-link-freetext" href="TAB:RB">TAB:RB</a>->asize;  jae >2  // Not in array part?
diff --git a/src/vm_x86.dasc b/src/vm_x86.dasc
index d9234f3b..dcfb0a8b 100644
--- a/src/vm_x86.dasc
+++ b/src/vm_x86.dasc
@@ -1853,10 +1853,9 @@ static void build_subroutines(BuildCtx *ctx)
   |  mov dword [BASE-4], LJ_TISNUM
   |  mov dword [BASE-8], RD
   |.else
-  |  movsd xmm0, qword [BASE+8]
-  |  sseconst_1 xmm1, RBa
-  |  addsd xmm0, xmm1
-  |  cvttsd2si RD, xmm0
+  |  cvttsd2si RD, qword [BASE+8]
+  |  add RD, 1
+  |  cvtsi2sd xmm0, RD
   |  movsd qword [BASE-8], xmm0
   |.endif
   |  mov <a class="moz-txt-link-freetext" href="TAB:RB">TAB:RB</a>, [BASE]
diff --git a/test/tarantool-tests/lj-1463-ipairs-aux-consistency.test.lua b/test/tarantool-tests/lj-1463-ipairs-aux-consistency.test.lua
new file mode 100644
index 00000000..1da3a76e
--- /dev/null
+++ b/test/tarantool-tests/lj-1463-ipairs-aux-consistency.test.lua
@@ -0,0 +1,32 @@
+local tap = require('tap')
+
+-- The test file to demonstrate the inconsistent behaviour between
+-- the JIT compiler and the VM for the `ipairs_aux()` function on
+-- x86 and x86_64 arches.
+-- See also: <a class="moz-txt-link-freetext" href="https://github.com/LuaJIT/LuaJIT/issues/1463">https://github.com/LuaJIT/LuaJIT/issues/1463</a>.
+
+local test = tap.test('lj-1463-ipairs-aux-consistency'):skipcond({
+  ['Test requires JIT enabled'] = not jit.status(),
+})
+
+test:plan(4)
+
+jit.opt.start('hotloop=1')
+
+local ipairs_aux = ipairs({})
+
+local rkeys = {}
+local rvals = {}
+
+for i = 1, 4 do
+  local key, val = ipairs_aux({[0] = 0, [1] = 1}, -0.1)
+  rkeys[i] = key
+  rvals[i] = val
+end
+
+test:is(rkeys[1], 1, 'correct key result')
+test:is(rvals[1], 1, 'correct value result')
+test:samevalues(rkeys, 'consistent JIT and VM behaviour for keys')
+test:samevalues(rvals, 'consistent JIT and VM behaviour for values')
+
+test:done(true)
</pre>
    </blockquote>
  </body>
  <lt-container></lt-container>
</html>